def create_resource(self, properties, location, is_full_object): res = json.loads(properties) if not is_full_object: if not location: if self.resource_id: rg_name = parse_resource_id(self.resource_id)['resource_group'] else: rg_name = self.resource_group_name location = self.rcf.resource_groups.get(rg_name).location res = GenericResource(location=location, properties=res) elif res.get('location', None) is None: raise IncorrectUsageError("location of the resource is required") if self.resource_id: resource = self.rcf.resources.create_or_update_by_id(self.resource_id, self.api_version, res) else: resource = self.rcf.resources.create_or_update(self.resource_group_name, self.resource_provider_namespace, self.parent_resource_path or '', self.resource_type, self.resource_name, self.api_version, res) return resource
def __init__(self, resource_group_name=None, resource_provider_namespace=None, parent_resource_path=None, resource_type=None, resource_name=None, resource_id=None, api_version=None, rcf=None): if bool(resource_id) == bool(resource_group_name or resource_type or parent_resource_path or resource_provider_namespace or resource_name): raise IncorrectUsageError( "(--id ID | --resource-group RG --name NAME --namespace NAMESPACE --resource-type TYPE -n NAME)") #pylint: disable=line-too-long #if the resouce_type is in format 'namespace/type' split it. #(we don't have to do this, but commands like 'vm show' returns such values) if resource_type and not resource_provider_namespace and not parent_resource_path: parts = resource_type.split('/') if len(parts) > 1: resource_provider_namespace = parts[0] resource_type = parts[1] self.rcf = rcf or _resource_client_factory() if api_version is None: if resource_id: api_version = _ResourceUtils._resolve_api_version_by_id(self.rcf, resource_id) else: api_version = _ResourceUtils._resolve_api_version(self.rcf, resource_provider_namespace, parent_resource_path, resource_type) self.resource_group_name = resource_group_name self.resource_provider_namespace = resource_provider_namespace self.parent_resource_path = parent_resource_path self.resource_type = resource_type self.resource_name = resource_name self.resource_id = resource_id self.api_version = api_version
def _list_resources_odata_filter_builder(location=None, resource_type=None, resource_group_name=None, tag=None, name=None): '''Build up OData filter string from parameters ''' filters = [] if resource_group_name: filters.append("resourceGroup eq '{}'".format(resource_group_name)) if name: filters.append("name eq '{}'".format(name)) if location: filters.append("location eq '{}'".format(location)) if resource_type: filters.append("resourceType eq '{}/{}'".format( resource_type.namespace, resource_type.type)) if tag: if name or location: raise IncorrectUsageError('you cannot use the tag filter with other filters') tag_name = list(tag.keys())[0] if isinstance(tag, dict) else tag tag_value = tag[tag_name] if isinstance(tag, dict) else '' if tag_name: if tag_name[-1] == '*': filters.append("startswith(tagname, '%s')" % tag_name[0:-1]) else: filters.append("tagname eq '%s'" % tag_name) if tag_value != '': filters.append("tagvalue eq '%s'" % tag_value) return ' and '.join(filters)
def _resolve_api_version(rcf, resource_provider_namespace, parent_resource_path, resource_type): provider = rcf.providers.get(resource_provider_namespace) #If available, we will use parent resource's api-version resource_type_str = (parent_resource_path.split('/')[0] if parent_resource_path else resource_type) rt = [t for t in provider.resource_types if t.resource_type.lower() == resource_type_str.lower()] if not rt: raise IncorrectUsageError('Resource type {} not found.' .format(resource_type_str)) if len(rt) == 1 and rt[0].api_versions: npv = [v for v in rt[0].api_versions if 'preview' not in v.lower()] return npv[0] if npv else rt[0].api_versions[0] else: raise IncorrectUsageError( 'API version is required and could not be resolved for resource {}' .format(resource_type))
def get_arm_resource_by_id(cli_ctx, arm_id, api_version=None): from msrestazure.tools import parse_resource_id, is_valid_resource_id if not is_valid_resource_id(arm_id): raise CLIError("'{}' is not a valid ID.".format(arm_id)) client = get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES) if not api_version: parts = parse_resource_id(arm_id) # to retrieve the provider, we need to know the namespace namespaces = {k: v for k, v in parts.items() if 'namespace' in k} # every ARM ID has at least one namespace, so start with that namespace = namespaces.pop('namespace') namespaces.pop('resource_namespace') # find the most specific child namespace (if any) and use that value instead highest_child = 0 for k, v in namespaces.items(): child_number = int(k.split('_')[2]) if child_number > highest_child: namespace = v highest_child = child_number # retrieve provider info for the namespace provider = client.providers.get(namespace) # assemble the resource type key used by the provider list operation. type1/type2/type3/... resource_type_str = '' if not highest_child: resource_type_str = parts['resource_type'] else: types = {int(k.split('_')[2]): v for k, v in parts.items() if k.startswith('child_type')} for k in sorted(types.keys()): if k < highest_child: continue resource_type_str = '{}{}/'.format(resource_type_str, parts['child_type_{}'.format(k)]) resource_type_str = resource_type_str.rstrip('/') api_version = None rt = next((t for t in provider.resource_types if t.resource_type.lower() == resource_type_str.lower()), None) if not rt: from azure.cli.core.parser import IncorrectUsageError raise IncorrectUsageError('Resource type {} not found.'.format(resource_type_str)) try: # if the service specifies, use the default API version api_version = rt.default_api_version except AttributeError: # if the service doesn't specify, use the most recent non-preview API version unless there is only a # single API version. API versions are returned by the service in a sorted list api_version = next((x for x in rt.api_versions if not x.endswith('preview')), rt.api_versions[0]) return client.resources.get_by_id(arm_id, api_version)
def _resolve_api_version(rcf, resource_type, parent=None): provider = rcf.providers.get(resource_type.namespace) resource_type_str = '{}/{}'.format(parent.type, resource_type.type) \ if parent else resource_type.type rt = [ t for t in provider.resource_types if t.resource_type == resource_type_str ] if not rt: raise IncorrectUsageError( 'Resource type {} not found.'.format(resource_type_str)) if len(rt) == 1 and rt[0].api_versions: npv = [v for v in rt[0].api_versions if 'preview' not in v.lower()] return npv[0] if npv else rt[0].api_versions[0] else: raise IncorrectUsageError( 'API version is required and could not be resolved for resource {}/{}' .format(resource_type.namespace, resource_type.type))
def validate_resource_type(string): ''' Validates that resource type is provided in <namespace>/<type> format ''' type_comps = string.split('/') try: namespace_comp = type_comps[0] resource_comp = type_comps[1] except IndexError: raise IncorrectUsageError( 'Parameter --resource-type must be in <namespace>/<type> format.') ResourceType = collections.namedtuple('ResourceType', 'namespace type') return ResourceType(namespace=namespace_comp, type=resource_comp)
def _resolve_api_version(rcf, resource_provider_namespace, parent_resource_path, resource_type): """ This is copied from src/azure-cli/azure/cli/command_modules/resource/custom.py in Azure/azure-cli """ from azure.cli.core.parser import IncorrectUsageError provider = rcf.providers.get(resource_provider_namespace) # If available, we will use parent resource's api-version resource_type_str = (parent_resource_path.split('/')[0] if parent_resource_path else resource_type) rt = [t for t in provider.resource_types if t.resource_type.lower() == resource_type_str.lower()] if not rt: raise IncorrectUsageError('Resource type {} not found.'.format(resource_type_str)) if len(rt) == 1 and rt[0].api_versions: npv = [v for v in rt[0].api_versions if 'preview' not in v.lower()] return npv[0] if npv else rt[0].api_versions[0] raise IncorrectUsageError( 'API version is required and could not be resolved for resource {}'.format(resource_type))
def validate_parent(string): ''' Validates that parent is provided in <type>/<name> format ''' if not string: return string parent_comps = string.split('/') try: type_comp = parent_comps[0] name_comp = parent_comps[1] except IndexError: raise IncorrectUsageError( 'Parameter --parent must be in <type>/<name> format.') ParentType = collections.namedtuple('ParentType', 'type name') return ParentType(type=type_comp, name=name_comp)
def _list_resources_odata_filter_builder( resource_group_name=None, # pylint: disable=too-many-arguments resource_provider_namespace=None, resource_type=None, name=None, tag=None, location=None): """Build up OData filter string from parameters """ filters = [] if resource_group_name: filters.append("resourceGroup eq '{}'".format(resource_group_name)) if name: filters.append("name eq '{}'".format(name)) if location: filters.append("location eq '{}'".format(location)) if resource_type: if resource_provider_namespace: f = "'{}/{}'".format(resource_provider_namespace, resource_type) else: if not re.match('[^/]+/[^/]+', resource_type): raise CLIError( 'Malformed resource-type: ' '--resource-type=<namespace>/<resource-type> expected.') # assume resource_type is <namespace>/<type>. The worst is to get a server error f = "'{}'".format(resource_type) filters.append("resourceType eq " + f) else: if resource_provider_namespace: raise CLIError('--namespace also requires --resource-type') if tag: if name or location: raise IncorrectUsageError( 'you cannot use the tag filter with other filters') tag_name = list(tag.keys())[0] if isinstance(tag, dict) else tag tag_value = tag[tag_name] if isinstance(tag, dict) else '' if tag_name: if tag_name[-1] == '*': filters.append("startswith(tagname, '%s')" % tag_name[0:-1]) else: filters.append("tagname eq '%s'" % tag_name) if tag_value != '': filters.append("tagvalue eq '%s'" % tag_value) return ' and '.join(filters)