def PromptToEnableApi(project, service_token, exception, is_batch_request=False): """Prompts to enable the API and throws if the answer is no. Args: project (str): The project that the API is not enabled on. service_token (str): The service token of the API to prompt for. exception (api_Exceptions.HttpException): Exception to throw if the prompt is denied. is_batch_request: If the request is a batch request. This determines how to get apitools to retry the request. Raises: api_exceptions.HttpException: API not enabled error if the user chooses to not enable the API. """ if console_io.PromptContinue( default=False, prompt_string=('API [{}] not enabled on project [{}]. ' 'Would you like to enable and retry (this will take a ' 'few minutes)?') .format(service_token, project)): enable_api.EnableServiceIfDisabled(project, service_token) # In the case of a batch request, as long as the error's retryable code # (in this case 403) was set, after this runs it should retry. This # error code should be consistent with apis.GetApiEnablementInfo if not is_batch_request: raise apitools_exceptions.RequestError('Retry') else: raise exception
def Enable(self, feature): project = properties.VALUES.core.project.GetOrFail() enable_api.EnableServiceIfDisabled(project, self.feature.api) parent = util.LocationResourceName(project) try: # Retry if we still get "API not activated"; it can take a few minutes # for Chemist to catch up. See b/28800908. # TODO(b/177098463): Add a spinner here? retryer = retry.Retryer(max_retrials=4, exponential_sleep_multiplier=1.75) op = retryer.RetryOnException( self.hubclient.CreateFeature, args=(parent, self.feature_name, feature), should_retry_if=self._FeatureAPINotEnabled, sleep_ms=1000) except retry.MaxRetrialsException: raise exceptions.Error( 'Retry limit exceeded waiting for {} to enable'.format( self.feature.api)) except apitools_exceptions.HttpConflictError as e: # If the error is not due to the object already existing, re-raise. error = core_api_exceptions.HttpErrorPayload(e) if error.status_description != 'ALREADY_EXISTS': raise # TODO(b/177098463): Decide if this should be a hard error if a spec was # set, but not applied, because the Feature already existed. log.status.Print( '{} Feature for project [{}] is already enabled'.format( self.feature.display_name, project)) return msg = 'Waiting for Feature {} to be created'.format( self.feature.display_name) return self.WaitForHubOp(self.hubclient.feature_waiter, op=op, message=msg)
def Run(self, args): if not args.config_membership: memberships = base.ListMemberships() if not memberships: raise exceptions.Error('No Memberships available in the fleet.') index = console_io.PromptChoice( options=memberships, message='Please specify a config membership:\n') config_membership = memberships[index] else: # Strip to the final path component to allow short and long names. # Assumes long names are for the same project and global location. # TODO(b/192580393): Use the resource args instead of this hack. config_membership = os.path.basename(args.config_membership) config_membership = self.MembershipResourceName(config_membership) # MCI requires MCSD. Enablement of the fleet feature for MCSD is taken care # of by CLH but we need to enable the OP API before that happens. If not, # CLH will return an error asking for the API to be enabled. mcsd_api = info.Get('multiclusterservicediscovery').api enable_api.EnableServiceIfDisabled(self.Project(), mcsd_api) f = self.messages.Feature( spec=self.messages.CommonFeatureSpec( multiclusteringress=self.messages.MultiClusterIngressFeatureSpec( configMembership=config_membership))) result = self.Enable(f) # We only want to poll for usability if everything above succeeded. if result is not None: self.PollForUsability()
def testEnableServiceIfDisabled_AlreadyEnabled(self): """Test EnableServiceIfDisabled runs successfully if already enabled.""" service = self._NewServiceConfig(self.PROJECT_NAME, self.DEFAULT_SERVICE_NAME, enabled=True) self.ExpectGetService(service) enable_api.EnableServiceIfDisabled(self.PROJECT_NAME, self.DEFAULT_SERVICE_NAME)
def testEnableServiceIfDisabled_NotYetEnabled_Success(self): """Test EnableServiceifDisabled enables service if not yet enabled.""" service = self._NewServiceConfig(self.PROJECT_NAME, self.DEFAULT_SERVICE_NAME) self.ExpectGetService(service) self.ExpectEnableApiCall(self.OPERATION_NAME) self.ExpectOperation(self.OPERATION_NAME, 3) enable_api.EnableServiceIfDisabled(self.PROJECT_NAME, self.DEFAULT_SERVICE_NAME)
def testEnableServiceIfDisabled_NotYetEnabled_EventualFailure(self): """Test EnableServiceIfDisabled raises if operation fails.""" service = self._NewServiceConfig(self.PROJECT_NAME, self.DEFAULT_SERVICE_NAME) self.ExpectGetService(service) self.ExpectEnableApiCall(self.OPERATION_NAME) server_error = http_error.MakeDetailedHttpError(code=403, message='Error.') self.ExpectOperation(self.OPERATION_NAME, 0, error=server_error) with self.assertRaises(exceptions.OperationErrorException): enable_api.EnableServiceIfDisabled(self.PROJECT_NAME, self.DEFAULT_SERVICE_NAME)
def PossiblyEnableFlex(project): """Attempts to enable the Flexible Environment API on the project. Possible scenarios: -If Flexible Environment is already enabled, success. -If Flexible Environment API is not yet enabled, attempts to enable it. If that succeeds, success. -If the account doesn't have permissions to confirm that the Flexible Environment API is or isn't enabled on this project, succeeds with a warning. -If the account is a service account, adds an additional warning that the Service Management API may need to be enabled. -If the Flexible Environment API is not enabled on the project and the attempt to enable it fails, raises PrepareFailureError. Args: project: str, the project ID. Raises: PrepareFailureError: if enabling the API fails with a 403 or 404 error code. googlecloudsdk.api_lib.util.exceptions.HttpException: miscellaneous errors returned by server. """ try: enable_api.EnableServiceIfDisabled(project, 'appengineflex.googleapis.com') except s_exceptions.ListServicesPermissionDeniedException: # If we can't find out whether the Flexible API is enabled, proceed with # a warning. warning = FLEXIBLE_SERVICE_VERIFY_WARNING.format(project) # If user is using a service account, add more info about what might # have gone wrong. credential = c_store.LoadIfEnabled() if credential: account_type = creds.CredentialType.FromCredentials(credential) if account_type in (creds.CredentialType.SERVICE_ACCOUNT, creds.CredentialType.P12_SERVICE_ACCOUNT): warning += '\n\n{}'.format( FLEXIBLE_SERVICE_VERIFY_WITH_SERVICE_ACCOUNT) log.warning(warning) except s_exceptions.EnableServicePermissionDeniedException: # If enabling the Flexible API fails due to a permissions error, the # deployment fails. raise PrepareFailureError(PREPARE_FAILURE_MSG.format(project)) except apitools_exceptions.HttpError as err: # The deployment should also fail if there are unforeseen errors in # enabling the Flexible API. If so, display detailed information. raise api_lib_exceptions.HttpException( err, error_format=('Error [{status_code}] {status_message}' '{error.details?' '\nDetailed error information:\n{?}}'))
def RunCommand(self, args, **kwargs): try: project = properties.VALUES.core.project.GetOrFail() enable_api.EnableServiceIfDisabled(project, self.FEATURE_API) return CreateFeature(project, self.FEATURE_NAME, self.FEATURE_DISPLAY_NAME, **kwargs) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to enable {} Feature from project [{}]. ' 'Underlying error: {}'.format(self.FEATURE_DISPLAY_NAME, project, e)) except properties.RequiredPropertyError as e: raise exceptions.Error('Failed to retrieve the project ID.') except apitools_exceptions.HttpConflictError as e: # If the error is not due to the object already existing, re-raise. error = core_api_exceptions.HttpErrorPayload(e) if error.status_description != 'ALREADY_EXISTS': raise else: log.status.Print( '{} Feature for project [{}] is already enabled'.format( self.FEATURE_DISPLAY_NAME, project))
def Run(self, args): cloudbuild_api = info.Get('cloudbuild').api enable_api.EnableServiceIfDisabled(self.Project(), cloudbuild_api) self.Enable(self.messages.Feature())