def testSingleScope_WithRegionGce(self): resource_name = 'forwarding rule' underspecified_names = ['salmon', 'herring'] scopes = [compute_scope.ScopeEnum.REGION] default_scope = None properties.VALUES.core.check_gce_metadata.Set(True) if c_gce.Metadata().connected: region = c_gce.Metadata().Region() else: region = 'north-sea' self.StartObjectPatch(c_gce._GCEMetadata, 'Region', return_value=region) self.WriteInput('Y') result = scope_prompter.PromptForScope(resource_name, underspecified_names, scopes, default_scope, scope_lister=None) self.AssertErrContains( 'Did you mean region [{0}] for forwarding rule: [salmon, herring]'. format(region)) self.assertEqual((compute_scope.ScopeEnum.REGION, region), result)
def GetComputeResources(release_track, cluster_name): """Returns a resources object with resolved GCE zone and region.""" holder = compute_base.ComputeApiHolder(release_track) region_prop = properties.VALUES.compute.region zone_prop = properties.VALUES.compute.zone resources = holder.resources # Prompt for scope if necessary zone = properties.VALUES.compute.zone.Get() if not zone: _, zone = scope_prompter.PromptForScope( resource_name='cluster', underspecified_names=[cluster_name], scopes=[compute_scope.ScopeEnum.ZONE], default_scope=None, scope_lister=flags.GetDefaultScopeLister(holder.client)) if not zone: # Still no zone, just raise error generated by this property. zone = properties.VALUES.compute.zone.GetOrFail() zone_ref = resources.Parse(zone, params={ 'project': properties.VALUES.core.project.GetOrFail, }, collection='compute.zones') zone_name = zone_ref.Name() zone_prop.Set(zone_name) region_name = compute_utils.ZoneNameToRegionName(zone_name) region_prop.Set(region_name) return resources
def testSingleScope(self): resource_name = 'forwarding rule' underspecified_names = ['salmon', 'herring'] scopes = [compute_scope.ScopeEnum.REGION] default_scope = None resource = collections.namedtuple('Resource', ['name']) def ScopeLister(scopes, unused_underspecified_names): self.assertEqual([compute_scope.ScopeEnum.REGION], scopes) return { compute_scope.ScopeEnum.REGION: [resource(name='north-sea'), resource(name='baltic')] } self.WriteInput('1') result = scope_prompter.PromptForScope(resource_name, underspecified_names, scopes, default_scope, scope_lister=ScopeLister) self.AssertErrEquals( r'{"ux": "PROMPT_CHOICE", "message": "For the following forwarding ' r'rules:\n - [herring]\n - [salmon]\nchoose a region:", "choices": ' '["baltic", "north-sea"]}\n') self.assertEqual((compute_scope.ScopeEnum.REGION, 'baltic'), result)
def testSingleScope_WithZoneGce(self): resource_name = 'forwarding rule' underspecified_names = ['salmon', 'herring'] scopes = [compute_scope.ScopeEnum.ZONE] default_scope = None properties.VALUES.core.check_gce_metadata.Set(True) if c_gce.Metadata().connected: zone = c_gce.Metadata().Zone() else: zone = 'skagerrak' self.StartObjectPatch(c_gce._GCEMetadata, 'Zone', return_value=zone) self.WriteInput('Y') result = scope_prompter.PromptForScope(resource_name, underspecified_names, scopes, default_scope, scope_lister=None) self.AssertErrContains( 'Did you mean zone [{0}] for forwarding rule: [salmon, herring]'. format(zone)) self.assertEqual((compute_scope.ScopeEnum.ZONE, zone), result)
def _ResolveUnderspecifiedNames(self, underspecified_names, default_scope, scope_lister, project, api_resource_registry, with_project=True): """Attempt to resolve scope for unresolved names. If unresolved_names was generated with _GetRefsAndUnderspecifiedNames changing them will change corresponding elements of refs list. Args: underspecified_names: list of one-items lists containing str default_scope: default scope for the resources scope_lister: callback used to list potential scopes for the resources project: str, id of the project api_resource_registry: resources Registry with_project: indicates whether or not project is associated. It should be False for flexible resource APIs Raises: UnderSpecifiedResourceError: when resource scope can't be resolved. """ if not underspecified_names: return names = [n[0] for n in underspecified_names] if not console_io.CanPrompt(): raise UnderSpecifiedResourceError(names, [s.flag for s in self.scopes]) resource_scope_enum, scope_value = scope_prompter.PromptForScope( self.resource_name, names, [s.scope_enum for s in self.scopes], default_scope.scope_enum if default_scope is not None else None, scope_lister) if resource_scope_enum is None: raise UnderSpecifiedResourceError(names, [s.flag for s in self.scopes]) resource_scope = self.scopes[resource_scope_enum] if with_project: params = { 'project': project, } else: params = {} if resource_scope.scope_enum != compute_scope.ScopeEnum.GLOBAL: params[resource_scope.scope_enum.param_name] = scope_value for name in underspecified_names: name[0] = api_resource_registry.Parse( name[0], params=params, collection=resource_scope.collection, enforce_collection=True)
def _GetZoneRef(self, cluster_name): """Get GCE zone resource prompting if necessary.""" zone = properties.VALUES.compute.zone.Get() if not zone: _, zone = scope_prompter.PromptForScope( resource_name='cluster', underspecified_names=[cluster_name], scopes=[compute_scope.ScopeEnum.ZONE], default_scope=None, scope_lister=flags.GetDefaultScopeLister( self._compute_client, self.project)) if not zone: # Still no zone, just raise error generated by this property. zone = properties.VALUES.compute.zone.Get(required=True) return self.resources.Parse(zone, collection='compute.zones')
def GetComputeResources(release_track, cluster_name, cluster_region=None): """Returns a resources object with resolved GCE zone and region.""" holder = compute_base.ComputeApiHolder(release_track) region_prop = properties.VALUES.compute.region zone_prop = properties.VALUES.compute.zone resources = holder.resources # Prompt for scope if necessary. If Dataproc regional stack is used, omitting # the zone allows the server to pick a zone zone = properties.VALUES.compute.zone.Get() if cluster_region: dataproc_region = cluster_region else: dataproc_region = properties.VALUES.dataproc.region.GetOrFail() if not zone and dataproc_region == 'global': _, zone = scope_prompter.PromptForScope( resource_name='cluster', underspecified_names=[cluster_name], scopes=[compute_scope.ScopeEnum.ZONE], default_scope=None, scope_lister=flags.GetDefaultScopeLister(holder.client)) if not zone: # Still no zone, just raise error generated by this property. zone = properties.VALUES.compute.zone.GetOrFail() if zone: zone_ref = resources.Parse( zone, params={ 'project': properties.VALUES.core.project.GetOrFail, }, collection='compute.zones') zone_name = zone_ref.Name() zone_prop.Set(zone_name) region_name = compute_utils.ZoneNameToRegionName(zone_name) region_prop.Set(region_name) else: # Auto zone zone_prop.Set('') # Set GCE region to dataproc region (which is a 1:1 mapping) region_prop.Set(dataproc_region) return resources
def testSingleScope_WithNoGceResolution(self): resource_name = 'forwarding rule' underspecified_names = ['salmon', 'herring'] scopes = [compute_scope.ScopeEnum.ZONE] default_scope = None zone = 'skagerrak' resource = collections.namedtuple('Resource', ['name']) def ScopeLister(unused_scopes, unused_underspecified_names): return {compute_scope.ScopeEnum.ZONE: [resource(name=zone)]} result = scope_prompter.PromptForScope(resource_name, underspecified_names, scopes, default_scope, scope_lister=ScopeLister) self.AssertErrEquals("""\ No zone specified. Using zone [{0}] \ for forwarding rules: [salmon, herring]. """.format(zone), normalize_space=True) self.assertEqual((compute_scope.ScopeEnum.ZONE, zone), result)
def testMultiScope(self): resource_name = 'forwarding rule' underspecified_names = ['salmon', 'herring'] scopes = [ compute_scope.ScopeEnum.GLOBAL, compute_scope.ScopeEnum.REGION ] default_scope = None resource = collections.namedtuple('Resource', ['name']) def ScopeLister(scopes, unused_underspecified_names): self.assertEqual( { compute_scope.ScopeEnum.REGION, compute_scope.ScopeEnum.GLOBAL }, set(scopes)) return { compute_scope.ScopeEnum.REGION: [resource(name='atlantic'), resource(name='indian')], compute_scope.ScopeEnum.GLOBAL: [resource(name='')] } self.WriteInput('1') result = scope_prompter.PromptForScope(resource_name, underspecified_names, scopes, default_scope, scope_lister=ScopeLister) self.AssertErrEquals( r'{"ux": "PROMPT_CHOICE", "message": "For the following forwarding ' r'rules:\n - [herring]\n - [salmon]\nchoose a region or global:", ' '"choices": ["global", "region: atlantic", "region: indian"]}\n') self.assertEqual((compute_scope.ScopeEnum.GLOBAL, ''), result)
def Run(self, args): datafusion = df.Datafusion() instance_ref = args.CONCEPTS.instance.Parse() # Prompt for zone if it is not specified zone = args.zone if not zone: holder = compute_base.ComputeApiHolder(self.ReleaseTrack()) _, zone = scope_prompter.PromptForScope( resource_name='instance', underspecified_names=[instance_ref.Name()], scopes=[compute_scope.ScopeEnum.ZONE], default_scope=None, scope_lister=flags.GetDefaultScopeLister(holder.client)) options = args.options if not options: options = {} labels = args.labels if not labels: labels = {} enable_stackdriver_logging = args.enable_stackdriver_logging if not enable_stackdriver_logging: enable_stackdriver_logging = False enable_stackdriver_monitoring = args.enable_stackdriver_monitoring if not enable_stackdriver_monitoring: enable_stackdriver_monitoring = False edition = args.edition.upper() if edition == 'ENTERPRISE': edition = datafusion.messages.Instance.TypeValueValuesEnum.ENTERPRISE else: edition = datafusion.messages.Instance.TypeValueValuesEnum.BASIC instance = datafusion.messages.Instance( zone=zone, type=edition, enableStackdriverLogging=enable_stackdriver_logging, enableStackdriverMonitoring=enable_stackdriver_monitoring, options=encoding.DictToAdditionalPropertyMessage( options, datafusion.messages.Instance.OptionsValue, True), labels=encoding.DictToAdditionalPropertyMessage( labels, datafusion.messages.Instance.LabelsValue, True)) req = datafusion.messages.DatafusionProjectsLocationsInstancesCreateRequest( instance=instance, instanceId=instance_ref.Name(), parent=instance_ref.Parent().RelativeName()) operation = datafusion.client.projects_locations_instances.Create(req) if args.async: log.CreatedResource( instance_ref.RelativeName(), kind='instance', is_async=True) return operation else: waiter.WaitFor( operation_poller.OperationPoller(), operation.name, 'Waiting for [{}] to complete. This may take several minutes.'.format( operation.name), wait_ceiling_ms=df.OPERATION_TIMEOUT) log.CreatedResource( instance_ref.RelativeName(), kind='instance', is_async=False)
def ResolveResources(self, names, resource_scope, scope_value, api_resource_registry, default_scope=None, scope_lister=None): """Resolve this resource against the arguments. Args: names: list of str, list of resource names resource_scope: ScopeEnum, kind of scope of resources; if this is not None scope_value should be name of scope of type specified by this argument. If this is None scope_value should be None, in that case if prompting is possible user will be prompted to select scope (if prompting is forbidden it will raise an exception). scope_value: ScopeEnum, scope of resources; if this is not None resource_scope should be type of scope specified by this argument. If this is None resource_scope should be None, in that case if prompting is possible user will be prompted to select scope (if prompting is forbidden it will raise an exception). api_resource_registry: instance of core.resources.Registry. default_scope: ScopeEnum, ZONE, REGION, GLOBAL, or None when resolving name and scope was not specified use this as default. If there is exactly one possible scope it will be used, there is no need to specify default_scope. scope_lister: func(scope, underspecified_names), a callback which returns list of items (with 'name' attribute) for given scope. Returns: Resource reference or list of references if plural. Raises: BadArgumentException: when names is not a list or default_scope is not one of the configured scopes. UnderSpecifiedResourceError: if it was not possible to resolve given names as resources references. """ if not isinstance(names, list): raise BadArgumentException( 'Expected names to be a list but it is {0!r}'.format(names)) if resource_scope is not None: resource_scope = self.scopes[resource_scope] if default_scope is not None: if default_scope not in self.scopes: raise BadArgumentException( 'Unexpected value for default_scope {0}, expected None or {1}' .format( default_scope, ' or '.join([s.scope_enum.name for s in self.scopes]))) default_scope = self.scopes[default_scope] params = {} if scope_value is not None: if resource_scope.scope_enum == compute_scope.ScopeEnum.GLOBAL: stored_value = scope_value else: collection = compute_scope.ScopeEnum.CollectionForScope( resource_scope.scope_enum) stored_value = api_resource_registry.Parse( scope_value, collection=collection).Name() params[resource_scope.scope_enum.param_name] = stored_value else: resource_scope = self.scopes.GetImplicitScope(default_scope) collection = resource_scope and resource_scope.collection # See if we can resolve names with so far deduced scope and its value. refs = [] underspecified_names = [] for name in names: try: # Make each element an array so that we can do in place updates. ref = [ api_resource_registry.Parse(name, params=params, collection=collection, enforce_collection=False) ] except (resources.UnknownCollectionException, resources.UnknownFieldException, properties.RequiredPropertyError): if scope_value: raise ref = [name] underspecified_names.append(ref) refs.append(ref) # If we still have some resources which need to be resolve see if we can # prompt the user and try to resolve these again. if underspecified_names: names = [n[0] for n in underspecified_names] if not console_io.CanPrompt(): raise UnderSpecifiedResourceError( names, [s.flag for s in self.scopes]) resource_scope_enum, scope_value = scope_prompter.PromptForScope( self.resource_name, names, [s.scope_enum for s in self.scopes], default_scope.scope_enum if default_scope is not None else None, scope_lister) if resource_scope_enum is None: raise UnderSpecifiedResourceError( names, [s.flag for s in self.scopes]) resource_scope = self.scopes[resource_scope_enum] for name in underspecified_names: name[0] = api_resource_registry.Parse( name[0], params={resource_scope.scope_enum.param_name: scope_value}, collection=resource_scope.collection, enforce_collection=True) # Now unpack each element. refs = [ref[0] for ref in refs] # Make sure correct collection was given for each resource, for example # URLs have implicit collections. expected_collections = [scope.collection for scope in self.scopes] for ref in refs: if ref.Collection() not in expected_collections: raise resources.WrongResourceCollectionException( expected=','.join(expected_collections), got=ref.Collection(), path=ref.SelfLink()) return refs