def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity if parsed_args.project: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --project option') raise exceptions.CommandError(msg) # NOTE(stephenfin): This is done client side because nova doesn't # currently support doing so server-side. If this is slow, we can # think about spinning up a threadpool or similar. project = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id users = identity_client.users.list(tenant_id=project) data = [] for user in users: data.extend(compute_client.keypairs(user_id=user.id)) elif parsed_args.user: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --user option') raise exceptions.CommandError(msg) user = identity_common.find_user( identity_client, parsed_args.user, parsed_args.user_domain, ) data = compute_client.keypairs(user_id=user.id) else: data = compute_client.keypairs() columns = ("Name", "Fingerprint") if sdk_utils.supports_microversion(compute_client, '2.2'): columns += ("Type", ) return ( columns, (utils.get_item_properties(s, columns) for s in data), )
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute columns = ( "id", "binary", "host", "availability_zone", "status", "state", "updated_at", ) column_headers = ( "ID", "Binary", "Host", "Zone", "Status", "State", "Updated At", ) if parsed_args.long: columns += ("disabled_reason", ) column_headers += ("Disabled Reason", ) if sdk_utils.supports_microversion(compute_client, '2.11'): columns += ("is_forced_down", ) column_headers += ("Forced Down", ) data = compute_client.services(host=parsed_args.host, binary=parsed_args.service) return (column_headers, (utils.get_item_properties(s, columns) for s in data))
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity kwargs = {} if parsed_args.user: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --user option') raise exceptions.CommandError(msg) kwargs['user_id'] = identity_common.find_user( identity_client, parsed_args.user, parsed_args.user_domain, ).id keypair = compute_client.find_keypair(parsed_args.name, **kwargs, ignore_missing=False) if not parsed_args.public_key: display_columns, columns = _get_keypair_columns(keypair, hide_pub_key=True) data = utils.get_item_properties(keypair, columns) return (display_columns, data) else: sys.stdout.write(keypair.public_key) return ({}, {})
def _get_microversion_for(self, session, action): """Get microversion to use for the given action. The base version uses :meth:`_get_microversion_for_list`. Subclasses can override this method if more complex logic is needed. :param session: :class`keystoneauth1.adapter.Adapter` :param action: One of "fetch", "commit", "create", "delete", "patch". Unused in the base implementation. :return: microversion as string or ``None`` """ if action not in ('fetch', 'commit', 'create', 'delete', 'patch'): raise ValueError('Invalid action: %s' % action) microversion = self._get_microversion_for_list(session) if action == 'create': # `policy` and `rules` are added with mv=2.64. In it also # `policies` are removed. if utils.supports_microversion(session, '2.64'): if self.policies: if not self.policy and isinstance(self.policies, list): self.policy = self.policies[0] self._body.clean(only={'policies'}) microversion = self._max_microversion else: if self.rules: message = ("API version %s is required to set rules, but " "it is not available.") % 2.64 raise exceptions.NotSupported(message) if self.policy: if not self.policies: self.policies = [self.policy] self._body.clean(only={'policy'}) return microversion
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity try: flavor = compute_client.find_flavor(parsed_args.flavor, get_extra_specs=True, ignore_missing=False) except sdk_exceptions.ResourceNotFound as e: raise exceptions.CommandError(e.message) if parsed_args.description: if not sdk_utils.supports_microversion(compute_client, '2.55'): msg = _( 'The --description parameter requires server support for ' 'API microversion 2.55') raise exceptions.CommandError(msg) compute_client.update_flavor(flavor=flavor.id, description=parsed_args.description) result = 0 if parsed_args.no_property: try: for key in flavor.extra_specs.keys(): compute_client.delete_flavor_extra_specs_property( flavor.id, key) except Exception as e: LOG.error(_("Failed to clear flavor properties: %s"), e) result += 1 if parsed_args.properties: try: compute_client.create_flavor_extra_specs( flavor.id, parsed_args.properties) except Exception as e: LOG.error(_("Failed to set flavor properties: %s"), e) result += 1 if parsed_args.project: try: if flavor.is_public: msg = _("Cannot set access for a public flavor") raise exceptions.CommandError(msg) else: project_id = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id compute_client.flavor_add_tenant_access( flavor.id, project_id) except Exception as e: LOG.error(_("Failed to set flavor access to project: %s"), e) result += 1 if result > 0: raise exceptions.CommandError( _("Command Failed: One or more of" " the operations failed"))
def live_migrate(self, session, host, force, block_migration): if utils.supports_microversion(session, '2.30'): return self._live_migrate_30(session, host, force=force, block_migration=block_migration) elif utils.supports_microversion(session, '2.25'): return self._live_migrate_25(session, host, force=force, block_migration=block_migration) else: return self._live_migrate(session, host, force=force, block_migration=block_migration)
def live_migrate(self, session, host, force, block_migration, disk_over_commit=False): if utils.supports_microversion(session, '2.30'): return self._live_migrate_30( session, host, force=force, block_migration=block_migration) elif utils.supports_microversion(session, '2.25'): return self._live_migrate_25( session, host, force=force, block_migration=block_migration) else: return self._live_migrate( session, host, force=force, block_migration=block_migration, disk_over_commit=disk_over_commit)
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity if parsed_args.project and parsed_args.public: msg = _("--project is only allowed with --private") raise exceptions.CommandError(msg) args = { 'name': parsed_args.name, 'ram': parsed_args.ram, 'vcpus': parsed_args.vcpus, 'disk': parsed_args.disk, 'id': parsed_args.id, 'ephemeral': parsed_args.ephemeral, 'swap': parsed_args.swap, 'rxtx_factor': parsed_args.rxtx_factor, 'is_public': parsed_args.public, } if parsed_args.description: if not sdk_utils.supports_microversion(compute_client, '2.55'): msg = _( 'The --description parameter requires server support for ' 'API microversion 2.55') raise exceptions.CommandError(msg) args['description'] = parsed_args.description flavor = compute_client.create_flavor(**args) if parsed_args.project: try: project_id = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id compute_client.flavor_add_tenant_access(flavor.id, project_id) except Exception as e: msg = _("Failed to add project %(project)s access to " "flavor: %(e)s") LOG.error(msg, {'project': parsed_args.project, 'e': e}) if parsed_args.properties: try: flavor = compute_client.create_flavor_extra_specs( flavor, parsed_args.properties) except Exception as e: LOG.error(_("Failed to set flavor properties: %s"), e) display_columns, columns = _get_flavor_columns(flavor) data = utils.get_dict_properties(flavor, columns, formatters=_formatters) return (display_columns, data)
def create(self, session, prepend_key=True, base_path=None, **params): if not self.protocol: self.protocol = \ CONSOLE_TYPE_PROTOCOL_MAPPING.get(self.type) if (not utils.supports_microversion(session, '2.8') and self.type == 'webmks'): raise ValueError('Console type webmks is not supported on ' 'server side') return super(ServerRemoteConsole, self).create(session, prepend_key=prepend_key, base_path=base_path, **params)
def get_uptime(self, session): """Get uptime information for the hypervisor Updates uptime attribute of the hypervisor object """ warnings.warn( "This call is deprecated and is only available until Nova 2.88") if utils.supports_microversion(session, '2.88'): raise exceptions.SDKException( 'Hypervisor.get_uptime is not supported anymore') url = utils.urljoin(self.base_path, self.id, 'uptime') microversion = self._get_microversion_for(session, 'fetch') response = session.get( url, microversion=microversion) self._translate_response(response) return self
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity kwargs = {} result = 0 if parsed_args.user: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --user option') raise exceptions.CommandError(msg) kwargs['user_id'] = identity_common.find_user( identity_client, parsed_args.user, parsed_args.user_domain, ).id for n in parsed_args.name: try: compute_client.delete_keypair(n, **kwargs, ignore_missing=False) except Exception as e: result += 1 LOG.error( _("Failed to delete key with name " "'%(name)s': %(e)s"), { 'name': n, 'e': e }) if result > 0: total = len(parsed_args.name) msg = (_("%(result)s of %(total)s keys failed " "to delete.") % { 'result': result, 'total': total }) raise exceptions.CommandError(msg)
def create_image(self, session, name, metadata=None): """Create image from server.""" action = {'name': name} if metadata is not None: action['metadata'] = metadata body = {'createImage': action} # You won't believe it - wait, who am I kidding - of course you will! # Nova returns the URL of the image created in the Location # header of the response. (what?) But, even better, the URL it responds # with has a very good chance of being wrong (it is built from # nova.conf values that point to internal API servers in any cloud # large enough to have both public and internal endpoints. # However, nobody has ever noticed this because novaclient doesn't # actually use that URL - it extracts the id from the end of # the url, then returns the id. This leads us to question: # a) why Nova is going to return a value in a header # b) why it's going to return data that probably broken # c) indeed the very nature of the fabric of reality # Although it fills us with existential dread, we have no choice but # to follow suit like a lemming being forced over a cliff by evil # producers from Disney. microversion = None if utils.supports_microversion(session, '2.45'): microversion = '2.45' response = self._action(session, body, microversion) body = None try: # There might be body, might be not body = response.json() except Exception: pass if body and 'image_id' in body: image_id = body['image_id'] else: image_id = response.headers['Location'].rsplit('/', 1)[1] return image_id
def set_forced_down( self, session, host=None, binary=None, forced=False ): """Update forced_down information of a service.""" microversion = session.default_microversion body = {} if not host: host = self.host if not binary: binary = self.binary body = { 'host': host, 'binary': binary, } if utils.supports_microversion(session, '2.11'): body['forced_down'] = forced # Using forced_down works only 2.11-2.52, therefore pin it microversion = '2.11' # This will not work with newest microversions return self._action( session, 'force-down', body, microversion=microversion)
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute if (parsed_args.enable or not parsed_args.disable) and \ parsed_args.disable_reason: msg = _("Cannot specify option --disable-reason without " "--disable specified.") raise exceptions.CommandError(msg) # Starting with microversion 2.53, there is a single # PUT /os-services/{service_id} API for updating nova-compute # services. If 2.53+ is used we need to find the nova-compute # service using the --host and --service (binary) values. requires_service_id = (sdk_utils.supports_microversion( compute_client, '2.53')) service_id = None if requires_service_id: # TODO(mriedem): Add an --id option so users can pass the service # id (as a uuid) directly rather than make us look it up using # host/binary. service_id = SetService._find_service_by_host_and_binary( compute_client, parsed_args.host, parsed_args.service).id result = 0 enabled = None try: if parsed_args.enable: enabled = True if parsed_args.disable: enabled = False if enabled is not None: if enabled: compute_client.enable_service(service_id, parsed_args.host, parsed_args.service) else: compute_client.disable_service(service_id, parsed_args.host, parsed_args.service, parsed_args.disable_reason) except Exception: status = "enabled" if enabled else "disabled" LOG.error("Failed to set service status to %s", status) result += 1 force_down = None if parsed_args.down: force_down = True if parsed_args.up: force_down = False if force_down is not None: if not sdk_utils.supports_microversion(compute_client, '2.11'): msg = _('--os-compute-api-version 2.11 or later is ' 'required') raise exceptions.CommandError(msg) try: compute_client.update_service_forced_down( service_id, parsed_args.host, parsed_args.service, force_down) except Exception: state = "down" if force_down else "up" LOG.error("Failed to set service state to %s", state) result += 1 if result > 0: msg = _("Compute service %(service)s of host %(host)s failed to " "set.") % { "service": parsed_args.service, "host": parsed_args.host } raise exceptions.CommandError(msg)
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity kwargs = {'name': parsed_args.name} public_key = parsed_args.public_key if public_key: try: with io.open(os.path.expanduser(parsed_args.public_key)) as p: public_key = p.read() except IOError as e: msg = _("Key file %(public_key)s not found: %(exception)s") raise exceptions.CommandError(msg % { "public_key": parsed_args.public_key, "exception": e }) kwargs['public_key'] = public_key if parsed_args.type: if not sdk_utils.supports_microversion(compute_client, '2.2'): msg = _( '--os-compute-api-version 2.2 or greater is required to ' 'support the --type option') raise exceptions.CommandError(msg) kwargs['key_type'] = parsed_args.type if parsed_args.user: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --user option') raise exceptions.CommandError(msg) kwargs['user_id'] = identity_common.find_user( identity_client, parsed_args.user, parsed_args.user_domain, ).id keypair = compute_client.create_keypair(**kwargs) private_key = parsed_args.private_key # Save private key into specified file if private_key: try: with io.open(os.path.expanduser(parsed_args.private_key), 'w+') as p: p.write(keypair.private_key) except IOError as e: msg = _("Key file %(private_key)s can not be saved: " "%(exception)s") raise exceptions.CommandError(msg % { "private_key": parsed_args.private_key, "exception": e }) # NOTE(dtroyer): how do we want to handle the display of the private # key when it needs to be communicated back to the user # For now, duplicate nova keypair-add command output if public_key or private_key: display_columns, columns = _get_keypair_columns(keypair, hide_pub_key=True, hide_priv_key=True) data = utils.get_item_properties(keypair, columns) return (display_columns, data) else: sys.stdout.write(keypair.private_key) return ({}, {})
def take_action(self, parsed_args): compute_client = self.app.client_manager.sdk_connection.compute identity_client = self.app.client_manager.identity kwargs = {} if parsed_args.marker: if not sdk_utils.supports_microversion(compute_client, '2.35'): msg = _('--os-compute-api-version 2.35 or greater is required ' 'to support the --marker option') raise exceptions.CommandError(msg) kwargs['marker'] = parsed_args.marker if parsed_args.limit: if not sdk_utils.supports_microversion(compute_client, '2.35'): msg = _('--os-compute-api-version 2.35 or greater is required ' 'to support the --limit option') raise exceptions.CommandError(msg) kwargs['limit'] = parsed_args.limit if parsed_args.project: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --project option') raise exceptions.CommandError(msg) if parsed_args.marker: # NOTE(stephenfin): Because we're doing this client-side, we # can't really rely on the marker, because we don't know what # user the marker is associated with msg = _('--project is not compatible with --marker') # NOTE(stephenfin): This is done client side because nova doesn't # currently support doing so server-side. If this is slow, we can # think about spinning up a threadpool or similar. project = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id users = identity_client.users.list(tenant_id=project) data = [] for user in users: kwargs['user_id'] = user.id data.extend(compute_client.keypairs(**kwargs)) elif parsed_args.user: if not sdk_utils.supports_microversion(compute_client, '2.10'): msg = _( '--os-compute-api-version 2.10 or greater is required to ' 'support the --user option') raise exceptions.CommandError(msg) user = identity_common.find_user( identity_client, parsed_args.user, parsed_args.user_domain, ) kwargs['user_id'] = user.id data = compute_client.keypairs(**kwargs) else: data = compute_client.keypairs(**kwargs) columns = ("Name", "Fingerprint") if sdk_utils.supports_microversion(compute_client, '2.2'): columns += ("Type", ) return ( columns, (utils.get_item_properties(s, columns) for s in data), )
def test_requested_not_supported_no_default(self): self.adapter.default_microversion = None self.assertFalse(utils.supports_microversion(self.adapter, '2.2'))
def test_requested_supported_equal_default(self): self.adapter.default_microversion = '1.8' self.assertTrue(utils.supports_microversion(self.adapter, '1.8'))
def test_requested_supported_lower_default(self): self.adapter.default_microversion = '1.2' self.assertFalse(utils.supports_microversion(self.adapter, '1.8'))