Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a simple command that knows how to download the dcos client. #1166

Merged
merged 6 commits into from
Oct 29, 2016

Conversation

brendandburns
Copy link
Member

@rgardler @ahowe

This is my first PR to the Azure CLI, please advise if I'm doing it wrong...

Copy link
Member

@tjprescott tjprescott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple comments. You also need to address the pylint errors. You can use 'scripts/lintall' locally to see the results before you open your PR since the CI can be slow. I would recommend @derekbekoe take a look at the PR as well, since it deals with installing things.

install_location = '/usr/local/bin/dcos'
file_url = 'https://downloads.dcos.io/binaries/cli/darwin/x86-64/dcos-1.8/dcos'
else:
logger.error('unknown system: %s' % system)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably raise a CLIError. Otherwise it will attempt to install to "".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like raise CLIError("Unknown system type '{}'".format(system))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

logger.error('unknown system: %s' % system)

user_location = input('dcos binary install location [%s]:' % install_location)
if len(user_location) == 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if not len(user_location): ?

Copy link
Member

@derekbekoe derekbekoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main comments are about the use of install_location.
It should be a command line argument (not interactive) and you can use the _params.py file to set the defaults for the user when the command line argument is registered in the CLI.

install_location = '/usr/local/bin/dcos'
file_url = 'https://downloads.dcos.io/binaries/cli/darwin/x86-64/dcos-1.8/dcos'
else:
logger.error('unknown system: %s' % system)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like raise CLIError("Unknown system type '{}'".format(system))

@@ -59,6 +61,33 @@ def dcos_browse(name, resource_group_name):

return

def dcos_install():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

install_location should be an optional argument to this function so it can be specified on the command line with acs dcos install --install-location ...

i.e.

def dcos_install(install_location=None):
   ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can the acs/_params.py file to define what install_location should be.
This means that when this method is called, the right install_location will be passed in.

So for example, you can remove the install locations that have been defined here and add the following lines to the acs/_params.py file:

import platform

def _get_default_install_location():
    system = platform.system()
    if system == 'Windows':
        return 'C:\Program Files\dcos.exe'
    if system == 'Linux':
        return '/usr/local/bin/dcos'
    if system == 'Darwin':
        return '/usr/local/bin/dcos'
    else:
        return None

register_cli_argument('acs dcos install', 'install_location', options_list=('--install-location',),
                      default=_get_default_install_location())

This means when the user runs az acs dcos install -h, they'll see:

Arguments
    --install-location                                        : Default: /usr/local/bin/dcos.

with the default being computed automatically.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

else:
logger.error('unknown system: %s' % system)

user_location = input('dcos binary install location [%s]:' % install_location)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our convention is to not take user input interactively like this.
It makes it difficult to set the install_location with a script.
I'd suggest removing this and adding an optional argument install_location like I've described above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

user_location = install_location

logger.info("Downloading client to %s\n" % user_location)
urllib.request.urlretrieve(file_url, user_location)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should wrap this in a try/except as it can raise an IOError if the connection cannot be made (https://docs.python.org/2/library/urllib.html#urllib.urlopen).

e.g.

try:
    urllib.request.urlretrieve(file_url, user_location)
except IOError:
    raise CLIError('Connection error attempting to download client')

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

if len(user_location) == 0:
user_location = install_location

logger.info("Downloading client to %s\n" % user_location)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need the '\n' in the log message

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

cli_command('acs dcos browse', dcos_browse)
cli_command('acs dcos install', dcos_install)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing new line that pylint was complaining about.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@derekbekoe
Copy link
Member

@brendandburns As an FYI, to prevent the 'cla-required' label from being applied, visit aka.ms/azuregithub to link your GitHub account.

@derekbekoe
Copy link
Member

Also, why is the command acs dcos install when it actually downloads the client only?

@brendandburns
Copy link
Member Author

@derekbekoe thanks for the fast review. addressed all coments, pylint is clean now.

Changed to acs dcos install-cli

Please take another look.

Thanks!
--brendan

Copy link
Member

@derekbekoe derekbekoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those changes.
I've added a few more comments with a suggestion for how to fix the CI error.

from azure.cli.core.commands import register_cli_argument
from azure.cli.core.commands.parameters import (
name_type,
resource_group_name_type)
from azure.cli.core._util import CLIError

def _get_default_install_location(exeName):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python convention is snake casing so exe_name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

elif system == 'Linux' or system == 'Darwin':
install_location = '/usr/local/bin/{}'.format(exeName)
else:
raise CLIError('Proxy server ({}) does not exist on the cluster.'.format(system))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, should just set install_location=None.
It would be too soon to raise a CLIError at this stage as it'll cause the 'acs' module to not load.

Then, in the dcos_install_cli() method, you'd have a check for:

def dcos_install_cli(install_location=None):
    if not install_location:
        raise CLIError("No install location specified and it could not be determined from the current platform '{}'".format(system))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

from azure.cli.core.commands import register_cli_argument
from azure.cli.core.commands.parameters import (
name_type,
resource_group_name_type)
from azure.cli.core._util import CLIError
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After making my other suggested change, this import would be unused so can be removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

import random
import string
import urllib.request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI build is failing because of this.
urllib.request is defined in Python 3 but not Python 2.

This should fix this:
from six.moves.urllib.request import urlretrieve
from: https://pythonhosted.org/six/#module-six.moves.urllib.request

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

def _get_default_install_location(exeName):
system = platform.system()
if system == 'Windows':
install_location = 'C:\\Program Files\\{}.exe'.format(exeName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use os.environ['ProgramFiles']

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x64 vs x86? And please verify behavior with both 64bit/32bit python on windows...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, os.environ.get('ProgramFiles') instead as then you don't get a KeyError from the dict and can check for None on the result and not set install location if you get none back from the call to os.environ.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

file_url = ''
system = platform.system()
if system == 'Windows':
file_url = 'https://downloads.dcos.io/binaries/cli/windows/x86-64/dcos-1.8/dcos.exe'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to add a command help to call out the version of 1.8, or expose the version as parameter people can pick; otherwise people will be surprised that we don't install newer stable one after some period.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@brendandburns
Copy link
Member Author

Comments addressed, please re-check.

Thanks!
--brendan

@yugangw-msft
Copy link
Contributor

@brendandburns, to merge the PR, you will need to suppress the pylint error of "E: 9, 0: Unable to import 'six.moves.urllib.request' (import-error)". I assume you favor this lib over the requests package for the simplicity reason

@brendandburns
Copy link
Member Author

@yugangw-msft do I need to worry about adding that to a dependency list somewhere?

THanks
--brendan

@yugangw-msft
Copy link
Contributor

yugangw-msft commented Oct 28, 2016

@brendandburns, six is already brought in through the common dependency of azure-cli-core. Still, I think you should update acs command package's setup.py with this dependency. The pylint error might still surface for you to suppress
//cc:@derekbekoe

@derekbekoe
Copy link
Member

@brendandburns: As @yugangw-msft mentioned, add #pylint: disable=import-error after the six import that's failing the pylint check.
Also, add six to the DEPENDENCIES section of the setup.py file that Yugang referenced.

@brendandburns
Copy link
Member Author

Done, please take another look.

Thanks!
--brendan

import random
import string
#pylint: disable=import-error
from six.moves.urllib.request import urlretrieve
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably should add the suppression at the same line ; otherwise the suppression will apply on all the imports in the rest of the file

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@brendandburns
Copy link
Member Author

Comments addressed, please take another look.

Thanks!
--brendan

@yugangw-msft yugangw-msft merged commit 3ff036b into Azure:master Oct 29, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants