[Python-modules-commits] [python-softlayer] 01/01: Imported Upstream version 5.2.7

Scott Kitterman kitterman at moszumanska.debian.org
Mon Jun 26 13:33:02 UTC 2017


This is an automated email from the git hooks/post-receive script.

kitterman pushed a commit to branch upstream
in repository python-softlayer.

commit d767b0bec86480329ddb51902630d0fa0be9f7ed
Author: Scott Kitterman <scott at kitterman.com>
Date:   Mon Jun 26 09:17:34 2017 -0400

    Imported Upstream version 5.2.7
---
 .travis.yml                                        |    2 +
 CHANGELOG.md                                       |   60 +-
 README.rst                                         |    4 +-
 RELEASE.md                                         |   12 +
 SoftLayer/CLI/block/detail.py                      |   11 +-
 SoftLayer/CLI/block/duplicate.py                   |   83 +
 SoftLayer/CLI/block/order.py                       |   15 +-
 SoftLayer/CLI/block/replication/locations.py       |   49 +
 SoftLayer/CLI/block/replication/order.py           |    2 +-
 SoftLayer/CLI/block/replication/partners.py        |   57 +
 SoftLayer/CLI/core.py                              |    2 +-
 SoftLayer/CLI/custom_types.py                      |   32 +
 SoftLayer/CLI/dns/record_list.py                   |   14 +-
 SoftLayer/CLI/file/detail.py                       |   14 +-
 SoftLayer/CLI/file/duplicate.py                    |   79 +
 SoftLayer/CLI/file/order.py                        |   23 +-
 SoftLayer/CLI/file/replication/locations.py        |   49 +
 SoftLayer/CLI/file/replication/order.py            |    2 +-
 SoftLayer/CLI/file/replication/partners.py         |   60 +
 SoftLayer/CLI/formatting.py                        |    4 +-
 SoftLayer/CLI/iscsi/__init__.py                    |    1 -
 SoftLayer/CLI/iscsi/cancel.py                      |   30 -
 SoftLayer/CLI/iscsi/create.py                      |   23 -
 SoftLayer/CLI/iscsi/detail.py                      |   54 -
 SoftLayer/CLI/iscsi/list.py                        |   43 -
 SoftLayer/CLI/loadbal/detail.py                    |   97 +-
 SoftLayer/CLI/routes.py                            |   31 +-
 SoftLayer/CLI/snapshot/__init__.py                 |    1 -
 SoftLayer/CLI/snapshot/cancel.py                   |   21 -
 SoftLayer/CLI/snapshot/create.py                   |   20 -
 SoftLayer/CLI/snapshot/create_space.py             |   22 -
 SoftLayer/CLI/snapshot/list.py                     |   37 -
 SoftLayer/CLI/snapshot/restore_volume.py           |   22 -
 SoftLayer/CLI/template.py                          |    2 +
 SoftLayer/CLI/vpn/__init__.py                      |    1 +
 SoftLayer/CLI/vpn/ipsec/__init__.py                |    1 +
 SoftLayer/CLI/vpn/ipsec/configure.py               |   31 +
 SoftLayer/CLI/vpn/ipsec/detail.py                  |  196 +++
 SoftLayer/CLI/vpn/ipsec/list.py                    |   31 +
 SoftLayer/CLI/vpn/ipsec/subnet/__init__.py         |    1 +
 SoftLayer/CLI/vpn/ipsec/subnet/add.py              |   81 +
 SoftLayer/CLI/vpn/ipsec/subnet/remove.py           |   51 +
 SoftLayer/CLI/vpn/ipsec/translation/__init__.py    |    1 +
 SoftLayer/CLI/vpn/ipsec/translation/add.py         |   44 +
 SoftLayer/CLI/vpn/ipsec/translation/remove.py      |   33 +
 SoftLayer/CLI/vpn/ipsec/translation/update.py      |   48 +
 SoftLayer/CLI/vpn/ipsec/update.py                  |  102 ++
 SoftLayer/consts.py                                |    2 +-
 .../fixtures/SoftLayer_Metric_Tracking_Object.py   |    1 -
 SoftLayer/fixtures/SoftLayer_Network_Storage.py    |   78 +-
 .../fixtures/SoftLayer_Network_Storage_Iscsi.py    |   68 -
 SoftLayer/fixtures/SoftLayer_Product_Package.py    |  133 ++
 SoftLayer/fixtures/SoftLayer_User_Customer.py      |    1 -
 SoftLayer/managers/__init__.py                     |    4 +-
 SoftLayer/managers/block.py                        |   66 +-
 SoftLayer/managers/file.py                         |   91 +-
 SoftLayer/managers/hardware.py                     |   10 +-
 SoftLayer/managers/ipsec.py                        |  290 ++++
 SoftLayer/managers/iscsi.py                        |  174 --
 SoftLayer/managers/object_storage.py               |   21 +-
 SoftLayer/managers/ordering.py                     |   22 +
 SoftLayer/managers/storage_utils.py                |  445 ++++-
 SoftLayer/managers/vs.py                           |   11 +-
 SoftLayer/testing/xmlrpc.py                        |    2 +-
 docs/api/managers/ipsec.rst                        |    5 +
 docs/api/managers/iscsi.rst                        |    5 -
 docs/cli.rst                                       |   99 +-
 docs/cli/ipsec.rst                                 |  220 +++
 docs/conf.py                                       |    6 +-
 setup.py                                           |    3 +-
 tests/CLI/custom_types_tests.py                    |   31 +
 tests/CLI/modules/block_tests.py                   |  125 +-
 tests/CLI/modules/file_tests.py                    |  146 +-
 tests/CLI/modules/ipsec_tests.py                   |  513 ++++++
 tests/managers/block_tests.py                      |  395 ++++-
 tests/managers/file_tests.py                       |  339 +++-
 tests/managers/ipsec_tests.py                      |  302 ++++
 tests/managers/iscsi_tests.py                      |  122 --
 tests/managers/object_storage_tests.py             |    9 +
 tests/managers/ordering_tests.py                   |   14 +
 tests/managers/storage_utils_tests.py              | 1715 ++++++++++++++++++++
 tox.ini                                            |    9 +-
 82 files changed, 6198 insertions(+), 878 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 6a26a77..fdb7114 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,8 @@ matrix:
       env: TOX_ENV=py34
     - python: "3.5"
       env: TOX_ENV=py35
+    - python: "3.6"
+      env: TOX_ENV=py36
     - python: "pypy"
       env: TOX_ENV=pypy
     - python: "2.7"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a899f1..e3433e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,67 @@
 # Change Log
 
-## [Unreleased]
- - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.1...HEAD
+## [5.2.7] - 2017-06-22
+ - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.6...v5.2.7
+
+Adds support for duplicating block and file storage volumes. Only works on Storage as a Service volumes (Volumes that support encryption at rest). 
+
+#### Added to CLI
+ * [block|file] volume-duplicate
+
+## [5.2.6] - 2017-05-22
+ - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.5...v5.2.6
+ 
+#### Added To CLI
+* ipsec list
+* ipsec detail
+* ipsec configure
+* ipsec update
+* ipsec subnet-add
+* ipsec subnet-remove
+* ipsec translation-add
+* ipsec translation-remove
+* ipsec translation-update
+
+
+## [5.2.5] - 2017-05-05
+ - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.1...v5.2.5
+ 
+The SoftLayer_Network_Storage::storageTierLevel relational property changed in https://softlayer.github.io/release_notes/20170503/ , this version fixes problems caused by that.
+
+### Changed
+ - https://github.com/softlayer/softlayer-python/issues/818
+ - https://github.com/softlayer/softlayer-python/pull/817
+ 
+## [5.2.4] - 2017-04-06
+ - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.3...v5.2.4
+ 
+### Changed
+Removed some debug code that was accidently added in the pypi release
+ 
+## [5.2.3] - 2017-04-05
+ - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.2...v5.2.3
+
+### Added
+ - Adds Python 3.6 support
+
+### Changed
+ - CLI+API: Removes the iSCSI manager and commands
+ - API: Fixes hardware order failing to find a single bare metal fast provision package to use
+
+## [5.2.2] - 2017-02-24
+ - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.1...v5.2.2
 
 ### Added
+ - Adds release process documentation
+ - CLI: Displays NFS mount point for volumes in volume list and detail commands
+ - CLI+API: Enables `slcli file` and `block` storage commands to order tier 10 endurance storage and replica
 
 ### Changed
+ - Updates docs to replace `sl` command with `slcli`
+ - CLI: Removes requirement to have `--os-type` provided for file storage ordering
+ - API: Fixes block storage ordering to handle size provided properly
+ - CLI: Fixes load balancer detail output so that JSON output is sane
+ - API: Includes check if object storage endpoints were provided by the API before trying to add them to the endpoints returned by `list_endpoints`
 
 ## [5.2.1] - 2016-10-4
  - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.0...v5.2.1
diff --git a/README.rst b/README.rst
index 8d46772..dba9d7f 100644
--- a/README.rst
+++ b/README.rst
@@ -9,8 +9,8 @@ SoftLayer API Python Client
 .. image:: https://badge.fury.io/py/SoftLayer.svg
     :target: http://badge.fury.io/py/SoftLayer
 
-.. image:: https://coveralls.io/repos/softlayer/softlayer-python/badge.svg
-    :target: https://coveralls.io/r/softlayer/softlayer-python
+.. image:: https://coveralls.io/repos/github/softlayer/softlayer-python/badge.svg?branch=master
+    :target: https://coveralls.io/github/softlayer/softlayer-python?branch=master
 
 
 This library provides a simple Python client to interact with `SoftLayer's
diff --git a/RELEASE.md b/RELEASE.md
new file mode 100644
index 0000000..d0a7712
--- /dev/null
+++ b/RELEASE.md
@@ -0,0 +1,12 @@
+# Release steps
+
+* Update version constants (find them by running `git grep [VERSION_NUMBER]`)
+* Create changelog entry (edit CHANGELOG.md with a one-liner for each closed issue going in the release)
+* Commit and push changes to master with the message: "Version Bump to v[VERSION_NUMBER]"
+* Push tag and PyPi `fab release:[VERSION_NUMBER]`. Before you do this, make sure you have fabric installed (`pip install fabric`) and also make sure that you have pip set up with your PyPi user credentials. The easiest way to do that is to create a file at `~/.pypirc` with the following contents:
+
+ ```
+[server-login]
+username:YOUR_USERNAME
+password:YOUR_PASSWORD
+ ```
diff --git a/SoftLayer/CLI/block/detail.py b/SoftLayer/CLI/block/detail.py
index 51a1fbd..b8ba8be 100644
--- a/SoftLayer/CLI/block/detail.py
+++ b/SoftLayer/CLI/block/detail.py
@@ -34,7 +34,7 @@ def cli(env, volume_id):
     if block_volume.get('storageTierLevel'):
         table.add_row([
             'Endurance Tier',
-            block_volume['storageTierLevel']['description'],
+            block_volume['storageTierLevel'],
         ])
 
     table.add_row([
@@ -99,4 +99,13 @@ def cli(env, volume_id):
             replicant_list.append(replicant_table)
         table.add_row(['Replicant Volumes', replicant_list])
 
+    if block_volume.get('originalVolumeSize'):
+        duplicate_info = formatting.Table(['Original Volume Name',
+                                           block_volume['originalVolumeName']])
+        duplicate_info.add_row(['Original Volume Size',
+                                block_volume['originalVolumeSize']])
+        duplicate_info.add_row(['Original Snapshot Name',
+                                block_volume['originalSnapshotName']])
+        table.add_row(['Duplicate Volume Properties', duplicate_info])
+
     env.fout(table)
diff --git a/SoftLayer/CLI/block/duplicate.py b/SoftLayer/CLI/block/duplicate.py
new file mode 100644
index 0000000..98ef1b7
--- /dev/null
+++ b/SoftLayer/CLI/block/duplicate.py
@@ -0,0 +1,83 @@
+"""Order a duplicate block storage volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+
+
+CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
+
+
+ at click.command(context_settings=CONTEXT_SETTINGS)
+ at click.argument('origin-volume-id')
+ at click.option('--origin-snapshot-id', '-o',
+              type=int,
+              help="ID of an origin volume snapshot to use for duplcation.")
+ at click.option('--duplicate-size', '-c',
+              type=int,
+              help='Size of duplicate block volume in GB. '
+                   '***If no size is specified, the size of '
+                   'the origin volume will be used.***\n'
+                   'Potential Sizes: [20, 40, 80, 100, 250, '
+                   '500, 1000, 2000, 4000, 8000, 12000] '
+                   'Minimum: [the size of the origin volume] '
+                   'Maximum: [the minimum of 12000 GB or '
+                   '10*(origin volume size)]')
+ at click.option('--duplicate-iops', '-i',
+              type=int,
+              help='Performance Storage IOPS, between 100 and 6000 in '
+                   'multiples of 100 [only used for performance volumes] '
+                   '***If no IOPS value is specified, the IOPS value of the '
+                   'origin volume will be used.***\n'
+                   'Requirements: [If IOPS/GB for the origin volume is less '
+                   'than 0.3, IOPS/GB for the duplicate must also be less '
+                   'than 0.3. If IOPS/GB for the origin volume is greater '
+                   'than or equal to 0.3, IOPS/GB for the duplicate must '
+                   'also be greater than or equal to 0.3.]')
+ at click.option('--duplicate-tier', '-t',
+              help='Endurance Storage Tier (IOPS per GB) [only used for '
+                   'endurance volumes] ***If no tier is specified, the tier '
+                   'of the origin volume will be used.***\n'
+                   'Requirements: [If IOPS/GB for the origin volume is 0.25, '
+                   'IOPS/GB for the duplicate must also be 0.25. If IOPS/GB '
+                   'for the origin volume is greater than 0.25, IOPS/GB '
+                   'for the duplicate must also be greater than 0.25.]',
+              type=click.Choice(['0.25', '2', '4', '10']))
+ at click.option('--duplicate-snapshot-size', '-s',
+              type=int,
+              help='The size of snapshot space to order for the duplicate. '
+                   '***If no snapshot space size is specified, the snapshot '
+                   'space size of the origin volume will be used.***\n'
+                   'Input "0" for this parameter to order a duplicate volume '
+                   'with no snapshot space.')
+ at environment.pass_env
+def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size,
+        duplicate_iops, duplicate_tier, duplicate_snapshot_size):
+    """Order a duplicate block storage volume."""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+
+    if duplicate_tier is not None:
+        duplicate_tier = float(duplicate_tier)
+
+    try:
+        order = block_manager.order_duplicate_volume(
+            origin_volume_id,
+            origin_snapshot_id=origin_snapshot_id,
+            duplicate_size=duplicate_size,
+            duplicate_iops=duplicate_iops,
+            duplicate_tier_level=duplicate_tier,
+            duplicate_snapshot_size=duplicate_snapshot_size
+        )
+    except ValueError as ex:
+        raise exceptions.ArgumentError(str(ex))
+
+    if 'placedOrder' in order.keys():
+        click.echo("Order #{0} placed successfully!".format(
+            order['placedOrder']['id']))
+        for item in order['placedOrder']['items']:
+            click.echo(" > %s" % item['description'])
+    else:
+        click.echo("Order could not be placed! Please verify your options " +
+                   "and try again.")
diff --git a/SoftLayer/CLI/block/order.py b/SoftLayer/CLI/block/order.py
index 22430e4..a5af2a6 100644
--- a/SoftLayer/CLI/block/order.py
+++ b/SoftLayer/CLI/block/order.py
@@ -17,7 +17,8 @@ CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
               required=True)
 @click.option('--size',
               type=int,
-              help='Size of block storage volume in GB',
+              help='Size of block storage volume in GB. Permitted Sizes:\n'
+                   '20, 40, 80, 100, 250, 500, 1000, 2000, 4000, 8000, 12000',
               required=True)
 @click.option('--iops',
               type=int,
@@ -27,7 +28,7 @@ CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
 @click.option('--tier',
               help='Endurance Storage Tier (IOP per GB)'
               '  [required for storage-type endurance]',
-              type=click.Choice(['0.25', '2', '4']))
+              type=click.Choice(['0.25', '2', '4', '10']))
 @click.option('--os-type',
               help='Operating System',
               type=click.Choice([
@@ -71,14 +72,14 @@ def cli(env, storage_type, size, iops, tier, os_type,
         if snapshot_size is not None:
             raise exceptions.CLIAbort(
                 'Option --snapshot-size not allowed for performance volumes.'
-                ' Snapshots are only available for endurance storage.'
+                'Snapshots are only available for endurance storage.'
             )
 
         try:
             order = block_manager.order_block_volume(
                 storage_type='performance_storage_iscsi',
                 location=location,
-                size=size,
+                size=int(size),
                 iops=iops,
                 os_type=os_type
             )
@@ -88,13 +89,15 @@ def cli(env, storage_type, size, iops, tier, os_type,
     if storage_type == 'endurance':
         if tier is None:
             raise exceptions.CLIAbort(
-                'Option --tier required with Endurance in IOPS/GB [0.25,2,4]')
+                'Option --tier required with Endurance in IOPS/GB '
+                '[0.25,2,4,10]'
+            )
 
         try:
             order = block_manager.order_block_volume(
                 storage_type='storage_service_enterprise',
                 location=location,
-                size=size,
+                size=int(size),
                 tier_level=float(tier),
                 os_type=os_type,
                 snapshot_size=snapshot_size
diff --git a/SoftLayer/CLI/block/replication/locations.py b/SoftLayer/CLI/block/replication/locations.py
new file mode 100644
index 0000000..80ba5d9
--- /dev/null
+++ b/SoftLayer/CLI/block/replication/locations.py
@@ -0,0 +1,49 @@
+"""List suitable replication datacenters for the given volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import columns as column_helper
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+
+COLUMNS = [
+    column_helper.Column('ID', ('id',), mask="id"),
+    column_helper.Column('Long Name', ('longName',), mask="longName"),
+    column_helper.Column('Short Name', ('name',), mask="name"),
+]
+
+DEFAULT_COLUMNS = [
+    'ID',
+    'Long Name',
+    'Short Name',
+]
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--sortby', help='Column to sort by', default='Long Name')
+ at click.option('--columns',
+              callback=column_helper.get_formatter(COLUMNS),
+              help='Columns to display. Options: {0}'.format(
+                  ', '.join(column.name for column in COLUMNS)),
+              default=','.join(DEFAULT_COLUMNS))
+ at environment.pass_env
+def cli(env, columns, sortby, volume_id):
+    """List suitable replication datacenters for the given volume."""
+    block_storage_manager = SoftLayer.BlockStorageManager(env.client)
+
+    legal_centers = block_storage_manager.get_replication_locations(
+        volume_id
+    )
+
+    if not legal_centers:
+        click.echo("No data centers compatible for replication.")
+    else:
+        table = formatting.KeyValueTable(columns.columns)
+        table.sortby = sortby
+        for legal_center in legal_centers:
+            table.add_row([value or formatting.blank()
+                           for value in columns.row(legal_center)])
+
+        env.fout(table)
diff --git a/SoftLayer/CLI/block/replication/order.py b/SoftLayer/CLI/block/replication/order.py
index c25a8be..5aebea1 100644
--- a/SoftLayer/CLI/block/replication/order.py
+++ b/SoftLayer/CLI/block/replication/order.py
@@ -24,7 +24,7 @@ CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
 @click.option('--tier',
               help='Endurance Storage Tier (IOPS per GB) of the primary'
               ' volume for which a replicant is ordered [optional]',
-              type=click.Choice(['0.25', '2', '4']))
+              type=click.Choice(['0.25', '2', '4', '10']))
 @click.option('--os-type',
               help='Operating System Type (e.g.: LINUX) of the primary'
               ' volume for which a replica is ordered [optional]',
diff --git a/SoftLayer/CLI/block/replication/partners.py b/SoftLayer/CLI/block/replication/partners.py
new file mode 100644
index 0000000..f19be0a
--- /dev/null
+++ b/SoftLayer/CLI/block/replication/partners.py
@@ -0,0 +1,57 @@
+"""List existing replicant volumes for a block volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import columns as column_helper
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+
+COLUMNS = [
+    column_helper.Column('ID', ('id',)),
+    column_helper.Column('Username', ('username',), mask="username"),
+    column_helper.Column('Account ID', ('accountId',), mask="accountId"),
+    column_helper.Column('Capacity (GB)', ('capacityGb',), mask="capacityGb"),
+    column_helper.Column('Hardware ID', ('hardwareId',), mask="hardwareId"),
+    column_helper.Column('Guest ID', ('guestId',), mask="guestId"),
+    column_helper.Column('Host ID', ('hostId',), mask="hostId"),
+]
+
+DEFAULT_COLUMNS = [
+    'ID',
+    'Username',
+    'Account ID',
+    'Capacity (GB)',
+    'Hardware ID',
+    'Guest ID',
+    'Host ID'
+]
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--sortby', help='Column to sort by', default='Username')
+ at click.option('--columns',
+              callback=column_helper.get_formatter(COLUMNS),
+              help='Columns to display. Options: {0}'.format(
+                  ', '.join(column.name for column in COLUMNS)),
+              default=','.join(DEFAULT_COLUMNS))
+ at environment.pass_env
+def cli(env, columns, sortby, volume_id):
+    """List existing replicant volumes for a block volume."""
+    block_storage_manager = SoftLayer.BlockStorageManager(env.client)
+
+    legal_volumes = block_storage_manager.get_replication_partners(
+        volume_id
+    )
+
+    if not legal_volumes:
+        click.echo("There are no replication partners for the given volume.")
+    else:
+        table = formatting.Table(columns.columns)
+        table.sortby = sortby
+        for legal_volume in legal_volumes:
+            table.add_row([value or formatting.blank()
+                           for value in columns.row(legal_volume)])
+
+        env.fout(table)
diff --git a/SoftLayer/CLI/core.py b/SoftLayer/CLI/core.py
index 02ef1e0..860cdff 100644
--- a/SoftLayer/CLI/core.py
+++ b/SoftLayer/CLI/core.py
@@ -21,7 +21,7 @@ from SoftLayer.CLI import formatting
 from SoftLayer import consts
 
 # pylint: disable=too-many-public-methods, broad-except, unused-argument
-# pylint: disable=redefined-builtin, super-init-not-called
+# pylint: disable=redefined-builtin, super-init-not-called, arguments-differ
 
 START_TIME = time.time()
 DEBUG_LOGGING_MAP = {
diff --git a/SoftLayer/CLI/custom_types.py b/SoftLayer/CLI/custom_types.py
new file mode 100644
index 0000000..66167b6
--- /dev/null
+++ b/SoftLayer/CLI/custom_types.py
@@ -0,0 +1,32 @@
+"""
+    SoftLayer.CLI.custom_types
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+    Custom type declarations extending click.ParamType
+
+    :license: MIT, see LICENSE for more details.
+"""
+
+import click
+
+
+class NetworkParamType(click.ParamType):
+    """Validates a network parameter type and converts to a tuple.
+
+    todo: Implement to ipaddress.ip_network once the ipaddress backport
+          module can be added as a dependency or is available on all
+          supported python versions.
+    """
+    name = 'network'
+
+    def convert(self, value, param, ctx):
+        try:
+            # Inlined from python standard ipaddress module
+            # https://docs.python.org/3/library/ipaddress.html
+            address = str(value).split('/')
+            if len(address) != 2:
+                raise ValueError("Only one '/' permitted in %r" % value)
+
+            ip_address, cidr = address
+            return (ip_address, int(cidr))
+        except ValueError:
+            self.fail('{} is not a valid network'.format(value), param, ctx)
diff --git a/SoftLayer/CLI/dns/record_list.py b/SoftLayer/CLI/dns/record_list.py
index bea7098..4e46cb8 100644
--- a/SoftLayer/CLI/dns/record_list.py
+++ b/SoftLayer/CLI/dns/record_list.py
@@ -7,7 +7,7 @@ import SoftLayer
 from SoftLayer.CLI import environment
 from SoftLayer.CLI import formatting
 from SoftLayer.CLI import helpers
-# pylint: disable=redefined-builtin
+# pylint: disable=redefined-builtin, redefined-argument-from-local
 
 
 @click.command()
@@ -37,13 +37,13 @@ def cli(env, zone, data, record, ttl, type):
                                   ttl=ttl,
                                   data=data)
 
-    for record in records:
+    for the_record in records:
         table.add_row([
-            record['id'],
-            record['host'],
-            record['type'].upper(),
-            record['ttl'],
-            record['data']
+            the_record['id'],
+            the_record['host'],
+            the_record['type'].upper(),
+            the_record['ttl'],
+            the_record['data']
         ])
 
     env.fout(table)
diff --git a/SoftLayer/CLI/file/detail.py b/SoftLayer/CLI/file/detail.py
index 25cdb95..3c9af3f 100644
--- a/SoftLayer/CLI/file/detail.py
+++ b/SoftLayer/CLI/file/detail.py
@@ -16,7 +16,8 @@ def cli(env, volume_id):
     file_manager = SoftLayer.FileStorageManager(env.client)
     file_volume = file_manager.get_file_volume_details(volume_id)
     file_volume = utils.NestedDict(file_volume)
-    used_space = int(file_volume['bytesUsed'])
+    used_space = int(file_volume['bytesUsed'])\
+        if file_volume['bytesUsed'] else 0
 
     table = formatting.KeyValueTable(['Name', 'Value'])
     table.align['Name'] = 'r'
@@ -43,7 +44,7 @@ def cli(env, volume_id):
     if file_volume.get('storageTierLevel'):
         table.add_row([
             'Endurance Tier',
-            file_volume['storageTierLevel']['description'],
+            file_volume['storageTierLevel'],
         ])
 
     table.add_row([
@@ -114,4 +115,13 @@ def cli(env, volume_id):
             replicant_list.append(replicant_table)
         table.add_row(['Replicant Volumes', replicant_list])
 
+    if file_volume.get('originalVolumeSize'):
+        duplicate_info = formatting.Table(['Original Volume Name',
+                                           file_volume['originalVolumeName']])
+        duplicate_info.add_row(['Original Volume Size',
+                                file_volume['originalVolumeSize']])
+        duplicate_info.add_row(['Original Snapshot Name',
+                                file_volume['originalSnapshotName']])
+        table.add_row(['Duplicate Volume Properties', duplicate_info])
+
     env.fout(table)
diff --git a/SoftLayer/CLI/file/duplicate.py b/SoftLayer/CLI/file/duplicate.py
new file mode 100644
index 0000000..e021697
--- /dev/null
+++ b/SoftLayer/CLI/file/duplicate.py
@@ -0,0 +1,79 @@
+"""Order a duplicate file storage volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+
+
+CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
+
+
+ at click.command(context_settings=CONTEXT_SETTINGS)
+ at click.argument('origin-volume-id')
+ at click.option('--origin-snapshot-id', '-o',
+              type=int,
+              help="ID of an origin volume snapshot to use for duplcation.")
+ at click.option('--duplicate-size', '-c',
+              type=int,
+              help='Size of duplicate file volume in GB. '
+                   '***If no size is specified, the size of '
+                   'the origin volume will be used.***\n'
+                   'Minimum: [the size of the origin volume]')
+ at click.option('--duplicate-iops', '-i',
+              type=int,
+              help='Performance Storage IOPS, between 100 and 6000 in '
+                   'multiples of 100 [only used for performance volumes] '
+                   '***If no IOPS value is specified, the IOPS value of the '
+                   'origin volume will be used.***\n'
+                   'Requirements: [If IOPS/GB for the origin volume is less '
+                   'than 0.3, IOPS/GB for the duplicate must also be less '
+                   'than 0.3. If IOPS/GB for the origin volume is greater '
+                   'than or equal to 0.3, IOPS/GB for the duplicate must '
+                   'also be greater than or equal to 0.3.]')
+ at click.option('--duplicate-tier', '-t',
+              help='Endurance Storage Tier (IOPS per GB) [only used for '
+                   'endurance volumes] ***If no tier is specified, the tier '
+                   'of the origin volume will be used.***\n'
+                   'Requirements: [If IOPS/GB for the origin volume is 0.25, '
+                   'IOPS/GB for the duplicate must also be 0.25. If IOPS/GB '
+                   'for the origin volume is greater than 0.25, IOPS/GB '
+                   'for the duplicate must also be greater than 0.25.]',
+              type=click.Choice(['0.25', '2', '4', '10']))
+ at click.option('--duplicate-snapshot-size', '-s',
+              type=int,
+              help='The size of snapshot space to order for the duplicate. '
+                   '***If no snapshot space size is specified, the snapshot '
+                   'space size of the origin volume will be used.***\n'
+                   'Input "0" for this parameter to order a duplicate volume '
+                   'with no snapshot space.')
+ at environment.pass_env
+def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size,
+        duplicate_iops, duplicate_tier, duplicate_snapshot_size):
+    """Order a duplicate file storage volume."""
+    file_manager = SoftLayer.FileStorageManager(env.client)
+
+    if duplicate_tier is not None:
+        duplicate_tier = float(duplicate_tier)
+
+    try:
+        order = file_manager.order_duplicate_volume(
+            origin_volume_id,
+            origin_snapshot_id=origin_snapshot_id,
+            duplicate_size=duplicate_size,
+            duplicate_iops=duplicate_iops,
+            duplicate_tier_level=duplicate_tier,
+            duplicate_snapshot_size=duplicate_snapshot_size
+        )
+    except ValueError as ex:
+        raise exceptions.ArgumentError(str(ex))
+
+    if 'placedOrder' in order.keys():
+        click.echo("Order #{0} placed successfully!".format(
+            order['placedOrder']['id']))
+        for item in order['placedOrder']['items']:
+            click.echo(" > %s" % item['description'])
+    else:
+        click.echo("Order could not be placed! Please verify your options " +
+                   "and try again.")
diff --git a/SoftLayer/CLI/file/order.py b/SoftLayer/CLI/file/order.py
index 0219efd..d13b952 100644
--- a/SoftLayer/CLI/file/order.py
+++ b/SoftLayer/CLI/file/order.py
@@ -27,18 +27,7 @@ CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
 @click.option('--tier',
               help='Endurance Storage Tier (IOP per GB)'
               '  [required for storage-type endurance]',
-              type=click.Choice(['0.25', '2', '4']))
- at click.option('--os-type',
-              help='Operating System',
-              type=click.Choice([
-                  'HYPER_V',
-                  'LINUX',
-                  'VMWARE',
-                  'WINDOWS_2008',
-                  'WINDOWS_GPT',
-                  'WINDOWS',
-                  'XEN']),
-              required=True)
+              type=click.Choice(['0.25', '2', '4', '10']))
 @click.option('--location',
               help='Datacenter short name (e.g.: dal09)',
               required=True)
@@ -48,7 +37,7 @@ CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
               'space along with endurance file storage; specifies '
               'the size (in GB) of snapshot space to order')
 @environment.pass_env
-def cli(env, storage_type, size, iops, tier, os_type,
+def cli(env, storage_type, size, iops, tier,
         location, snapshot_size):
     """Order a file storage volume."""
     file_manager = SoftLayer.FileStorageManager(env.client)
@@ -79,8 +68,7 @@ def cli(env, storage_type, size, iops, tier, os_type,
                 storage_type='performance_storage_nfs',
                 location=location,
                 size=size,
-                iops=iops,
-                os_type=os_type
+                iops=iops
             )
         except ValueError as ex:
             raise exceptions.ArgumentError(str(ex))
@@ -88,7 +76,9 @@ def cli(env, storage_type, size, iops, tier, os_type,
     if storage_type == 'endurance':
         if tier is None:
             raise exceptions.CLIAbort(
-                'Option --tier required with Endurance in IOPS/GB [0.25,2,4]')
+                'Option --tier required with Endurance in IOPS/GB '
+                '[0.25,2,4,10]'
+            )
 
         try:
             order = file_manager.order_file_volume(
@@ -96,7 +86,6 @@ def cli(env, storage_type, size, iops, tier, os_type,
                 location=location,
                 size=size,
                 tier_level=float(tier),
-                os_type=os_type,
                 snapshot_size=snapshot_size
             )
         except ValueError as ex:
diff --git a/SoftLayer/CLI/file/replication/locations.py b/SoftLayer/CLI/file/replication/locations.py
new file mode 100644
index 0000000..58f979f
--- /dev/null
+++ b/SoftLayer/CLI/file/replication/locations.py
@@ -0,0 +1,49 @@
+"""List suitable replication datacenters for the given volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import columns as column_helper
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+
+COLUMNS = [
+    column_helper.Column('ID', ('id',), mask="id"),
+    column_helper.Column('Long Name', ('longName',), mask="longName"),
+    column_helper.Column('Short Name', ('name',), mask="name"),
+]
+
+DEFAULT_COLUMNS = [
+    'ID',
+    'Long Name',
+    'Short Name',
+]
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--sortby', help='Column to sort by', default='Long Name')
+ at click.option('--columns',
+              callback=column_helper.get_formatter(COLUMNS),
+              help='Columns to display. Options: {0}'.format(
+                  ', '.join(column.name for column in COLUMNS)),
+              default=','.join(DEFAULT_COLUMNS))
+ at environment.pass_env
+def cli(env, columns, sortby, volume_id):
+    """List suitable replication datacenters for the given volume."""
+    file_storage_manager = SoftLayer.FileStorageManager(env.client)
+
+    legal_centers = file_storage_manager.get_replication_locations(
+        volume_id
+    )
+
+    if not legal_centers:
+        click.echo("No data centers compatible for replication.")
+    else:
+        table = formatting.KeyValueTable(columns.columns)
+        table.sortby = sortby
+        for legal_center in legal_centers:
+            table.add_row([value or formatting.blank()
+                           for value in columns.row(legal_center)])
+
+        env.fout(table)
diff --git a/SoftLayer/CLI/file/replication/order.py b/SoftLayer/CLI/file/replication/order.py
index 7c4617f..4b3231e 100644
--- a/SoftLayer/CLI/file/replication/order.py
+++ b/SoftLayer/CLI/file/replication/order.py
@@ -24,7 +24,7 @@ CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
 @click.option('--tier',
               help='Endurance Storage Tier (IOPS per GB) of the primary'
               ' volume for which a replicant is ordered [optional]',
-              type=click.Choice(['0.25', '2', '4']))
+              type=click.Choice(['0.25', '2', '4', '10']))
 @environment.pass_env
 def cli(env, volume_id, snapshot_schedule, location, tier):
     """Order a file storage replica volume."""
diff --git a/SoftLayer/CLI/file/replication/partners.py b/SoftLayer/CLI/file/replication/partners.py
new file mode 100644
index 0000000..866248f
--- /dev/null
+++ b/SoftLayer/CLI/file/replication/partners.py
@@ -0,0 +1,60 @@
+"""List existing replicant volumes for a file volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import columns as column_helper
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+
+COLUMNS = [
+    column_helper.Column('ID', ('id',)),
+    column_helper.Column('Username', ('username',), mask="username"),
+    column_helper.Column('Account ID', ('accountId',), mask="accountId"),
+    column_helper.Column('Capacity (GB)', ('capacityGb',), mask="capacityGb"),
+    column_helper.Column('Hardware ID', ('hardwareId',), mask="hardwareId"),
+    column_helper.Column('Guest ID', ('guestId',), mask="guestId"),
+    column_helper.Column('Host ID', ('hostId',), mask="hostId"),
+]
+
+# In-line comment to avoid similarity flag with block version
+
+DEFAULT_COLUMNS = [
+    'ID',
+    'Username',
+    'Account ID',
+    'Capacity (GB)',
+    'Hardware ID',
+    'Guest ID',
+    'Host ID'
+]
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--sortby', help='Column to sort by', default='Username')
+ at click.option('--columns',
+              callback=column_helper.get_formatter(COLUMNS),
+              help='Columns to display. Options: {0}'.format(
+                  ', '.join(column.name for column in COLUMNS)),
+              default=','.join(DEFAULT_COLUMNS))
+ at environment.pass_env
+def cli(env, columns, sortby, volume_id):
+    """List existing replicant volumes for a file volume."""
+    file_storage_manager = SoftLayer.FileStorageManager(env.client)
+
+    legal_volumes = file_storage_manager.get_replication_partners(
+        volume_id
+    )
+
+    if not legal_volumes:
+        click.echo("There are no replication partners for the given volume.")
+    else:
+        table = formatting.Table(columns.columns)
+        table.sortby = sortby
+
+        for legal_volume in legal_volumes:
+            table.add_row([value or formatting.blank()
+                           for value in columns.row(legal_volume)])
+
+        env.fout(table)
diff --git a/SoftLayer/CLI/formatting.py b/SoftLayer/CLI/formatting.py
index 59917b0..bb3d72d 100644
--- a/SoftLayer/CLI/formatting.py
+++ b/SoftLayer/CLI/formatting.py
@@ -6,7 +6,7 @@
 
     :license: MIT, see LICENSE for more details.
 """
-# pylint: disable=E0202
+# pylint: disable=E0202, consider-merging-isinstance, arguments-differ
 import collections
 import json
 import os
@@ -48,7 +48,7 @@ def format_output(data, fmt='table'):  # pylint: disable=R0911,R0912
                 cls=CLIJSONEncoder)
         elif fmt == 'jsonraw':
             return json.dumps(format_output(data, fmt='python'),
-                              CLIJSONEncoder)
+                              cls=CLIJSONEncoder)
         elif fmt == 'python':
             return data.to_python()
 
diff --git a/SoftLayer/CLI/iscsi/__init__.py b/SoftLayer/CLI/iscsi/__init__.py
deleted file mode 100644
index 2b37904..0000000
--- a/SoftLayer/CLI/iscsi/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""iSCSI storage."""
diff --git a/SoftLayer/CLI/iscsi/cancel.py b/SoftLayer/CLI/iscsi/cancel.py
deleted file mode 100644
index f744cb6..0000000
--- a/SoftLayer/CLI/iscsi/cancel.py
+++ /dev/null
@@ -1,30 +0,0 @@
-"""Cancel an existing iSCSI account."""
-# :license: MIT, see LICENSE for more details.
-
-import click
-
-import SoftLayer
-from SoftLayer.CLI import environment
-from SoftLayer.CLI import exceptions
-from SoftLayer.CLI import formatting
-from SoftLayer.CLI import helpers
-
-
- at click.command()
- at click.argument('identifier')
- at click.option('--reason', help="An optional reason for cancellation")
- at click.option('--immediate',
-              is_flag=True,
-              help="Cancels the iSCSI immediately instead of on the billing "
-                   "anniversary")
- at environment.pass_env
-def cli(env, identifier, reason, immediate):
-    """Cancel an existing iSCSI account."""
-
-    iscsi_mgr = SoftLayer.ISCSIManager(env.client)
-    iscsi_id = helpers.resolve_id(iscsi_mgr.resolve_ids, identifier, 'iSCSI')
-
-    if not (env.skip_confirmations or formatting.no_going_back(iscsi_id)):
-        raise exceptions.CLIAbort('Aborted')
-
-    iscsi_mgr.cancel_iscsi(iscsi_id, reason, immediate)
diff --git a/SoftLayer/CLI/iscsi/create.py b/SoftLayer/CLI/iscsi/create.py
deleted file mode 100644
index 95872c7..0000000
--- a/SoftLayer/CLI/iscsi/create.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""Creates an iSCSI target."""
-# :license: MIT, see LICENSE for more details.
-
-import click
-
-import SoftLayer
-from SoftLayer.CLI import environment
-
-
- at click.command()
- at click.option('--size',
-              type=click.INT,
... 7412 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-softlayer.git



More information about the Python-modules-commits mailing list