diff options
| author | Jenkins <jenkins@review.openstack.org> | 2017-01-27 00:55:55 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2017-01-27 00:55:55 +0000 |
| commit | 7d140d0896fe54c4fc03fa501544da4e67d666c6 (patch) | |
| tree | 2226f94d28e47fa940a18b6c2ae24994615ed77e | |
| parent | 61f690920a68be9f48880010f22944fffd958171 (diff) | |
| parent | 22c3693f8c03ba4b9a22697656a519370d6b5eaf (diff) | |
| download | python-cinderclient-7d140d0896fe54c4fc03fa501544da4e67d666c6.tar.gz | |
| -rw-r--r-- | cinderclient/v3/attachments.py | 68 | ||||
| -rw-r--r-- | cinderclient/v3/client.py | 4 | ||||
| -rw-r--r-- | cinderclient/v3/shell.py | 203 |
3 files changed, 273 insertions, 2 deletions
diff --git a/cinderclient/v3/attachments.py b/cinderclient/v3/attachments.py new file mode 100644 index 0000000..326e7a7 --- /dev/null +++ b/cinderclient/v3/attachments.py @@ -0,0 +1,68 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Attachment interface.""" + +from cinderclient import base + + +class VolumeAttachment(base.Resource): + """An attachment is a connected volume.""" + def __repr__(self): + """Obj to Str method.""" + return "<Attachment: %s>" % self.id + + +class VolumeAttachmentManager(base.ManagerWithFind): + resource_class = VolumeAttachment + + def create(self, volume_id, connector, instance_id): + """Create a attachment for specified volume.""" + body = {'attachment': {'volume_uuid': volume_id, + 'instance_uuid': instance_id, + 'connector': connector}} + retval = self._create('/attachments', body, 'attachment') + return retval.to_dict() + + def delete(self, attachment): + """Delete an attachment by ID.""" + return self._delete("/attachments/%s" % base.getid(attachment)) + + def list(self, detailed=False, search_opts=None, marker=None, limit=None, + sort_key=None, sort_dir=None, sort=None): + """List all attachments.""" + resource_type = "attachments" + url = self._build_list_url(resource_type, + detailed=detailed, + search_opts=search_opts, + marker=marker, + limit=limit, + sort_key=sort_key, + sort_dir=sort_dir, sort=sort) + return self._list(url, resource_type, limit=limit) + + def show(self, id): + """Attachment show. + + :param name: Attachment ID. + """ + url = '/attachments/%s' % id + resp, body = self.api.client.get(url) + return self.resource_class(self, body['attachment'], loaded=True, + resp=resp) + + def update(self, id, connector): + """Attachment update.""" + body = {'attachment': {'connector': connector}} + resp = self._update('/attachments/%s' % id, body) + return self.resource_class(self, resp['attachment'], loaded=True, + resp=resp) diff --git a/cinderclient/v3/client.py b/cinderclient/v3/client.py index 79bb110..a3dcdde 100644 --- a/cinderclient/v3/client.py +++ b/cinderclient/v3/client.py @@ -17,6 +17,7 @@ import logging from cinderclient import client from cinderclient import api_versions +from cinderclient.v3 import attachments from cinderclient.v3 import availability_zones from cinderclient.v3 import cgsnapshots from cinderclient.v3 import clusters @@ -71,7 +72,6 @@ class Client(object): self.limits = limits.LimitsManager(self) self.api_version = api_version or api_versions.APIVersion(self.version) - # extensions self.volumes = volumes.VolumeManager(self) self.volume_snapshots = volume_snapshots.SnapshotManager(self) self.volume_types = volume_types.VolumeTypeManager(self) @@ -98,6 +98,8 @@ class Client(object): availability_zones.AvailabilityZoneManager(self) self.pools = pools.PoolManager(self) self.capabilities = capabilities.CapabilitiesManager(self) + self.attachments = \ + attachments.VolumeAttachmentManager(self) # Add in any extensions... if extensions: diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py index 6424ccc..aabe1bc 100644 --- a/cinderclient/v3/shell.py +++ b/cinderclient/v3/shell.py @@ -1181,7 +1181,6 @@ def do_message_delete(cs, args): raise exceptions.CommandError("Unable to delete any of the specified " "messages.") - @utils.arg('--all-tenants', dest='all_tenants', metavar='<0|1>', @@ -1276,3 +1275,205 @@ def do_snapshot_list(cs, args): utils.print_list(snapshots, ['ID', 'Volume ID', 'Status', 'Name', 'Size'], sortby_index=sortby_index) + +@api_versions.wraps('3.27') +@utils.arg('--all-tenants', + dest='all_tenants', + metavar='<0|1>', + nargs='?', + type=int, + const=1, + default=0, + help='Shows details for all tenants. Admin only.') +@utils.arg('--volume-id', + metavar='<volume-id>', + default=None, + help='Filters results by a volume ID. Default=None.') +@utils.arg('--status', + metavar='<status>', + default=None, + help='Filters results by a status. Default=None.') +@utils.arg('--marker', + metavar='<marker>', + default=None, + help='Begin returning attachments that appear later in ' + 'attachment list than that represented by this id. ' + 'Default=None.') +@utils.arg('--limit', + metavar='<limit>', + default=None, + help='Maximum number of attachemnts to return. Default=None.') +@utils.arg('--sort', + metavar='<key>[:<direction>]', + default=None, + help=(('Comma-separated list of sort keys and directions in the ' + 'form of <key>[:<asc|desc>]. ' + 'Valid keys: %s. ' + 'Default=None.') % ', '.join(base.SORT_KEY_VALUES))) +@utils.arg('--tenant', + type=str, + dest='tenant', + nargs='?', + metavar='<tenant>', + help='Display information from single tenant (Admin only).') +def do_attachment_list(cs, args): + """Lists all attachments.""" + search_opts = { + 'all_tenants': args.all_tenants, + 'status': args.status, + 'volume_id': args.volume_id, + } + + attachments = cs.attachments.list(search_opts=search_opts, + marker=args.marker, + limit=args.limit, + sort=args.sort) + columns = ['ID', 'Volume ID', 'Status', 'Instance'] + if args.sort: + sortby_index = None + else: + sortby_index = 0 + utils.print_list(attachments, columns, sortby_index=sortby_index) + + +@api_versions.wraps('3.27') +@utils.arg('attachment', + metavar='<attachment>', + help='ID of attachment.') +def do_attachment_show(cs, args): + """Show detailed information for attachment.""" + attachment = cs.attachments.show(args.attachment) + attachment_dict = attachment.to_dict() + connection_dict = attachment_dict.pop('connection_info', {}) + utils.print_dict(attachment_dict) + + # TODO(jdg): Need to add checks here like admin/policy for displaying the + # connection_info, this is still experimental so we'll leave it enabled for + # now + if connection_dict: + utils.print_dict(connection_dict) + + +@api_versions.wraps('3.27') +@utils.arg('volume', + metavar='<volume>', + help='Name or ID of volume or volumes to attach.') +@utils.arg('--instance', + metavar='<instance>', + default=None, + help='UUID of Instance attaching to. Default=None.') +@utils.arg('--connect', + metavar='<connect>', + default=False, + help='Make an active connection using provided connector info ' + '(True or False).') +@utils.arg('--initiator', + metavar='<initiator>', + default=None, + help='iqn of the initiator attaching to. Default=None.') +@utils.arg('--ip', + metavar='<ip>', + default=None, + help='ip of the system attaching to. Default=None.') +@utils.arg('--host', + metavar='<host>', + default=None, + help='Name of the host attaching to. Default=None.') +@utils.arg('--platform', + metavar='<platform>', + default='x86_64', + help='Platform type. Default=x86_64.') +@utils.arg('--ostype', + metavar='<ostype>', + default='linux2', + help='OS type. Default=linux2.') +@utils.arg('--multipath', + metavar='<multipath>', + default=False, + help='OS type. Default=False.') +@utils.arg('--mountpoint', + metavar='<mountpoint>', + default=None, + help='Mountpoint volume will be attached at. Default=None.') +def do_attachment_create(cs, args): + """Create an attachment for a cinder volume.""" + + connector = {} + if strutils.bool_from_string(args.connect, strict=True): + # FIXME(jdg): Add in all the options when they're finalized + connector = {'initiator': args.initiator, + 'ip': args.ip, + 'platform': args.platform, + 'host': args.host, + 'os_type': args.ostype, + 'multipath': args.multipath} + attachment = cs.attachments.create(args.volume, + connector, + args.instance) + connector_dict = attachment.pop('connection_info', None) + utils.print_dict(attachment) + if connector_dict: + utils.print_dict(connector_dict) + + +@api_versions.wraps('3.27') +@utils.arg('attachment', + metavar='<attachment>', + help='ID of attachment.') +@utils.arg('--initiator', + metavar='<initiator>', + default=None, + help='iqn of the initiator attaching to. Default=None.') +@utils.arg('--ip', + metavar='<ip>', + default=None, + help='ip of the system attaching to. Default=None.') +@utils.arg('--host', + metavar='<host>', + default=None, + help='Name of the host attaching to. Default=None.') +@utils.arg('--platform', + metavar='<platform>', + default='x86_64', + help='Platform type. Default=x86_64.') +@utils.arg('--ostype', + metavar='<ostype>', + default='linux2', + help='OS type. Default=linux2.') +@utils.arg('--multipath', + metavar='<multipath>', + default=False, + help='OS type. Default=False.') +@utils.arg('--mountpoint', + metavar='<mountpoint>', + default=None, + help='Mountpoint volume will be attached at. Default=None.') +def do_attachment_update(cs, args): + """Update an attachment for a cinder volume. + This call is designed to be more of an attachment completion than anything + else. It expects the value of a connector object to notify the driver that + the volume is going to be connected and where it's being connected to. + """ + connector = {'initiator': args.initiator, + 'ip': args.ip, + 'platform': args.platform, + 'host': args.host, + 'os_type': args.ostype, + 'multipath': args.multipath} + attachment = cs.attachments.update(args.attachment, + connector) + attachment_dict = attachment.to_dict() + connector_dict = attachment_dict.pop('connection_info', None) + utils.print_dict(attachment_dict) + if connector_dict: + utils.print_dict(connector_dict) + + +@api_versions.wraps('3.27') +@utils.arg('attachment', + metavar='<attachment>', nargs='+', + help='ID of attachment or attachments to delete.') +def do_attachment_delete(cs, args): + """Delete an attachment for a cinder volume.""" + for attachment in args.attachment: + cs.attachments.delete(attachment) |
