# -*- coding: utf-8 -*- # # Copyright 2015 Google LLC. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Commands for updating backend buckets.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals from apitools.base.py import encoding from googlecloudsdk.api_lib.compute import base_classes from googlecloudsdk.calliope import base from googlecloudsdk.command_lib.compute import cdn_flags_utils as cdn_flags from googlecloudsdk.command_lib.compute import exceptions from googlecloudsdk.command_lib.compute import flags as compute_flags from googlecloudsdk.command_lib.compute import scope as compute_scope from googlecloudsdk.command_lib.compute import signed_url_flags from googlecloudsdk.command_lib.compute.backend_buckets import backend_buckets_utils from googlecloudsdk.command_lib.compute.backend_buckets import flags as backend_buckets_flags from googlecloudsdk.command_lib.compute.security_policies import ( flags as security_policy_flags) from googlecloudsdk.core import log @base.ReleaseTracks(base.ReleaseTrack.GA) @base.UniverseCompatible class Update(base.UpdateCommand): """Update a backend bucket. *{command}* is used to update backend buckets. """ BACKEND_BUCKET_ARG = None EDGE_SECURITY_POLICY_ARG = None support_regional_global_flags = False @classmethod def Args(cls, parser): """Set up arguments for this command.""" backend_buckets_flags.AddUpdatableArgs( cls, parser, 'update', cls.support_regional_global_flags ) backend_buckets_flags.GCS_BUCKET_ARG.AddArgument(parser) signed_url_flags.AddSignedUrlCacheMaxAge( parser, required=False, unspecified_help='') cdn_flags.AddCdnPolicyArgs(parser, 'backend bucket', update_command=True) cls.EDGE_SECURITY_POLICY_ARG = ( security_policy_flags.EdgeSecurityPolicyArgumentForTargetResource( resource='backend bucket')) cls.EDGE_SECURITY_POLICY_ARG.AddArgument(parser) backend_buckets_flags.AddCacheKeyExtendedCachingArgs(parser) backend_buckets_flags.AddCompressionMode(parser) def AnyArgsSpecified(self, args): """Returns true if any args for updating backend bucket were specified.""" return (args.IsSpecified('description') or args.IsSpecified('gcs_bucket_name') or args.IsSpecified('enable_cdn') or args.IsSpecified('edge_security_policy') or args.IsSpecified('cache_key_include_http_header') or args.IsSpecified('cache_key_query_string_whitelist') or args.IsSpecified('compression_mode')) def AnyFlexibleCacheArgsSpecified(self, args): """Returns true if any Flexible Cache args for updating backend bucket were specified.""" return any( (args.IsSpecified('cache_mode'), args.IsSpecified('client_ttl'), args.IsSpecified('no_client_ttl'), args.IsSpecified('default_ttl'), args.IsSpecified('no_default_ttl'), args.IsSpecified('max_ttl'), args.IsSpecified('no_max_ttl'), args.IsSpecified('custom_response_header'), args.IsSpecified('no_custom_response_headers'), args.IsSpecified('negative_caching'), args.IsSpecified('negative_caching_policy'), args.IsSpecified('no_negative_caching_policies'), args.IsSpecified('serve_while_stale'), args.IsSpecified('no_serve_while_stale'), args.IsSpecified('bypass_cache_on_request_headers'), args.IsSpecified('no_bypass_cache_on_request_headers'))) def GetGetRequest(self, client, backend_bucket_ref): """Returns a request to retrieve the backend bucket.""" if backend_bucket_ref.Collection() == 'compute.regionBackendBuckets': return ( client.apitools_client.regionBackendBuckets, 'Get', client.messages.ComputeRegionBackendBucketsGetRequest( project=backend_bucket_ref.project, region=backend_bucket_ref.region, backendBucket=backend_bucket_ref.Name(), ), ) return (client.apitools_client.backendBuckets, 'Get', client.messages.ComputeBackendBucketsGetRequest( project=backend_bucket_ref.project, backendBucket=backend_bucket_ref.Name())) def GetSetRequest(self, client, backend_bucket_ref, replacement): """Returns a request to update the backend bucket.""" if backend_bucket_ref.Collection() == 'compute.regionBackendBuckets': return ( client.apitools_client.regionBackendBuckets, 'Patch', client.messages.ComputeRegionBackendBucketsPatchRequest( project=backend_bucket_ref.project, region=backend_bucket_ref.region, backendBucket=backend_bucket_ref.Name(), backendBucketResource=replacement, ), ) return (client.apitools_client.backendBuckets, 'Patch', client.messages.ComputeBackendBucketsPatchRequest( project=backend_bucket_ref.project, backendBucket=backend_bucket_ref.Name(), backendBucketResource=replacement)) def GetSetEdgeSecurityPolicyRequest(self, client, backend_bucket_ref, security_policy_ref): """Returns a request to set the edge policy for the backend bucket.""" if backend_bucket_ref.Collection() == 'compute.regionBackendBuckets': raise exceptions.ArgumentError( 'Regional backend buckets do not support edge security policies.') return (client.apitools_client.backendBuckets, 'SetEdgeSecurityPolicy', client.messages.ComputeBackendBucketsSetEdgeSecurityPolicyRequest( project=backend_bucket_ref.project, backendBucket=backend_bucket_ref.Name(), securityPolicyReference=client.messages.SecurityPolicyReference( securityPolicy=security_policy_ref))) def Modify(self, args, existing): """Modifies and returns the updated backend bucket.""" holder = base_classes.ComputeApiHolder(self.ReleaseTrack()) client = holder.client replacement = encoding.CopyProtoMessage(existing) cleared_fields = [] if args.IsSpecified('description'): replacement.description = args.description if args.gcs_bucket_name: replacement.bucketName = args.gcs_bucket_name if args.enable_cdn is not None: replacement.enableCdn = args.enable_cdn backend_buckets_utils.ApplyCdnPolicyArgs( client, args, replacement, is_update=True, cleared_fields=cleared_fields) if args.custom_response_header is not None: replacement.customResponseHeaders = args.custom_response_header if args.no_custom_response_headers: replacement.customResponseHeaders = [] if not replacement.customResponseHeaders: cleared_fields.append('customResponseHeaders') if (replacement.cdnPolicy is not None and replacement.cdnPolicy.cacheMode and args.enable_cdn is not False): # pylint: disable=g-bool-id-comparison replacement.enableCdn = True if args.compression_mode is not None: replacement.compressionMode = ( client.messages.BackendBucket.CompressionModeValueValuesEnum( args.compression_mode)) if not replacement.description: cleared_fields.append('description') return replacement, cleared_fields def MakeRequests(self, args): """Makes the requests for updating the backend bucket.""" holder = base_classes.ComputeApiHolder(self.ReleaseTrack()) client = holder.client if self.support_regional_global_flags: backend_bucket_ref = backend_buckets_flags.GLOBAL_REGIONAL_BACKEND_BUCKET_ARG.ResolveAsResource( args, holder.resources, scope_lister=compute_flags.GetDefaultScopeLister(client), default_scope=compute_scope.ScopeEnum.GLOBAL, ) else: backend_bucket_ref = self.BACKEND_BUCKET_ARG.ResolveAsResource( args, holder.resources ) get_request = self.GetGetRequest(client, backend_bucket_ref) objects = client.MakeRequests([get_request]) new_object, cleared_fields = self.Modify(args, objects[0]) # If existing object is equal to the proposed object or if # Modify() returns None, then there is no work to be done, so we # print the resource and return. if objects[0] == new_object: # Only skip update if edge_security_policy is not set. if getattr(args, 'edge_security_policy', None) is None: log.status.Print( 'No change requested; skipping update for [{0}].'.format( objects[0].name)) return objects backend_bucket_result = [] else: with client.apitools_client.IncludeFields(cleared_fields): backend_bucket_result = client.MakeRequests( [self.GetSetRequest(client, backend_bucket_ref, new_object)]) # Empty string is a valid value. if getattr(args, 'edge_security_policy', None) is not None: if backend_bucket_ref.Collection() == 'compute.regionBackendBuckets': raise exceptions.ArgumentError( 'argument --edge-security-policy: Regional backend buckets do not' ' support edge security policies.' ) if getattr(args, 'edge_security_policy', None): security_policy_ref = self.EDGE_SECURITY_POLICY_ARG.ResolveAsResource( args, holder.resources).SelfLink() # If security policy is an empty string we should clear the current policy else: security_policy_ref = None edge_security_policy_request = self.GetSetEdgeSecurityPolicyRequest( client, backend_bucket_ref, security_policy_ref) edge_security_policy_result = client.MakeRequests( [edge_security_policy_request]) else: edge_security_policy_result = [] return backend_bucket_result + edge_security_policy_result def Run(self, args): """Issues the request necessary for updating a backend bucket.""" if (not self.AnyArgsSpecified(args) and not args.IsSpecified('signed_url_cache_max_age') and not args.IsSpecified('request_coalescing') and not self.AnyFlexibleCacheArgsSpecified(args)): raise exceptions.UpdatePropertyError( 'At least one property must be modified.') return self.MakeRequests(args) @base.ReleaseTracks(base.ReleaseTrack.BETA) @base.UniverseCompatible class UpdateBeta(Update): """Update a backend bucket. *{command}* is used to update backend buckets. To delete a global backend bucket, run either of the following: $ {command} my-backend-bucket --no-enable-cdn --global $ {command} my-backend-bucket --no-enable-cdn To delete a regional backend bucket, run the following: $ {command} my-backend-bucket --region=us-central1 --no-enable-cdn """ support_regional_global_flags = True @base.ReleaseTracks(base.ReleaseTrack.ALPHA) @base.UniverseCompatible class UpdateAlpha(UpdateBeta): """Update a backend bucket. *{command}* is used to update backend buckets. To delete a global backend bucket, run either of the following: $ {command} my-backend-bucket --no-enable-cdn --global $ {command} my-backend-bucket --no-enable-cdn To delete a regional backend bucket, run the following: $ {command} my-backend-bucket --region=us-central1 --no-enable-cdn """ support_regional_global_flags = True