def testInitializeFails(self): """Tests Initialize raises a useful error message when attribute not found. """ self.UnsetProject() fallthroughs_map = { 'book': [deps.ArgFallthrough('--book')], 'shelf': [deps.ArgFallthrough('--book-shelf')], 'project': [ deps.ArgFallthrough('--book-project'), deps.ArgFallthrough('--project'), deps.PropertyFallthrough(properties.VALUES.core.project) ] } parsed_args = self._GetMockNamespace(book='example', book_shelf='exampleshelf', book_project=None) resource_spec = concepts.ResourceSpec('example.projects.shelves.books', resource_name='book', **self._MakeAttributeConfigs()) msg = re.escape( 'The [book] resource is not properly specified.\n' 'Failed to find attribute [project]. The attribute can be set in the ' 'following ways: \n' '- provide the argument [--book-project] on the command line\n' '- provide the argument [--project] on the command line\n' '- set the property [core/project]') with self.assertRaisesRegex(concepts.InitializationError, msg): resource_spec.Initialize(fallthroughs_map, parsed_args=parsed_args)
def Args(parser): key_spec_group = parser.add_group( mutex=True, help='The key configuration used for the CA certificate. Defaults to a ' 'managed key if not specified.') x509_config_group = parser.add_group( mutex=True, required=False, help='The X.509 configuration used for the CA certificate.') concept_parsers.ConceptParser([ presentation_specs.ResourcePresentationSpec( 'CERTIFICATE_AUTHORITY', resource_args.CreateCertAuthorityResourceSpec( 'Certificate Authority'), 'The name of the root CA to create.', required=True), presentation_specs.ResourcePresentationSpec( '--kms-key-version', resource_args.CreateKmsKeyVersionResourceSpec(), 'An existing KMS key version to back this CA.', group=key_spec_group), presentation_specs.ResourcePresentationSpec( '--from-ca', resource_args.CreateCertAuthorityResourceSpec( 'source CA', location_fallthroughs=[ deps.ArgFallthrough('--location'), resource_args.LOCATION_PROPERTY_FALLTHROUGH ], pool_id_fallthroughs=[deps.ArgFallthrough('--pool')]), 'An existing CA from which to copy configuration values for the new CA. ' 'You can still override any of those values by explicitly providing ' 'the appropriate flags. The specified existing CA must be part of ' 'the same pool as the one being created.', flag_name_overrides={ 'project': '', 'location': '', 'pool': '', }, prefixes=True) ]).AddToParser(parser) flags_v1.AddSubjectFlags(parser, subject_required=False) flags_v1.AddKeyAlgorithmFlag( key_spec_group, default='rsa-pkcs1-4096-sha256') flags_v1.AddValidityFlag( parser, resource_name='CA', default_value='P10Y', default_value_text='10 years') labels_util.AddCreateLabelsFlags(parser) flags_v1.AddBucketFlag(parser) flags_v1.AddUsePresetProfilesFlag(x509_config_group) # If max_chain_len is unspecified, no max length will be provided to the # server on create, this allowing any number of subordinates. flags_v1.AddInlineX509ParametersFlags( x509_config_group, is_ca_command=True, default_max_chain_length=None) flags_v1.AddAutoEnableFlag(parser)
def GetZoneAttributeConfig(): return concepts.ResourceParameterAttributeConfig( # TODO(b/180447280): Switch to use location as the default argument here. 'zone', 'The zone of the {resource}.', fallthroughs=[ deps.ArgFallthrough('region'), deps.ArgFallthrough('location'), deps.PropertyFallthrough(properties.VALUES.filestore.zone), deps.PropertyFallthrough(properties.VALUES.filestore.region), deps.PropertyFallthrough(properties.VALUES.filestore.location), ])
def testGet_UseProperty(self): """Test the deps object can initialize attributes using PropertyFallthrough. """ result = deps.Get( 'project', { 'project': [ deps.ArgFallthrough('--myresource-project'), deps.ArgFallthrough('--project'), deps.PropertyFallthrough(properties.VALUES.core.project) ] }, parsed_args=self._GetMockNamespace(myresource_project=None)) self.assertEqual(self.Project(), result)
def testParsePluralAnchorFallthroughMultitypeArgFallthrough(self): properties.VALUES.core.project.Set('xyz') fallthrough = deps.ArgFallthrough('--other') resource_spec = self.SetUpFallthroughSpec(fallthrough=fallthrough, is_multitype=True) # Remove the fallthrough for the organization. for attribute in resource_spec.attributes: if attribute.name == 'organization': attribute.fallthroughs = [] resource = self.PresentationSpecType(is_multitype=True)( '--books', resource_spec, 'Group Help', prefixes=False, required=False, plural=True, flag_name_overrides={'project': '--book-project'} ) concept_parser = concept_parsers.ConceptParser([resource]) concept_parser.AddToParser(self.parser) self.parser.add_argument('--other', help='h') namespace = self.parser.parser.parse_args(['--other', 'xyz']) self.AssertParsedListEquals( ['projects/xyz/shelves/xyz/books/xyz'], namespace.CONCEPTS.books.Parse(), is_multitype=True)
def GetArgAndBaseFallthroughsForAttribute(self, attribute_to_args_map, base_fallthroughs_map, attribute, plural=False): """Gets all fallthroughs for an attribute except anchor-dependent ones.""" attribute_name = attribute.name attribute_fallthroughs = [] # The only args that should be lists are anchor args for plural # resources. attribute_is_plural = self.IsAnchor(attribute) and plural # Start the fallthroughs list with the primary associated arg for the # attribute. arg_name = attribute_to_args_map.get(attribute_name) if arg_name: attribute_fallthroughs.append( deps_lib.ArgFallthrough(arg_name, plural=attribute_is_plural)) given_fallthroughs = base_fallthroughs_map.get(attribute_name, []) for fallthrough in given_fallthroughs: if attribute_is_plural: fallthrough = copy.deepcopy(fallthrough) fallthrough.plural = attribute_is_plural attribute_fallthroughs.append(fallthrough) return attribute_fallthroughs
def BuildFullFallthroughsMap(self): """Builds map of all fallthroughs including arg names. Fallthroughs are a list of objects that, when called, try different ways of getting values for attributes (see googlecloudsdk.calliope.concepts.deps. _Fallthrough). This method builds a map from the name of each attribute to its fallthroughs, including the "primary" fallthrough representing its corresponding argument value in parsed_args if any, and any fallthroughs that were configured for the attribute beyond that. Returns: {str: [deps_lib._Fallthrough]}, a map from attribute name to its fallthroughs. """ fallthroughs_map = {} for attribute in self.concept_spec.attributes: attribute_name = attribute.name attribute_fallthroughs = [] # Start the fallthroughs list with the primary associated arg for the # attribute. arg_name = self.attribute_to_args_map.get(attribute_name) if arg_name: # The only args that should be lists are anchor args for plural # resources. plural = (attribute_name == self.concept_spec.anchor.name and self.plural) attribute_fallthroughs.append( deps_lib.ArgFallthrough(arg_name, plural=plural)) attribute_fallthroughs += self.fallthroughs_map.get(attribute_name, []) fallthroughs_map[attribute_name] = attribute_fallthroughs return fallthroughs_map
def _BuildFullFallthroughsMap(self, parsed_args=None): """Helper method to build all fallthroughs including arg names.""" fallthroughs_map = {} for attribute in self.concept_spec.attributes: attribute_name = attribute.name attribute_fallthroughs = [] # Start the fallthroughs list with the primary associated arg for the # attribute. arg_name = self.attribute_to_args_map.get(attribute_name) if arg_name: arg_value = getattr(parsed_args, util.NamespaceFormat(arg_name), None) # The only args that should be lists are anchor args for plural # resources. plural = (attribute_name == self.concept_spec.anchor.name and self.plural) if isinstance(arg_value, list) and not plural: arg_value = arg_value[0] if arg_value else None if plural and arg_value is None: arg_value = [] attribute_fallthroughs.append( deps_lib.ArgFallthrough(arg_name, arg_value)) attribute_fallthroughs += self.fallthroughs_map.get( attribute_name, []) fallthroughs_map[attribute_name] = attribute_fallthroughs return fallthroughs_map
def testCreateAttributeConfigFromData(self): attribute_config = concepts.ResourceParameterAttributeConfig.FromData({ 'parameter_name': 'projectsId', 'attribute_name': 'project', 'help': 'help1', 'prop': 'core/project', 'completion_id_field': 'id', 'completion_request_params': [{ 'fieldName': 'fieldMask', 'value': 'name' }] }) self.assertEqual('project', attribute_config.attribute_name) self.assertEqual(None, attribute_config.completer) self.assertEqual('id', attribute_config.completion_id_field) self.assertEqual({'fieldMask': 'name'}, attribute_config.completion_request_params) self.assertEqual('projectsId', attribute_config.parameter_name) self.assertEqual([ deps.ArgFallthrough('--project'), deps.PropertyFallthrough(properties.VALUES.core.project) ], attribute_config.fallthroughs)
def GetDeps(self): """Builds the deps.Deps object to get attribute values. Gets a set of fallthroughs for each attribute of the handler's concept spec, including any argument values that were registered through RegisterArg. Then initializes the deps object. Returns: (deps_lib.Deps) the deps object representing all data dependencies. """ final_fallthroughs_map = {} for attribute in self.concept_spec.attributes: attribute_name = attribute.name attribute_fallthroughs = [] # Start the fallthroughs list with the primary associated arg for the # attribute. arg_name = self.attribute_to_args_map.get(attribute_name) if arg_name: arg_info = self.arg_info_map.get(attribute_name, None) attribute_fallthroughs.append( deps_lib.ArgFallthrough(arg_name, arg_info)) attribute_fallthroughs += self.fallthroughs_map.get(attribute_name, []) final_fallthroughs_map[attribute_name] = attribute_fallthroughs return deps_lib.Deps(final_fallthroughs_map)
def testCompleterWithArbitraryArgFallthrough(self): collections = [ ('example.projects.shelves.books', True), ('example.projects.shelves', True), ('cloudresourcemanager.projects', True)] self.MockCRUDMethods(*collections) self.PatchBookResourceReturnTypes() parent_name = 'projects/exampleproject/shelves/s0' self.mock_client.projects_shelves_books.List.return_value = ( self.BuildBooksList(['{}/books/b0'.format(parent_name), '{}/books/b1'.format(parent_name)])) resource_spec = util.GetBookResource() resource_spec.attributes[1].fallthroughs.append( deps.ArgFallthrough('--other')) expected_results = ['b0', 'b1'] self.RunResourceCompleter( resource_spec, 'book', presentation_name='--book', dest='book', args={'--book-project': 'exampleproject', '--other': 's0'}, flag_name_overrides={'project': '--book-project'}, expected_completions=expected_results)
def ApiConfigProjectAttributeConfig(name='api-config-project'): return concepts.ResourceParameterAttributeConfig( name=name, help_text='Cloud project API Config resource is in.', fallthroughs=[ deps.ArgFallthrough('--project'), deps.PropertyFallthrough(properties.VALUES.core.project) ])
def LocationAttributeConfig(region_fallthrough=False): fallthroughs = [] if region_fallthrough: fallthroughs.append(deps.ArgFallthrough('--region')) return concepts.ResourceParameterAttributeConfig( name='kms-location', help_text='The Cloud location for the {resource}.', fallthroughs=fallthroughs)
def testAnchorFallthroughFails(self, proj_param, anchor_value): """Test failures with FullySpecifiedAnchorFallthrough.""" proj_fallthrough = deps.FullySpecifiedAnchorFallthrough( deps.ArgFallthrough('--a'), self.book_collection, proj_param) parsed_args = self._GetMockNamespace(a=anchor_value) with self.assertRaises(deps.FallthroughNotFoundError): proj_fallthrough.GetValue(parsed_args)
def LocationAttributeConfig(spoke_location_arguments): location_fallthroughs = [ deps.ArgFallthrough(arg) for arg in spoke_location_arguments ] return concepts.ResourceParameterAttributeConfig( name='location', help_text='The location Id.', fallthroughs=location_fallthroughs)
def testParseWithArbitraryArgFallthrough(self, args_to_parse): fallthroughs_map = {'shelf': [deps_lib.ArgFallthrough('--other-flag')]} self.SetUpConceptParserWithFallthroughs('--book', fallthroughs_map) self.parser.add_argument('--other-flag', help='h') parsed_args = self.parser.parser.parse_args(args_to_parse) self.assertEqual( 'projects/exampleproject/shelves/exampleshelf/books/examplebook', parsed_args.CONCEPTS.book.Parse().RelativeName())
def GetZoneAttributeConfig(): return concepts.ResourceParameterAttributeConfig( 'zone', 'The zone of the {resource}.', fallthroughs=[ deps.PropertyFallthrough(properties.VALUES.filestore.zone), deps.ArgFallthrough('--location'), deps.PropertyFallthrough(properties.VALUES.filestore.location), ])
def testGet_ArgsGiven(self): """Test the deps object can initialize attributes using ArgFallthrough.""" fallthroughs_map = { 'name': [deps.ArgFallthrough('--myresource-name')], 'project': [ deps.ArgFallthrough('--myresource-project'), deps.ArgFallthrough('--project'), deps.PropertyFallthrough(properties.VALUES.core.project) ] } parsed_args = self._GetMockNamespace( myresource_name='example', myresource_project='exampleproject') self.assertEqual( 'example', deps.Get('name', fallthroughs_map, parsed_args=parsed_args)) self.assertEqual( 'exampleproject', deps.Get('project', fallthroughs_map, parsed_args=parsed_args))
def NamespaceAttributeConfig(): return concepts.ResourceParameterAttributeConfig( name='namespace', help_text='The Kubernetes-style namespace for the {resource}.', fallthroughs=[ deps.PropertyFallthrough(properties.VALUES.serverless.namespace), DefaultFallthrough(), deps.ArgFallthrough('project'), deps.PropertyFallthrough(properties.VALUES.core.project), ])
def testGet_BothFail(self): """Test the deps object raises an error if an attribute can't be found.""" self.UnsetProject() fallthroughs_map = { 'project': [ deps.ArgFallthrough('--myresource-project'), deps.ArgFallthrough('--project'), deps.PropertyFallthrough(properties.VALUES.core.project) ] } parsed_args = self._GetMockNamespace(myresource_project=None) regex = re.escape( 'Failed to find attribute [project]. The attribute can be set in the ' 'following ways: \n' '- provide the argument [--myresource-project] on the command line\n' '- provide the argument [--project] on the command line\n' '- set the property [core/project]') with self.assertRaisesRegex(deps.AttributeNotFoundError, regex): deps.Get('project', fallthroughs_map, parsed_args=parsed_args)
def NamespaceAttributeConfig(): return concepts.ResourceParameterAttributeConfig( name='namespace', help_text='Specific to Cloud Run for Anthos: ' 'Kubernetes namespace for the {resource}.', fallthroughs=[ deps.PropertyFallthrough(properties.VALUES.run.namespace), DefaultFallthrough(), deps.ArgFallthrough('project'), deps.PropertyFallthrough(properties.VALUES.core.project), ])
def _MakeFallthrough(self, fallthrough_string): """Make an ArgFallthrough from a formatted string.""" values = fallthrough_string.split('.') if len(values) == 1: arg_name = values return deps.ArgFallthrough(values[0]) elif len(values) == 2: spec_name, attribute_name = values spec = self.specs.get(spec_name) arg_name = spec.attribute_to_args_map.get(attribute_name, None) if not arg_name: raise ValueError( 'Invalid fallthrough value [{}]: No argument associated with ' 'attribute [{}] in concept argument named [{}]'.format( fallthrough_string, attribute_name, spec_name)) return deps.ArgFallthrough(arg_name) else: # Defensive only, should be validated earlier raise ValueError( 'bad fallthrough string [{}]'.format(fallthrough_string))
def RegionAttributeConfig(prompt_func=region_util.PromptForRegion): return concepts.ResourceParameterAttributeConfig( name='region', help_text='Cloud region for the {resource}.', fallthroughs=[ deps.ArgFallthrough('--region'), deps.PropertyFallthrough(properties.VALUES.ai.region), deps.Fallthrough( function=prompt_func, hint='choose one from the prompted list of available regions') ])
def testInitialize(self): """Tests that a resource is initialized correctly using a deps object.""" fallthroughs_map = { 'book': [deps.ArgFallthrough('--book')], 'shelf': [deps.ArgFallthrough('--book-shelf')], 'project': [deps.ArgFallthrough('--book-project')] } parsed_args = self._GetMockNamespace(book='example', book_shelf='exampleshelf', book_project='exampleproject') resource_spec = concepts.ResourceSpec('example.projects.shelves.books', resource_name='book', **self._MakeAttributeConfigs()) registry_resource = resource_spec.Initialize(fallthroughs_map, parsed_args=parsed_args) self.assertEqual( 'projects/exampleproject/shelves/exampleshelf/books/example', registry_resource.RelativeName())
def testGet_AnotherProperty(self): """Test the deps object handles non-project property. """ properties.VALUES.compute.zone.Set('us-east1b') result = deps.Get( 'zone', { 'zone': [ deps.ArgFallthrough('--myresource-zone'), deps.PropertyFallthrough(properties.VALUES.compute.zone) ] }, parsed_args=self._GetMockNamespace(myresource_zone=None)) self.assertEqual('us-east1b', result)
def CreateKmsKeyVersionResourceSpec(): """Creates a resource spec for a KMS CryptoKeyVersion. Defaults to the location and project of the CA, specified through flags or properties. Returns: A concepts.ResourceSpec for a CryptoKeyVersion. """ return concepts.ResourceSpec( 'cloudkms.projects.locations.keyRings.cryptoKeys.cryptoKeyVersions', resource_name='key version', cryptoKeyVersionsId=kms_args.KeyVersionAttributeConfig( kms_prefix=True), cryptoKeysId=kms_args.KeyAttributeConfig(kms_prefix=True), keyRingsId=kms_args.KeyringAttributeConfig(kms_prefix=True), locationsId=LocationAttributeConfig( 'kms-location', [deps.ArgFallthrough('location'), LOCATION_PROPERTY_FALLTHROUGH]), projectsId=ProjectAttributeConfig( 'kms-project', [deps.ArgFallthrough('project'), PROJECT_PROPERTY_FALLTHROUGH]))
def ProjectAttributeConfig(): """Create a project attribute config. This is identical to the default project attribute config but without a property fallthrough. This way the help text about reading the project ID from core/project will not show. Returns: A project attribute config. """ return concepts.ResourceParameterAttributeConfig( name='project', help_text='The Cloud project for the {resource}.', fallthroughs=[deps.ArgFallthrough('--project')])
def LocationAttributeConfig(): return concepts.ResourceParameterAttributeConfig( name='{}location'.format('' if positional else 'environment-'), help_text= ('Google Cloud location of this environment ' 'https://cloud.google.com/compute/docs/regions-zones/#locations.' ), completer=completers.LocationCompleter, fallthroughs=[ deps.ArgFallthrough('--location'), deps.PropertyFallthrough( properties.VALUES.notebooks.location) ], )
def testInitializeWithRelativeName(self): """Tests Initialize when a fully specified name is given to the anchor. """ fallthroughs_map = { 'book': [deps.ArgFallthrough('--book')], 'shelf': [deps.ArgFallthrough('--book-shelf')], 'project': [deps.PropertyFallthrough(properties.VALUES.core.project)] } parsed_args = self._GetMockNamespace( book='projects/exampleproject/shelves/exampleshelf/books/example', book_shelf='anothershelf', book_project=None) resource_spec = concepts.ResourceSpec('example.projects.shelves.books', resource_name='book', **self._MakeAttributeConfigs()) registry_resource = resource_spec.Initialize(fallthroughs_map, parsed_args=parsed_args) self.assertEqual( 'projects/exampleproject/shelves/exampleshelf/books/example', registry_resource.RelativeName())
def BuildFullFallthroughsMap(self): """Builds map of all fallthroughs including arg names. Fallthroughs are a list of objects that, when called, try different ways of getting values for attributes (see googlecloudsdk.calliope.concepts.deps. _Fallthrough). This method builds a map from the name of each attribute to its fallthroughs, including the "primary" fallthrough representing its corresponding argument value in parsed_args if any, and any fallthroughs that were configured for the attribute beyond that. Returns: {str: [deps_lib._Fallthrough]}, a map from attribute name to its fallthroughs. """ fallthroughs_map = {} for attribute in self.concept_spec.attributes: # The only args that should be lists are anchor args for plural # resources. attribute_name = attribute.name attribute_fallthroughs = [] plural = (attribute_name == self.concept_spec.anchor.name and self.plural) # Start the fallthroughs list with the primary associated arg for the # attribute. arg_name = self.attribute_to_args_map.get(attribute_name) if arg_name: attribute_fallthroughs.append( deps_lib.ArgFallthrough(arg_name, plural=plural)) given_fallthroughs = self.fallthroughs_map.get(attribute_name, []) for fallthrough in given_fallthroughs: final_fallthrough = copy.deepcopy(fallthrough) final_fallthrough.plural = plural attribute_fallthroughs.append(final_fallthrough) fallthroughs_map[attribute_name] = attribute_fallthroughs anchor_fallthroughs = fallthroughs_map[self.concept_spec.anchor.name] for attribute in self.concept_spec.attributes[:-1]: parameter_name = self.concept_spec.ParamName(attribute.name) anchor_based_fallthroughs = [ deps_lib.FullySpecifiedAnchorFallthrough( anchor_fallthrough, self.concept_spec.collection_info, parameter_name) for anchor_fallthrough in anchor_fallthroughs ] fallthroughs_map[attribute.name] = ( anchor_based_fallthroughs + fallthroughs_map[attribute.name]) return fallthroughs_map