[Python-modules-commits] [python-softlayer] 01/05: Import python-softlayer_5.2.0.orig.tar.gz
Scott Kitterman
kitterman at moszumanska.debian.org
Fri Sep 9 19:12:21 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 08809a72b57bec66c5b7cd6b97af2baeb4d8e396
Author: Scott Kitterman <scott at kitterman.com>
Date: Fri Sep 9 14:47:54 2016 -0400
Import python-softlayer_5.2.0.orig.tar.gz
---
CHANGELOG | 18 +
CONTRIBUTING.md | 4 +-
CONTRIBUTORS | 1 +
README.rst | 2 +-
SoftLayer/API.py | 68 +-
SoftLayer/CLI/block/access/__init__.py | 1 +
SoftLayer/CLI/block/access/authorize.py | 45 ++
SoftLayer/CLI/block/access/list.py | 38 +
SoftLayer/CLI/block/access/revoke.py | 41 ++
SoftLayer/CLI/block/cancel.py | 13 +-
SoftLayer/CLI/block/detail.py | 51 +-
SoftLayer/CLI/block/list.py | 15 +-
SoftLayer/CLI/block/order.py | 23 +-
SoftLayer/CLI/block/replication/__init__.py | 1 +
SoftLayer/CLI/block/replication/failback.py | 25 +
SoftLayer/CLI/block/replication/failover.py | 30 +
SoftLayer/CLI/block/replication/order.py | 65 ++
SoftLayer/CLI/block/snapshot/__init__.py | 1 +
SoftLayer/CLI/block/snapshot/cancel.py | 40 ++
SoftLayer/CLI/block/snapshot/create.py | 24 +
.../{snapshot_delete.py => snapshot/delete.py} | 7 +-
SoftLayer/CLI/block/snapshot/disable.py | 29 +
SoftLayer/CLI/block/snapshot/enable.py | 58 ++
.../block/{snapshot_list.py => snapshot/list.py} | 23 +-
SoftLayer/CLI/block/snapshot/order.py | 52 ++
SoftLayer/CLI/block/snapshot/restore.py | 22 +
SoftLayer/CLI/call_api.py | 34 +-
SoftLayer/CLI/environment.py | 2 +-
SoftLayer/CLI/file/__init__.py | 1 +
SoftLayer/CLI/file/access/__init__.py | 1 +
SoftLayer/CLI/file/access/authorize.py | 49 ++
SoftLayer/CLI/file/access/list.py | 38 +
SoftLayer/CLI/file/access/revoke.py | 46 ++
SoftLayer/CLI/file/cancel.py | 39 ++
SoftLayer/CLI/file/detail.py | 111 +++
SoftLayer/CLI/{block => file}/list.py | 31 +-
SoftLayer/CLI/{block => file}/order.py | 35 +-
SoftLayer/CLI/file/replication/__init__.py | 1 +
SoftLayer/CLI/file/replication/failback.py | 26 +
SoftLayer/CLI/file/replication/failover.py | 30 +
SoftLayer/CLI/file/replication/order.py | 53 ++
SoftLayer/CLI/file/snapshot/__init__.py | 1 +
SoftLayer/CLI/file/snapshot/cancel.py | 40 ++
SoftLayer/CLI/file/snapshot/create.py | 24 +
.../snapshot_delete.py => file/snapshot/delete.py} | 9 +-
SoftLayer/CLI/file/snapshot/disable.py | 29 +
SoftLayer/CLI/file/snapshot/enable.py | 58 ++
.../snapshot_list.py => file/snapshot/list.py} | 31 +-
SoftLayer/CLI/file/snapshot/order.py | 52 ++
SoftLayer/CLI/file/snapshot/restore.py | 22 +
SoftLayer/CLI/formatting.py | 17 +-
SoftLayer/CLI/hardware/detail.py | 28 +-
SoftLayer/CLI/report/__init__.py | 1 +
SoftLayer/CLI/report/bandwidth.py | 231 +++++++
SoftLayer/CLI/routes.py | 45 +-
.../CLI/{block/access_list.py => storage_utils.py} | 35 +-
SoftLayer/CLI/subnet/detail.py | 3 +
SoftLayer/CLI/subnet/list.py | 13 +-
SoftLayer/CLI/ticket/upload.py | 37 +
SoftLayer/CLI/virt/create_options.py | 2 +-
SoftLayer/CLI/virt/detail.py | 18 +-
SoftLayer/consts.py | 2 +-
SoftLayer/fixtures/SoftLayer_Account.py | 24 +-
SoftLayer/fixtures/SoftLayer_Hardware_Server.py | 12 +-
.../fixtures/SoftLayer_Metric_Tracking_Object.py | 1 +
SoftLayer/fixtures/SoftLayer_Network_Storage.py | 59 +-
SoftLayer/fixtures/SoftLayer_Ticket.py | 12 +
SoftLayer/fixtures/SoftLayer_Virtual_Guest.py | 9 +-
...er_Virtual_Guest_Block_Device_Template_Group.py | 6 +-
SoftLayer/managers/__init__.py | 2 +
SoftLayer/managers/block.py | 492 +++++++------
SoftLayer/managers/cdn.py | 8 +-
SoftLayer/managers/dns.py | 6 +-
SoftLayer/managers/file.py | 473 +++++++++++++
SoftLayer/managers/firewall.py | 8 +-
SoftLayer/managers/hardware.py | 66 +-
SoftLayer/managers/image.py | 7 +-
SoftLayer/managers/iscsi.py | 9 +-
SoftLayer/managers/load_balancer.py | 7 +-
SoftLayer/managers/messaging.py | 10 +-
SoftLayer/managers/metadata.py | 7 +-
SoftLayer/managers/network.py | 18 +-
SoftLayer/managers/object_storage.py | 8 +-
SoftLayer/managers/ordering.py | 4 +-
SoftLayer/managers/sshkey.py | 7 +-
SoftLayer/managers/ssl.py | 6 +-
SoftLayer/managers/storage_utils.py | 454 ++++++++++++
SoftLayer/managers/ticket.py | 47 +-
SoftLayer/managers/vs.py | 95 +--
SoftLayer/testing/__init__.py | 11 +-
SoftLayer/testing/xmlrpc.py | 7 +-
docs/conf.py | 4 +-
docs/{ => dev}/cla-corporate.md | 0
docs/{ => dev}/cla-individual.md | 0
docs/dev/index.rst | 23 +-
setup.py | 2 +-
tests/CLI/helper_tests.py | 14 +
tests/CLI/modules/block_tests.py | 304 +++++++-
tests/CLI/modules/call_api_tests.py | 45 ++
tests/CLI/modules/file_tests.py | 400 +++++++++++
tests/CLI/modules/report_tests.py | 185 +++++
tests/CLI/modules/server_tests.py | 5 +-
tests/CLI/modules/ticket_tests.py | 37 +
tests/CLI/modules/vs_tests.py | 4 +-
tests/api_tests.py | 44 +-
tests/managers/block_tests.py | 612 +++++++++++++++-
tests/managers/file_tests.py | 766 +++++++++++++++++++++
tests/managers/network_tests.py | 14 +-
tests/resources/attachment_upload | 1 +
109 files changed, 5657 insertions(+), 570 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 60b8a22..07b9dd0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,21 @@
+5.2.0
+
+ * Significant additions to `slcli file` and `slcli block` commands. You can now authorize hosts, revoke access. You can also create, delete, restore, disable, enable snapshots. These features need to be battle-tested so report any issues that you see.
+
+ * Adds logic to `SoftLayer.create_client_from_env` that detects if a REST endpoint_url was given in order to use the REST transport automatically. This means that you can also configure REST endpoints for `slcli`. The default still uses XML-RPC endpoint, but from a small amount of testing shows that the REST transport is significantly faster.
+
+ * Adds `--network-space` to `slcli subnet list` in order to filter subnets based on network space. The two main options are PUBLIC and PRIVATE. For example, to list all public subnets, you can run: `slcli subnet list --network-space=PUBLIC`
+
+ * Fixes a UnicodeEncodeError when piping slcli output with unicode characters. This was mostly reported with `slcli image list` but could also happen with many other calls.
+
+ * Adds a new, non-default column, "created_by" that shows who ordered the volume for `slcli file volume-list` and `slcli block volume-list`.
+
+ * Fixed a bug where os_version was not displaying correctly in `slcli virtual detail` or `slcli virtual detail`
+
+ * Adds a new `slcli report bandwidth` command that will print a report of all bandwidth pools and virtual/hardware servers that your user has access to.
+
+ * Adds an "IN" syntax to the `slcli call-api` command. For example, to find VSIs that are in either the dal05 or sng01 datacenter you can run this command: `slcli call-api Account getVirtualGuests -f 'virtualGuests.datacenter.name IN dal05,sng01'`
+
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.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7a82eb1..460e436 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,9 +3,9 @@
We are happy to accept contributions to softlayer-python. Please follow the
guidelines below.
-* Sign our contributor agreement (CLA) You can find the [CLA here](./docs/cla-individual.md).
+* Sign our contributor agreement (CLA) You can find the [CLA here](./docs/dev/cla-individual.md).
-* If you're contributing on behalf of your employer we'll need a signed copy of our corporate contributor agreement (CCLA) as well. You can find the [CCLA here](./docs/cla-corporate.md).
+* If you're contributing on behalf of your employer we'll need a signed copy of our corporate contributor agreement (CCLA) as well. You can find the [CCLA here](./docs/dev/cla-corporate.md).
* Fork the repo, make your changes, and open a pull request.
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 8844223..6197a85 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -11,6 +11,7 @@ Jason Johnson <spligak at gmail.com>
Kevin Landreth <klandreth at softlayer.com>
Kevin McDonald <kmcdonald at softlayer.com>
Łukasz Oleś <loles at mirantis.com>
+Michael Fork <mjfork at us.ibm.com>
Nathan Beittenmiller <nbeittenmiller at softlayer.com>
Neetu Jain <njain at softlayer.com>
Paul Sroufe <psroufe at softlayer.com>
diff --git a/README.rst b/README.rst
index 31da9b6..8d46772 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 higher.
+* Python 2.7, 3.3, 3.4 or 3.5.
* 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/API.py b/SoftLayer/API.py
index dc887d4..322309f 100644
--- a/SoftLayer/API.py
+++ b/SoftLayer/API.py
@@ -34,6 +34,7 @@ VALID_CALL_ARGS = set((
'raw_headers',
'limit',
'offset',
+ 'verify',
))
@@ -84,14 +85,24 @@ def create_client_from_env(username=None,
proxy=proxy,
config_file=config_file)
- # Default the transport to use XMLRPC
if transport is None:
- transport = transports.XmlRpcTransport(
- endpoint_url=settings.get('endpoint_url'),
- proxy=settings.get('proxy'),
- timeout=settings.get('timeout'),
- user_agent=user_agent,
- )
+ url = settings.get('endpoint_url')
+ if url is not None and '/rest' in url:
+ # If this looks like a rest endpoint, use the rest transport
+ transport = transports.RestTransport(
+ endpoint_url=settings.get('endpoint_url'),
+ proxy=settings.get('proxy'),
+ timeout=settings.get('timeout'),
+ user_agent=user_agent,
+ )
+ else:
+ # Default the transport to use XMLRPC
+ transport = transports.XmlRpcTransport(
+ endpoint_url=settings.get('endpoint_url'),
+ proxy=settings.get('proxy'),
+ timeout=settings.get('timeout'),
+ user_agent=user_agent,
+ )
# If we have enough information to make an auth driver, let's do it
if auth is None and settings.get('username') and settings.get('api_key'):
@@ -174,15 +185,22 @@ class BaseClient(object):
return Service(self, name)
def call(self, service, method, *args, **kwargs):
- """Make a SoftLayer API call
+ """Make a SoftLayer API call.
- :param service: the name of the SoftLayer API service
:param method: the method to call on the service
- :param \\*args: same optional arguments that ``Service.call`` takes
- :param \\*\\*kwargs: same optional keyword arguments that
- ``Service.call`` takes
-
- :param service: the name of the SoftLayer API service
+ :param \\*args: (optional) arguments for the remote call
+ :param id: (optional) id for the resource
+ :param mask: (optional) object mask
+ :param dict filter: (optional) filter dict
+ :param dict headers: (optional) optional XML-RPC headers
+ :param boolean compress: (optional) Enable/Disable HTTP compression
+ :param dict raw_headers: (optional) HTTP transport headers
+ :param int limit: (optional) return at most this many results
+ :param int offset: (optional) offset results by this many
+ :param boolean iter: (optional) if True, returns a generator with the
+ results
+ :param bool verify: verify SSL cert
+ :param cert: client certificate path
Usage:
>>> import SoftLayer
@@ -222,6 +240,7 @@ class BaseClient(object):
request.filter = kwargs.get('filter')
request.limit = kwargs.get('limit')
request.offset = kwargs.get('offset')
+ request.verify = kwargs.get('verify')
if self.auth:
extra_headers = self.auth.get_headers()
@@ -314,22 +333,15 @@ class Service(object):
self.name = name
def call(self, name, *args, **kwargs):
- """Make a SoftLayer API call.
+ """Make a SoftLayer API call
+ :param service: the name of the SoftLayer API service
:param method: the method to call on the service
- :param \\*args: (optional) arguments for the remote call
- :param id: (optional) id for the resource
- :param mask: (optional) object mask
- :param dict filter: (optional) filter dict
- :param dict headers: (optional) optional XML-RPC headers
- :param boolean compress: (optional) Enable/Disable HTTP compression
- :param dict raw_headers: (optional) HTTP transport headers
- :param int limit: (optional) return at most this many results
- :param int offset: (optional) offset results by this many
- :param boolean iter: (optional) if True, returns a generator with the
- results
- :param bool verify: verify SSL cert
- :param cert: client certificate path
+ :param \\*args: same optional arguments that ``BaseClient.call`` takes
+ :param \\*\\*kwargs: same optional keyword arguments that
+ ``BaseClient.call`` takes
+
+ :param service: the name of the SoftLayer API service
Usage:
>>> import SoftLayer
diff --git a/SoftLayer/CLI/block/access/__init__.py b/SoftLayer/CLI/block/access/__init__.py
new file mode 100644
index 0000000..050b393
--- /dev/null
+++ b/SoftLayer/CLI/block/access/__init__.py
@@ -0,0 +1 @@
+"""Block Storage Access Control."""
diff --git a/SoftLayer/CLI/block/access/authorize.py b/SoftLayer/CLI/block/access/authorize.py
new file mode 100644
index 0000000..df76b60
--- /dev/null
+++ b/SoftLayer/CLI/block/access/authorize.py
@@ -0,0 +1,45 @@
+"""Authorizes hosts on a specific block volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at click.option('--hardware-id', '-h', multiple=True,
+ help='The id of one SoftLayer_Hardware to authorize')
+ at click.option('--virtual-id', '-v', multiple=True,
+ help='The id of one SoftLayer_Virtual_Guest to authorize')
+ at click.option('--ip-address-id', '-i', multiple=True,
+ help='The id of one SoftLayer_Network_Subnet_IpAddress'
+ ' to authorize')
+ at click.option('--ip-address', multiple=True,
+ help='An IP address to authorize')
+ at environment.pass_env
+def cli(env, volume_id, hardware_id, virtual_id, ip_address_id, ip_address):
+ """Authorizes hosts to access a given volume"""
+ block_manager = SoftLayer.BlockStorageManager(env.client)
+ ip_address_id_list = list(ip_address_id)
+
+ # Convert actual IP Addresses to their SoftLayer ids
+ if ip_address is not None:
+ network_manager = SoftLayer.NetworkManager(env.client)
+ for ip_address_value in ip_address:
+ ip_address_object = network_manager.ip_lookup(ip_address_value)
+ if ip_address_object == "":
+ click.echo("IP Address not found on your account. " +
+ "Please confirm IP and try again.")
+ raise exceptions.ArgumentError('Incorrect IP Address')
+ else:
+ ip_address_id_list.append(ip_address_object['id'])
+
+ block_manager.authorize_host_to_volume(volume_id,
+ hardware_id,
+ virtual_id,
+ ip_address_id_list)
+
+ # If no exception was raised, the command succeeded
+ click.echo('The specified hosts were authorized to access %s' % volume_id)
diff --git a/SoftLayer/CLI/block/access/list.py b/SoftLayer/CLI/block/access/list.py
new file mode 100644
index 0000000..b011e26
--- /dev/null
+++ b/SoftLayer/CLI/block/access/list.py
@@ -0,0 +1,38 @@
+"""List hosts with access to 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
+from SoftLayer.CLI import storage_utils
+
+
+ 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(storage_utils.COLUMNS),
+ help='Columns to display. Options: {0}'.format(
+ ', '.join(column.name for column in storage_utils.COLUMNS)),
+ default=','.join(storage_utils.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/access/revoke.py b/SoftLayer/CLI/block/access/revoke.py
new file mode 100644
index 0000000..c2284be
--- /dev/null
+++ b/SoftLayer/CLI/block/access/revoke.py
@@ -0,0 +1,41 @@
+"""Revokes hosts' access on a specific block volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at click.option('--hardware-id', '-h', multiple=True,
+ help='The id of one SoftLayer_Hardware'
+ ' to revoke authorization')
+ at click.option('--virtual-id', '-v', multiple=True,
+ help='The id of one SoftLayer_Virtual_Guest'
+ ' to revoke authorization')
+ at click.option('--ip-address-id', '-i', multiple=True,
+ help='The id of one SoftLayer_Network_Subnet_IpAddress'
+ ' to revoke authorization')
+ at click.option('--ip-address', multiple=True,
+ help='An IP address to revoke authorization')
+ at environment.pass_env
+def cli(env, volume_id, hardware_id, virtual_id, ip_address_id, ip_address):
+ """Revokes authorization for hosts accessing a given volume"""
+ block_manager = SoftLayer.BlockStorageManager(env.client)
+ ip_address_id_list = list(ip_address_id)
+
+ # Convert actual IP Addresses to their SoftLayer ids
+ if ip_address is not None:
+ network_manager = SoftLayer.NetworkManager(env.client)
+ for ip_address_value in ip_address:
+ ip_address_object = network_manager.ip_lookup(ip_address_value)
+ ip_address_id_list.append(ip_address_object['id'])
+
+ block_manager.deauthorize_host_to_volume(volume_id,
+ hardware_id,
+ virtual_id,
+ ip_address_id_list)
+
+ # If no exception was raised, the command succeeded
+ click.echo('Access to %s was revoked for the specified hosts' % volume_id)
diff --git a/SoftLayer/CLI/block/cancel.py b/SoftLayer/CLI/block/cancel.py
index a23cee0..0311845 100644
--- a/SoftLayer/CLI/block/cancel.py
+++ b/SoftLayer/CLI/block/cancel.py
@@ -25,4 +25,15 @@ def cli(env, volume_id, reason, immediate):
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)
+ cancelled = block_storage_manager.cancel_block_volume(volume_id,
+ reason, immediate)
+
+ if cancelled:
+ if immediate:
+ click.echo('Block volume with id %s has been marked'
+ ' for immediate cancellation' % volume_id)
+ else:
+ click.echo('Block volume with id %s has been marked'
+ ' for cancellation' % volume_id)
+ else:
+ click.echo('Unable to cancel block volume %s' % volume_id)
diff --git a/SoftLayer/CLI/block/detail.py b/SoftLayer/CLI/block/detail.py
index c98736e..51a1fbd 100644
--- a/SoftLayer/CLI/block/detail.py
+++ b/SoftLayer/CLI/block/detail.py
@@ -51,9 +51,52 @@ def cli(env, volume_id):
'Snapshot Capacity (GB)',
block_volume['snapshotCapacityGb'],
])
- table.add_row([
- 'Snapshot Used (Bytes)',
- block_volume['parentVolume']['snapshotSizeBytes'],
- ])
+ if 'snapshotSizeBytes' in block_volume['parentVolume']:
+ table.add_row([
+ 'Snapshot Used (Bytes)',
+ block_volume['parentVolume']['snapshotSizeBytes'],
+ ])
+
+ table.add_row(['# of Active Transactions', "%i"
+ % block_volume['activeTransactionCount']])
+
+ if block_volume['activeTransactions']:
+ for trans in block_volume['activeTransactions']:
+ table.add_row([
+ 'Ongoing Transactions',
+ trans['transactionStatus']['friendlyName']])
+
+ table.add_row(['Replicant Count', "%u"
+ % block_volume['replicationPartnerCount']])
+
+ if block_volume['replicationPartnerCount'] > 0:
+ # This if/else temporarily handles a bug in which the SL API
+ # returns a string or object for 'replicationStatus'; it seems that
+ # the type is string for File volumes and object for Block volumes
+ if 'message' in block_volume['replicationStatus']:
+ table.add_row(['Replication Status', "%s"
+ % block_volume['replicationStatus']['message']])
+ else:
+ table.add_row(['Replication Status', "%s"
+ % block_volume['replicationStatus']])
+
+ replicant_list = []
+ for replicant in block_volume['replicationPartners']:
+ replicant_table = formatting.Table(['Replicant ID',
+ replicant['id']])
+ replicant_table.add_row([
+ 'Volume Name',
+ replicant['username']])
+ replicant_table.add_row([
+ 'Target IP',
+ replicant['serviceResourceBackendIpAddress']])
+ replicant_table.add_row([
+ 'Data Center',
+ replicant['serviceResource']['datacenter']['name']])
+ replicant_table.add_row([
+ 'Schedule',
+ replicant['replicationSchedule']['type']['keyname']])
+ replicant_list.append(replicant_table)
+ table.add_row(['Replicant Volumes', replicant_list])
env.fout(table)
diff --git a/SoftLayer/CLI/block/list.py b/SoftLayer/CLI/block/list.py
index 40edcb7..41e09ca 100644
--- a/SoftLayer/CLI/block/list.py
+++ b/SoftLayer/CLI/block/list.py
@@ -16,12 +16,21 @@ COLUMNS = [
mask="serviceResource.datacenter.name"),
column_helper.Column(
'storage_type',
- lambda b: b['storageType']['keyName'].split('_').pop(0),
+ lambda b: b['storageType']['keyName'].split('_').pop(0)
+ if 'storageType' in b and 'keyName' in b['storageType']
+ and isinstance(b['storageType']['keyName'], str)
+ else '-',
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"),
+ column_helper.Column('lunId', ('lunId',), mask="lunId"),
+ column_helper.Column('active_transactions', ('activeTransactionCount',),
+ mask="activeTransactionCount"),
+ column_helper.Column(
+ 'created_by',
+ ('billingItem', 'orderItem', 'order', 'userRecord', 'username')),
]
DEFAULT_COLUMNS = [
@@ -31,7 +40,9 @@ DEFAULT_COLUMNS = [
'storage_type',
'capacity_gb',
'bytes_used',
- 'ip_addr'
+ 'ip_addr',
+ 'lunId',
+ 'active_transactions'
]
diff --git a/SoftLayer/CLI/block/order.py b/SoftLayer/CLI/block/order.py
index f184007..22430e4 100644
--- a/SoftLayer/CLI/block/order.py
+++ b/SoftLayer/CLI/block/order.py
@@ -7,17 +7,17 @@ from SoftLayer.CLI import environment
from SoftLayer.CLI import exceptions
-CONTEXT_SETTINGS = dict(token_normalize_func=lambda x: x.upper())
+CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()}
@click.command(context_settings=CONTEXT_SETTINGS)
@click.option('--storage-type',
- help='Type of storage volume',
+ help='Type of block storage volume',
type=click.Choice(['performance', 'endurance']),
required=True)
@click.option('--size',
type=int,
- help='Size of storage volume in GB',
+ help='Size of block storage volume in GB',
required=True)
@click.option('--iops',
type=int,
@@ -42,8 +42,14 @@ CONTEXT_SETTINGS = dict(token_normalize_func=lambda x: x.upper())
@click.option('--location',
help='Datacenter short name (e.g.: dal09)',
required=True)
+ at click.option('--snapshot-size',
+ type=int,
+ help='Optional parameter for ordering snapshot '
+ 'space along with endurance block storage; specifies '
+ 'the size (in GB) of snapshot space to order')
@environment.pass_env
-def cli(env, storage_type, size, iops, tier, os_type, location):
+def cli(env, storage_type, size, iops, tier, os_type,
+ location, snapshot_size):
"""Order a block storage volume."""
block_manager = SoftLayer.BlockStorageManager(env.client)
storage_type = storage_type.lower()
@@ -62,6 +68,12 @@ def cli(env, storage_type, size, iops, tier, os_type, location):
'Option --iops must be a multiple of 100'
)
+ if snapshot_size is not None:
+ raise exceptions.CLIAbort(
+ 'Option --snapshot-size not allowed for performance volumes.'
+ ' Snapshots are only available for endurance storage.'
+ )
+
try:
order = block_manager.order_block_volume(
storage_type='performance_storage_iscsi',
@@ -84,7 +96,8 @@ def cli(env, storage_type, size, iops, tier, os_type, location):
location=location,
size=size,
tier_level=float(tier),
- os_type=os_type
+ os_type=os_type,
+ snapshot_size=snapshot_size
)
except ValueError as ex:
raise exceptions.ArgumentError(str(ex))
diff --git a/SoftLayer/CLI/block/replication/__init__.py b/SoftLayer/CLI/block/replication/__init__.py
new file mode 100644
index 0000000..ac0a44b
--- /dev/null
+++ b/SoftLayer/CLI/block/replication/__init__.py
@@ -0,0 +1 @@
+"""Block Storage Replication Control."""
diff --git a/SoftLayer/CLI/block/replication/failback.py b/SoftLayer/CLI/block/replication/failback.py
new file mode 100644
index 0000000..3887c29
--- /dev/null
+++ b/SoftLayer/CLI/block/replication/failback.py
@@ -0,0 +1,25 @@
+"""Failback from a replicant volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--replicant-id', help="ID of the replicant volume")
+ at environment.pass_env
+def cli(env, volume_id, replicant_id):
+ """Failback a block volume from the given replicant volume."""
+ block_storage_manager = SoftLayer.BlockStorageManager(env.client)
+
+ success = block_storage_manager.failback_from_replicant(
+ volume_id,
+ replicant_id
+ )
+
+ if success:
+ click.echo("Failback from replicant is now in progress.")
+ else:
+ click.echo("Failback operation could not be initiated.")
diff --git a/SoftLayer/CLI/block/replication/failover.py b/SoftLayer/CLI/block/replication/failover.py
new file mode 100644
index 0000000..545175c
--- /dev/null
+++ b/SoftLayer/CLI/block/replication/failover.py
@@ -0,0 +1,30 @@
+"""Failover to a replicant volume."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+
+
+ at click.command()
+ at click.argument('volume-id')
+ at click.option('--replicant-id', help="ID of the replicant volume")
+ at click.option('--immediate',
+ is_flag=True,
+ default=False,
+ help="Failover to replicant immediately.")
+ at environment.pass_env
+def cli(env, volume_id, replicant_id, immediate):
+ """Failover a block volume to the given replicant volume."""
+ block_storage_manager = SoftLayer.BlockStorageManager(env.client)
+
+ success = block_storage_manager.failover_to_replicant(
+ volume_id,
+ replicant_id,
+ immediate
+ )
+
+ if success:
+ click.echo("Failover to replicant is now in progress.")
+ else:
+ click.echo("Failover operation could not be initiated.")
diff --git a/SoftLayer/CLI/block/replication/order.py b/SoftLayer/CLI/block/replication/order.py
new file mode 100644
index 0000000..c25a8be
--- /dev/null
+++ b/SoftLayer/CLI/block/replication/order.py
@@ -0,0 +1,65 @@
+"""Order a block storage replica 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('volume_id')
+ at click.option('--snapshot-schedule', '-s',
+ help='Snapshot schedule to use for replication, '
+ '(HOURLY | DAILY | WEEKLY)',
+ required=True,
+ type=click.Choice(['HOURLY', 'DAILY', 'WEEKLY']))
+ at click.option('--location', '-l',
+ help='Short name of the data center for the replicant '
+ '(e.g.: dal09)',
+ required=True)
+ at 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']))
+ at click.option('--os-type',
+ help='Operating System Type (e.g.: LINUX) of the primary'
+ ' volume for which a replica is ordered [optional]',
+ type=click.Choice([
+ 'HYPER_V',
+ 'LINUX',
+ 'VMWARE',
+ 'WINDOWS_2008',
+ 'WINDOWS_GPT',
+ 'WINDOWS',
+ 'XEN']))
+ at environment.pass_env
+def cli(env, volume_id, snapshot_schedule, location, tier, os_type):
+ """Order a block storage replica volume."""
+ block_manager = SoftLayer.BlockStorageManager(env.client)
+
+ if tier is not None:
+ tier = float(tier)
+
+ try:
+ order = block_manager.order_replicant_volume(
+ volume_id,
+ snapshot_schedule=snapshot_schedule,
+ location=location,
+ tier=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/__init__.py b/SoftLayer/CLI/block/snapshot/__init__.py
new file mode 100644
index 0000000..eb4d41b
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot/__init__.py
@@ -0,0 +1 @@
+"""Block Storage Snapshot Control."""
diff --git a/SoftLayer/CLI/block/snapshot/cancel.py b/SoftLayer/CLI/block/snapshot/cancel.py
new file mode 100644
index 0000000..7a6150b
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot/cancel.py
@@ -0,0 +1,40 @@
+"""Cancel a snapshot space subscription."""
+# :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 snapshot space immediately instead "
+ "of on the billing anniversary")
+ at environment.pass_env
+def cli(env, volume_id, reason, immediate):
+ """Cancel existing snapshot space for a given volume."""
+
+ block_storage_manager = SoftLayer.BlockStorageManager(env.client)
+
+ if not (env.skip_confirmations or formatting.no_going_back(volume_id)):
+ raise exceptions.CLIAbort('Aborted')
+
+ cancelled = block_storage_manager.cancel_snapshot_space(
+ volume_id, reason, immediate)
+
+ if cancelled:
+ if immediate:
+ click.echo('Block volume with id %s has been marked'
+ ' for immediate snapshot cancellation' % volume_id)
+ else:
+ click.echo('Block volume with id %s has been marked'
+ ' for snapshot cancellation' % volume_id)
+ else:
+ click.echo('Unable to cancel snapshot space for block volume %s'
+ % volume_id)
diff --git a/SoftLayer/CLI/block/snapshot/create.py b/SoftLayer/CLI/block/snapshot/create.py
new file mode 100644
index 0000000..68dc976
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot/create.py
@@ -0,0 +1,24 @@
+"""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('volume_id')
+ at click.option('--notes', '-n',
+ help='Notes to set on the new snapshot')
+ at environment.pass_env
+def cli(env, volume_id, notes):
+ """Creates a snapshot on a given volume"""
+ block_manager = SoftLayer.BlockStorageManager(env.client)
+ snapshot = block_manager.create_snapshot(volume_id, notes=notes)
+
+ if 'id' in snapshot:
+ click.echo('New snapshot created with id: %s' % snapshot['id'])
+ else:
+ click.echo('Error occurred while creating snapshot.\n'
+ 'Ensure volume is not failed over or in another '
+ 'state which prevents taking snapshots.')
diff --git a/SoftLayer/CLI/block/snapshot_delete.py b/SoftLayer/CLI/block/snapshot/delete.py
similarity index 65%
copy from SoftLayer/CLI/block/snapshot_delete.py
copy to SoftLayer/CLI/block/snapshot/delete.py
index 6daa3f4..229a5d7 100644
--- a/SoftLayer/CLI/block/snapshot_delete.py
+++ b/SoftLayer/CLI/block/snapshot/delete.py
@@ -1,4 +1,4 @@
-"""Create a block storage snapshot."""
+"""Delete a block storage snapshot."""
# :license: MIT, see LICENSE for more details.
import click
@@ -12,4 +12,7 @@ from SoftLayer.CLI import environment
def cli(env, snapshot_id):
"""Deletes a snapshot on a given volume"""
block_manager = SoftLayer.BlockStorageManager(env.client)
- block_manager.delete_snapshot(snapshot_id)
+ deleted = block_manager.delete_snapshot(snapshot_id)
+
+ if deleted:
+ click.echo('Snapshot %s deleted' % snapshot_id)
diff --git a/SoftLayer/CLI/block/snapshot/disable.py b/SoftLayer/CLI/block/snapshot/disable.py
new file mode 100644
index 0000000..f34d348
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot/disable.py
@@ -0,0 +1,29 @@
+"""Disable scheduled snapshots of a specific volume"""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at click.option('--schedule-type',
+ help='Snapshot schedule [HOURLY|DAILY|WEEKLY]',
+ required=True)
+ at environment.pass_env
+def cli(env, volume_id, schedule_type):
+ """Disables snapshots on the specified schedule for a given volume"""
+
+ if (schedule_type != 'HOURLY' and schedule_type != 'DAILY'
+ and schedule_type != 'WEEKLY'):
+ raise exceptions.CLIAbort(
+ '--schedule-type must be HOURLY, DAILY, or WEEKLY')
+
+ block_manager = SoftLayer.BlockStorageManager(env.client)
+ disabled = block_manager.disable_snapshots(volume_id, schedule_type)
+
+ if disabled:
+ click.echo('%s snapshots have been disabled for volume %s'
+ % (schedule_type, volume_id))
diff --git a/SoftLayer/CLI/block/snapshot/enable.py b/SoftLayer/CLI/block/snapshot/enable.py
new file mode 100644
index 0000000..6ade946
--- /dev/null
+++ b/SoftLayer/CLI/block/snapshot/enable.py
@@ -0,0 +1,58 @@
+# snapshot_enable.py
+"""Create a block storage snapshot [ENABLE]."""
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+
+
+ at click.command()
+ at click.argument('volume_id')
+ at click.option('--schedule-type',
+ help='Snapshot schedule [HOURLY|DAILY|WEEKLY]',
+ required=True)
+ at click.option('--retention-count',
+ help='Number of snapshots to retain',
+ required=True)
+ at click.option('--minute',
+ help='Minute of the day when snapshots should be taken',
+ default=0)
+ at click.option('--hour',
+ help='Hour of the day when snapshots should be taken',
+ default=0)
+ at click.option('--day-of-week',
+ help='Day of the week when snapshots should be taken',
+ default='SUNDAY')
+ at environment.pass_env
+def cli(env, volume_id, schedule_type, retention_count,
+ minute, hour, day_of_week):
+ """Enables snapshots for a given volume on the specified schedule"""
+ block_manager = SoftLayer.BlockStorageManager(env.client)
+
+ valid_schedule_types = {'HOURLY', 'DAILY', 'WEEKLY'}
+ valid_days = {'SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY',
+ 'FRIDAY', 'SATURDAY'}
+
+ if schedule_type not in valid_schedule_types:
+ raise exceptions.CLIAbort(
+ '--schedule-type must be HOURLY, DAILY, or WEEKLY, not '
+ + schedule_type)
+
+ if minute < 0 or minute > 59:
+ raise exceptions.CLIAbort(
+ '--minute value must be between 0 and 59')
+ if hour < 0 or hour > 23:
+ raise exceptions.CLIAbort(
+ '--hour value must be between 0 and 23')
+ if day_of_week not in valid_days:
+ raise exceptions.CLIAbort(
+ '--day_of_week value must be a valid day (ex: SUNDAY)')
+
+ enabled = block_manager.enable_snapshots(volume_id, schedule_type,
+ retention_count, minute,
+ hour, day_of_week)
+
+ if enabled:
+ click.echo('%s snapshots have been enabled for volume %s'
+ % (schedule_type, volume_id))
diff --git a/SoftLayer/CLI/block/snapshot_list.py b/SoftLayer/CLI/block/snapshot/list.py
similarity index 65%
copy from SoftLayer/CLI/block/snapshot_list.py
copy to SoftLayer/CLI/block/snapshot/list.py
index 7ffea3f..b47f594 100644
--- a/SoftLayer/CLI/block/snapshot_list.py
+++ b/SoftLayer/CLI/block/snapshot/list.py
@@ -9,17 +9,12 @@ 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'),
... 7186 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