From fe5dc14f0002443a8f8a07e6b0a9cac601f5754c Mon Sep 17 00:00:00 2001 From: Neetu Jain Date: Thu, 7 May 2015 15:32:16 -0500 Subject: [PATCH 01/16] pass the environment variable --- SoftLayer/CLI/virt/ready.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SoftLayer/CLI/virt/ready.py b/SoftLayer/CLI/virt/ready.py index 1a1f05661..2ad1722a7 100644 --- a/SoftLayer/CLI/virt/ready.py +++ b/SoftLayer/CLI/virt/ready.py @@ -2,6 +2,7 @@ # :license: MIT, see LICENSE for more details. import SoftLayer +from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import helpers @@ -11,14 +12,13 @@ @click.command() @click.argument('identifier') @click.option('--wait', default=0, type=click.INT, help="Name of the image") +@environment.pass_env def cli(env, identifier, wait): """Check if a virtual server is ready.""" vsi = SoftLayer.VSManager(env.client) - vs_id = helpers.resolve_id(vsi.resolve_ids, identifier, 'VS') ready = vsi.wait_for_ready(vs_id, wait) - if ready: return "READY" else: From 2ead9e8038c4444061328f5a4b01e0c3d1a2602b Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Sun, 10 May 2015 22:46:00 -0500 Subject: [PATCH 02/16] Adds validation for vs/hardware create CLI commands --- SoftLayer/CLI/server/create.py | 19 +++++++++++++++++++ SoftLayer/CLI/virt/create.py | 8 ++++++++ tox.ini | 11 +++++------ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/SoftLayer/CLI/server/create.py b/SoftLayer/CLI/server/create.py index 7e2517a84..704f5b5b3 100644 --- a/SoftLayer/CLI/server/create.py +++ b/SoftLayer/CLI/server/create.py @@ -52,6 +52,8 @@ def cli(env, **args): """Order/create a dedicated server.""" template.update_with_template_args(args, list_args=['key']) + _validate_args(args) + mgr = SoftLayer.HardwareManager(env.client) # Get the SSH keys @@ -125,3 +127,20 @@ def cli(env, **args): output = table return output + + +def _validate_args(args): + """Raises an ArgumentError if the given arguments are not valid.""" + missing = [] + for arg in ['size', + 'datacenter', + 'os', + 'port_speed', + 'hostname', + 'domain']: + if not args.get(arg): + missing.append(arg) + + if missing: + raise exceptions.ArgumentError('Missing required options: %s' + % ', '.join(missing)) diff --git a/SoftLayer/CLI/virt/create.py b/SoftLayer/CLI/virt/create.py index 6f8ab6fa4..db09191b4 100644 --- a/SoftLayer/CLI/virt/create.py +++ b/SoftLayer/CLI/virt/create.py @@ -154,6 +154,14 @@ def cli(env, **args): def _validate_args(args): """Raises an ArgumentError if the given arguments are not valid.""" + missing = [] + for arg in ['cpu', 'memory', 'hostname', 'domain']: + if not args.get(arg): + missing.append(arg) + + if missing: + raise exceptions.ArgumentError('Missing required options: %s' + % ', '.join(missing)) if all([args['userdata'], args['userfile']]): raise exceptions.ArgumentError( diff --git a/tox.ini b/tox.ini index cc18582c9..1cb1903b3 100644 --- a/tox.ini +++ b/tox.ini @@ -24,13 +24,12 @@ commands = pylint SoftLayer \ -r n \ # Don't show the long report --ignore=tests,fixtures \ - -d too-many-locals \ # Too many local variables - -d star-args \ # Used * or ** magic - -d I0011 \ # Locally Disabling + -d too-many-locals \ + -d star-args \ + -d locally-disabled \ --max-args=20 \ - --max-branches=40 \ - --max-statements=87 \ - --max-returns=8 \ + --max-branches=20 \ + --max-statements=60 \ --min-public-methods=0 \ --min-similarity-lines=30 pylint SoftLayer/testing/fixtures \ From 0537c765f967b97dea814119d99206a4ad45000f Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Thu, 14 May 2015 17:46:20 -0500 Subject: [PATCH 03/16] Make test_no_hostname a bit more lenient --- SoftLayer/tests/functional_tests.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/SoftLayer/tests/functional_tests.py b/SoftLayer/tests/functional_tests.py index 53abe6eb9..69972319c 100644 --- a/SoftLayer/tests/functional_tests.py +++ b/SoftLayer/tests/functional_tests.py @@ -47,12 +47,10 @@ def test_no_hostname(self): endpoint_url='http://notvalidsoftlayer.com', ) transport(request) - except SoftLayer.SoftLayerAPIError as ex: - self.assertIn('not known', str(ex)) - self.assertIn('not known', ex.faultString) + except SoftLayer.TransportError as ex: self.assertEqual(ex.faultCode, 0) else: - self.fail('No Exception Raised') + self.fail('Transport Error Exception Not Raised') class AuthedUser(FunctionalTest): From 4fc69fc2a1f2c7170dd84725745c0a2d4f3f1290 Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Thu, 14 May 2015 18:18:09 -0500 Subject: [PATCH 04/16] Open the readme file as utf-8 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 087610c3a..5d4c52171 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ DESCRIPTION = "A library for SoftLayer's API" if os.path.exists('README.rst'): - with open('README.rst') as readme_file: + with open('README.rst', 'r', 'utf-8') as readme_file: LONG_DESCRIPTION = readme_file.read() else: LONG_DESCRIPTION = DESCRIPTION From 51e8721b1667df87de7bf472ab48fcb51c3837bc Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Thu, 14 May 2015 18:23:26 -0500 Subject: [PATCH 05/16] Adds missing codec import --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 5d4c52171..1c811f4ad 100644 --- a/setup.py +++ b/setup.py @@ -2,6 +2,8 @@ import sys import os +from codecs import open + try: from setuptools import setup, find_packages except ImportError: From aafd94726d8e58bf7b47255b32ad9edc2fd05c1f Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Mon, 1 Jun 2015 09:59:32 -0500 Subject: [PATCH 06/16] Adds a hacky setting of the locale --- SoftLayer/CLI/core.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/SoftLayer/CLI/core.py b/SoftLayer/CLI/core.py index a68395225..fc64ae481 100644 --- a/SoftLayer/CLI/core.py +++ b/SoftLayer/CLI/core.py @@ -34,6 +34,22 @@ if sys.stdout.isatty(): DEFAULT_FORMAT = 'table' +# Attempt to set the locale for the user if the default encoding is +# ascii. More information here: +# http://click.pocoo.org/4/python3/#python-3-surrogate-handling +import codecs +import locale +try: + ENC = codecs.lookup(locale.getpreferredencoding()).name +except Exception: + ENC = 'ascii' + +if ENC == 'ascii': + try: + locale.setlocale(locale.LC_ALL, 'C.UTF-8') + except Exception: + pass + class CommandLoader(click.MultiCommand): """Loads module for click.""" From 29a1ee9fef7313fa28f8e99287e63bfc75ab0c02 Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Mon, 1 Jun 2015 11:25:37 -0500 Subject: [PATCH 07/16] Passes the LANG env var from tox to the tests --- SoftLayer/CLI/core.py | 17 +---------------- tox.ini | 4 ++++ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/SoftLayer/CLI/core.py b/SoftLayer/CLI/core.py index fc64ae481..066b2173e 100644 --- a/SoftLayer/CLI/core.py +++ b/SoftLayer/CLI/core.py @@ -34,22 +34,6 @@ if sys.stdout.isatty(): DEFAULT_FORMAT = 'table' -# Attempt to set the locale for the user if the default encoding is -# ascii. More information here: -# http://click.pocoo.org/4/python3/#python-3-surrogate-handling -import codecs -import locale -try: - ENC = codecs.lookup(locale.getpreferredencoding()).name -except Exception: - ENC = 'ascii' - -if ENC == 'ascii': - try: - locale.setlocale(locale.LC_ALL, 'C.UTF-8') - except Exception: - pass - class CommandLoader(click.MultiCommand): """Loads module for click.""" @@ -192,6 +176,7 @@ def output_result(ctx, result, timings=False, **kwargs): def main(): """Main program. Catches several common errors and displays them nicely.""" exit_status = 0 + try: cli.main() except SoftLayer.SoftLayerAPIError as ex: diff --git a/tox.ini b/tox.ini index cc18582c9..61b3626d5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,10 @@ [tox] envlist = py26,py27,py33,py34,pypy,analysis,coverage + [testenv] +setenv = + LANG = {env:LANG:C.UTF-8} + deps = -r{toxinidir}/tools/test-requirements.txt commands = nosetests From 7d4bace82679e6dbba4e1c267c10f237e3c425ef Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Mon, 1 Jun 2015 11:55:16 -0500 Subject: [PATCH 08/16] Ingore a mistaken pylint error --- SoftLayer/CLI/environment.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SoftLayer/CLI/environment.py b/SoftLayer/CLI/environment.py index f58005900..ab3d1dbe0 100644 --- a/SoftLayer/CLI/environment.py +++ b/SoftLayer/CLI/environment.py @@ -16,6 +16,9 @@ # pylint: disable=too-many-instance-attributes, invalid-name, no-self-use +# Calling pkg_resources.iter_entry_points shows a false-positive +# pylint: disable=no-member + class Environment(object): """Provides access to the current CLI environment.""" From 1c7efebc967d3326cf935ea0df3d6f5da8f9b44a Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Thu, 14 May 2015 18:04:19 -0500 Subject: [PATCH 09/16] Two Bug Fixes Fixes key error when vlans don't have datacenters Gives a better error for when a price can't be found for iscsi. Resolves #549 and #552 --- SoftLayer/CLI/vlan/list.py | 3 ++- SoftLayer/managers/iscsi.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/SoftLayer/CLI/vlan/list.py b/SoftLayer/CLI/vlan/list.py index e2b8d2670..cc7beef84 100644 --- a/SoftLayer/CLI/vlan/list.py +++ b/SoftLayer/CLI/vlan/list.py @@ -4,6 +4,7 @@ import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting +from SoftLayer import utils import click @@ -43,7 +44,7 @@ def cli(env, sortby, datacenter, number, name): table.add_row([ vlan['id'], vlan['vlanNumber'], - vlan['primaryRouter']['datacenter']['name'], + utils.lookup(vlan, 'primaryRouter', 'datacenter', 'name'), vlan.get('name') or formatting.blank(), vlan['totalPrimaryIpAddressCount'], len(vlan['hardware']), diff --git a/SoftLayer/managers/iscsi.py b/SoftLayer/managers/iscsi.py index 221cafd46..9c07a15da 100644 --- a/SoftLayer/managers/iscsi.py +++ b/SoftLayer/managers/iscsi.py @@ -5,6 +5,7 @@ :license: MIT, see LICENSE for more details. """ +from SoftLayer import exceptions from SoftLayer import utils @@ -28,8 +29,13 @@ def _find_item_prices(self, size, categorycode=''): 'categories': { 'categoryCode': {'operation': categorycode} }}}) - item_price = item_prices[0]['prices'][0]['id'] - return item_price + + for item_price in item_prices: + for price in item_price['prices']: + return price['id'] + + raise exceptions.SoftLayerError( + "Could not find a valid price with for the given size") def _build_order(self, item_price, location): """Returns a dict appropriate for Product_Order::placeOrder().""" From 4085123e0239a272ca729a43f3f888267add974e Mon Sep 17 00:00:00 2001 From: underscorephil Date: Tue, 2 Jun 2015 13:49:38 -0500 Subject: [PATCH 10/16] add requests min version 2.7.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1c811f4ad..2c2ab46f4 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ 'six >= 1.7.0', 'prettytable >= 0.7.0', 'click', - 'requests', + 'requests >= 2.7.0', ] if sys.version_info < (2, 7): From b69b0b8aa4804bd73a7fd5adedd4dfe935464703 Mon Sep 17 00:00:00 2001 From: Pritam Baral Date: Fri, 5 Jun 2015 22:49:06 +0530 Subject: [PATCH 11/16] Fix typo in docs --- SoftLayer/managers/vs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py index c7f9fbcfb..ebd523f45 100644 --- a/SoftLayer/managers/vs.py +++ b/SoftLayer/managers/vs.py @@ -449,7 +449,7 @@ def create_instance(self, **kwargs): incur a fee on your account. :param int public_vlan: The ID of the public VLAN on which you want this VS placed. - :param int private_vlan: The ID of the public VLAN on which you want + :param int private_vlan: The ID of the private VLAN on which you want this VS placed. :param list disks: A list of disk capacities for this server. :param string post_uri: The URI of the post-install script to run From 79e2c8d9cff8cf2f16a4b9c33ed3fd800ac3b770 Mon Sep 17 00:00:00 2001 From: Neetu Jain Date: Thu, 14 May 2015 10:41:18 -0500 Subject: [PATCH 12/16] correct arguement name --- SoftLayer/CLI/loadbal/service_add.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SoftLayer/CLI/loadbal/service_add.py b/SoftLayer/CLI/loadbal/service_add.py index 5a9fa982a..0b0d0da9f 100644 --- a/SoftLayer/CLI/loadbal/service_add.py +++ b/SoftLayer/CLI/loadbal/service_add.py @@ -24,7 +24,7 @@ @click.option('--healthcheck-type', required=True, help="The health check type") -@click.option('--ip-address', '--ip', +@click.option('--ip-address', required=True, help="The IP of the service") @environment.pass_env From 97e0d925588a3b5ad7f71ddba5a5d0b87906069b Mon Sep 17 00:00:00 2001 From: Neetu Jain Date: Thu, 14 May 2015 10:47:19 -0500 Subject: [PATCH 13/16] change argument name --- SoftLayer/CLI/loadbal/service_add.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/SoftLayer/CLI/loadbal/service_add.py b/SoftLayer/CLI/loadbal/service_add.py index 0b0d0da9f..9b84c8505 100644 --- a/SoftLayer/CLI/loadbal/service_add.py +++ b/SoftLayer/CLI/loadbal/service_add.py @@ -24,11 +24,11 @@ @click.option('--healthcheck-type', required=True, help="The health check type") -@click.option('--ip-address', +@click.option('--ip', required=True, help="The IP of the service") @environment.pass_env -def cli(env, identifier, enabled, port, weight, healthcheck_type, ip_address): +def cli(env, identifier, enabled, port, weight, healthcheck_type, ip): """Adds a new load balancer service.""" mgr = SoftLayer.LoadBalancerManager(env.client) @@ -37,10 +37,11 @@ def cli(env, identifier, enabled, port, weight, healthcheck_type, ip_address): # check if the IP is valid ip_address_id = None - if ip_address: + if ip: ip_service = env.client['Network_Subnet_IpAddress'] - ip_record = ip_service.getByIpAddress(ip_address) - ip_address_id = ip_record['id'] + ip_record = ip_service.getByIpAddress(ip) + if len(ip_record)>0: + ip_address_id = ip_record['id'] mgr.add_service(loadbal_id, group_id, From bdff0e2cc984357ae573a4fc6cf778445c5a06e0 Mon Sep 17 00:00:00 2001 From: Neetu Jain Date: Tue, 26 May 2015 13:27:37 -0500 Subject: [PATCH 14/16] cleaning --- SoftLayer/CLI/loadbal/service_add.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SoftLayer/CLI/loadbal/service_add.py b/SoftLayer/CLI/loadbal/service_add.py index 9b84c8505..735aee75a 100644 --- a/SoftLayer/CLI/loadbal/service_add.py +++ b/SoftLayer/CLI/loadbal/service_add.py @@ -40,7 +40,7 @@ def cli(env, identifier, enabled, port, weight, healthcheck_type, ip): if ip: ip_service = env.client['Network_Subnet_IpAddress'] ip_record = ip_service.getByIpAddress(ip) - if len(ip_record)>0: + if len(ip_record) > 0: ip_address_id = ip_record['id'] mgr.add_service(loadbal_id, From b4484ef88ac3ae2cecb4ef8539a1dd20af8c1b71 Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Fri, 5 Jun 2015 21:11:25 -0500 Subject: [PATCH 15/16] Fix small style issue --- SoftLayer/CLI/loadbal/service_add.py | 10 +++++----- SoftLayer/testing/xmlrpc.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/SoftLayer/CLI/loadbal/service_add.py b/SoftLayer/CLI/loadbal/service_add.py index 735aee75a..a9fdc04d9 100644 --- a/SoftLayer/CLI/loadbal/service_add.py +++ b/SoftLayer/CLI/loadbal/service_add.py @@ -24,11 +24,11 @@ @click.option('--healthcheck-type', required=True, help="The health check type") -@click.option('--ip', +@click.option('--ip-address', required=True, - help="The IP of the service") + help="The IP address of the service") @environment.pass_env -def cli(env, identifier, enabled, port, weight, healthcheck_type, ip): +def cli(env, identifier, enabled, port, weight, healthcheck_type, ip_address): """Adds a new load balancer service.""" mgr = SoftLayer.LoadBalancerManager(env.client) @@ -37,9 +37,9 @@ def cli(env, identifier, enabled, port, weight, healthcheck_type, ip): # check if the IP is valid ip_address_id = None - if ip: + if ip_address: ip_service = env.client['Network_Subnet_IpAddress'] - ip_record = ip_service.getByIpAddress(ip) + ip_record = ip_service.getByIpAddress(ip_address) if len(ip_record) > 0: ip_address_id = ip_record['id'] diff --git a/SoftLayer/testing/xmlrpc.py b/SoftLayer/testing/xmlrpc.py index 920f86e17..47272616e 100644 --- a/SoftLayer/testing/xmlrpc.py +++ b/SoftLayer/testing/xmlrpc.py @@ -92,6 +92,6 @@ def create_test_server(transport, host='localhost', port=0): """Create a test XML-RPC server in a new thread.""" server = TestServer(transport, (host, port), TestHandler) thread = threading.Thread(target=server.serve_forever, - kwargs={'poll_interval': 0.05}) + kwargs={'poll_interval': 0.01}) thread.start() return server From 26562d3af794af4c8f25e3db79f94898fd8fa202 Mon Sep 17 00:00:00 2001 From: Kevin McDonald Date: Mon, 15 Jun 2015 17:24:27 -0500 Subject: [PATCH 16/16] Version bump to v4.0.3 --- CHANGELOG | 10 ++++++++++ SoftLayer/consts.py | 2 +- docs/conf.py | 4 ++-- setup.py | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9e49ae9cf..3397760f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +4.0.3 + + * Fixes bug with `slcli vs ready` command + + * Fixes bug with `slcli loadbal service-add` command + + * Fixes bug with `slcli vlan list` with vlans that don't have a datacenter + + * Improves validation of virtual server and hardware create commands + 4.0.2 * Fixes a bug that breaks user confirmation prompts diff --git a/SoftLayer/consts.py b/SoftLayer/consts.py index e0b285363..674f04608 100644 --- a/SoftLayer/consts.py +++ b/SoftLayer/consts.py @@ -5,7 +5,7 @@ :license: MIT, see LICENSE for more details. """ -VERSION = 'v4.0.2' +VERSION = 'v4.0.3' API_PUBLIC_ENDPOINT = 'https://api.softlayer.com/xmlrpc/v3.1/' API_PRIVATE_ENDPOINT = 'https://api.service.softlayer.com/xmlrpc/v3.1/' API_PUBLIC_ENDPOINT_REST = 'https://api.softlayer.com/rest/v3.1/' diff --git a/docs/conf.py b/docs/conf.py index 55abd0f3f..0472001bc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -55,9 +55,9 @@ # built documents. # # The short X.Y version. -version = '4.0.2' +version = '4.0.3' # The full version, including alpha/beta/rc tags. -release = '4.0.2' +release = '4.0.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 2c2ab46f4..88132dbe8 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name='SoftLayer', - version='4.0.2', + version='4.0.3', description=DESCRIPTION, long_description=LONG_DESCRIPTION, author='SoftLayer Technologies, Inc.',