def _heat_deploy(self, stack, stack_name, template_path, parameters, env_files, timeout, tht_root, env, update_plan_only, run_validations, skip_deploy_identifier, plan_env_file, deployment_options=None): """Verify the Baremetal nodes are available and do a stack update""" if stack: self.log.debug( "Checking compatibilities of neutron drivers for {0}".format( stack_name)) msg = update.check_neutron_mechanism_drivers( env, stack, self.object_client, stack_name) if msg: raise oscexc.CommandError(msg) self.log.debug("Getting template contents from plan %s" % stack_name) # We need to reference the plan here, not the local # tht root, as we need template_object to refer to # the rendered overcloud.yaml, not the tht_root overcloud.j2.yaml # FIXME(shardy) we need to move more of this into mistral actions plan_yaml_path = os.path.relpath(template_path, tht_root) # heatclient template_utils needs a function that can # retrieve objects from a container by name/path def do_object_request(method='GET', object_path=None): obj = self.object_client.get_object(stack_name, object_path) return obj and obj[1] template_files, template = template_utils.get_template_contents( template_object=plan_yaml_path, object_request=do_object_request) files = dict(list(template_files.items()) + list(env_files.items())) moved_files = self._upload_missing_files(stack_name, files, tht_root) self._process_and_upload_environment(stack_name, env, moved_files, tht_root) # Invokes the workflows specified in plan environment file if plan_env_file: workflow_params.invoke_plan_env_workflows( self.clients, stack_name, plan_env_file, verbosity=utils.playbook_verbosity(self=self)) workflow_params.check_deprecated_parameters(self.clients, stack_name) if not update_plan_only: print("Deploying templates in the directory {0}".format( os.path.abspath(tht_root))) deployment.deploy_and_wait( log=self.log, clients=self.clients, stack=stack, plan_name=stack_name, verbose_level=utils.playbook_verbosity(self=self), timeout=timeout, run_validations=run_validations, skip_deploy_identifier=skip_deploy_identifier, deployment_options=deployment_options)
def take_action(self, parsed_args): # Copied from overwritten method! client = self.app.client_manager.network obj = client.find_port(parsed_args.port, ignore_missing=False) # SDK ignores update() if it receives a modified obj and attrs # To handle the same tmp_obj is created in all take_action of # Unset* classes tmp_fixed_ips = copy.deepcopy(obj.fixed_ips) tmp_binding_profile = copy.deepcopy(obj.binding_profile) tmp_secgroups = copy.deepcopy(obj.security_group_ids) tmp_addr_pairs = copy.deepcopy(obj.allowed_address_pairs) port._prepare_fixed_ips(self.app.client_manager, parsed_args) attrs = {} if parsed_args.fixed_ip: try: for ip in parsed_args.fixed_ip: tmp_fixed_ips.remove(ip) except ValueError: msg = _("Port does not contain fixed-ip %s") % ip raise exceptions.CommandError(msg) attrs['fixed_ips'] = tmp_fixed_ips if parsed_args.binding_profile: try: for key in parsed_args.binding_profile: del tmp_binding_profile[key] except KeyError: msg = _("Port does not contain binding-profile %s") % key raise exceptions.CommandError(msg) attrs['binding:profile'] = tmp_binding_profile if parsed_args.security_group_ids: try: for sg in parsed_args.security_group_ids: sg_id = client.find_security_group(sg, ignore_missing=False).id tmp_secgroups.remove(sg_id) except ValueError: msg = _("Port does not contain security group %s") % sg raise exceptions.CommandError(msg) attrs['security_group_ids'] = tmp_secgroups if parsed_args.allowed_address_pairs: try: for addr in port._convert_address_pairs(parsed_args): tmp_addr_pairs.remove(addr) except ValueError: msg = _("Port does not contain allowed-address-pair %s") % addr raise exceptions.CommandError(msg) attrs['allowed_address_pairs'] = tmp_addr_pairs if parsed_args.qos_policy: attrs['qos_policy_id'] = None if parsed_args.data_plane_status: attrs['data_plane_status'] = None # Nuage specific attributes self._handle_nuage_specific_attributes( parsed_args, attrs, obj, self.app.client_manager.nuageclient) if attrs: client.update_port(obj, **attrs) # tags is a subresource and it needs to be updated separately. _tag.update_tags_for_unset(client, obj, parsed_args)
def test_image_create_file(self, mock_open): mock_file = mock.Mock(name='File') mock_open.return_value = mock_file mock_open.read.return_value = image_fakes.image_data mock_exception = { 'find.side_effect': exceptions.CommandError('x'), 'get.side_effect': exceptions.CommandError('x'), } self.images_mock.configure_mock(**mock_exception) arglist = [ '--file', 'filer', '--unprotected', '--public', '--property', 'Alpha=1', '--property', 'Beta=2', image_fakes.image_name, ] verifylist = [ ('file', 'filer'), ('protected', False), ('unprotected', True), ('public', True), ('private', False), ('properties', { 'Alpha': '1', 'Beta': '2' }), ('name', image_fakes.image_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # In base command class ShowOne in cliff, abstract method take_action() # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. columns, data = self.cmd.take_action(parsed_args) # Ensure input file is opened mock_open.assert_called_with('filer', 'rb') # Ensure the input file is closed mock_file.close.assert_called_with() # ImageManager.get(name) not to be called since update action exists self.images_mock.get.assert_not_called() # ImageManager.create(name=, **) self.images_mock.create.assert_called_with( name=image_fakes.image_name, container_format=image.DEFAULT_CONTAINER_FORMAT, disk_format=image.DEFAULT_DISK_FORMAT, protected=False, is_public=True, properties={ 'Alpha': '1', 'Beta': '2', }, data=mock_file, ) # Verify update() was not called, if it was show the args self.assertEqual(self.images_mock.update.call_args_list, []) self.assertEqual(image_fakes.IMAGE_columns, columns) self.assertEqual(image_fakes.IMAGE_data, data)
def take_action_network(self, client, parsed_args): # Get the security group ID to hold the rule. security_group_id = client.find_security_group(parsed_args.group, ignore_missing=False).id # Build the create attributes. attrs = {} attrs['protocol'] = self._get_protocol(parsed_args) if parsed_args.description is not None: attrs['description'] = parsed_args.description # NOTE(rtheis): A direction must be specified and ingress # is the default. if parsed_args.ingress or not parsed_args.egress: attrs['direction'] = 'ingress' if parsed_args.egress: attrs['direction'] = 'egress' # NOTE(rtheis): Use ethertype specified else default based # on IP protocol. attrs['ethertype'] = self._get_ethertype(parsed_args, attrs['protocol']) # NOTE(rtheis): Validate the port range and ICMP type and code. # It would be ideal if argparse could do this. if parsed_args.dst_port and (parsed_args.icmp_type or parsed_args.icmp_code): msg = _('Argument --dst-port not allowed with arguments ' '--icmp-type and --icmp-code') raise exceptions.CommandError(msg) if parsed_args.icmp_type is None and parsed_args.icmp_code is not None: msg = _('Argument --icmp-type required with argument --icmp-code') raise exceptions.CommandError(msg) is_icmp_protocol = _is_icmp_protocol(attrs['protocol']) if not is_icmp_protocol and (parsed_args.icmp_type or parsed_args.icmp_code): msg = _('ICMP IP protocol required with arguments ' '--icmp-type and --icmp-code') raise exceptions.CommandError(msg) # NOTE(rtheis): For backwards compatibility, continue ignoring # the destination port range when an ICMP IP protocol is specified. if parsed_args.dst_port and not is_icmp_protocol: attrs['port_range_min'] = parsed_args.dst_port[0] attrs['port_range_max'] = parsed_args.dst_port[1] if parsed_args.icmp_type is not None and parsed_args.icmp_type >= 0: attrs['port_range_min'] = parsed_args.icmp_type if parsed_args.icmp_code is not None and parsed_args.icmp_code >= 0: attrs['port_range_max'] = parsed_args.icmp_code if parsed_args.remote_group is not None: attrs['remote_group_id'] = client.find_security_group( parsed_args.remote_group, ignore_missing=False).id elif parsed_args.remote_address_group is not None: attrs['remote_address_group_id'] = client.find_address_group( parsed_args.remote_address_group, ignore_missing=False).id elif parsed_args.remote_ip is not None: attrs['remote_ip_prefix'] = parsed_args.remote_ip elif attrs['ethertype'] == 'IPv4': attrs['remote_ip_prefix'] = '0.0.0.0/0' elif attrs['ethertype'] == 'IPv6': attrs['remote_ip_prefix'] = '::/0' attrs['security_group_id'] = security_group_id if parsed_args.project is not None: identity_client = self.app.client_manager.identity project_id = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id attrs['project_id'] = project_id attrs.update(self._parse_extra_properties( parsed_args.extra_properties)) # Create and show the security group rule. obj = client.create_security_group_rule(**attrs) display_columns, columns = _get_columns(obj) data = utils.get_item_properties(obj, columns) return (display_columns, data)
def test_image_reserve_options(self, mock_open): mock_file = mock.MagicMock(name='File') mock_open.return_value = mock_file mock_open.read.return_value = None mock_exception = { 'find.side_effect': exceptions.CommandError('x'), } self.images_mock.configure_mock(**mock_exception) arglist = [ '--container-format', 'ovf', '--disk-format', 'ami', '--min-disk', '10', '--min-ram', '4', ('--protected' if self.new_image.protected else '--unprotected'), ('--private' if self.new_image.visibility == 'private' else '--public'), '--project', self.new_image.owner, '--project-domain', self.domain.id, self.new_image.name, ] verifylist = [ ('container_format', 'ovf'), ('disk_format', 'ami'), ('min_disk', 10), ('min_ram', 4), ('protected', self.new_image.protected), ('unprotected', not self.new_image.protected), ('public', self.new_image.visibility == 'public'), ('private', self.new_image.visibility == 'private'), ('project', self.new_image.owner), ('project_domain', self.domain.id), ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # In base command class ShowOne in cliff, abstract method take_action() # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. columns, data = self.cmd.take_action(parsed_args) # ImageManager.create(name=, **) self.images_mock.create.assert_called_with( name=self.new_image.name, container_format='ovf', disk_format='ami', min_disk=10, min_ram=4, owner=self.project.id, protected=self.new_image.protected, visibility=self.new_image.visibility, ) # Verify update() was not called, if it was show the args self.assertEqual(self.images_mock.update.call_args_list, []) self.images_mock.upload.assert_called_with( mock.ANY, mock.ANY, ) self.assertEqual( image_fakes.FakeImage.get_image_columns(self.new_image), columns) self.assertEqual( image_fakes.FakeImage.get_image_data(self.new_image), data)
def take_action(self, parsed_args): image_client = self.app.client_manager.image image = image_client.find_image(parsed_args.image, ignore_missing=False) kwargs = {} tagret = 0 propret = 0 if parsed_args.tags: for k in parsed_args.tags: try: image_client.remove_tag(image.id, k) except Exception: LOG.error( _("tag unset failed, '%s' is a " "nonexistent tag "), k) tagret += 1 if parsed_args.properties: for k in parsed_args.properties: if k in image: kwargs[k] = None elif k in image.properties: # Since image is an "evil" object from SDK POV we need to # pass modified properties object, so that SDK can figure # out, what was changed inside # NOTE: ping gtema to improve that in SDK new_props = kwargs.get('properties', image.get('properties').copy()) new_props.pop(k, None) kwargs['properties'] = new_props else: LOG.error( _("property unset failed, '%s' is a " "nonexistent property "), k) propret += 1 # We must give to update a current image for the reference on what # has changed image_client.update_image(image, **kwargs) tagtotal = len(parsed_args.tags) proptotal = len(parsed_args.properties) if (tagret > 0 and propret > 0): msg = ( _("Failed to unset %(tagret)s of %(tagtotal)s tags," "Failed to unset %(propret)s of %(proptotal)s properties.") % { 'tagret': tagret, 'tagtotal': tagtotal, 'propret': propret, 'proptotal': proptotal }) raise exceptions.CommandError(msg) elif tagret > 0: msg = (_("Failed to unset %(tagret)s of %(tagtotal)s tags.") % { 'tagret': tagret, 'tagtotal': tagtotal }) raise exceptions.CommandError(msg) elif propret > 0: msg = (_("Failed to unset %(propret)s of %(proptotal)s" " properties.") % { 'propret': propret, 'proptotal': proptotal }) raise exceptions.CommandError(msg)
def take_action(self, parsed_args): identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: if getattr(parsed_args, deadopt.replace('-', '_'), None): raise exceptions.CommandError( _("ERROR: --%s was given, which is an Image v1 option" " that is no longer supported in Image v2") % deadopt) kwargs = {} copy_attrs = ('architecture', 'container_format', 'disk_format', 'file', 'instance_id', 'kernel_id', 'locations', 'min_disk', 'min_ram', 'name', 'os_distro', 'os_version', 'prefix', 'progress', 'ramdisk_id', 'tags', 'visibility') for attr in copy_attrs: if attr in parsed_args: val = getattr(parsed_args, attr, None) if val is not None: # Only include a value in kwargs for attributes that are # actually present on the command line kwargs[attr] = val # Properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in six.iteritems(parsed_args.properties): kwargs[k] = str(v) # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not # a single value for the pair of options because the default must be # to do nothing when no options are present as opposed to always # setting a default. if parsed_args.protected: kwargs['protected'] = True if parsed_args.unprotected: kwargs['protected'] = False if parsed_args.public: kwargs['visibility'] = 'public' if parsed_args.private: kwargs['visibility'] = 'private' if parsed_args.community: kwargs['visibility'] = 'community' if parsed_args.shared: kwargs['visibility'] = 'shared' # Handle deprecated --owner option project_arg = parsed_args.project if parsed_args.owner: project_arg = parsed_args.owner LOG.warning( _('The --owner option is deprecated, ' 'please use --project instead.')) project_id = None if project_arg: project_id = common.find_project( identity_client, project_arg, parsed_args.project_domain, ).id kwargs['owner'] = project_id image = utils.find_resource(image_client.images, parsed_args.image) activation_status = None if parsed_args.deactivate: image_client.images.deactivate(image.id) activation_status = "deactivated" if parsed_args.activate: image_client.images.reactivate(image.id) activation_status = "activated" membership_group_args = ('accept', 'reject', 'pending') membership_status = [ status for status in membership_group_args if getattr(parsed_args, status) ] if membership_status: # If a specific project is not passed, assume we want to update # our own membership if not project_id: project_id = self.app.client_manager.auth_ref.project_id # The mutually exclusive group of the arg parser ensure we have at # most one item in the membership_status list. if membership_status[0] != 'pending': membership_status[0] += 'ed' # Glance expects the past form image_client.image_members.update(image.id, project_id, membership_status[0]) if parsed_args.tags: # Tags should be extended, but duplicates removed kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags))) try: image = image_client.images.update(image.id, **kwargs) except Exception: if activation_status is not None: LOG.info(_("Image %(id)s was %(status)s."), { 'id': image.id, 'status': activation_status }) raise
def _validate_args(self, parsed_args): # TODO(bcrochet): This should be removed after Rocky or 'S'. if any(map(lambda x: getattr(parsed_args, x) is not None, [ 'control_scale', 'compute_scale', 'ceph_storage_scale', 'block_storage_scale', 'swift_storage_scale', 'control_flavor', 'compute_flavor', 'ceph_storage_flavor', 'block_storage_flavor', 'swift_storage_flavor' ])): raise oscexc.CommandError( "A scale or flavor argument was passed to the command line. " "These arguments are no longer valid. They MUST be replaced " "with an environment file that contains a valid " "parameter_default. Failure to do so may cause possible data " "loss or a decommisioning of nodes.") if parsed_args.templates is None and parsed_args.answers_file is None: raise oscexc.CommandError( "You must specify either --templates or --answers-file") if parsed_args.environment_files: nonexisting_envs = [] jinja2_envs = [] for env_file in parsed_args.environment_files: if env_file.endswith(".j2.yaml"): jinja2_envs.append(env_file) elif not os.path.isfile(env_file): # Tolerate missing file if there's a j2.yaml file that will # be rendered in the plan but not available locally (yet) if not os.path.isfile(env_file.replace(".yaml", ".j2.yaml")): nonexisting_envs.append(env_file) # Check networks_file existence if parsed_args.networks_file: if not os.path.isfile(parsed_args.networks_file): nonexisting_envs.append(parsed_args.networks_file) # check plan_environment_file existence if parsed_args.plan_environment_file: if not os.path.isfile(parsed_args.plan_environment_file): nonexisting_envs.append(parsed_args.plan_environment_file) # check answers_file existence if parsed_args.answers_file: if not os.path.isfile(parsed_args.answers_file): nonexisting_envs.append(parsed_args.answers_file) if jinja2_envs: rewritten_paths = [e.replace(".j2.yaml", ".yaml") for e in jinja2_envs] raise oscexc.CommandError( "Error: The following jinja2 files were provided: -e " "{}. Did you mean -e {}?".format( ' -e '.join(jinja2_envs), ' -e '.join(rewritten_paths))) if nonexisting_envs: raise oscexc.CommandError( "Error: The following files were not found: {0}".format( ", ".join(nonexisting_envs))) if (parsed_args.baremetal_deployment and not parsed_args.deployed_server): raise oscexc.CommandError( "Error: --deployed-server must be used when using " "--baremetal-deployment") if parsed_args.deployed_server and (parsed_args.run_validations or not parsed_args.disable_validations): raise oscexc.CommandError( "Error: The --deployed-server cannot be used without " "the --disable-validations") if parsed_args.environment_directories: self._validate_args_environment_directory( parsed_args.environment_directories)
def take_action(self, parsed_args): identity_client = self.app.client_manager.identity if parsed_args.user: user = common.find_user( identity_client, parsed_args.user, parsed_args.user_domain, ) elif parsed_args.group: group = common.find_group( identity_client, parsed_args.group, parsed_args.group_domain, ) if parsed_args.domain: domain = common.find_domain( identity_client, parsed_args.domain, ) elif parsed_args.project: project = common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ) # no user or group specified, list all roles in the system if not parsed_args.user and not parsed_args.group: if not parsed_args.domain: columns = ('ID', 'Name') data = identity_client.roles.list() else: columns = ('ID', 'Name', 'Domain') data = identity_client.roles.list(domain_id=domain.id) for role in data: role.domain = domain.name elif parsed_args.user and parsed_args.domain: columns = ('ID', 'Name', 'Domain', 'User') data = identity_client.roles.list( user=user, domain=domain, os_inherit_extension_inherited=parsed_args.inherited) for user_role in data: user_role.user = user.name user_role.domain = domain.name self.log.warning( _('Listing assignments using role list is ' 'deprecated. Use role assignment list --user ' '<user-name> --domain <domain-name> --names ' 'instead.')) elif parsed_args.user and parsed_args.project: columns = ('ID', 'Name', 'Project', 'User') data = identity_client.roles.list( user=user, project=project, os_inherit_extension_inherited=parsed_args.inherited) for user_role in data: user_role.user = user.name user_role.project = project.name self.log.warning( _('Listing assignments using role list is ' 'deprecated. Use role assignment list --user ' '<user-name> --project <project-name> --names ' 'instead.')) elif parsed_args.user: columns = ('ID', 'Name') data = identity_client.roles.list( user=user, domain='default', os_inherit_extension_inherited=parsed_args.inherited) self.log.warning( _('Listing assignments using role list is ' 'deprecated. Use role assignment list --user ' '<user-name> --domain default --names ' 'instead.')) elif parsed_args.group and parsed_args.domain: columns = ('ID', 'Name', 'Domain', 'Group') data = identity_client.roles.list( group=group, domain=domain, os_inherit_extension_inherited=parsed_args.inherited) for group_role in data: group_role.group = group.name group_role.domain = domain.name self.log.warning( _('Listing assignments using role list is ' 'deprecated. Use role assignment list --group ' '<group-name> --domain <domain-name> --names ' 'instead.')) elif parsed_args.group and parsed_args.project: columns = ('ID', 'Name', 'Project', 'Group') data = identity_client.roles.list( group=group, project=project, os_inherit_extension_inherited=parsed_args.inherited) for group_role in data: group_role.group = group.name group_role.project = project.name self.log.warning( _('Listing assignments using role list is ' 'deprecated. Use role assignment list --group ' '<group-name> --project <project-name> --names ' 'instead.')) else: msg = _("Error: If a user or group is specified, " "either --domain or --project must also be " "specified to list role grants.") raise exceptions.CommandError(msg) return (columns, (utils.get_item_properties( s, columns, formatters={}, ) for s in data))
def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) result = 0 if parsed_args.size: try: if volume.status != 'available': msg = (_("Volume is in %s state, it must be available " "before size can be extended") % volume.status) raise exceptions.CommandError(msg) if parsed_args.size <= volume.size: msg = (_("New size must be greater than %s GB") % volume.size) raise exceptions.CommandError(msg) volume_client.volumes.extend(volume.id, parsed_args.size) except Exception as e: LOG.error(_("Failed to set volume size: %s"), e) result += 1 if parsed_args.no_property: try: volume_client.volumes.delete_metadata(volume.id, volume.metadata.keys()) except Exception as e: LOG.error(_("Failed to clean volume properties: %s"), e) result += 1 if parsed_args.property: try: volume_client.volumes.set_metadata(volume.id, parsed_args.property) except Exception as e: LOG.error(_("Failed to set volume property: %s"), e) result += 1 if parsed_args.bootable or parsed_args.non_bootable: try: volume_client.volumes.set_bootable(volume.id, parsed_args.bootable) except Exception as e: LOG.error(_("Failed to set volume bootable property: %s"), e) result += 1 if parsed_args.read_only or parsed_args.read_write: try: volume_client.volumes.update_readonly_flag( volume.id, parsed_args.read_only) except Exception as e: LOG.error( _("Failed to set volume read-only access " "mode flag: %s"), e) result += 1 kwargs = {} if parsed_args.name: kwargs['display_name'] = parsed_args.name if parsed_args.description: kwargs['display_description'] = parsed_args.description if kwargs: try: volume_client.volumes.update(volume.id, **kwargs) except Exception as e: LOG.error( _("Failed to update volume display name " "or display description: %s"), e) result += 1 if result > 0: raise exceptions.CommandError( _("One or more of the " "set operations failed"))
def take_action(self, parsed_args): def _deprecated(): # NOTE(henry-nash): Deprecated as of Newton, so we should remove # this in the 'P' release. self.log.warning( _('Listing assignments using role list is ' 'deprecated as of the Newton release. Use role ' 'assignment list --user <user-name> --project ' '<project-name> --names instead.')) identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref # No user or project specified, list all roles in the system if not parsed_args.user and not parsed_args.project: columns = ('ID', 'Name') data = identity_client.roles.list() elif parsed_args.user and parsed_args.project: user = utils.find_resource( identity_client.users, parsed_args.user, ) project = utils.find_resource( identity_client.projects, parsed_args.project, ) _deprecated() data = identity_client.roles.roles_for_user(user.id, project.id) elif parsed_args.user: user = utils.find_resource( identity_client.users, parsed_args.user, ) if self.app.client_manager.auth_ref: project = utils.find_resource(identity_client.projects, auth_ref.project_id) else: msg = _("Project must be specified") raise exceptions.CommandError(msg) _deprecated() data = identity_client.roles.roles_for_user(user.id, project.id) elif parsed_args.project: project = utils.find_resource( identity_client.projects, parsed_args.project, ) if self.app.client_manager.auth_ref: user = utils.find_resource(identity_client.users, auth_ref.user_id) else: msg = _("User must be specified") raise exceptions.CommandError(msg) _deprecated() data = identity_client.roles.roles_for_user(user.id, project.id) if parsed_args.user or parsed_args.project: columns = ('ID', 'Name', 'Project', 'User') for user_role in data: user_role.user = user.name user_role.project = project.name return (columns, (utils.get_item_properties( s, columns, formatters={}, ) for s in data))
def _get_attrs(client_manager, parsed_args, is_create=True): attrs = {} if 'name' in parsed_args and parsed_args.name is not None: attrs['name'] = str(parsed_args.name) if is_create: if 'project' in parsed_args and parsed_args.project is not None: identity_client = client_manager.identity project_id = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id attrs['tenant_id'] = project_id client = client_manager.network attrs['network_id'] = client.find_network(parsed_args.network, ignore_missing=False).id if parsed_args.subnet_pool is not None: subnet_pool = client.find_subnet_pool(parsed_args.subnet_pool, ignore_missing=False) attrs['subnetpool_id'] = subnet_pool.id if parsed_args.use_default_subnet_pool: attrs['use_default_subnet_pool'] = True if parsed_args.prefix_length is not None: attrs['prefixlen'] = parsed_args.prefix_length if parsed_args.subnet_range is not None: attrs['cidr'] = parsed_args.subnet_range if parsed_args.ip_version is not None: attrs['ip_version'] = parsed_args.ip_version if parsed_args.ipv6_ra_mode is not None: attrs['ipv6_ra_mode'] = parsed_args.ipv6_ra_mode if parsed_args.ipv6_address_mode is not None: attrs['ipv6_address_mode'] = parsed_args.ipv6_address_mode if parsed_args.network_segment is not None: attrs['segment_id'] = client.find_segment( parsed_args.network_segment, ignore_missing=False).id if 'gateway' in parsed_args and parsed_args.gateway is not None: gateway = parsed_args.gateway.lower() if not is_create and gateway == 'auto': msg = _("Auto option is not available for Subnet Set. " "Valid options are <ip-address> or none") raise exceptions.CommandError(msg) elif gateway != 'auto': if gateway == 'none': attrs['gateway_ip'] = None else: attrs['gateway_ip'] = gateway if ('allocation_pools' in parsed_args and parsed_args.allocation_pools is not None): attrs['allocation_pools'] = parsed_args.allocation_pools if parsed_args.dhcp: attrs['enable_dhcp'] = True if parsed_args.no_dhcp: attrs['enable_dhcp'] = False if ('dns_nameservers' in parsed_args and parsed_args.dns_nameservers is not None): attrs['dns_nameservers'] = parsed_args.dns_nameservers if 'host_routes' in parsed_args and parsed_args.host_routes is not None: # Change 'gateway' entry to 'nexthop' to match the API attrs['host_routes'] = convert_entries_to_nexthop( parsed_args.host_routes) if ('service_types' in parsed_args and parsed_args.service_types is not None): attrs['service_types'] = parsed_args.service_types if parsed_args.description is not None: attrs['description'] = parsed_args.description # wrs extensions if ('vlan_id' in parsed_args and parsed_args.vlan_id is not None): attrs['wrs-net:vlan_id'] = parsed_args.vlan_id if ('network_type' in parsed_args and parsed_args.network_type is not None): attrs['wrs-provider:network_type'] = parsed_args.network_type if ('physical_network' in parsed_args and parsed_args.physical_network is not None): attrs['wrs-provider:vlan_id'] = parsed_args.physical_network if ('segmentation_id' in parsed_args and parsed_args.segmentation_id is not None): attrs['wrs-provider:segmentation_id'] = parsed_args.segmentation_id if ('unmanaged' in parsed_args and parsed_args.unmanaged is not False): attrs['wrs-net:managed'] = False return attrs
def take_action_compute(self, client, parsed_args): raise exceptions.CommandError("This command needs access to" " a network endpoint.") return
def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) senlin_client = self.app.client_manager.clustering action_args = {} capacity = parsed_args.capacity adjustment = parsed_args.adjustment percentage = parsed_args.percentage min_size = parsed_args.min_size max_size = parsed_args.max_size min_step = parsed_args.min_step if sum(v is not None for v in (capacity, adjustment, percentage)) > 1: raise exc.CommandError(_("Only one of 'capacity', 'adjustment' and" " 'percentage' can be specified.")) action_args['adjustment_type'] = None action_args['number'] = None if capacity is not None: if capacity < 0: raise exc.CommandError(_('Cluster capacity must be larger than' ' or equal to zero.')) action_args['adjustment_type'] = 'EXACT_CAPACITY' action_args['number'] = capacity if adjustment is not None: if adjustment == 0: raise exc.CommandError(_('Adjustment cannot be zero.')) action_args['adjustment_type'] = 'CHANGE_IN_CAPACITY' action_args['number'] = adjustment if percentage is not None: if (percentage == 0 or percentage == 0.0): raise exc.CommandError(_('Percentage cannot be zero.')) action_args['adjustment_type'] = 'CHANGE_IN_PERCENTAGE' action_args['number'] = percentage if min_step is not None: if percentage is None: raise exc.CommandError(_('Min step is only used with ' 'percentage.')) if min_size is not None: if min_size < 0: raise exc.CommandError(_('Min size cannot be less than zero.')) if max_size is not None and max_size >= 0 and min_size > max_size: raise exc.CommandError(_('Min size cannot be larger than ' 'max size.')) if capacity is not None and min_size > capacity: raise exc.CommandError(_('Min size cannot be larger than the ' 'specified capacity')) if max_size is not None: if capacity is not None and max_size > 0 and max_size < capacity: raise exc.CommandError(_('Max size cannot be less than the ' 'specified capacity.')) # do a normalization if max_size < 0: max_size = -1 action_args['min_size'] = min_size action_args['max_size'] = max_size action_args['min_step'] = min_step action_args['strict'] = parsed_args.strict resp = senlin_client.cluster_resize(parsed_args.cluster, **action_args) print('Request accepted by action: %s' % resp['action'])
def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) heat_client = self.app.client_manager.orchestration try: if not parsed_args.yes and sys.stdin.isatty(): sys.stdout.write( _("Are you sure you want to delete this stack(s) [y/N]? ")) prompt_response = sys.stdin.readline().lower() if not prompt_response.startswith('y'): self.log.info(_LI('User did not confirm stack delete so ' 'taking no action.')) return except KeyboardInterrupt: # ctrl-c self.log.info(_LI('User did not confirm stack delete ' '(ctrl-c) so taking no action.')) return except EOFError: # ctrl-d self.log.info(_LI('User did not confirm stack delete ' '(ctrl-d) so taking no action.')) return failure_count = 0 stacks_waiting = [] for sid in parsed_args.stack: marker = None if parsed_args.wait: try: # find the last event to use as the marker events = event_utils.get_events(heat_client, stack_id=sid, event_args={ 'sort_dir': 'desc'}, limit=1) if events: marker = events[0].id except heat_exc.CommandError as ex: failure_count += 1 print(ex) continue try: heat_client.stacks.delete(sid) stacks_waiting.append((sid, marker)) except heat_exc.HTTPNotFound: failure_count += 1 print(_('Stack not found: %s') % sid) except heat_exc.Forbidden: failure_count += 1 print(_('Forbidden: %s') % sid) if parsed_args.wait: for sid, marker in stacks_waiting: try: stack_status, msg = event_utils.poll_for_events( heat_client, sid, action='DELETE', marker=marker) except heat_exc.CommandError: continue if stack_status == 'DELETE_FAILED': failure_count += 1 print(msg) if failure_count: msg = (_('Unable to delete %(count)d of the %(total)d stacks.') % {'count': failure_count, 'total': len(parsed_args.stack)}) raise exc.CommandError(msg)
def take_action(self, parsed_args): identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: if getattr(parsed_args, deadopt.replace('-', '_'), None): raise exceptions.CommandError( _("ERROR: --%s was given, which is an Image v1 option" " that is no longer supported in Image v2") % deadopt) image = image_client.find_image( parsed_args.image, ignore_missing=False, ) project_id = None if parsed_args.project: project_id = common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id # handle activation status changes activation_status = None if parsed_args.deactivate or parsed_args.activate: if parsed_args.deactivate: image_client.deactivate_image(image.id) activation_status = "deactivated" if parsed_args.activate: image_client.reactivate_image(image.id) activation_status = "activated" # handle membership changes if parsed_args.membership: # If a specific project is not passed, assume we want to update # our own membership if not project_id: project_id = self.app.client_manager.auth_ref.project_id image_client.update_member( image=image.id, member=project_id, status=parsed_args.membership, ) # handle everything else kwargs = {} copy_attrs = ('architecture', 'container_format', 'disk_format', 'file', 'instance_id', 'kernel_id', 'locations', 'min_disk', 'min_ram', 'name', 'os_distro', 'os_version', 'prefix', 'progress', 'ramdisk_id', 'tags', 'visibility') for attr in copy_attrs: if attr in parsed_args: val = getattr(parsed_args, attr, None) if val is not None: # Only include a value in kwargs for attributes that are # actually present on the command line kwargs[attr] = val # Properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in parsed_args.properties.items(): kwargs[k] = str(v) # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not # a single value for the pair of options because the default must be # to do nothing when no options are present as opposed to always # setting a default. if parsed_args.protected: kwargs['is_protected'] = True if parsed_args.unprotected: kwargs['is_protected'] = False if parsed_args.public: kwargs['visibility'] = 'public' if parsed_args.private: kwargs['visibility'] = 'private' if parsed_args.community: kwargs['visibility'] = 'community' if parsed_args.shared: kwargs['visibility'] = 'shared' if parsed_args.project: # We already did the project lookup above kwargs['owner_id'] = project_id if parsed_args.tags: # Tags should be extended, but duplicates removed kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags))) if parsed_args.hidden is not None: kwargs['is_hidden'] = parsed_args.hidden try: image = image_client.update_image(image.id, **kwargs) except Exception: if activation_status is not None: LOG.info(_("Image %(id)s was %(status)s."), { 'id': image.id, 'status': activation_status }) raise
def take_action_network(self, client, parsed_args): # Get the security group ID to hold the rule. security_group_id = client.find_security_group( parsed_args.group, ignore_missing=False ).id # Build the create attributes. attrs = {} attrs['protocol'] = self._get_protocol(parsed_args) if parsed_args.description is not None: attrs['description'] = parsed_args.description # NOTE(rtheis): A direction must be specified and ingress # is the default. if parsed_args.ingress or not parsed_args.egress: attrs['direction'] = 'ingress' if parsed_args.egress: attrs['direction'] = 'egress' # NOTE(rtheis): Use ethertype specified else default based # on IP protocol. if parsed_args.ethertype: attrs['ethertype'] = parsed_args.ethertype elif self._is_ipv6_protocol(attrs['protocol']): attrs['ethertype'] = 'IPv6' else: attrs['ethertype'] = 'IPv4' # NOTE(rtheis): Validate the port range and ICMP type and code. # It would be ideal if argparse could do this. if parsed_args.dst_port and (parsed_args.icmp_type or parsed_args.icmp_code): msg = _('Argument --dst-port not allowed with arguments ' '--icmp-type and --icmp-code') raise exceptions.CommandError(msg) if parsed_args.icmp_type is None and parsed_args.icmp_code is not None: msg = _('Argument --icmp-type required with argument --icmp-code') raise exceptions.CommandError(msg) is_icmp_protocol = _is_icmp_protocol(attrs['protocol']) if not is_icmp_protocol and (parsed_args.icmp_type or parsed_args.icmp_code): msg = _('ICMP IP protocol required with arguments ' '--icmp-type and --icmp-code') raise exceptions.CommandError(msg) # NOTE(rtheis): For backwards compatibility, continue ignoring # the destination port range when an ICMP IP protocol is specified. if parsed_args.dst_port and not is_icmp_protocol: attrs['port_range_min'] = parsed_args.dst_port[0] attrs['port_range_max'] = parsed_args.dst_port[1] if parsed_args.icmp_type: attrs['port_range_min'] = parsed_args.icmp_type if parsed_args.icmp_code: attrs['port_range_max'] = parsed_args.icmp_code # NOTE(dtroyer): --src-ip and --src-group were deprecated in Nov 2016. # Do not remove before 4.x release or Nov 2017. if not (parsed_args.remote_group is None and parsed_args.src_group is None): attrs['remote_group_id'] = client.find_security_group( parsed_args.remote_group or parsed_args.src_group, ignore_missing=False ).id if parsed_args.src_group: LOG.warning( _("The %(old)s option is deprecated, " "please use %(new)s instead."), {'old': '--src-group', 'new': '--remote-group'}, ) elif not (parsed_args.remote_ip is None and parsed_args.src_ip is None): attrs['remote_ip_prefix'] = ( parsed_args.remote_ip or parsed_args.src_ip ) if parsed_args.src_ip: LOG.warning( _("The %(old)s option is deprecated, " "please use %(new)s instead."), {'old': '--src-ip', 'new': '--remote-ip'}, ) elif attrs['ethertype'] == 'IPv4': attrs['remote_ip_prefix'] = '0.0.0.0/0' attrs['security_group_id'] = security_group_id if parsed_args.project is not None: identity_client = self.app.client_manager.identity project_id = identity_common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id attrs['tenant_id'] = project_id # Create and show the security group rule. obj = client.create_security_group_rule(**attrs) display_columns, columns = _get_columns(obj) data = utils.get_item_properties(obj, columns) return (display_columns, data)
def take_action(self, parsed_args): identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: if getattr(parsed_args, deadopt.replace('-', '_'), None): raise exceptions.CommandError( _("ERROR: --%s was given, which is an Image v1 option" " that is no longer supported in Image v2") % deadopt) # Build an attribute dict from the parsed args, only include # attributes that were actually set on the command line kwargs = {'allow_duplicates': True} copy_attrs = ('name', 'id', 'container_format', 'disk_format', 'min_disk', 'min_ram', 'tags', 'visibility') for attr in copy_attrs: if attr in parsed_args: val = getattr(parsed_args, attr, None) if val: # Only include a value in kwargs for attributes that # are actually present on the command line kwargs[attr] = val # properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in parsed_args.properties.items(): kwargs[k] = str(v) # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not # a single value for the pair of options because the default must be # to do nothing when no options are present as opposed to always # setting a default. if parsed_args.protected: kwargs['is_protected'] = True if parsed_args.unprotected: kwargs['is_protected'] = False if parsed_args.public: kwargs['visibility'] = 'public' if parsed_args.private: kwargs['visibility'] = 'private' if parsed_args.community: kwargs['visibility'] = 'community' if parsed_args.shared: kwargs['visibility'] = 'shared' if parsed_args.project: kwargs['owner_id'] = common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id if parsed_args.use_import: kwargs['use_import'] = True # open the file first to ensure any failures are handled before the # image is created. Get the file name (if it is file, and not stdin) # for easier further handling. (fp, fname) = get_data_file(parsed_args) info = {} if fp is not None and parsed_args.volume: raise exceptions.CommandError( _("Uploading data and using " "container are not allowed at " "the same time")) if fp is None and parsed_args.file: LOG.warning(_("Failed to get an image file.")) return {}, {} if fp is not None and parsed_args.progress: filesize = os.path.getsize(fname) if filesize is not None: kwargs['validate_checksum'] = False kwargs['data'] = progressbar.VerboseFileWrapper(fp, filesize) elif fname: kwargs['filename'] = fname elif fp: kwargs['validate_checksum'] = False kwargs['data'] = fp # sign an image using a given local private key file if parsed_args.sign_key_path or parsed_args.sign_cert_id: if not parsed_args.file: msg = (_("signing an image requires the --file option, " "passing files via stdin when signing is not " "supported.")) raise exceptions.CommandError(msg) if (len(parsed_args.sign_key_path) < 1 or len(parsed_args.sign_cert_id) < 1): msg = (_("'sign-key-path' and 'sign-cert-id' must both be " "specified when attempting to sign an image.")) raise exceptions.CommandError(msg) else: sign_key_path = parsed_args.sign_key_path sign_cert_id = parsed_args.sign_cert_id signer = image_signer.ImageSigner() try: pw = utils.get_password( self.app.stdin, prompt=("Please enter private key password, leave " "empty if none: "), confirm=False) if not pw or len(pw) < 1: pw = None else: # load_private_key() requires the password to be # passed as bytes pw = pw.encode() signer.load_private_key(sign_key_path, password=pw) except Exception: msg = (_("Error during sign operation: private key " "could not be loaded.")) raise exceptions.CommandError(msg) signature = signer.generate_signature(fp) signature_b64 = b64encode(signature) kwargs['img_signature'] = signature_b64 kwargs['img_signature_certificate_uuid'] = sign_cert_id kwargs['img_signature_hash_method'] = signer.hash_method if signer.padding_method: kwargs['img_signature_key_type'] = \ signer.padding_method # If a volume is specified. if parsed_args.volume: volume_client = self.app.client_manager.volume source_volume = utils.find_resource( volume_client.volumes, parsed_args.volume, ) response, body = volume_client.volumes.upload_to_image( source_volume.id, parsed_args.force, parsed_args.name, parsed_args.container_format, parsed_args.disk_format, visibility=kwargs.get('visibility', 'private'), protected=True if parsed_args.protected else False) info = body['os-volume_upload_image'] try: info['volume_type'] = info['volume_type']['name'] except TypeError: info['volume_type'] = None else: image = image_client.create_image(**kwargs) if not info: info = _format_image(image) return zip(*sorted(info.items()))
def take_action(self, parsed_args): identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: if getattr(parsed_args, deadopt.replace('-', '_'), None): raise exceptions.CommandError( _("ERROR: --%s was given, which is an Image v1 option" " that is no longer supported in Image v2") % deadopt) # Build an attribute dict from the parsed args, only include # attributes that were actually set on the command line kwargs = {} copy_attrs = ('name', 'id', 'container_format', 'disk_format', 'min_disk', 'min_ram', 'tags', 'visibility') for attr in copy_attrs: if attr in parsed_args: val = getattr(parsed_args, attr, None) if val: # Only include a value in kwargs for attributes that # are actually present on the command line kwargs[attr] = val # properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in six.iteritems(parsed_args.properties): kwargs[k] = str(v) # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not # a single value for the pair of options because the default must be # to do nothing when no options are present as opposed to always # setting a default. if parsed_args.protected: kwargs['protected'] = True if parsed_args.unprotected: kwargs['protected'] = False if parsed_args.public: kwargs['visibility'] = 'public' if parsed_args.private: kwargs['visibility'] = 'private' if parsed_args.community: kwargs['visibility'] = 'community' if parsed_args.shared: kwargs['visibility'] = 'shared' # Handle deprecated --owner option project_arg = parsed_args.project if parsed_args.owner: project_arg = parsed_args.owner LOG.warning( _('The --owner option is deprecated, ' 'please use --project instead.')) if project_arg: kwargs['owner'] = common.find_project( identity_client, project_arg, parsed_args.project_domain, ).id # open the file first to ensure any failures are handled before the # image is created fp = gc_utils.get_data_file(parsed_args) info = {} if fp is not None and parsed_args.volume: raise exceptions.CommandError( _("Uploading data and using " "container are not allowed at " "the same time")) if fp is None and parsed_args.file: LOG.warning(_("Failed to get an image file.")) return {}, {} if parsed_args.owner: kwargs['owner'] = common.find_project( identity_client, parsed_args.owner, parsed_args.project_domain, ).id # sign an image using a given local private key file if parsed_args.sign_key_path or parsed_args.sign_cert_id: if not parsed_args.file: msg = (_("signing an image requires the --file option, " "passing files via stdin when signing is not " "supported.")) raise exceptions.CommandError(msg) if (len(parsed_args.sign_key_path) < 1 or len(parsed_args.sign_cert_id) < 1): msg = (_("'sign-key-path' and 'sign-cert-id' must both be " "specified when attempting to sign an image.")) raise exceptions.CommandError(msg) else: sign_key_path = parsed_args.sign_key_path sign_cert_id = parsed_args.sign_cert_id signer = image_signer.ImageSigner() try: pw = utils.get_password( self.app.stdin, prompt=("Please enter private key password, leave " "empty if none: "), confirm=False) if not pw or len(pw) < 1: pw = None signer.load_private_key(sign_key_path, password=pw) except Exception: msg = (_("Error during sign operation: private key could " "not be loaded.")) raise exceptions.CommandError(msg) signature = signer.generate_signature(fp) signature_b64 = b64encode(signature) kwargs['img_signature'] = signature_b64 kwargs['img_signature_certificate_uuid'] = sign_cert_id kwargs['img_signature_hash_method'] = signer.hash_method if signer.padding_method: kwargs['img_signature_key_type'] = signer.padding_method # If a volume is specified. if parsed_args.volume: volume_client = self.app.client_manager.volume source_volume = utils.find_resource( volume_client.volumes, parsed_args.volume, ) response, body = volume_client.volumes.upload_to_image( source_volume.id, parsed_args.force, parsed_args.name, parsed_args.container_format, parsed_args.disk_format, ) info = body['os-volume_upload_image'] try: info['volume_type'] = info['volume_type']['name'] except TypeError: info['volume_type'] = None else: image = image_client.images.create(**kwargs) if fp is not None: with fp: try: image_client.images.upload(image.id, fp) except Exception: # If the upload fails for some reason attempt to remove the # dangling queued image made by the create() call above but # only if the user did not specify an id which indicates # the Image already exists and should be left alone. try: if 'id' not in kwargs: image_client.images.delete(image.id) except Exception: pass # we don't care about this one raise # now, throw the upload exception again # update the image after the data has been uploaded image = image_client.images.get(image.id) if not info: info = _format_image(image) return zip(*sorted(six.iteritems(info)))
def take_action(self, parsed_args): def _show_progress(progress): if progress: self.app.stderr.write('\rProgress: %s' % progress) self.app.stderr.flush() compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, parsed_args.server, ) # Set sane defaults as this API wants all mouths to be fed if parsed_args.name is None: backup_name = server.name else: backup_name = parsed_args.name if parsed_args.type is None: backup_type = "" else: backup_type = parsed_args.type if parsed_args.rotate is None: backup_rotation = 1 else: backup_rotation = parsed_args.rotate compute_client.servers.backup( server.id, backup_name, backup_type, backup_rotation, ) image_client = self.app.client_manager.image image = utils.find_resource( image_client.images, backup_name, ) if parsed_args.wait: if utils.wait_for_status( image_client.images.get, image.id, callback=_show_progress, ): self.app.stdout.write('\n') else: msg = _('Error creating server backup: %s') % parsed_args.name raise exceptions.CommandError(msg) if self.app.client_manager._api_version['image'] == '1': info = {} info.update(image._info) info['properties'] = utils.format_dict(info.get('properties', {})) else: # Get the right image module to format the output image_module = importutils.import_module(self.IMAGE_API_VERSIONS[ self.app.client_manager._api_version['image']]) info = image_module._format_image(image) return zip(*sorted(info.items()))
def find_resource(manager, name_or_id, **kwargs): """Helper for the _find_* methods. :param manager: A client manager class :param name_or_id: The resource we are trying to find :param kwargs: To be used in calling .find() :rtype: The found resource This method will attempt to find a resource in a variety of ways. Primarily .get() methods will be called with `name_or_id` as an integer value, and tried again as a string value. If both fail, then a .find() is attempted, which is essentially calling a .list() function with a 'name' query parameter that is set to `name_or_id`. Lastly, if any kwargs are passed in, they will be treated as additional query parameters. This is particularly handy in the case of finding resources in a domain. """ # Case 1: name_or_id is an ID, we need to call get() directly # for example: /projects/454ad1c743e24edcad846d1118837cac # For some projects, the name only will work. For keystone, this is not # enough information, and domain information is necessary. try: return manager.get(name_or_id) except Exception: pass if kwargs: # Case 2: name_or_id is a name, but we have query args in kwargs # for example: /projects/demo&domain_id=30524568d64447fbb3fa8b7891c10dd try: return manager.get(name_or_id, **kwargs) except Exception: pass # Case 3: Try to get entity as integer id. Keystone does not have integer # IDs, they are UUIDs, but some things in nova do, like flavors. try: if isinstance(name_or_id, int) or name_or_id.isdigit(): return manager.get(int(name_or_id), **kwargs) # FIXME(dtroyer): The exception to catch here is dependent on which # client library the manager passed in belongs to. # Eventually this should be pulled from a common set # of client exceptions. except Exception as ex: if (type(ex).__name__ == 'NotFound' or type(ex).__name__ == 'HTTPNotFound' or type(ex).__name__ == 'TypeError'): pass else: raise # Case 4: Try to use find. # Reset the kwargs here for find if len(kwargs) == 0: kwargs = {} try: # Prepare the kwargs for calling find if 'NAME_ATTR' in manager.resource_class.__dict__: # novaclient does this for oddball resources kwargs[manager.resource_class.NAME_ATTR] = name_or_id else: kwargs['name'] = name_or_id except Exception: pass # finally try to find entity by name try: return manager.find(**kwargs) # FIXME(dtroyer): The exception to catch here is dependent on which # client library the manager passed in belongs to. # Eventually this should be pulled from a common set # of client exceptions. except Exception as ex: if type(ex).__name__ == 'NotFound': msg = _("No %(resource)s with a name or ID of '%(id)s' exists.") raise exceptions.CommandError( msg % { 'resource': manager.resource_class.__name__.lower(), 'id': name_or_id, }) if type(ex).__name__ == 'NoUniqueMatch': msg = _( "More than one %(resource)s exists with the name '%(id)s'.") raise exceptions.CommandError( msg % { 'resource': manager.resource_class.__name__.lower(), 'id': name_or_id, }) if type(ex).__name__ == 'Forbidden': msg = _("You are not authorized to find %(resource)s with the " "name '%(id)s'.") raise exceptions.CommandError( msg % { 'resource': manager.resource_class.__name__.lower(), 'id': name_or_id, }) else: pass # Case 5: For client with no find function, list all resources and hope # to find a matching name or ID. count = 0 for resource in manager.list(): if (resource.get('id') == name_or_id or resource.get('name') == name_or_id): count += 1 _resource = resource if count == 0: # we found no match, report back this error: msg = _("Could not find resource %s") raise exceptions.CommandError(msg % name_or_id) elif count == 1: return _resource else: # we found multiple matches, report back this error msg = _("More than one resource exists with the name or ID '%s'.") raise exceptions.CommandError(msg % name_or_id)
def _get_required_firewall_rule(client, parsed_args): if not parsed_args.firewall_rule: msg = (_("Firewall rule (name or ID) is required.")) raise exceptions.CommandError(msg) return client.find_resource( const.FWR, parsed_args.firewall_rule, cmd_resource=const.CMD_FWR)['id']
def take_action(self, parsed_args): client = self.app.client_manager.network obj = client.find_router(parsed_args.router, ignore_missing=False) # Get the common attributes. attrs = _get_attrs(self.app.client_manager, parsed_args) # Get the route attributes. if parsed_args.ha: attrs['ha'] = True elif parsed_args.no_ha: attrs['ha'] = False if parsed_args.clear_routes: LOG.warning( _('The --clear-routes option is deprecated, ' 'please use --no-route instead.')) if parsed_args.routes is not None: for route in parsed_args.routes: route['nexthop'] = route.pop('gateway') attrs['routes'] = parsed_args.routes if not (parsed_args.no_route or parsed_args.clear_routes): # Map the route keys and append to the current routes. # The REST API will handle route validation and duplicates. attrs['routes'] += obj.routes elif parsed_args.no_route or parsed_args.clear_routes: attrs['routes'] = [] if (parsed_args.disable_snat or parsed_args.enable_snat or parsed_args.fixed_ip) and not parsed_args.external_gateway: msg = (_("You must specify '--external-gateway' in order " "to update the SNAT or fixed-ip values")) raise exceptions.CommandError(msg) if parsed_args.external_gateway: gateway_info = {} network = client.find_network(parsed_args.external_gateway, ignore_missing=False) gateway_info['network_id'] = network.id if parsed_args.disable_snat: gateway_info['enable_snat'] = False if parsed_args.enable_snat: gateway_info['enable_snat'] = True if parsed_args.fixed_ip: ips = [] for ip_spec in parsed_args.fixed_ip: if ip_spec.get('subnet', False): subnet_name_id = ip_spec.pop('subnet') if subnet_name_id: subnet = client.find_subnet(subnet_name_id, ignore_missing=False) ip_spec['subnet_id'] = subnet.id if ip_spec.get('ip-address', False): ip_spec['ip_address'] = ip_spec.pop('ip-address') ips.append(ip_spec) gateway_info['external_fixed_ips'] = ips attrs['external_gateway_info'] = gateway_info if ((parsed_args.qos_policy or parsed_args.no_qos_policy) and not parsed_args.external_gateway): try: original_net_id = obj.external_gateway_info['network_id'] except (KeyError, TypeError): msg = (_("You must specify '--external-gateway' or the router " "must already have an external network in order to " "set router gateway IP QoS")) raise exceptions.CommandError(msg) else: if not attrs.get('external_gateway_info'): attrs['external_gateway_info'] = {} attrs['external_gateway_info']['network_id'] = original_net_id if parsed_args.qos_policy: check_qos_id = client.find_qos_policy(parsed_args.qos_policy, ignore_missing=False).id attrs['external_gateway_info']['qos_policy_id'] = check_qos_id if 'no_qos_policy' in parsed_args and parsed_args.no_qos_policy: attrs['external_gateway_info']['qos_policy_id'] = None if attrs: client.update_router(obj, **attrs) # tags is a subresource and it needs to be updated separately. _tag.update_tags_for_set(client, obj, parsed_args)
def find_attr( self, path, value=None, attr=None, resource=None, ): """Find a resource via attribute or ID Most APIs return a list wrapped by a dict with the resource name as key. Some APIs (Identity) return a dict when a query string is present and there is one return value. Take steps to unwrap these bodies and return a single dict without any resource wrappers. :param string path: The API-specific portion of the URL path :param string value: value to search for :param string attr: attribute to use for resource search :param string resource: plural of the object resource name; defaults to path For example: n = find(netclient, 'network', 'networks', 'matrix') """ # Default attr is 'name' if attr is None: attr = 'name' # Default resource is path - in many APIs they are the same if resource is None: resource = path def getlist(kw): """Do list call, unwrap resource dict if present""" ret = self.list(path, **kw) if isinstance(ret, dict) and resource in ret: ret = ret[resource] return ret # Search by attribute kwargs = {attr: value} data = getlist(kwargs) if isinstance(data, dict): return data if len(data) == 1: return data[0] if len(data) > 1: msg = _("Multiple %(resource)s exist with %(attr)s='%(value)s'") raise exceptions.CommandError(msg % { 'resource': resource, 'attr': attr, 'value': value }) # Search by id kwargs = {'id': value} data = getlist(kwargs) if len(data) == 1: return data[0] msg = _("No %(resource)s with a %(attr)s or ID of '%(value)s' found") raise exceptions.CommandError(msg % { 'resource': resource, 'attr': attr, 'value': value })
def test_image_create_file(self, mock_open): mock_file = mock.MagicMock(name='File') mock_open.return_value = mock_file mock_open.read.return_value = ( image_fakes.FakeImage.get_image_data(self.new_image)) mock_exception = { 'find.side_effect': exceptions.CommandError('x'), } self.images_mock.configure_mock(**mock_exception) arglist = [ '--file', 'filer', ('--unprotected' if not self.new_image.protected else '--protected'), ('--public' if self.new_image.visibility == 'public' else '--private'), '--property', 'Alpha=1', '--property', 'Beta=2', '--tag', self.new_image.tags[0], '--tag', self.new_image.tags[1], self.new_image.name, ] verifylist = [ ('file', 'filer'), ('protected', self.new_image.protected), ('unprotected', not self.new_image.protected), ('public', self.new_image.visibility == 'public'), ('private', self.new_image.visibility == 'private'), ('properties', {'Alpha': '1', 'Beta': '2'}), ('tags', self.new_image.tags), ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # In base command class ShowOne in cliff, abstract method take_action() # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. columns, data = self.cmd.take_action(parsed_args) # ImageManager.create(name=, **) self.images_mock.create.assert_called_with( name=self.new_image.name, container_format=image.DEFAULT_CONTAINER_FORMAT, disk_format=image.DEFAULT_DISK_FORMAT, protected=self.new_image.protected, visibility=self.new_image.visibility, Alpha='1', Beta='2', tags=self.new_image.tags, ) # Verify update() was not called, if it was show the args self.assertEqual(self.images_mock.update.call_args_list, []) self.images_mock.upload.assert_called_with( mock.ANY, mock.ANY, ) self.assertEqual( image_fakes.FakeImage.get_image_columns(self.new_image), columns) self.assertEqual( image_fakes.FakeImage.get_image_data(self.new_image), data)
def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) client = self.app.client_manager.orchestration tpl_files, template = template_utils.process_template_path( parsed_args.template, object_request=http.authenticated_fetcher(client)) env_files_list = [] env_files, env = ( template_utils.process_multiple_environments_and_files( env_paths=parsed_args.environment, env_list_tracker=env_files_list)) parameters = heat_utils.format_all_parameters( parsed_args.parameter, parsed_args.parameter_file, parsed_args.template) if parsed_args.pre_create: template_utils.hooks_to_env(env, parsed_args.pre_create, 'pre-create') fields = { 'stack_name': parsed_args.name, 'disable_rollback': not parsed_args.enable_rollback, 'parameters': parameters, 'template': template, 'files': dict(list(tpl_files.items()) + list(env_files.items())), 'environment': env } # If one or more environments is found, pass the listing to the server if env_files_list: fields['environment_files'] = env_files_list if parsed_args.tags: fields['tags'] = parsed_args.tags if parsed_args.timeout: fields['timeout_mins'] = parsed_args.timeout if parsed_args.dry_run: stack = client.stacks.preview(**fields) formatters = { 'description': heat_utils.text_wrap_formatter, 'template_description': heat_utils.text_wrap_formatter, 'stack_status_reason': heat_utils.text_wrap_formatter, 'parameters': heat_utils.json_formatter, 'outputs': heat_utils.json_formatter, 'resources': heat_utils.json_formatter, 'links': heat_utils.link_formatter, } columns = [] for key in stack.to_dict(): columns.append(key) columns.sort() return ( columns, utils.get_item_properties(stack, columns, formatters=formatters) ) stack = client.stacks.create(**fields)['stack'] if parsed_args.wait: stack_status, msg = event_utils.poll_for_events( client, parsed_args.name, action='CREATE') if stack_status == 'CREATE_FAILED': raise exc.CommandError(msg) return _show_stack(client, stack['id'], format='table', short=True)
def take_action_network(self, client, parsed_args): msg = _("Floating ip pool operations are only available for " "Compute v2 network.") raise exceptions.CommandError(msg)
def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) client = self.app.client_manager.orchestration tpl_files, template = template_utils.process_template_path( parsed_args.template, object_request=http.authenticated_fetcher(client), existing=parsed_args.existing) env_files_list = [] env_files, env = ( template_utils.process_multiple_environments_and_files( env_paths=parsed_args.environment, env_list_tracker=env_files_list)) parameters = heat_utils.format_all_parameters( parsed_args.parameter, parsed_args.parameter_file, parsed_args.template) if parsed_args.pre_update: template_utils.hooks_to_env(env, parsed_args.pre_update, 'pre-update') fields = { 'stack_id': parsed_args.stack, 'parameters': parameters, 'existing': parsed_args.existing, 'template': template, 'files': dict(list(tpl_files.items()) + list(env_files.items())), 'environment': env } # If one or more environments is found, pass the listing to the server if env_files_list: fields['environment_files'] = env_files_list if parsed_args.tags: fields['tags'] = parsed_args.tags if parsed_args.timeout: fields['timeout_mins'] = parsed_args.timeout if parsed_args.clear_parameter: fields['clear_parameters'] = list(parsed_args.clear_parameter) if parsed_args.rollback: rollback = parsed_args.rollback.strip().lower() if rollback not in ('enabled', 'disabled', 'keep'): msg = _('--rollback invalid value: %s') % parsed_args.rollback raise exc.CommandError(msg) if rollback != 'keep': fields['disable_rollback'] = rollback == 'disabled' if parsed_args.dry_run: changes = client.stacks.preview_update(**fields) fields = ['state', 'resource_name', 'resource_type', 'resource_identity'] columns = sorted(changes.get("resource_changes", {}).keys()) data = [heat_utils.json_formatter(changes["resource_changes"][key]) for key in columns] return columns, data if parsed_args.wait: # find the last event to use as the marker events = event_utils.get_events(client, stack_id=parsed_args.stack, event_args={'sort_dir': 'desc'}, limit=1) marker = events[0].id if events else None client.stacks.update(**fields) if parsed_args.wait: stack = client.stacks.get(parsed_args.stack) stack_status, msg = event_utils.poll_for_events( client, stack.stack_name, action='UPDATE', marker=marker) if stack_status == 'UPDATE_FAILED': raise exc.CommandError(msg) return _show_stack(client, parsed_args.stack, format='table', short=True)
def take_action(self, parsed_args): http = self.app.client_manager.placement if parsed_args.aggregate: self.check_version(version.ge('1.3')) filters = {'member_of': parsed_args.uuid} url = common.url_with_filters(RP_BASE_URL, filters) rps = http.request('GET', url).json()['resource_providers'] if not rps: raise exceptions.CommandError( 'No resource providers found in aggregate with uuid %s.' % parsed_args.uuid) else: url = RP_BASE_URL + '/' + parsed_args.uuid rps = [http.request('GET', url).json()] resources_list = [] ret = 0 for rp in rps: inventories = collections.defaultdict(dict) url = BASE_URL.format(uuid=rp['uuid']) if parsed_args.amend: # Get existing inventories # TODO(melwitt): Do something to handle the possibility of the # GET failing here (example: resource provider deleted from # underneath us). payload = http.request('GET', url).json() inventories.update(payload['inventories']) payload['inventories'] = inventories else: payload = { 'inventories': inventories, 'resource_provider_generation': rp['generation'] } # Apply resource values to inventories for r in parsed_args.resource: name, field, value = parse_resource_argument(r) inventories[name][field] = value try: if not parsed_args.dry_run: resources = http.request('PUT', url, json=payload).json() else: resources = payload except Exception as exp: with excutils.save_and_reraise_exception() as err_ctx: if parsed_args.aggregate: self.log.error( _('Failed to set inventory for ' 'resource provider %(rp)s: %(exp)s.'), { 'rp': rp['uuid'], 'exp': exp }) err_ctx.reraise = False ret += 1 continue resources_list.append((rp['uuid'], resources)) if ret > 0: msg = _('Failed to set inventory for %(ret)s of %(total)s ' 'resource providers.') % { 'ret': ret, 'total': len(rps) } raise exceptions.CommandError(msg) def get_rows(fields, resources, rp_uuid=None): inventories = [ dict(resource_class=k, **v) for k, v in resources['inventories'].items() ] prepend = (rp_uuid, ) if rp_uuid else () # This is a generator expression rows = (prepend + utils.get_dict_properties(i, fields) for i in inventories) return rows fields = ('resource_class', ) + FIELDS if parsed_args.aggregate: # If this is an aggregate batch, create output that will include # resource provider as the first field to differentiate the values rows = () for rp_uuid, resources in resources_list: subrows = get_rows(fields, resources, rp_uuid=rp_uuid) rows = itertools.chain(rows, subrows) fields = ('resource_provider', ) + fields return fields, rows else: # If this was not an aggregate batch, show output for the one # resource provider (show payload of the first item in the list), # keeping the behavior prior to the addition of --aggregate option return fields, get_rows(fields, resources_list[0][1])
def _validate_args(self, parsed_args): if parsed_args.stack in (None, ''): raise oscexc.CommandError("You must specify a stack name")