def Args(parser, version=base.ReleaseTrack.GA): """Args is called by calliope to gather arguments for this command. Args: parser: An argparse parser that you can use to add arguments that go on the command line after this command. Positional arguments are allowed. version: The version this tool is running as. base.ReleaseTrack.GA is the default. """ flags.AddDeploymentNameFlag(parser) flags.AddPropertiesFlag(parser) flags.AddAsyncFlag(parser) parser.add_argument('--description', help='The new description of the deployment.', dest='description') group = parser.add_mutually_exclusive_group() group.add_argument( '--config', help='Filename of config that specifies resources to deploy. ' 'Required unless launching an already-previewed update to this ' 'deployment. More information is available at ' 'https://cloud.google.com/deployment-manager/docs/configuration/.', dest='config') if version in [base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA]: group.add_argument('--manifest-id', help='Manifest Id of a previous deployment. ' 'This flag cannot be used with --config.', dest='manifest_id') if version in [base.ReleaseTrack.ALPHA]: labels_util.AddUpdateLabelsFlags(parser) parser.add_argument( '--preview', help='Preview the requested update without making any changes to the' 'underlying resources. (default=False)', dest='preview', default=False, action='store_true') parser.add_argument( '--create-policy', help='Create policy for resources that have changed in the update.', default='CREATE_OR_ACQUIRE', choices=(sorted( dm_base.GetMessages().DeploymentmanagerDeploymentsUpdateRequest .CreatePolicyValueValuesEnum.to_dict().keys()))) flags.AddDeletePolicyFlag( parser, dm_base.GetMessages().DeploymentmanagerDeploymentsUpdateRequest) flags.AddFingerprintFlag(parser) parser.display_info.AddFormat(flags.RESOURCES_AND_OUTPUTS_FORMAT)
def Run(self, args): """Run 'deployments describe'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: The requested Deployment. Raises: HttpException: An http error response was received while executing api request. """ try: deployment = dm_base.GetClient().deployments.Get( dm_base.GetMessages().DeploymentmanagerDeploymentsGetRequest( project=dm_base.GetProject(), deployment=args.deployment_name)) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) try: response = dm_base.GetClient().resources.List( dm_base.GetMessages().DeploymentmanagerResourcesListRequest( project=dm_base.GetProject(), deployment=deployment.name)) resources = response.resources except apitools_exceptions.HttpError: # Couldn't get resources, skip adding them to the table. resources = None outputs = [] manifest = dm_v2_util.ExtractManifestName(deployment) if manifest: manifest_response = dm_base.GetClient().manifests.Get( dm_base.GetMessages().DeploymentmanagerManifestsGetRequest( project=dm_base.GetProject(), deployment=args.deployment_name, manifest=manifest, )) # We might be lacking a layout if the manifest failed expansion. if manifest_response.layout: outputs = dm_v2_util.FlattenLayoutOutputs( manifest_response.layout) return _Results(deployment, resources, outputs)
def _PerformRollback(self, deployment_name, error_message): # Print information about the failure. log.warn('There was an error deploying ' + deployment_name + ':\n' + error_message) log.status.Print('`--automatic-rollback-on-error` flag was supplied; ' 'deleting failed deployment...') # Delete the deployment. try: delete_operation = dm_base.GetClient().deployments.Delete( dm_base.GetMessages( ).DeploymentmanagerDeploymentsDeleteRequest( project=dm_base.GetProject(), deployment=deployment_name, )) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) # TODO(b/37481635): Use gcloud default operation polling. dm_write.WaitForOperation(delete_operation.name, 'delete', dm_base.GetProject(), timeout=OPERATION_TIMEOUT) completed_operation = dm_v2_util.GetOperation(delete_operation, dm_base.GetProject()) return completed_operation
def _SetMetadata(self, args, deployment): label_dict = labels_util.GetUpdateLabelsDictFromArgs(args) label_entry = [] if label_dict: label_entry = [ dm_base.GetMessages().DeploymentLabelEntry(key=k, value=v) for k, v in sorted(label_dict.iteritems()) ] deployment.labels = label_entry super(CreateALPHA, self)._SetMetadata(args, deployment)
def Args(parser): """Args is called by calliope to gather arguments for this command. Args: parser: An argparse parser that you can use to add arguments that go on the command line after this command. Positional arguments are allowed. """ parser.add_argument('deployment_name', nargs='+', help='Deployment name.') flags.AddDeletePolicyFlag( parser, dm_base.GetMessages().DeploymentmanagerDeploymentsDeleteRequest) flags.AddAsyncFlag(parser)
def WaitForOperation(operation_name, operation_description=None, project=None, timeout=180): """Wait for an operation to complete. Polls the operation requested approximately every second, showing a progress indicator. Returns when the operation has completed. Args: operation_name: The name of the operation to wait on, as returned by operations.list. operation_description: A short description of the operation to wait on, such as 'create' or 'delete'. Will be displayed to the user. project: The name of the project that this operation belongs to. timeout: Number of seconds to wait for. Defaults to 3 minutes. Raises: HttpException: A http error response was received while executing api request. Will be raised if the operation cannot be found. OperationError: The operation finished with error(s). Error: The operation the timeout without completing. """ tick_increment = 1 # every second(s) ticks = 0 message = ('Waiting for {0}[{1}]'.format( operation_description + ' ' if operation_description else '', operation_name)) request = dm_base.GetMessages().DeploymentmanagerOperationsGetRequest( project=project, operation=operation_name) with progress_tracker.ProgressTracker(message, autotick=False) as ticker: while ticks < timeout: operation = dm_base.GetClient().operations.Get(request) # Operation status is one of PENDING, RUNNING, DONE if operation.status == 'DONE': if operation.error: raise exceptions.OperationError( 'Error in Operation [{0}]: {1}'.format( operation_name, GetOperationError(operation.error))) else: # Operation succeeded return ticks += tick_increment ticker.Tick() time.sleep(tick_increment) # Timeout exceeded raise exceptions.Error( 'Wait for Operation [{0}] exceeded timeout [{1}].'.format( operation_name, str(timeout)))
def Run(self, args): """Run 'manifests describe'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: The requested manifest. Raises: HttpException: An http error response was received while executing api request. """ if not args.manifest: try: deployment = dm_base.GetClient().deployments.Get( dm_base.GetMessages( ).DeploymentmanagerDeploymentsGetRequest( project=dm_base.GetProject(), deployment=args.deployment)) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error) manifest = dm_v2_util.ExtractManifestName(deployment) if manifest: args.manifest = manifest try: return dm_base.GetClient().manifests.Get( dm_base.GetMessages().DeploymentmanagerManifestsGetRequest( project=dm_base.GetProject(), deployment=args.deployment, manifest=args.manifest, )) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT)
def Run(self, args): """Run 'types list'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: The list of types for this project. Raises: HttpException: An http error response was received while executing api request. """ request = dm_base.GetMessages().DeploymentmanagerTypesListRequest( project=dm_base.GetProject()) return dm_v2_util.YieldWithHttpExceptions( list_pager.YieldFromList(dm_base.GetClient().types, request, field='types', batch_size=args.page_size, limit=args.limit))
def GetOperation(operation, project): """Helper method gets an operation by name, or raises our custom error. Args: operation: The operation to get. project: The project in which to look for the operation. Returns: The specified operation with up-to-date fields. """ try: new_operation = dm_base.GetClient().operations.Get( dm_base.GetMessages().DeploymentmanagerOperationsGetRequest( project=project, operation=operation.name, )) return new_operation except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, HTTP_ERROR_FORMAT)
def Run(self, args): """Run 'resources describe'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: The requested resource. Raises: HttpException: An http error response was received while executing api request. """ try: return dm_base.GetClient().resources.Get( dm_base.GetMessages().DeploymentmanagerResourcesGetRequest( project=dm_base.GetProject(), deployment=args.deployment, resource=args.resource)) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT)
def Run(self, args): """Run 'deployments update'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns a struct containing the list of resources and list of outputs in the deployment. Raises: HttpException: An http error response was received while executing api request. """ deployment = dm_base.GetMessages().Deployment( name=args.deployment_name, ) if args.config: deployment.target = importer.BuildTargetConfig( dm_base.GetMessages(), args.config, args.properties) elif (self.ReleaseTrack() in [base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA] and args.manifest_id): deployment.target = importer.BuildTargetConfigFromManifest( dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name, args.manifest_id, args.properties) # Get the fingerprint from the deployment to update. try: current_deployment = dm_base.GetClient().deployments.Get( dm_base.GetMessages().DeploymentmanagerDeploymentsGetRequest( project=dm_base.GetProject(), deployment=args.deployment_name)) # Update the labels of the deployment if self.ReleaseTrack() in [base.ReleaseTrack.ALPHA]: update_labels = labels_util.GetUpdateLabelsDictFromArgs(args) remove_labels = labels_util.GetRemoveLabelsListFromArgs(args) current_labels = current_deployment.labels deployment.labels = dm_labels.UpdateLabels( current_labels, dm_base.GetMessages().DeploymentLabelEntry, update_labels, remove_labels) # If no config or manifest_id are specified, but try to update labels, # only get current manifest when it is not a preveiw request if not args.config and not args.manifest_id: if args.update_labels or args.remove_labels: if not args.preview: current_manifest = dm_v2_util.ExtractManifestName( current_deployment) deployment.target = importer.BuildTargetConfigFromManifest( dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name, current_manifest) # If no fingerprint is present, default to an empty fingerprint. # This empty default can be removed once the fingerprint change is # fully implemented and all deployments have fingerprints. deployment.fingerprint = current_deployment.fingerprint or '' if args.description is None: deployment.description = current_deployment.description elif not args.description or args.description.isspace(): deployment.description = None else: deployment.description = args.description except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) try: operation = dm_base.GetClient().deployments.Update( dm_base.GetMessages( ).DeploymentmanagerDeploymentsUpdateRequest( deploymentResource=deployment, project=dm_base.GetProject(), deployment=args.deployment_name, preview=args.preview, createPolicy=(dm_base.GetMessages( ).DeploymentmanagerDeploymentsUpdateRequest. CreatePolicyValueValuesEnum( args.create_policy)), deletePolicy=(dm_base.GetMessages( ).DeploymentmanagerDeploymentsUpdateRequest. DeletePolicyValueValuesEnum( args.delete_policy)), )) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) if args. async: return operation else: op_name = operation.name try: dm_write.WaitForOperation(op_name, 'update', dm_base.GetProject(), timeout=OPERATION_TIMEOUT) log.status.Print('Update operation ' + op_name + ' completed successfully.') except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) return dm_v2_util.FetchResourcesAndOutputs(dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name)
def Run(self, args): """Run 'deployments create'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns a struct containing the list of resources and list of outputs in the deployment. Raises: HttpException: An http error response was received while executing api request. ConfigError: Config file could not be read or parsed, or the deployment creation operation encountered an error. """ deployment = dm_base.GetMessages().Deployment( name=args.deployment_name, target=importer.BuildTargetConfig(dm_base.GetMessages(), args.config, args.properties), ) if self.ReleaseTrack() in [base.ReleaseTrack.ALPHA]: label_dict = labels_util.GetUpdateLabelsDictFromArgs(args) label_entry = [] if label_dict: label_entry = [ dm_base.GetMessages().DeploymentLabelEntry(key=k, value=v) for k, v in sorted(label_dict.iteritems()) ] deployment.labels = label_entry if args.description: deployment.description = args.description try: operation = dm_base.GetClient().deployments.Insert( dm_base.GetMessages( ).DeploymentmanagerDeploymentsInsertRequest( project=dm_base.GetProject(), deployment=deployment, preview=args.preview, )) # Fetch and print the latest fingerprint of the deployment. fingerprint = dm_v2_util.FetchDeploymentFingerprint( dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name) dm_util.PrintFingerprint(fingerprint) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) if args. async: return operation else: op_name = operation.name try: dm_write.WaitForOperation(op_name, operation_description='create', project=dm_base.GetProject(), timeout=OPERATION_TIMEOUT) log.status.Print('Create operation ' + op_name + ' completed successfully.') except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) return dm_v2_util.FetchResourcesAndOutputs(dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name)
def Run(self, args): """Run 'deployments delete'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns boolean indicating whether insert operation succeeded. Raises: HttpException: An http error response was received while executing api request. """ prompt_message = ('The following deployments will be deleted:\n- ' + '\n- '.join(args.deployment_name)) if not args.quiet: if not console_io.PromptContinue(message=prompt_message, default=False): raise exceptions.OperationError('Deletion aborted by user.') operations = [] for deployment_name in args.deployment_name: try: operation = dm_base.GetClient().deployments.Delete( dm_base.GetMessages( ).DeploymentmanagerDeploymentsDeleteRequest( project=dm_base.GetProject(), deployment=deployment_name, deletePolicy=(dm_base.GetMessages( ).DeploymentmanagerDeploymentsDeleteRequest. DeletePolicyValueValuesEnum( args.delete_policy)), )) except apitools_exceptions.HttpError as error: raise api_exceptions.HttpException( error, dm_v2_util.HTTP_ERROR_FORMAT) if args. async: operations.append(operation) else: op_name = operation.name try: dm_write.WaitForOperation(op_name, 'delete', dm_base.GetProject(), timeout=OPERATION_TIMEOUT) log.status.Print('Delete operation ' + op_name + ' completed successfully.') except exceptions.OperationError as e: log.error(u'Delete operation {0} failed.\n{1}'.format( op_name, e)) except apitools_exceptions.HttpError as error: raise api_exceptions.HttpException( error, dm_v2_util.HTTP_ERROR_FORMAT) try: completed_operation = dm_base.GetClient().operations.Get( dm_base.GetMessages( ).DeploymentmanagerOperationsGetRequest( project=dm_base.GetProject(), operation=op_name, )) except apitools_exceptions.HttpError as error: raise api_exceptions.HttpException( error, dm_v2_util.HTTP_ERROR_FORMAT) operations.append(completed_operation) return operations
def Run(self, args): """Run 'deployments cancel-preview'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns boolean indicating whether cancel preview operation succeeded. Raises: HttpException: An http error response was received while executing api request. """ if args.fingerprint: fingerprint = dm_util.DecodeFingerprint(args.fingerprint) else: # If no fingerprint is present, default to an empty fingerprint. # TODO(b/34966984): Remove the empty default after cleaning up all # deployments that has no fingerprint fingerprint = dm_v2_util.FetchDeploymentFingerprint( dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name, ) or '' try: operation = dm_base.GetClient().deployments.CancelPreview( dm_base.GetMessages( ).DeploymentmanagerDeploymentsCancelPreviewRequest( project=dm_base.GetProject(), deployment=args.deployment_name, deploymentsCancelPreviewRequest=dm_base.GetMessages(). DeploymentsCancelPreviewRequest(fingerprint=fingerprint, ), )) # Fetch and print the latest fingerprint of the deployment. new_fingerprint = dm_v2_util.FetchDeploymentFingerprint( dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name) dm_util.PrintFingerprint(new_fingerprint) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) if args. async: return operation else: op_name = operation.name try: dm_write.WaitForOperation(op_name, 'cancel-preview', dm_base.GetProject(), timeout=OPERATION_TIMEOUT) log.status.Print('Cancel preview operation ' + op_name + ' completed successfully.') except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) try: # Fetch a list of the canceled resources. response = dm_base.GetClient().resources.List( dm_base.GetMessages( ).DeploymentmanagerResourcesListRequest( project=dm_base.GetProject(), deployment=args.deployment_name, )) # TODO(user): Pagination return response.resources if response.resources else [] except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT)
def Run(self, args): """Run 'deployments cancel-preview'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns boolean indicating whether cancel preview operation succeeded. Raises: HttpException: An http error response was received while executing api request. """ # Get the fingerprint from the previewing deployment to cancel. try: current_deployment = dm_base.GetClient().deployments.Get( dm_base.GetMessages().DeploymentmanagerDeploymentsGetRequest( project=dm_base.GetProject(), deployment=args.deployment_name)) # If no fingerprint is present, default to an empty fingerprint. # This empty default can be removed once the fingerprint change is # fully implemented and all deployments have fingerprints. fingerprint = current_deployment.fingerprint or '' except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) try: operation = dm_base.GetClient().deployments.CancelPreview( dm_base.GetMessages( ).DeploymentmanagerDeploymentsCancelPreviewRequest( project=dm_base.GetProject(), deployment=args.deployment_name, deploymentsCancelPreviewRequest=dm_base.GetMessages(). DeploymentsCancelPreviewRequest(fingerprint=fingerprint, ), )) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) if args. async: return operation else: op_name = operation.name try: dm_write.WaitForOperation(op_name, 'cancel-preview', dm_base.GetProject(), timeout=OPERATION_TIMEOUT) log.status.Print('Cancel preview operation ' + op_name + ' completed successfully.') except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) try: # Fetch a list of the canceled resources. response = dm_base.GetClient().resources.List( dm_base.GetMessages( ).DeploymentmanagerResourcesListRequest( project=dm_base.GetProject(), deployment=args.deployment_name, )) # TODO(user): Pagination return response.resources if response.resources else [] except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT)
def Run(self, args): """Run 'deployments create'. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: If --async=true, returns Operation to poll. Else, returns a struct containing the list of resources and list of outputs in the deployment. Raises: HttpException: An http error response was received while executing api request. ConfigError: Config file could not be read or parsed, or the deployment creation operation encountered an error. """ if ((not args.IsSpecified('format')) and (args. async or getattr(args, 'automatic_rollback', False))): args.format = flags.OPERATION_FORMAT deployment = dm_base.GetMessages().Deployment( name=args. deployment_name, # TODO(b/37913150): Use resource parser. target=importer.BuildTargetConfig(dm_base.GetMessages(), args.config, args.properties), ) self._SetMetadata(args, deployment) try: operation = dm_base.GetClient().deployments.Insert( dm_base.GetMessages( ).DeploymentmanagerDeploymentsInsertRequest( project=dm_base.GetProject(), deployment=deployment, preview=args.preview, )) # Fetch and print the latest fingerprint of the deployment. fingerprint = dm_v2_util.FetchDeploymentFingerprint( dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name) dm_util.PrintFingerprint(fingerprint) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) if args. async: return operation else: op_name = operation.name try: dm_write.WaitForOperation(op_name, operation_description='create', project=dm_base.GetProject(), timeout=OPERATION_TIMEOUT) log.status.Print('Create operation ' + op_name + ' completed successfully.') except apitools_exceptions.HttpError as error: # TODO(b/37911296): Use gcloud default error handling. raise exceptions.HttpException(error, dm_v2_util.HTTP_ERROR_FORMAT) except dm_exceptions.OperationError as error: response = self._HandleOperationError(error, args, operation, dm_base.GetProject()) return response return dm_v2_util.FetchResourcesAndOutputs(dm_base.GetClient(), dm_base.GetMessages(), dm_base.GetProject(), args.deployment_name)