def ValidateInstanceID(value, param_name): """Performs syntax check on an instance ID; doesn't check whether it exists. Args: value: str, the instance ID to check param_name: str, the parameter's name; included in the exception's message Raises: exceptions.Error: if value is an invalid instance ID """ if not value: raise exceptions.Error('Missing required parameter ' + param_name) if re.match(r'^\d+$', value): return raise exceptions.Error( 'Invalid value `{value}` for parameter {param_name}. ' 'For details on valid instance IDs, refer to the criteria ' 'documented under the field `id` at: {url}'.format( value=value, param_name=param_name, url='https://cloud.google.com/compute/docs/reference/rest/v1/instances' ))
def _RetrieveWorkloadServiceAccount(workload_manifest): """Retrieve the service account used for the workload.""" if not workload_manifest: raise WorkloadError('Cannot verify an empty workload from the cluster') try: workload_data = yaml.load(workload_manifest) except yaml.Error as e: raise exceptions.Error( 'Invalid workload from the cluster {}'.format(workload_manifest), e) service_account = _GetNestedKeyFromManifest(workload_data, 'spec', 'template', 'serviceAccount') return service_account
def GetMembershipOwnerID(self): """Looks up the owner id field in the Membership resource.""" if not self.MembershipCRDExists(): return None out, err = self._RunKubectl([ 'get', 'membership', 'membership', '-o', 'jsonpath={.spec.owner.id}' ], None) if err: if 'NotFound' in err: return None raise exceptions.Error( 'Error retrieving membership id: {}'.format(err)) return out
def ValidateUpdateMask(args, complex_type_dict): """Validate the update mask in update complex type requests.""" update_masks = list(args.update_mask.split(',')) for mask in update_masks: # walk the path in the dictionary to ensure it's correct mask_path = mask.split('.') mask_path_index = 0 complex_type_walker = complex_type_dict while mask_path_index < len(mask_path): if mask_path[mask_path_index] not in complex_type_walker: raise exceptions.Error( 'unrecognized field in update_mask: {0}.'.format(mask)) complex_type_walker = complex_type_walker[ mask_path[mask_path_index]] mask_path_index += 1
def _get_feature(self, project): """Fetch the Config Management Feature. Args: project: project id Returns: configManagementFeature """ try: name = 'projects/{0}/locations/global/features/{1}'.format( project, self.FEATURE_NAME) response = base.GetFeature(name) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to see the status of {} ' 'Feature from project [{}]. Underlying error: {}'.format( self.FEATURE_DISPLAY_NAME, project, e)) except apitools_exceptions.HttpNotFoundError as e: raise exceptions.Error( '{} Feature for project [{}] is not enabled'.format( self.FEATURE_DISPLAY_NAME, project)) return response
def IdentityProviderCRExists(self): """Verifies if the google Identity Provider CR exists.""" if not self._IdentityProviderCRDExists(): return None _, err = self._RunKubectl( ['get', 'identityproviders.security.cloud.google.com', 'google'], None) if err: if 'NotFound' in err: return False raise exceptions.Error( 'Error retrieving the google Identity Provider CR: {}'.format( err)) return True
def Update(self): """Updates this operation with the latest state of the agent pod.""" out, err = self.kube_client.GetPodField(self.namespace, self.agent_pod_name, '.status.phase') if err: self.done = True self.succeeded = False self.error = err return # The .status.phase field contains one of five values. They map to the # staus of this operation as follows: # - "Pending": operation is ongoing # - "Running": operation is ongoing # - "Succeeded": operation is complete, successfully # - "Failed": operation is complete, unsuccessfully # - "Unknown": operation is complete, unsuccessfully # The JSONPath expression above prints the value of the .status.phase field # (i.e., one of these five strings) to stdout if out == 'Pending' or out == 'Running': return self.done = True if out == 'Failed': self.succeeded = False # TODO(b/130295119): Is there a way to get a failure message? self.error = exceptions.Error('Connect agent pod failed.') return if out == 'Unknown': self.succeeded = False self.error = exceptions.Error( 'Connect agent pod in an unknown state.') return self.succeeded = True
def _WriteTempFile(data): """Write a new temporary file and register for cleanup at program exit. Args: data: data to write to the file Returns: string: the path to the new temporary file Raises: Error: if the write failed """ try: _, f = tempfile.mkstemp() except Exception as e: # pylint: disable=broad-except raise exceptions.Error('failed to create temp file: {}'.format(e)) try: files.WriteFileContents(f, data, private=True) atexit.register(lambda: os.remove(f)) return f except Exception as e: # pylint: disable=broad-except os.remove(f) raise exceptions.Error('failed to write temp file {}: {}'.format(f, e))
def _ClusterRequest(self, method, url, headers=None): """Internal method to make requests against the target cluster. Args: method: request method, e.g. GET url: request URL headers: dictionary of request headers Returns: Response body as a string. Raises: Error: If the response has a status code >= 400. """ r = self.cluster_pool_manager.request(method, url, headers=headers) if not r: raise exceptions.Error('null response') elif r.status >= 400: raise exceptions.Error( 'status: {}, reason: {}'.format(r.status, r.reason)) elif not hasattr(r, 'data'): raise exceptions.Error('missing response data: {}'.format(r)) return r.data.decode('utf-8')
def Run(self, args): memberships = base.ListMemberships() if not memberships: raise exceptions.Error('No Memberships available in the fleet.') # User should choose an existing membership if not provide one if not args.membership: index = console_io.PromptChoice( options=memberships, message='Please specify a membership to ' 'unmanage in configmanagement:\n') membership = memberships[index] else: membership = args.membership if membership not in memberships: raise exceptions.Error( 'Membership {} is not in the fleet.'.format(membership)) # Setup a patch to set the MembershipSpec to the empty proto ("delete"). membership_key = self.MembershipResourceName(membership) specs = {membership_key: self.messages.MembershipFeatureSpec()} patch = self.messages.Feature( membershipSpecs=self.hubclient.ToMembershipSpecs(specs)) self.Update(['membership_specs'], patch)
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Returns: Some value that we want to have printed later. """ repository_arg = args.repository if not repository_arg: repository_arg = 'gcr.io/{0}'.format( properties.VALUES.core.project.Get(required=True)) # Throws if invalid. repository = util.ValidateRepositoryPath(repository_arg) def _DisplayName(c): """Display the fully-qualified name.""" return '{0}/{1}'.format(repository, c) http_obj = http.Http() with docker_image.FromRegistry(basic_creds=util.CredentialProvider(), name=repository, transport=http_obj) as r: try: images = [{'name': _DisplayName(c)} for c in r.children()] return images except docker_http.V2DiagnosticException as err: if err.http_status_code == 403: raise exceptions.Error('Access denied: {0}'.format(repository)) elif err.http_status_code == 404: raise exceptions.Error('Not found: {0}'.format(repository)) else: raise
def CreateWorkloadIdentityBucket(project, issuer_url, openid_config_json, openid_keyset_json): """Creates a storage bucket to serve the issuer's discovery information. Creates a bucket named after the first path segment of issuer_url, configures it as a public bucket, and uploads the provided OpenID Provider Configuration and JSON Web Key Set to the bucket. Args: project: The same project as this cluster's Hub membership. issuer_url: The issuer URL that uniquely identifies a cluster as an OpenID Provider. openid_config_json: The JSON OpenID Provider Configuration response from the cluster's built-in OIDC discovery endpoint. openid_keyset_json: The OpenID Provider JSON Web Key Set response from the cluster's built-in JWKS endpoint. Raises: exceptions.Error: If it fails to create, configure, and populate the bucket. """ try: issuer_name = _ParseBucketIssuerURL(issuer_url) storage_client = _StorageClient() _CreateBucketIfNotExists(storage_client, issuer_name, project) _SetPublicBucket(storage_client, issuer_name) # Do NOT add leading slash, doing so nests the bucket path inside a subdir # named "". config_name = '.well-known/openid-configuration' keyset_name = 'openid/v1/jwks' # TODO(b/151111297): This is the hardcoded Cache-Control value in K8s # clusters, but if the bucket approach makes it to beta (which it should # not, it's a temporary solution until Google can serve the keys), we should # read it out of the header from the cluster's response. cache_control = 'public, max-age=3600' config_content_type = 'application/json' keyset_content_type = 'application/jwk-set+json' _UploadToBucket(storage_client, issuer_name, config_name, openid_config_json, config_content_type, cache_control) _UploadToBucket(storage_client, issuer_name, keyset_name, openid_keyset_json, keyset_content_type, cache_control) except Exception as e: raise exceptions.Error('Failed to configure bucket for ' 'Workload Identity: {}'.format(e))
def testDeleteWIMembershipContextManageBucketDeleteException(self): self.mock_kubernetes_client.GetNamespaceUID.return_value = 'fake-uid' self.mock_kubernetes_client.DeleteNamespace.return_value = None self.mock_kubernetes_client.CheckClusterAdminPermissions.return_value = True self.mock_kubernetes_client.NamespacesWithLabelSelector.return_value = [ 'gke-connect-12321' ] self.StartObjectPatch(kube_util, 'IsGKECluster', return_value=False) mock_delete_membership = self.StartObjectPatch(api_util, 'DeleteMembership') mock_delete_membership_resource = self.StartObjectPatch( exclusivity_util, 'DeleteMembershipResources') mock_delete_connect_namespace = self.StartObjectPatch( agent_util, 'DeleteConnectNamespace') self.StartObjectPatch(p_util, 'GetProjectNumber', return_value=12321) self.StartObjectPatch(exclusivity_util, 'GetMembershipCROwnerID', return_value=None) self.mock_kubernetes_client.GetOpenIDConfiguration.return_value = json.dumps( {'issuer': TEST_BUCKET_ISSUER_URL}) mock_delete_bucket = self.StartObjectPatch( api_util, 'DeleteWorkloadIdentityBucket') mock_delete_bucket.side_effect = exceptions.Error('Oops!') mock_get_membership = self.StartObjectPatch(api_util, 'GetMembership') membership = self._MakeMembership(description='my-cluster', external_id='fake-uid') mock_get_membership.return_value = membership self.mockValidateExclusivitySucceed() # Test that the command works and only bucket deletion is skipped. self.RunCommand([ 'my-cluster', '--kubeconfig=' + self.kubeconfig, '--context=test-context', '--project=fake-project', '--manage-workload-identity-bucket', ]) self.mock_kubernetes_client.GetOpenIDConfiguration.assert_called_once_with( ) mock_delete_bucket.assert_called_with(TEST_BUCKET_ISSUER_URL) mock_delete_connect_namespace.assert_called_once() mock_delete_membership.assert_called_with( 'projects/fake-project/locations/global/memberships/my-cluster', self.track) mock_delete_membership_resource.assert_called_once()
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Returns: Some value that we want to have printed later. """ wp_region = args.region release_track = self.ReleaseTrack() client = cloudbuild_util.GetClientInstance(release_track) messages = cloudbuild_util.GetMessagesModule(release_track) parent = properties.VALUES.core.project.Get(required=True) wp_name = args.WORKER_POOL # Get the workerpool ref wp_resource = resources.REGISTRY.Parse( None, collection='cloudbuild.projects.locations.workerPools', api_version=cloudbuild_util.RELEASE_TRACK_TO_API_VERSION[release_track], params={ 'projectsId': parent, 'locationsId': wp_region, 'workerPoolsId': wp_name, }) # Send the Get request wp = client.projects_locations_workerPools.Get( messages.CloudbuildProjectsLocationsWorkerPoolsGetRequest( name=wp_resource.RelativeName())) if release_track != base.ReleaseTrack.ALPHA: if wp.hybridPoolConfig is not None: raise exceptions.Error('NOT_FOUND: Requested entity was not found.') # Format the workerpool name for display try: wp.name = cloudbuild_util.WorkerPoolShortName(wp.name) except ValueError: pass # Must be an old version. return wp
def _Run(args, legacy_output=False, schema=None, message_encoding=None): """Creates one or more topics.""" client = topics.TopicsClient() labels = labels_util.ParseCreateArgs(args, client.messages.Topic.LabelsValue) kms_key = None kms_ref = args.CONCEPTS.kms_key.Parse() if kms_ref: kms_key = kms_ref.RelativeName() else: # Did user supply any topic-encryption-key flags? for keyword in [ 'topic-encryption-key', 'topic-encryption-key-project', 'topic-encryption-key-location', 'topic-encryption-key-keyring' ]: if args.IsSpecified(keyword.replace('-', '_')): raise core_exceptions.Error( '--topic-encryption-key was not fully specified.') message_storage_policy_allowed_regions = args.message_storage_policy_allowed_regions failed = [] for topic_ref in args.CONCEPTS.topic.Parse(): try: result = client.Create(topic_ref, labels=labels, kms_key=kms_key, message_storage_policy_allowed_regions= message_storage_policy_allowed_regions, schema=schema, message_encoding=message_encoding) except api_ex.HttpError as error: exc = exceptions.HttpException(error) log.CreatedResource(topic_ref.RelativeName(), kind='topic', failed=exc.payload.status_message) failed.append(topic_ref.topicsId) continue if legacy_output: result = util.TopicDisplayDict(result) log.CreatedResource(topic_ref.RelativeName(), kind='topic') yield result if failed: raise util.RequestsFailedError(failed, 'create')
def UpdateDockerCredentials(server): """Updates the docker config to have fresh credentials.""" # Loading credentials will ensure that we're logged in. # And prompt/abort to 'run gcloud auth login' otherwise. cred = c_store.Load() # Ensure our credential has a valid access token, # which has the full duration available. c_store.Refresh(cred) if not cred.access_token: raise exceptions.Error('No access token could be obtained ' 'from the current credentials.') # Update the docker configuration file passing the access token # as a password, and a benign value as the username. _UpdateDockerConfig(server, USERNAME, cred.access_token)
def Run(self, args): """Run 'services identity create'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: Nothing. """ project = properties.VALUES.core.project.Get(required=True) email, _ = serviceusage.GenerateServiceIdentity(project, args.service) if not email: raise exceptions.Error('Service identity not created successfully') else: log.status.Print('Service identity created: {0}'.format(email))
def _CreateBucketIfNotExists(storage_client, bucket_name, project): """Create a GCS bucket if it does not exist. The bucket will be created with a Uniform Bucket Level Access policy, so that access can be configured with IAM. Does not raise any exceptions if the bucket already exists. Note that ownership is not checked by this method (an existing bucket could belong to a malicious user, so callers should either check that the bucket is contained in the project, or ensure that the bucket name can't be guessed and claimed of time). Args: storage_client: v1 storage client bucket_name: string, the name of the bucket to create project: string, the project to create the bucket in Raises: Error: If unable to create the bucket, and the bucket does not already exist. """ m = storage_client.MESSAGES_MODULE # TODO(b/150317886): Bucket location default seems to be US (multiple region). # Unclear if this is based on request origin, gcloud settings, or just the # overall default. We might consider letting customers set a location, but # since we're also exploring having Gaia serve the keys, it's just as likely # we will move away from the GCS bucket approach before our beta. request = m.StorageBucketsInsertRequest(bucket=m.Bucket( iamConfiguration=m.Bucket.IamConfigurationValue( uniformBucketLevelAccess=m.Bucket.IamConfigurationValue. UniformBucketLevelAccessValue(enabled=True)), name=bucket_name), project=project) try: log.status.Print('Creating bucket {}'.format(bucket_name)) storage_client.buckets.Insert(request) log.status.Print('Successfully created bucket {}'.format(bucket_name)) except apitools_exceptions.HttpConflictError: # Bucket likely already exists, get the bucket to be sure. request = m.StorageBucketsGetRequest(bucket=bucket_name) storage_client.buckets.Get(request) log.status.Print('Bucket {} already exists. ' 'Skipping creation.'.format(bucket_name)) except Exception as e: raise exceptions.Error('Unable to create bucket {}: ' '{}'.format(bucket_name, e))
def Run(self, args): """Run the helper command.""" if args.method == DockerHelper.LIST: return { # This tells Docker that the secret will be an access token, not a # username/password. # Docker normally expects a prefixed 'https://' for auth configs. ('https://' + url): '_dcgcloud_token' for url in credential_utils.DefaultAuthenticatedRegistries() } elif args.method == DockerHelper.GET: # docker credential helper protocol expects that error is printed to # stdout. try: cred = c_store.Load(use_google_auth=True) except creds_exceptions.NoActiveAccountException: log.Print( 'You do not currently have an active account selected. ' 'See https://cloud.google.com/sdk/docs/authorizing for more ' 'information.') sys.exit(1) c_store.RefreshIfExpireWithinWindow(cred, window=TOKEN_MIN_LIFETIME) url = sys.stdin.read().strip() if (url.replace('https://', '', 1) not in credential_utils.SupportedRegistries()): raise exceptions.Error( 'Repository url [{url}] is not supported'.format(url=url)) # Putting an actual username in the response doesn't work. Docker will # then prompt for a password instead of using the access token. token = (cred.token if c_creds.IsGoogleAuthCredentials(cred) else cred.access_token) return { 'Secret': token, 'Username': '******', } # Don't print anything if we are not supporting the given action. # The credential helper protocol also support 'store' and 'erase' actions # that don't apply here. The full spec can be found here: # https://github.com/docker/docker-credential-helpers#development args.GetDisplayInfo().AddFormat('none') return None
def CleanUpRbacPolicy(self, membership, role, project_id, user, anthos_support): """Get the RBAC cluster role binding policy.""" # TODO(b/200192930): Remove the regex in next change. cluster_pattern = re.compile('^clusterrole/') namespace_pattern = re.compile('^role/') rbac_to_check = [('clusterrole', self.RbacPolicyName('impersonate', project_id, membership, user)), ('clusterrolebinding', self.RbacPolicyName('impersonate', project_id, membership, user))] # Check anthos-support permission policy when '--anthos-support' specified. if anthos_support: rbac_to_check.append(('clusterrolebinding', self.RbacPolicyName('anthos', project_id, membership, user))) # Check namespace permission policy when role is specified as # 'role/namespace/namespace-permission'. elif cluster_pattern.match(role.lower()): rbac_to_check.append(('clusterrolebinding', self.RbacPolicyName('permission', project_id, membership, user))) # Check RBAC permission policy for general clusterrole. elif namespace_pattern.match(role.lower()): rbac_to_check.append(('rolebinding', self.RbacPolicyName('permission', project_id, membership, user))) for rbac_policy_pair in rbac_to_check: rbac_type = rbac_policy_pair[0] rbac_name = rbac_policy_pair[1] out, err = self._RunKubectl(['delete', rbac_type, rbac_name], None) if err: if 'NotFound' in err: log.status.Print( '{} for RBAC policy: {} not exist.'.format( rbac_type, rbac_name)) continue else: raise exceptions.Error( 'Error deleting RBAC policy: {}'.format(err)) else: log.status.Print('{}'.format(out)) return True
def ParseYearlyPrice(api_version, price_string): """Parses money string as type Money.""" if not price_string: return None try: units, cents, currency = _ParseMoney(price_string) except ValueError: raise exceptions.Error( ('Yearly price \'{}\' is invalid. Please specify the amount followed ' 'by the currency code.').format(price_string)) if currency == '$': currency = 'USD' messages = registrations.GetMessagesModule(api_version) return messages.Money( units=int(units), nanos=cents * 10**7, currencyCode=currency)
def _GetSchedulerJobLocation(self): messages = apis.GetMessagesModule('cloudscheduler', 'v1') client = apis.GetClientInstance('cloudscheduler', 'v1') project = properties.VALUES.core.project.Get(required=True) try: locations_res = client.projects_locations.List( messages.CloudschedulerProjectsLocationsListRequest( name='projects/' + project)) except HttpNotFoundError: raise core_exceptions.Error( 'You must create an App Engine application in your project to use ' 'Cloud Scheduler. Visit ' 'https://console.developers.google.com/appengine?project={} to ' 'add an App Engine application.'.format(project)) return locations_res.locations[0].labels.additionalProperties[0].value
def ParseYearlyPrice(price_string): """Parses money string as type Money.""" if not price_string: return None try: units, cents, currency = _ParseMoney(price_string) except ValueError: raise exceptions.Error( 'Yearly price \'{}\' is not valid.'.format(price_string)) if currency == '$': currency = 'USD' messages = registrations.GetMessagesModule() return messages.Money(units=int(units), nanos=cents * 10**7, currencyCode=currency)
def Run(self, args): # pylint: disable=missing-docstring def Push(image, dest_name, creds, http_obj, src_name, session_push_type): with session_push_type(dest_name, creds, http_obj) as push: push.upload(image) log.CreatedResource(dest_name) log.UpdatedResource(src_name) http_obj = http.Http() src_name = util.GetDockerImageFromTagOrDigest(args.src_image) dest_name = docker_name.Tag(args.dest_image) if '/' not in dest_name.repository: raise exceptions.Error( 'Pushing to project root-level images is disabled. ' 'Please designate an image within a project, ' 'e.g. gcr.io/project-id/my-image:tag') console_io.PromptContinue('This will tag {0} with {1}'.format( src_name, dest_name), default=True, cancel_on_no=True) creds = util.CredentialProvider() with util.WrapExpectedDockerlessErrors(): with docker_image_list.FromRegistry(src_name, creds, http_obj) as manifest_list: if manifest_list.exists(): Push(manifest_list, dest_name, creds, http_obj, src_name, v2_2_session.Push) return with v2_2_image.FromRegistry(src_name, creds, http_obj, accepted_mimes=docker_http. SUPPORTED_MANIFEST_MIMES) as v2_2_img: if v2_2_img.exists(): Push(v2_2_img, dest_name, creds, http_obj, src_name, v2_2_session.Push) return with v2_image.FromRegistry(src_name, creds, http_obj) as v2_img: Push(v2_img, dest_name, creds, http_obj, src_name, v2_session.Push)
def Modify(self, client, args, existing_check): """Returns a modified HealthCheck message.""" # We do not support using 'update udp' with a health check of a # different protocol. if (existing_check.type != client.messages.HealthCheck.TypeValueValuesEnum.UDP): raise core_exceptions.Error( 'update udp subcommand applied to health check with protocol ' + existing_check.type.name) # Description and PortName are the only attributes that can be cleared by # passing in an empty string (but we don't want to set it to empty string). if args.description: description = args.description elif args.description is None: description = existing_check.description else: description = None if args.port_name: port_name = args.port_name elif args.port_name is None: port_name = existing_check.udpHealthCheck.portName else: port_name = None new_health_check = client.messages.HealthCheck( name=existing_check.name, description=description, type=client.messages.HealthCheck.TypeValueValuesEnum.UDP, udpHealthCheck=client.messages.UDPHealthCheck( request=args.request or existing_check.udpHealthCheck.request, response=args.response or existing_check.udpHealthCheck.response, port=args.port or existing_check.udpHealthCheck.port, portName=port_name), checkIntervalSec=(args.check_interval or existing_check.checkIntervalSec), timeoutSec=args.timeout or existing_check.timeoutSec, healthyThreshold=(args.healthy_threshold or existing_check.healthyThreshold), unhealthyThreshold=(args.unhealthy_threshold or existing_check.unhealthyThreshold), ) return new_health_check
def UpdateDockerCredentials(server, refresh=True): """Updates the docker config to have fresh credentials. This reads the current contents of Docker's keyring, and extends it with a fresh entry for the provided 'server', based on the active gcloud credential. If a credential exists for 'server' this replaces it. Args: server: The hostname of the registry for which we're freshening the credential. refresh: Whether to force a token refresh on the active credential. Raises: core.credentials.exceptions.Error: There was an error loading the credentials. """ if refresh: access_token = store.GetFreshAccessToken() else: access_token = store.GetAccessToken() if not access_token: raise exceptions.Error( 'No access token could be obtained from the current credentials.') if _CredentialStoreConfigured(): try: # Update the credentials stored by docker, passing the sentinel username # and access token. DockerLogin(server, _USERNAME, access_token) except client_lib.DockerError as e: # Only catch docker-not-found error if six.text_type(e) != client_lib.DOCKER_NOT_FOUND_ERROR: raise # Fall back to the previous manual .dockercfg manipulation # in order to support gcloud app's docker-binaryless use case. _UpdateDockerConfig(server, _USERNAME, access_token) log.warning( "'docker' was not discovered on the path. Credentials have been " 'stored, but are not guaranteed to work with the Docker client ' ' if an external credential store is configured.') else: _UpdateDockerConfig(server, _USERNAME, access_token)
def Fingerprint(path, params): """Check for a Ruby app. Args: path: (str) Application path. params: (fingerprinting.Params) Parameters passed through to the fingerprinters. Returns: (RubyConfigurator or None) Returns a configurator if the path contains a Ruby app, or None if not. """ appinfo = params.appinfo entrypoint = None is_explicit_runtime = False if appinfo: if appinfo.GetEffectiveRuntime() != 'ruby': return None is_explicit_runtime = True if appinfo.entrypoint: entrypoint = appinfo.entrypoint log.info('Checking for Ruby.') gemfile_path = os.path.join(path, 'Gemfile') if not os.path.isfile(gemfile_path): if is_explicit_runtime: raise exceptions.Error('Gemfile required for Ruby runtime') else: return None _CheckFiles(path) gems = _DetectGems() ruby_version = _DetectRubyInterpreter(path) packages = _DetectNeededPackages(gems) if not entrypoint: default_entrypoint = _DetectDefaultEntrypoint(path, gems) entrypoint = _ChooseEntrypoint(default_entrypoint, appinfo) if not entrypoint: return None return RubyConfigurator(path, params, ruby_version, entrypoint, packages)
def GetRbacPolicy(self, membership, role, project_id, user, anthos_support): """Get the RBAC cluster role binding policy.""" not_found = False # TODO(b/200192930): Remove the regex in next change. cluster_pattern = re.compile('^clusterrole/') namespace_pattern = re.compile('^role/') rbac_to_check = [('clusterrole', self.RbacPolicyName('impersonate', project_id, membership, user)), ('clusterrolebinding', self.RbacPolicyName('impersonate', project_id, membership, user))] # Check anthos-support permission policy when '--anthos-support' specified. if anthos_support: rbac_to_check.append(('clusterrolebinding', self.RbacPolicyName('anthos', project_id, membership, user))) # Check namespace permission policy when role is specified as # 'role/namespace/namespace-permission'. elif cluster_pattern.match(role.lower()): rbac_to_check.append(('clusterrolebinding', self.RbacPolicyName('permission', project_id, membership, user))) # Check RBAC permission policy for general clusterrole. elif namespace_pattern.match(role.lower()): rbac_to_check.append(('rolebinding', self.RbacPolicyName('permission', project_id, membership, user))) for rbac_policy_pair in rbac_to_check: rbac_type = rbac_policy_pair[0] rbac_name = rbac_policy_pair[1] _, err = self._RunKubectl(['get', rbac_type, rbac_name]) if err: if 'NotFound' in err: not_found = True else: raise exceptions.Error( 'Error retrieving RBAC policy: {}'.format(err)) else: return False if not_found: return True
def _UploadToBucket(storage_client, bucket_name, obj_name, str_data, content_type, cache_control): """Uploads an object to a storage bucket. Args: storage_client: v1 storage client bucket_name: string, name of the bucket to upload the object to obj_name: string, name the object should be uploaded as (path in bucket) str_data: string, the string that comprises the object data to upload content_type: string, the Content-Type header the bucket will serve for the uploaded object. cache_control: string, the Cache-Control header the bucket will serve for the uploaded object. Raises: Error: If unable to upload the object to the bucket. """ m = storage_client.MESSAGES_MODULE stream = six.StringIO(str_data) upload = transfer.Upload.FromStream( stream, mime_type=content_type, # Use apitools default (1048576 B). # GCS requires a multiple of 256 KiB. chunksize=None) request = m.StorageObjectsInsertRequest(bucket=bucket_name, name=obj_name, object=m.Object( contentType=content_type, cacheControl=cache_control)) try: log.status.Print('Uploading object {} to bucket {}'.format( obj_name, bucket_name)) # Uploading again just overwrites the object, so we don't have to worry # about conflicts with pre-existing objects. storage_client.objects.Insert(request, upload=upload) log.status.Print('Successfully uploaded object {} to bucket {}'.format( obj_name, bucket_name)) except Exception as e: raise exceptions.Error('Unable to upload object to bucket {} at {}: ' '{}'.format(bucket_name, obj_name, e)) finally: # apitools doesn't automatically close the stream. upload.stream.close()
def Run(self, args): project = properties.VALUES.core.project.GetOrFail() if not args.config_membership: memberships = base.ListMemberships(project) if not memberships: raise exceptions.Error('No Memberships available in Hub.') index = console_io.PromptChoice( options=memberships, message='Please specify a config membership:\n') config_membership = memberships[index] else: config_membership = args.config_membership config_membership = ('projects/{0}/locations/global/memberships/{1}' .format(project, os.path.basename(config_membership))) self.RunCommand(args, multiclusteringressFeatureSpec=( base.CreateMultiClusterIngressFeatureSpec( config_membership)))