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. """ adapter = self.context['api_adapter'] location_get = self.context['location_get'] location = location_get(args) cluster_ref = adapter.ParseCluster(args.name, location) project_id = properties.VALUES.core.project.Get(required=True) concurrent_node_count = getattr(args, 'concurrent_node_count', None) try: cluster = adapter.GetCluster(cluster_ref) except (exceptions.HttpException, apitools_exceptions.HttpForbiddenError, util.Error) as error: log.warning( ('Problem loading details of cluster to upgrade:\n\n{}\n\n' 'You can still attempt to upgrade the cluster.\n').format( console_attr.SafeText(error))) cluster = None try: server_conf = adapter.GetServerConfig(project_id, location) except (exceptions.HttpException, apitools_exceptions.HttpForbiddenError, util.Error) as error: log.warning( ('Problem loading server config:\n\n{}\n\n' 'You can still attempt to upgrade the cluster.\n').format( console_attr.SafeText(error))) server_conf = None upgrade_message = container_command_util.ClusterUpgradeMessage( name=args.name, server_conf=server_conf, cluster=cluster, master=args.master, node_pool_name=args.node_pool, new_version=args.cluster_version, concurrent_node_count=concurrent_node_count) console_io.PromptContinue(message=upgrade_message, throw_if_unattended=True, cancel_on_no=True) options = self.ParseUpgradeOptions(args) try: op_ref = adapter.UpdateCluster(cluster_ref, options) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) if not args. async: adapter.WaitForOperation(op_ref, 'Upgrading {0}'.format( cluster_ref.clusterId), timeout_s=args.timeout) log.UpdatedResource(cluster_ref)
def write(self, msg): self._Write(console_attr.SafeText(msg, encoding='utf-8', escape=False))
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. """ adapter = self.context['api_adapter'] location_get = self.context['location_get'] location = location_get(args) cluster_ref = adapter.ParseCluster(args.name, location) cluster_name = args.name cluster_node_count = None cluster_zone = cluster_ref.zone try: # Attempt to get cluster for better prompts and to validate args. # Error is a warning but not fatal. Should only exit with a failure on # the actual update API calls below. cluster = adapter.GetCluster(cluster_ref) cluster_name = cluster.name cluster_node_count = cluster.currentNodeCount cluster_zone = cluster.zone except (exceptions.HttpException, apitools_exceptions.HttpForbiddenError, util.Error) as error: log.warning(('Problem loading details of cluster to update:\n\n{}\n\n' 'You can still attempt updates to the cluster.\n') .format(console_attr.SafeText(error))) # locations will be None if additional-zones was specified, an empty list # if it was specified with no argument, or a populated list if zones were # provided. We want to distinguish between the case where it isn't # specified (and thus shouldn't be passed on to the API) and the case where # it's specified as wanting no additional zones, in which case we must pass # the cluster's primary zone to the API. # TODO(b/29578401): Remove the hasattr once the flag is GA. locations = None if hasattr(args, 'additional_zones') and args.additional_zones is not None: locations = sorted([cluster_ref.zone] + args.additional_zones) if hasattr(args, 'node_locations') and args.node_locations is not None: locations = sorted(args.node_locations) if args.username is not None or args.enable_basic_auth is not None: flags.MungeBasicAuthFlags(args) options = api_adapter.SetMasterAuthOptions( action=api_adapter.SetMasterAuthOptions.SET_USERNAME, username=args.username, password=args.password) try: op_ref = adapter.SetMasterAuth(cluster_ref, options) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif (args.generate_password or args.set_password or args.password is not None): if args.generate_password: password = '' options = api_adapter.SetMasterAuthOptions( action=api_adapter.SetMasterAuthOptions.GENERATE_PASSWORD, password=password) else: password = args.password if args.password is None: password = input('Please enter the new password:'******'Enabling/Disabling Network Policy causes a rolling ' 'update of all cluster nodes, similar to performing a cluster ' 'upgrade. This operation is long-running and will block other ' 'operations on the cluster (including delete) until it has run ' 'to completion.', cancel_on_no=True) options = api_adapter.SetNetworkPolicyOptions( enabled=args.enable_network_policy) try: op_ref = adapter.SetNetworkPolicy(cluster_ref, options) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif args.start_ip_rotation or args.start_credential_rotation: if args.start_ip_rotation: msg_tmpl = """This will start an IP Rotation on cluster [{name}]. The \ master will be updated to serve on a new IP address in addition to the current \ IP address. Kubernetes Engine will then recreate all nodes ({num_nodes} nodes) \ to point to the new IP address. This operation is long-running and will block \ other operations on the cluster (including delete) until it has run to \ completion.""" rotate_credentials = False elif args.start_credential_rotation: msg_tmpl = """This will start an IP and Credentials Rotation on cluster\ [{name}]. The master will be updated to serve on a new IP address in addition \ to the current IP address, and cluster credentials will be rotated. Kubernetes \ Engine will then recreate all nodes ({num_nodes} nodes) to point to the new IP \ address. This operation is long-running and will block other operations on the \ cluster (including delete) until it has run to completion.""" rotate_credentials = True console_io.PromptContinue( message=msg_tmpl.format( name=cluster_name, num_nodes=cluster_node_count if cluster_node_count else '?'), cancel_on_no=True) try: op_ref = adapter.StartIpRotation( cluster_ref, rotate_credentials=rotate_credentials) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif args.complete_ip_rotation or args.complete_credential_rotation: if args.complete_ip_rotation: msg_tmpl = """This will complete the in-progress IP Rotation on \ cluster [{name}]. The master will be updated to stop serving on the old IP \ address and only serve on the new IP address. Make sure all API clients have \ been updated to communicate with the new IP address (e.g. by running `gcloud \ container clusters get-credentials --project {project} --zone {zone} {name}`). \ This operation is long-running and will block other operations on the cluster \ (including delete) until it has run to completion.""" elif args.complete_credential_rotation: msg_tmpl = """This will complete the in-progress Credential Rotation on\ cluster [{name}]. The master will be updated to stop serving on the old IP \ address and only serve on the new IP address. Old cluster credentials will be \ invalidated. Make sure all API clients have been updated to communicate with \ the new IP address (e.g. by running `gcloud container clusters get-credentials \ --project {project} --zone {zone} {name}`). This operation is long-running and \ will block other operations on the cluster (including delete) until it has run \ to completion.""" console_io.PromptContinue( message=msg_tmpl.format( name=cluster_name, project=cluster_ref.projectId, zone=cluster_zone), cancel_on_no=True) try: op_ref = adapter.CompleteIpRotation(cluster_ref) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif args.update_labels is not None: try: op_ref = adapter.UpdateLabels(cluster_ref, args.update_labels) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif args.remove_labels is not None: try: op_ref = adapter.RemoveLabels(cluster_ref, args.remove_labels) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif args.logging_service is not None: try: op_ref = adapter.SetLoggingService(cluster_ref, args.logging_service) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) elif args.maintenance_window is not None: try: op_ref = adapter.SetMaintenanceWindow(cluster_ref, args.maintenance_window) except apitools_exceptions.HttpError as error: raise exceptions.HttpException(error, util.HTTP_ERROR_FORMAT) else: if args.enable_legacy_authorization is not None: op_ref = adapter.SetLegacyAuthorization( cluster_ref, args.enable_legacy_authorization) else: options = self.ParseUpdateOptions(args, locations) op_ref = adapter.UpdateCluster(cluster_ref, options) if not args.async: adapter.WaitForOperation(op_ref, 'Updating {0}'.format(cluster_ref.clusterId)) log.UpdatedResource(cluster_ref) cluster_url = util.GenerateClusterUrl(cluster_ref) log.status.Print( 'To inspect the contents of your cluster, go to: ' + cluster_url) if (args.start_ip_rotation or args.complete_ip_rotation or args.start_credential_rotation or args.complete_credential_rotation): cluster = adapter.GetCluster(cluster_ref) try: util.ClusterConfig.Persist(cluster, cluster_ref.projectId) except kconfig.MissingEnvVarError as error: log.warning(error)
def __init__(self, attr, string): self._string = console_attr.SafeText(string, encoding=attr.GetEncoding(), escape=False) self._adjust = attr.DisplayWidth(self._string) - len(self._string)