[Python-modules-commits] [python-softlayer] 01/10: Import python-softlayer_5.1.0.orig.tar.gz

Scott Kitterman kitterman at moszumanska.debian.org
Thu May 26 12:44:28 UTC 2016


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

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

commit 6245ba4560ae1a6a4f13dadcdc2df91e58aa5cd9
Author: Scott Kitterman <scott at kitterman.com>
Date:   Thu May 26 08:05:16 2016 -0400

    Import python-softlayer_5.1.0.orig.tar.gz
---
 CHANGELOG                                       |  10 +
 README.rst                                      |   2 +-
 SoftLayer/CLI/block/__init__.py                 |   1 +
 SoftLayer/CLI/block/access_list.py              | 123 ++++++++
 SoftLayer/CLI/block/cancel.py                   |  28 ++
 SoftLayer/CLI/block/detail.py                   |  59 ++++
 SoftLayer/CLI/block/list.py                     |  66 ++++
 SoftLayer/CLI/block/order.py                    |  99 ++++++
 SoftLayer/CLI/block/snapshot_delete.py          |  15 +
 SoftLayer/CLI/block/snapshot_list.py            |  58 ++++
 SoftLayer/CLI/routes.py                         |  11 +
 SoftLayer/CLI/ticket/attach.py                  |  42 +++
 SoftLayer/CLI/ticket/create.py                  |  36 ++-
 SoftLayer/CLI/ticket/detach.py                  |  42 +++
 SoftLayer/CLI/virt/detail.py                    |  16 +-
 SoftLayer/CLI/vlan/detail.py                    |   6 +-
 SoftLayer/consts.py                             |   2 +-
 SoftLayer/fixtures/SoftLayer_Account.py         |  20 ++
 SoftLayer/fixtures/SoftLayer_Network_Storage.py |  65 ++++
 SoftLayer/fixtures/SoftLayer_Ticket.py          |  17 +
 SoftLayer/fixtures/SoftLayer_Virtual_Guest.py   |   5 +
 SoftLayer/managers/__init__.py                  |   2 +
 SoftLayer/managers/block.py                     | 403 ++++++++++++++++++++++++
 SoftLayer/managers/network.py                   |  11 +-
 SoftLayer/managers/ticket.py                    |  40 ++-
 SoftLayer/managers/vs.py                        |   3 +
 SoftLayer/testing/__init__.py                   |   7 +
 SoftLayer/utils.py                              |   9 +-
 docs/conf.py                                    |   4 +-
 fabfile.py                                      |   8 +-
 setup.py                                        |   2 +-
 tests/CLI/core_tests.py                         |   6 +-
 tests/CLI/modules/block_tests.py                |  98 ++++++
 tests/CLI/modules/call_api_tests.py             |  16 +-
 tests/CLI/modules/cdn_tests.py                  |  14 +-
 tests/CLI/modules/config_tests.py               |   4 +-
 tests/CLI/modules/dns_tests.py                  |  16 +-
 tests/CLI/modules/firewall_tests.py             |   2 +-
 tests/CLI/modules/globalip_tests.py             |   8 +-
 tests/CLI/modules/nas_tests.py                  |   2 +-
 tests/CLI/modules/object_storage_tests.py       |   4 +-
 tests/CLI/modules/rwhois_tests.py               |   6 +-
 tests/CLI/modules/server_tests.py               |  38 +--
 tests/CLI/modules/sshkey_tests.py               |  14 +-
 tests/CLI/modules/summary_tests.py              |   2 +-
 tests/CLI/modules/ticket_tests.py               | 137 +++++++-
 tests/CLI/modules/vs_tests.py                   |  30 +-
 tests/managers/block_tests.py                   | 212 +++++++++++++
 tests/managers/ticket_tests.py                  |  25 ++
 tox.ini                                         |   7 +-
 50 files changed, 1733 insertions(+), 120 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 39c1ee4..60b8a22 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+5.1.0
+
+    * Added block storage functionality. You can order, list, detail, cancel volumes. You can list and delete snapshots. You can also list ACLs for volumes.
+
+    * Added functionality to attach/detach devices to tickets
+
+    * Virtual list now lists users and passwords for all known software
+
+    * Fixes bug with `vlan detail` CLI command
+
 5.0.1
 
     * Adds missing depdendency that was previously pulled in by prompt_toolkit
diff --git a/README.rst b/README.rst
index d8949f2..31da9b6 100644
--- a/README.rst
+++ b/README.rst
@@ -57,7 +57,7 @@ This library relies on the `requests <http://docs.python-requests.org/>`_ librar
 
 System Requirements
 -------------------
-* Python 2.7, 3.3, or 3.4.
+* Python 2.7, 3.3 or higher.
 * A valid SoftLayer API username and key.
 * A connection to SoftLayer's private network is required to use
   our private network API endpoints.
diff --git a/SoftLayer/CLI/block/__init__.py b/SoftLayer/CLI/block/__init__.py
new file mode 100644
index 0000000..7ccee03
--- /dev/null
+++ b/SoftLayer/CLI/block/__init__.py
@@ -0,0 +1 @@
+"""Block Storage."""
diff --git a/SoftLayer/CLI/block/access_list.py b/SoftLayer/CLI/block/access_list.py
new file mode 100644
index 0000000..4b45a54
--- /dev/null
+++ b/SoftLayer/CLI/block/access_list.py
@@ -0,0 +1,123 @@
+"""List hosts with access to 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
+
+
+def _format_name(obj):
+    if obj['type'] == 'VIRTUAL':
+        return "{0}.{1}".format(obj['hostname'], obj['domain'])
+
+    elif obj['type'] == 'HARDWARE':
+        return "{0}.{1}".format(obj['hostname'], obj['domain'])
+
+    elif obj['type'] == 'SUBNET':
+        name = "{0}/{1}".format(
+            obj['networkIdentifier'],
+            obj['cidr']
+        )
+        if 'note' in obj.keys():
+            name = "{0} ({1})".format(name, obj['note'])
+
+        return name
+
+    elif obj['type'] == 'IP':
+        name = obj['ipAddress']
+        if 'note' in obj.keys():
+            name = "{0} ({1})".format(name, obj['note'])
+
+        return name
+    else:
+        raise Exception('Unknown type %s' % obj['type'])
+
+
+COLUMNS = [
+    column_helper.Column('id', ('id',)),
+    column_helper.Column('name', _format_name, """
+allowedVirtualGuests[hostname,domain],
+allowedHardware[hostname,domain],
+allowedSubnets[networkIdentifier,cidr,note],
+allowedIpAddresses[ipAddress,note],
+"""),
+    column_helper.Column('type', ('type',)),
+    column_helper.Column(
+        'private_ip_address',
+        ('primaryBackendIpAddress',),
+        """
+allowedVirtualGuests.primaryBackendIpAddress
+allowedHardware.primaryBackendIpAddress
+allowedSubnets.primaryBackendIpAddress
+allowedIpAddresses.primaryBackendIpAddress
+"""),
+    column_helper.Column(
+        'host_iqn',
+        ('allowedHost', 'name',),
+        """
+allowedVirtualGuests.allowedHost.name
+allowedHardware.allowedHost.name
+allowedSubnets.allowedHost.name
+allowedIpAddresses.allowedHost.name
+"""),
+    column_helper.Column(
+        'username',
+        ('allowedHost', 'credential', 'username',),
+        """
+allowedVirtualGuests.allowedHost.credential.username
+allowedHardware.allowedHost.credential.username
+allowedSubnets.allowedHost.credential.username
+allowedIpAddresses.allowedHost.credential.username
+"""),
+    column_helper.Column(
+        'password',
+        ('allowedHost', 'credential', 'password',),
+        """
+allowedVirtualGuests.allowedHost.credential.password
+allowedHardware.allowedHost.credential.password
+allowedSubnets.allowedHost.credential.password
+allowedIpAddresses.allowedHost.credential.password
+"""),
+]
+
+
+DEFAULT_COLUMNS = [
+    'id',
+    'name',
+    'type',
+    'private_ip_address',
+    'host_iqn',
+    'username',
+    'password',
+]
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at click.option('--sortby', help='Column to sort by', default='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 ACLs."""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    access_list = block_manager.get_block_volume_access_list(
+        volume_id=volume_id)
+    table = formatting.Table(columns.columns)
+    table.sortby = sortby
+
+    for key, type_name in [('allowedVirtualGuests', 'VIRTUAL'),
+                           ('allowedHardware', 'HARDWARE'),
+                           ('allowedSubnets', 'SUBNET'),
+                           ('allowedIpAddresses', 'IP')]:
+        for obj in access_list.get(key, []):
+            obj['type'] = type_name
+            table.add_row([value or formatting.blank()
+                           for value in columns.row(obj)])
+
+    env.fout(table)
diff --git a/SoftLayer/CLI/block/cancel.py b/SoftLayer/CLI/block/cancel.py
new file mode 100644
index 0000000..a23cee0
--- /dev/null
+++ b/SoftLayer/CLI/block/cancel.py
@@ -0,0 +1,28 @@
+"""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
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--reason', help="An optional reason for cancellation")
+ at click.option('--immediate',
+              is_flag=True,
+              help="Cancels the block storage volume immediately instead "
+                   "of on the billing anniversary")
+ at environment.pass_env
+def cli(env, volume_id, reason, immediate):
+    """Cancel an existing block storage volume."""
+
+    block_storage_manager = SoftLayer.BlockStorageManager(env.client)
+
+    if not (env.skip_confirmations or formatting.no_going_back(volume_id)):
+        raise exceptions.CLIAbort('Aborted')
+
+    block_storage_manager.cancel_block_volume(volume_id, reason, immediate)
diff --git a/SoftLayer/CLI/block/detail.py b/SoftLayer/CLI/block/detail.py
new file mode 100644
index 0000000..c98736e
--- /dev/null
+++ b/SoftLayer/CLI/block/detail.py
@@ -0,0 +1,59 @@
+"""Display details for a specified volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+from SoftLayer import utils
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at environment.pass_env
+def cli(env, volume_id):
+    """Display details for a specified volume."""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    block_volume = block_manager.get_block_volume_details(volume_id)
+    block_volume = utils.NestedDict(block_volume)
+
+    table = formatting.KeyValueTable(['Name', 'Value'])
+    table.align['Name'] = 'r'
+    table.align['Value'] = 'l'
+
+    storage_type = block_volume['storageType']['keyName'].split('_').pop(0)
+    table.add_row(['ID', block_volume['id']])
+    table.add_row(['Username', block_volume['username']])
+    table.add_row(['Type', storage_type])
+    table.add_row(['Capacity (GB)', "%iGB" % block_volume['capacityGb']])
+    table.add_row(['LUN Id', "%s" % block_volume['lunId']])
+
+    if block_volume.get('iops'):
+        table.add_row(['IOPs', block_volume['iops']])
+
+    if block_volume.get('storageTierLevel'):
+        table.add_row([
+            'Endurance Tier',
+            block_volume['storageTierLevel']['description'],
+        ])
+
+    table.add_row([
+        'Data Center',
+        block_volume['serviceResource']['datacenter']['name'],
+    ])
+    table.add_row([
+        'Target IP',
+        block_volume['serviceResourceBackendIpAddress'],
+    ])
+
+    if block_volume['snapshotCapacityGb']:
+        table.add_row([
+            'Snapshot Capacity (GB)',
+            block_volume['snapshotCapacityGb'],
+        ])
+        table.add_row([
+            'Snapshot Used (Bytes)',
+            block_volume['parentVolume']['snapshotSizeBytes'],
+        ])
+
+    env.fout(table)
diff --git a/SoftLayer/CLI/block/list.py b/SoftLayer/CLI/block/list.py
new file mode 100644
index 0000000..40edcb7
--- /dev/null
+++ b/SoftLayer/CLI/block/list.py
@@ -0,0 +1,66 @@
+"""List block storage volumes."""
+# :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('username', ('username',), mask="username"),
+    column_helper.Column('datacenter',
+                         ('serviceResource', 'datacenter', 'name'),
+                         mask="serviceResource.datacenter.name"),
+    column_helper.Column(
+        'storage_type',
+        lambda b: b['storageType']['keyName'].split('_').pop(0),
+        mask="storageType.keyName"),
+    column_helper.Column('capacity_gb', ('capacityGb',), mask="capacityGb"),
+    column_helper.Column('bytes_used', ('bytesUsed',), mask="bytesUsed"),
+    column_helper.Column('ip_addr', ('serviceResourceBackendIpAddress',),
+                         mask="serviceResourceBackendIpAddress"),
+]
+
+DEFAULT_COLUMNS = [
+    'id',
+    'username',
+    'datacenter',
+    'storage_type',
+    'capacity_gb',
+    'bytes_used',
+    'ip_addr'
+]
+
+
+ at click.command()
+ at click.option('--username', '-u', help='Volume username')
+ at click.option('--datacenter', '-d', help='Datacenter shortname')
+ at click.option('--storage-type',
+              help='Type of storage volume',
+              type=click.Choice(['performance', 'endurance']))
+ 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, sortby, columns, datacenter, username, storage_type):
+    """List block storage."""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    block_volumes = block_manager.list_block_volumes(datacenter=datacenter,
+                                                     username=username,
+                                                     storage_type=storage_type,
+                                                     mask=columns.mask())
+
+    table = formatting.Table(columns.columns)
+    table.sortby = sortby
+
+    for block_volume in block_volumes:
+        table.add_row([value or formatting.blank()
+                       for value in columns.row(block_volume)])
+
+    env.fout(table)
diff --git a/SoftLayer/CLI/block/order.py b/SoftLayer/CLI/block/order.py
new file mode 100644
index 0000000..f184007
--- /dev/null
+++ b/SoftLayer/CLI/block/order.py
@@ -0,0 +1,99 @@
+"""Order a 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 = dict(token_normalize_func=lambda x: x.upper())
+
+
+ at click.command(context_settings=CONTEXT_SETTINGS)
+ at click.option('--storage-type',
+              help='Type of storage volume',
+              type=click.Choice(['performance', 'endurance']),
+              required=True)
+ at click.option('--size',
+              type=int,
+              help='Size of storage volume in GB',
+              required=True)
+ at click.option('--iops',
+              type=int,
+              help='Performance Storage IOPs,'
+              ' between 100 and 6000 in multiples of 100'
+              '  [required for storage-type performance]')
+ at 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)
+ at click.option('--location',
+              help='Datacenter short name (e.g.: dal09)',
+              required=True)
+ at environment.pass_env
+def cli(env, storage_type, size, iops, tier, os_type, location):
+    """Order a block storage volume."""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    storage_type = storage_type.lower()
+
+    if storage_type == 'performance':
+        if iops is None:
+            raise exceptions.CLIAbort(
+                'Option --iops required with Performance')
+
+        if iops < 100 or iops > 6000:
+            raise exceptions.CLIAbort(
+                'Option --iops must be between 100 and 6000, inclusive')
+
+        if iops % 100 != 0:
+            raise exceptions.CLIAbort(
+                'Option --iops must be a multiple of 100'
+            )
+
+        try:
+            order = block_manager.order_block_volume(
+                storage_type='performance_storage_iscsi',
+                location=location,
+                size=size,
+                iops=iops,
+                os_type=os_type
+            )
+        except ValueError as ex:
+            raise exceptions.ArgumentError(str(ex))
+
+    if storage_type == 'endurance':
+        if tier is None:
+            raise exceptions.CLIAbort(
+                'Option --tier required with Endurance in IOPS/GB [0.25,2,4]')
+
+        try:
+            order = block_manager.order_block_volume(
+                storage_type='storage_service_enterprise',
+                location=location,
+                size=size,
+                tier_level=float(tier),
+                os_type=os_type
+            )
+        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/snapshot_delete.py b/SoftLayer/CLI/block/snapshot_delete.py
new file mode 100644
index 0000000..6daa3f4
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot_delete.py
@@ -0,0 +1,15 @@
+"""Create a block storage snapshot."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+
+
+ at click.command()
+ at click.argument('snapshot_id')
+ at environment.pass_env
+def cli(env, snapshot_id):
+    """Deletes a snapshot on a given volume"""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    block_manager.delete_snapshot(snapshot_id)
diff --git a/SoftLayer/CLI/block/snapshot_list.py b/SoftLayer/CLI/block/snapshot_list.py
new file mode 100644
index 0000000..7ffea3f
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot_list.py
@@ -0,0 +1,58 @@
+"""List block storage snapshots."""
+# :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',
+        ('snapshots', 'id',),
+        mask='snapshots.id'),
+    column_helper.Column('name', ('snapshots', 'notes',),
+                         mask='snapshots.notes'),
+    column_helper.Column('created',
+                         ('snapshots', 'snapshotCreationTimestamp',),
+                         mask='snapshots.snapshotCreationTimestamp'),
+    column_helper.Column('size_bytes', ('snapshots', 'snapshotSizeBytes',),
+                         mask='snapshots.snapshotSizeBytes'),
+]
+
+DEFAULT_COLUMNS = [
+    'id',
+    'name',
+    'created',
+    'size_bytes'
+]
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at click.option('--sortby', help='Column to sort by',
+              default='created')
+ 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, sortby, columns, volume_id):
+    """List block storage snapshots."""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    snapshots = block_manager.get_block_volume_snapshot_list(
+        volume_id=volume_id,
+        mask=columns.mask(),
+    )
+
+    table = formatting.Table(columns.columns)
+    table.sortby = sortby
+
+    for snapshot in snapshots:
+        table.add_row([value or formatting.blank()
+                       for value in columns.row(snapshot)])
+
+    env.fout(table)
diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py
index 0d93f2e..a9aec3c 100644
--- a/SoftLayer/CLI/routes.py
+++ b/SoftLayer/CLI/routes.py
@@ -56,6 +56,15 @@ ALL_ROUTES = [
     ('dns:zone-list', 'SoftLayer.CLI.dns.zone_list:cli'),
     ('dns:zone-print', 'SoftLayer.CLI.dns.zone_print:cli'),
 
+    ('block', 'SoftLayer.CLI.block'),
+    ('block:volume-list', 'SoftLayer.CLI.block.list:cli'),
+    ('block:volume-detail', 'SoftLayer.CLI.block.detail:cli'),
+    ('block:volume-cancel', 'SoftLayer.CLI.block.cancel:cli'),
+    ('block:volume-order', 'SoftLayer.CLI.block.order:cli'),
+    ('block:snapshot-list', 'SoftLayer.CLI.block.snapshot_list:cli'),
+    ('block:snapshot-delete', 'SoftLayer.CLI.block.snapshot_delete:cli'),
+    ('block:access-list', 'SoftLayer.CLI.block.access_list:cli'),
+
     ('firewall', 'SoftLayer.CLI.firewall'),
     ('firewall:add', 'SoftLayer.CLI.firewall.add:cli'),
     ('firewall:cancel', 'SoftLayer.CLI.firewall.cancel:cli'),
@@ -188,6 +197,8 @@ ALL_ROUTES = [
     ('ticket:update', 'SoftLayer.CLI.ticket.update:cli'),
     ('ticket:subjects', 'SoftLayer.CLI.ticket.subjects:cli'),
     ('ticket:summary', 'SoftLayer.CLI.ticket.summary:cli'),
+    ('ticket:attach', 'SoftLayer.CLI.ticket.attach:cli'),
+    ('ticket:detach', 'SoftLayer.CLI.ticket.detach:cli'),
 
     ('vlan', 'SoftLayer.CLI.vlan'),
     ('vlan:detail', 'SoftLayer.CLI.vlan.detail:cli'),
diff --git a/SoftLayer/CLI/ticket/attach.py b/SoftLayer/CLI/ticket/attach.py
new file mode 100644
index 0000000..98adaa6
--- /dev/null
+++ b/SoftLayer/CLI/ticket/attach.py
@@ -0,0 +1,42 @@
+"""Attach devices to a ticket."""
+# :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 helpers
+
+
+ at click.command()
+ at click.argument('identifier', type=int)
+ at click.option('--hardware',
+              'hardware_identifier',
+              help="The identifier for hardware to attach")
+ at click.option('--virtual',
+              'virtual_identifier',
+              help="The identifier for a virtual server to attach")
+ at environment.pass_env
+def cli(env, identifier, hardware_identifier, virtual_identifier):
+    """Attach devices to a ticket."""
+    ticket_mgr = SoftLayer.TicketManager(env.client)
+
+    if hardware_identifier and virtual_identifier:
+        raise exceptions.ArgumentError(
+            "Cannot attach hardware and a virtual server at the same time")
+    elif hardware_identifier:
+        hardware_mgr = SoftLayer.HardwareManager(env.client)
+        hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
+                                         hardware_identifier,
+                                         'hardware')
+        ticket_mgr.attach_hardware(identifier, hardware_id)
+    elif virtual_identifier:
+        vs_mgr = SoftLayer.VSManager(env.client)
+        vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
+                                   virtual_identifier,
+                                   'VS')
+        ticket_mgr.attach_virtual_server(identifier, vs_id)
+    else:
+        raise exceptions.ArgumentError(
+            "Must have a hardware or virtual server identifier to attach")
diff --git a/SoftLayer/CLI/ticket/create.py b/SoftLayer/CLI/ticket/create.py
index 82f81ee..71ebd26 100644
--- a/SoftLayer/CLI/ticket/create.py
+++ b/SoftLayer/CLI/ticket/create.py
@@ -5,25 +5,49 @@ import click
 
 import SoftLayer
 from SoftLayer.CLI import environment
+from SoftLayer.CLI import helpers
 from SoftLayer.CLI import ticket
 
 
 @click.command()
 @click.option('--title', required=True, help="The title of the ticket")
 @click.option('--subject-id',
+              type=int,
               required=True,
               help="""The subject id to use for the ticket,
  issue 'slcli ticket subjects' to get the list""")
 @click.option('--body', help="The ticket body")
+ at click.option('--hardware',
+              'hardware_identifier',
+              help="The identifier for hardware to attach")
+ at click.option('--virtual',
+              'virtual_identifier',
+              help="The identifier for a virtual server to attach")
 @environment.pass_env
-def cli(env, title, subject_id, body):
+def cli(env, title, subject_id, body, hardware_identifier, virtual_identifier):
     """Create a support ticket."""
-    mgr = SoftLayer.TicketManager(env.client)
+    ticket_mgr = SoftLayer.TicketManager(env.client)
 
     if body is None:
         body = click.edit('\n\n' + ticket.TEMPLATE_MSG)
 
-    created_ticket = mgr.create_ticket(title=title,
-                                       body=body,
-                                       subject=subject_id)
-    env.fout(ticket.get_ticket_results(mgr, created_ticket['id']))
+    created_ticket = ticket_mgr.create_ticket(
+        title=title,
+        body=body,
+        subject=subject_id)
+
+    if hardware_identifier:
+        hardware_mgr = SoftLayer.HardwareManager(env.client)
+        hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
+                                         hardware_identifier,
+                                         'hardware')
+        ticket_mgr.attach_hardware(created_ticket['id'], hardware_id)
+
+    if virtual_identifier:
+        vs_mgr = SoftLayer.VSManager(env.client)
+        vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
+                                   virtual_identifier,
+                                   'VS')
+        ticket_mgr.attach_virtual_server(created_ticket['id'], vs_id)
+
+    env.fout(ticket.get_ticket_results(ticket_mgr, created_ticket['id']))
diff --git a/SoftLayer/CLI/ticket/detach.py b/SoftLayer/CLI/ticket/detach.py
new file mode 100644
index 0000000..8c8cae0
--- /dev/null
+++ b/SoftLayer/CLI/ticket/detach.py
@@ -0,0 +1,42 @@
+"""Detach devices from a ticket."""
+# :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 helpers
+
+
+ at click.command()
+ at click.argument('identifier', type=int)
+ at click.option('--hardware',
+              'hardware_identifier',
+              help="The identifier for hardware to detach")
+ at click.option('--virtual',
+              'virtual_identifier',
+              help="The identifier for a virtual server to detach")
+ at environment.pass_env
+def cli(env, identifier, hardware_identifier, virtual_identifier):
+    """Detach devices from a ticket."""
+    ticket_mgr = SoftLayer.TicketManager(env.client)
+
+    if hardware_identifier and virtual_identifier:
+        raise exceptions.ArgumentError(
+            "Cannot detach hardware and a virtual server at the same time")
+    elif hardware_identifier:
+        hardware_mgr = SoftLayer.HardwareManager(env.client)
+        hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
+                                         hardware_identifier,
+                                         'hardware')
+        ticket_mgr.detach_hardware(identifier, hardware_id)
+    elif virtual_identifier:
+        vs_mgr = SoftLayer.VSManager(env.client)
+        vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
+                                   virtual_identifier,
+                                   'VS')
+        ticket_mgr.detach_virtual_server(identifier, vs_id)
+    else:
+        raise exceptions.ArgumentError(
+            "Must have a hardware or virtual server identifier to detach")
diff --git a/SoftLayer/CLI/virt/detail.py b/SoftLayer/CLI/virt/detail.py
index 957cce8..a4464e6 100644
--- a/SoftLayer/CLI/virt/detail.py
+++ b/SoftLayer/CLI/virt/detail.py
@@ -90,9 +90,19 @@ def cli(env, identifier, passwords=False, price=False):
                        result['billingItem']['recurringFee']])
 
     if passwords:
-        pass_table = formatting.Table(['username', 'password'])
-        for item in result['operatingSystem']['passwords']:
-            pass_table.add_row([item['username'], item['password']])
+        pass_table = formatting.Table(['software', 'username', 'password'])
+
+        for component in result['softwareComponents']:
+            for item in component['passwords']:
+                pass_table.add_row([
+                    utils.lookup(component,
+                                 'softwareLicense',
+                                 'softwareDescription',
+                                 'name'),
+                    item['username'],
+                    item['password'],
+                ])
+
         table.add_row(['users', pass_table])
 
     table.add_row(['tags', formatting.tags(result['tagReferences'])])
diff --git a/SoftLayer/CLI/vlan/detail.py b/SoftLayer/CLI/vlan/detail.py
index f97928a..59a0865 100644
--- a/SoftLayer/CLI/vlan/detail.py
+++ b/SoftLayer/CLI/vlan/detail.py
@@ -39,7 +39,7 @@ def cli(env, identifier, no_vs, no_hardware):
     table.add_row(['firewall',
                    'Yes' if vlan['firewallInterfaces'] else 'No'])
     subnets = []
-    for subnet in vlan['subnets']:
+    for subnet in vlan.get('subnets', []):
         subnet_table = formatting.KeyValueTable(['name', 'value'])
         subnet_table.align['name'] = 'r'
         subnet_table.align['value'] = 'l'
@@ -57,7 +57,7 @@ def cli(env, identifier, no_vs, no_hardware):
     server_columns = ['hostname', 'domain', 'public_ip', 'private_ip']
 
     if not no_vs:
-        if vlan['virtualGuests']:
+        if vlan.get('virtualGuests'):
             vs_table = formatting.KeyValueTable(server_columns)
             for vsi in vlan['virtualGuests']:
                 vs_table.add_row([vsi['hostname'],
@@ -69,7 +69,7 @@ def cli(env, identifier, no_vs, no_hardware):
             table.add_row(['vs', 'none'])
 
     if not no_hardware:
-        if vlan['hardware']:
+        if vlan.get('hardware'):
             hw_table = formatting.Table(server_columns)
             for hardware in vlan['hardware']:
                 hw_table.add_row([hardware['hostname'],
diff --git a/SoftLayer/consts.py b/SoftLayer/consts.py
index abcd90c..184730e 100644
--- a/SoftLayer/consts.py
+++ b/SoftLayer/consts.py
@@ -5,7 +5,7 @@
 
     :license: MIT, see LICENSE for more details.
 """
-VERSION = 'v5.0.1'
+VERSION = 'v5.1.0'
 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/SoftLayer/fixtures/SoftLayer_Account.py b/SoftLayer/fixtures/SoftLayer_Account.py
index a1fde3c..b03c26d 100644
--- a/SoftLayer/fixtures/SoftLayer_Account.py
+++ b/SoftLayer/fixtures/SoftLayer_Account.py
@@ -509,3 +509,23 @@ getNextInvoiceTotalAmount = 2
 
 getHubNetworkStorage = [{'id': 12345, 'username': 'SLOS12345-1'},
                         {'id': 12346, 'username': 'SLOS12345-2'}]
+
+getIscsiNetworkStorage = [{
+    'accountId': 1234,
+    'billingItem': {'id': 449},
+    'capacityGb': 20,
+    'createDate': '2015:50:15-04:00',
+    'guestId': '',
+    'hardwareId': '',
+    'hostId': '',
+    'id': 100,
+    'nasType': 'ISCSI',
+    'notes': """{'status': 'available'}""",
+    'password': '',
+    'serviceProviderId': 1,
+    'serviceResource': {'datacenter': {'id': 449500}},
+    'serviceResourceBackendIpAddress': '10.1.2.3',
+    'serviceResourceName': 'Storage Type 01 Aggregate staaspar0101_pc01',
+    'username': 'username',
+    'storageType': {'keyName': 'ENDURANCE_STORAGE'},
+}]
diff --git a/SoftLayer/fixtures/SoftLayer_Network_Storage.py b/SoftLayer/fixtures/SoftLayer_Network_Storage.py
new file mode 100644
index 0000000..0257b16
--- /dev/null
+++ b/SoftLayer/fixtures/SoftLayer_Network_Storage.py
@@ -0,0 +1,65 @@
+getObject = {
+    'accountId': 1234,
+    'billingItem': {'id': 449},
+    'capacityGb': 20,
+    'createDate': '2015:50:15-04:00',
+    'guestId': '',
+    'hardwareId': '',
+    'hostId': '',
+    'id': 100,
+    'nasType': 'ISCSI',
+    'notes': """{'status': 'available'}""",
+    'password': '',
+    'serviceProviderId': 1,
+    'iops': 1000,
+    'storageTierLevel': {'description': 'Tier 1'},
+    'snapshotCapacityGb': 10,
+    'parentVolume': {'snapshotSizeBytes': 1024},
+    'serviceResource': {'datacenter': {'id': 449500, 'name': 'dal05'}},
+    'serviceResourceBackendIpAddress': '10.1.2.3',
+    'serviceResourceName': 'Storage Type 01 Aggregate staaspar0101_pc01',
+    'username': 'username',
+    'storageType': {'keyName': 'ENDURANCE_STORAGE'},
+    'allowedVirtualGuests': [{
+        'id': 1234,
+        'hostname': 'test-server',
+        'domain': 'example.com',
+        'primaryBackendIpAddress': '10.0.0.1',
+        'allowedHost': {
+            'name': 'test-server',
+            'credential': {'username': 'joe', 'password': '12345'},
+        },
+    }],
+    'lunId': 2,
+    'allowedHardware': [{
+        'id': 1234,
+        'hostname': 'test-server',
+        'domain': 'example.com',
+        'primaryBackendIpAddress': '10.0.0.2',
+        'allowedHost': {
+            'name': 'test-server',
+            'credential': {'username': 'joe', 'password': '12345'},
+        },
+    }],
+    'allowedSubnets': [{
+        'id': 1234,
+        'networkIdentifier': '10.0.0.1',
+        'cidr': '24',
+        'note': 'backend subnet',
+        'allowedHost': {
+            'name': 'test-server',
+            'credential': {'username': 'joe', 'password': '12345'},
+        },
+    }],
+    'allowedIpAddresses': [{
+        'id': 1234,
+        'ipAddress': '10.0.0.1',
+        'note': 'backend ip',
+        'allowedHost': {
+            'name': 'test-server',
+            'credential': {'username': 'joe', 'password': '12345'},
+        },
+    }],
+}
+getSnapshots = []
+deleteObject = True
diff --git a/SoftLayer/fixtures/SoftLayer_Ticket.py b/SoftLayer/fixtures/SoftLayer_Ticket.py
index 4933cc6..c85deda 100644
--- a/SoftLayer/fixtures/SoftLayer_Ticket.py
+++ b/SoftLayer/fixtures/SoftLayer_Ticket.py
@@ -33,3 +33,20 @@ createStandardTicket = {
 }
 edit = True
 addUpdate = {}
+
+addAttachedHardware = {
+    "id": 123,
+    "createDate": "2013-08-01T14:14:04-07:00",
+    "hardwareId": 1,
+    "ticketId": 100
+}
+
+addAttachedVirtualGuest = {
+    "id": 123,
+    "createDate": "2013-08-01T14:14:04-07:00",
+    "virtualGuestId": 1,
+    "ticketId": 100
+}
+
+removeAttachedHardware = True
+removeAttachedVirtualGuest = True
diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
index 4380096..cb067b4 100644
--- a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
+++ b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
@@ -40,6 +40,11 @@ getObject = {
             'softwareDescription': {'version': '12.04-64 Minimal for VSI',
                                     'name': 'Ubuntu'}}
     },
+    'softwareComponents': [{
+        'passwords': [{'username': 'user', 'password': 'pass'}],
+        'softwareLicense': {
+            'softwareDescription': {'name': 'Ubuntu'}}
+    }],
     'tagReferences': [{'tag': {'name': 'production'}}],
 }
 
diff --git a/SoftLayer/managers/__init__.py b/SoftLayer/managers/__init__.py
index ff8b040..cab39fb 100644
--- a/SoftLayer/managers/__init__.py
+++ b/SoftLayer/managers/__init__.py
@@ -7,6 +7,7 @@
 
     :license: MIT, see LICENSE for more details.
 """
+from SoftLayer.managers.block import BlockStorageManager
 from SoftLayer.managers.cdn import CDNManager
 from SoftLayer.managers.dns import DNSManager
 from SoftLayer.managers.firewall import FirewallManager
@@ -25,6 +26,7 @@ from SoftLayer.managers.ticket import TicketManager
 from SoftLayer.managers.vs import VSManager
 
 __all__ = [
+    'BlockStorageManager',
     'CDNManager',
... 1900 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