def _ParseResourceArg(self, namespace): """Gets the resource ref for the resource specified as the positional arg. Args: namespace: The argparse namespace. Returns: The parsed resource ref or None if no resource arg was generated for this method. """ resource_args = self.resource_arg_info if not resource_args: return anchor_field = resource_args[-1] resource = arg_utils.GetFromNamespace(namespace, anchor_field.arg_name, fallback=anchor_field.fallback, use_defaults=True) params = {} for field in resource_args[:-1]: # Since these parameters might be redundant with information in the anchor # field, we only want to evaluate anchor_field.fallback in Parse() when we # know it's needed. params[field.api_field] = arg_utils.GetFromNamespace( namespace, field.arg_name, use_defaults=True) or field.fallback return resources.REGISTRY.Parse( resource, collection=self.method.resource_argument_collection.full_name, params=params)
def _ParseResourceArg(self, namespace): """Gets the resource ref for the resource specified as the positional arg. Args: namespace: The argparse namespace. Returns: The parsed resource ref or None if no resource arg was generated for this method. """ resource_args = self.resource_arg_info if not resource_args: return anchor_field = resource_args[-1] resource = arg_utils.GetFromNamespace(namespace, anchor_field.arg_name, use_defaults=True) params = {} for field in resource_args[:-1]: params[field.api_field] = arg_utils.GetFromNamespace( namespace, field.arg_name, use_defaults=True) return resources.REGISTRY.Parse( resource, collection=self.method.resource_argument_collection.full_name, params=params)
def testGetFromNamespace(self): ns = mock.MagicMock(foo_bar='baz', qux=None, project=None) value = arg_utils.GetFromNamespace(ns, 'foo-bar') self.assertEqual(value, 'baz') value = arg_utils.GetFromNamespace(ns, 'qux', fallback=lambda: 42) self.assertEqual(value, 42) properties.VALUES.core.project.Set('fake-project') value = arg_utils.GetFromNamespace(ns, 'project') self.assertEqual(value, None) value = arg_utils.GetFromNamespace(ns, 'project', use_defaults=True) self.assertEqual(value, 'fake-project')
def _ParseArguments(self, namespace, prefix, message): """Recursively generates the request message and any sub-messages. Args: namespace: The argparse namespace containing the all the parsed arguments. prefix: str, The flag prefix for the sub-message being generated. message: The apitools class for the message. Returns: The instantiated apitools Message with all fields filled in from flags. """ kwargs = {} for field in message.all_fields(): arg_name = self._GetArgName(field.name) if not arg_name: continue arg_name = prefix + arg_name # Field is a sub-message, recursively generate it. if field.variant == messages.Variant.MESSAGE: sub_kwargs = self._ParseArguments(namespace, arg_name + '.', field.type) if sub_kwargs: # Only construct the sub-message if we have something to put in it. value = field.type(**sub_kwargs) # TODO(b/38000796): Handle repeated fields correctly. kwargs[field.name] = value if not field.repeated else [ value ] # Field is a scalar, just get the value. else: value = arg_utils.GetFromNamespace(namespace, arg_name) if value is not None: kwargs[field.name] = arg_utils.ConvertValue(field, value) return kwargs
def Run(self, args): # TODO(b/145953996): api_utils map release_track to an api_version. # All old commands needs to use 'v1beta1' irrespective of the release track, # till they are removed (already deprecation policy applied). self.release_track = base.ReleaseTrack.BETA project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = kube_util.OldKubernetesClient(args) uuid = kube_util.GetClusterUUID(kube_client) # Delete membership from GKE Hub API. try: name = 'projects/{}/locations/global/memberships/{}'.format( project, uuid) api_util.DeleteMembership(name, self.release_track) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership for [{}] was not found. It may already have been ' 'deleted, or it may never have existed.'.format(args.context)) # Get namespace for the connect resource label. selector = '{}={}'.format(agent_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: raise exceptions.Error( 'There\'s no namespace for the label {}. ' 'If gke-connect is labeled with another project,' 'You\'ll have to manually delete the namespace.' 'You can find all namespaces by running:\n\n' ' `kubectl get ns -l {}`'.format( agent_util.CONNECT_RESOURCE_LABEL, agent_util.CONNECT_RESOURCE_LABEL)) registered_project = exclusivity_util.GetMembershipCROwnerID( kube_client) if registered_project: if registered_project != project: raise exceptions.Error( 'This cluster is registered to another project [{}]. ' 'Please unregister this cluster from the correct project:\n\n' ' gcloud {}container hub unregister-cluster --project {} --context {}' .format( registered_project, hub_util.ReleaseTrackCommandPrefix( self.ReleaseTrack()), registered_project, args.context)) # Delete membership resources. exclusivity_util.DeleteMembershipResources(kube_client) # Delete the connect agent. agent_util.DeleteConnectNamespace(kube_client, args)
def Run(self, args): util.CheckKubectlInstalled() log.status.Print('Starting to build Gateway kubeconfig...') # Parse Args: get project_id from flag or default project_id = arg_utils.GetFromNamespace( args, '--project', use_defaults=True) log.status.Print('Current project_id: ' + project_id) self.RunIamCheck(project_id) self.ReadClusterMembership(project_id, args.MEMBERSHIP) self.GenerateKubeconfig(project_id, args.MEMBERSHIP)
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = hub_util.KubernetesClient(args) uuid = hub_util.GetClusterUUID(kube_client) # Delete membership from GKE Hub API. try: name = 'projects/{}/locations/global/memberships/{}'.format( project, uuid) hub_util.DeleteMembership(name) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership for [{}] was not found. It may already have been ' 'deleted, or it may never have existed. You can safely run the ' '`register-cluster` command again for this cluster.'.format( args.context)) # Get namespace for the connect resource label. selector = '{}={}'.format(hub_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: raise exceptions.Error( 'There\'s no namespace for the label {}. ' 'If gke-connect is labeled with another project,' 'You\'ll have to manually delete the namespace.' 'You can find all namespaces by running:\n\n' ' `kubectl get ns -l {}`'.format( hub_util.CONNECT_RESOURCE_LABEL, hub_util.CONNECT_RESOURCE_LABEL)) registered_project = hub_util.GetMembershipCROwnerID(kube_client) if registered_project: if registered_project != project: raise exceptions.Error( 'This cluster is registered to another project [{}]. ' 'Please unregister this cluster from the correct project:\n\n' ' gcloud {}container hub unregister-cluster --project {} --context {}' .format( registered_project, hub_util.ReleaseTrackCommandPrefix( self.ReleaseTrack()), registered_project, args.context)) # Delete membership resources. hub_util.DeleteMembershipResources(kube_client) # Delete the connect agent. hub_util.DeleteConnectNamespace(args)
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = kube_util.KubernetesClient(args) kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) membership_id = args.CLUSTER_NAME # Delete membership from Hub API. try: name = 'projects/{}/locations/global/memberships/{}'.format( project, membership_id) api_util.DeleteMembership(name, self.ReleaseTrack()) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership [{}] for the cluster [{}] was not found on the Hub. ' 'It may already have been deleted, or it may never have existed.' .format(name, args.CLUSTER_NAME)) # Get namespace for the connect resource label. selector = '{}={}'.format(agent_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: log.status.Print( 'There\'s no namespace for the label [{}]. ' 'If [gke-connect] is labeled with another project, ' 'You\'ll have to manually delete the namespace. ' 'You can find all namespaces by running:\n' ' `kubectl get ns -l {}`'.format( agent_util.CONNECT_RESOURCE_LABEL, agent_util.CONNECT_RESOURCE_LABEL)) # Delete in-cluster membership resources. try: exclusivity_util.DeleteMembershipResources(kube_client) except exceptions.Error as e: log.status.Print( '{} error in deleting in-cluster membership resources. ' 'You can manually delete these membership related ' 'resources from your cluster by running the command:\n' ' `kubectl delete memberships membership`.\nBy doing so, ' 'the cluster will lose its association to the Hub in ' 'project [{}] and can be registered into a different ' 'project. '.format(e, project)) # Delete the connect agent. agent_util.DeleteConnectNamespace(kube_client, args)
def _ParseResourceArg(self, namespace): """Gets the resource ref for the resource specified as the positional arg. Args: namespace: The argparse namespace. Returns: The parsed resource ref or None if no resource arg was generated for this method. """ if not self.resource_arg: return return arg_utils.GetFromNamespace( namespace.CONCEPTS, self.resource_spec.anchor.name).Parse()
def _ParseArguments(self, message, namespace): """Parse all the arguments from the namespace into the message object. Args: message: A constructed apitools message object to inject the value into. namespace: The argparse namespace. """ message_type = self.method.GetRequestType() for attributes in self.arg_info: value = arg_utils.GetFromNamespace(namespace, attributes.arg_name) if value is None: continue field = arg_utils.GetFieldFromMessage(message_type, attributes.api_field) value = arg_utils.ConvertValue(field, value, attributes) arg_utils.SetFieldInMessage(message, attributes.api_field, value)
def Parse(self, message, namespace): """Sets the argument message value, if any, from the parsed args. Args: message: The API message, None for non-resource args. namespace: The parsed command line argument namespace. """ if self.api_field is None: return value = arg_utils.GetFromNamespace( namespace, self.arg_name, fallback=self.fallback) if value is None: return field = arg_utils.GetFieldFromMessage(message, self.api_field) value = arg_utils.ConvertValue(field, value, self) arg_utils.SetFieldInMessage(message, self.api_field, value)
def _ParseResourceArg(self, namespace): """Gets the resource ref for the resource specified as the positional arg. Args: namespace: The argparse namespace. Returns: The parsed resource ref or None if no resource arg was generated for this method. """ if not self.resource_arg: return result = arg_utils.GetFromNamespace(namespace.CONCEPTS, self._GetAnchorArgName()).Parse() if isinstance(result, multitype.TypedConceptResult): result = result.result return result
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = kube_util.KubernetesClient(args) kube_util.ValidateClusterIdentifierFlags(kube_client, args) membership_id = args.CLUSTER_NAME # Delete membership from Hub API. try: name = 'projects/{}/locations/global/memberships/{}'.format( project, membership_id) api_util.DeleteMembership(name, self.ReleaseTrack()) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership for [{}] was not found. It may already have been ' 'deleted, or it may never have existed.'.format( args.context)) # Get namespace for the connect resource label. selector = '{}={}'.format(agent_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: log.status.Print('There\'s no namespace for the label {}. ' 'If gke-connect is labeled with another project,' 'You\'ll have to manually delete the namespace.' 'You can find all namespaces by running:\n\n' ' `kubectl get ns -l {}`'.format( agent_util.CONNECT_RESOURCE_LABEL, agent_util.CONNECT_RESOURCE_LABEL)) # Delete membership resources. try: exclusivity_util.DeleteMembershipResources(kube_client) except exceptions.Error: log.status.Print('{} You can delete the membership CR manually by ' '`kubectl delete memberships membership`.') # Delete the connect agent. agent_util.DeleteConnectNamespace(kube_client, args)
def Run(self, args): util.CheckKubectlInstalled() # Parse Args: get project_id from flag or default project_id = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) if project_id is None: msg = """\ The required property [project] is not currently set. You may set it for your current workspace by running: \n $ gcloud config set project VALUE""" raise Exception(msg) log.status.Print('Starting to build Gateway kubeconfig...') log.status.Print('Current project_id: ' + project_id) self.RunIamCheck(project_id) self.ReadClusterMembership(project_id, args.MEMBERSHIP) self.GenerateKubeconfig(project_id, args.MEMBERSHIP) msg = 'A new kubeconfig entry \"' + KUBECONTEXT_FORMAT.format( project=project_id, membership=args.MEMBERSHIP ) + '\" has been generated and set as the current context.' log.status.Print(msg)
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = hub_util.KubernetesClient(args) registered_project = hub_util.GetMembershipCROwnerID(kube_client) authorized_projects = hub_util.UserAccessibleProjectIDSet() if registered_project: if registered_project not in authorized_projects: raise exceptions.Error( 'The cluster is already registered to [{}], which you are not ' 'authorized to access.'.format(registered_project)) elif registered_project != project: raise exceptions.Error( 'This cluster is registered to another project [{}]. ' 'Please unregister this cluster from the correct project:\n\n' ' gcloud {}container hub unregister-cluster --project {} --context {}' .format( registered_project, hub_util.ReleaseTrackCommandPrefix( self.ReleaseTrack()), registered_project, args.context)) if project not in authorized_projects: raise exceptions.Error( 'The project you are attempting to register with [{}] either ' 'doesn\'t exist or you are not authorized to access it.'. format(project)) uuid = hub_util.GetClusterUUID(kube_client) try: registered_membership_project = hub_util.ProjectForClusterUUID( uuid, [project, registered_project]) except apitools_exceptions.HttpNotFoundError as e: raise exceptions.Error( 'Could not access Memberships API. Is your project whitelisted for ' 'API access? Underlying error: {}'.format(e)) if registered_membership_project and project != registered_membership_project: raise exceptions.Error( 'This cluster is registered to another project [{}]. ' 'Please unregister this cluster from the appropriate project:\n\n' ' gcloud {}container hub unregister-cluster --project {} --context {}' .format( registered_membership_project, hub_util.ReleaseTrackCommandPrefix(self.ReleaseTrack()), registered_membership_project, args.context)) if not registered_membership_project: log.status.Print( 'Membership for [{}] was not found. It may already have been ' 'deleted, or it may never have existed. You can safely run the ' '`register-cluster` command again for this cluster.'.format( args.context)) # There is no Membership for this cluster, but there is a Membership CR. # We can safely remove the Membership CR, so users can register to another # hub without issue. if registered_project: hub_util.DeleteMembershipResources(kube_client) return hub_util.DeleteConnectNamespace(args) try: name = 'projects/{}/locations/global/memberships/{}'.format( project, uuid) hub_util.DeleteMembership(name) hub_util.DeleteMembershipResources(kube_client) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e))
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) # This incidentally verifies that the kubeconfig and context args are valid. kube_client = hub_util.KubernetesClient(args) uuid = hub_util.GetClusterUUID(kube_client) self._VerifyClusterExclusivity(kube_client, project, args.context, uuid) # Read the service account files provided in the arguments early, in order # to catch invalid files before performing mutating operations. try: service_account_key_data = hub_util.Base64EncodedFileContents( args.service_account_key_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( SERVICE_ACCOUNT_KEY_FILE_FLAG, e)) docker_credential_data = None if args.docker_credential_file: try: docker_credential_data = hub_util.Base64EncodedFileContents( args.docker_credential_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( DOCKER_CREDENTIAL_FILE_FLAG, e)) # The full resource name of the membership for this registration flow. name = 'projects/{}/locations/global/memberships/{}'.format( project, uuid) # Attempt to create a membership. already_exists = False try: hub_util.ApplyMembershipResources(kube_client, project) obj = hub_util.CreateMembership(project, uuid, args.CLUSTER_NAME) 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 # The membership already exists. Check to see if it has the same # description (i.e., user-visible cluster name). obj = hub_util.GetMembership(name) if obj.description != args.CLUSTER_NAME: # A membership exists, but does not have the same description. This is # possible if two different users attempt to register the same # cluster, or if the user is upgrading and has passed a different # cluster name. Treat this as an error: even in the upgrade case, # this is useful to prevent the user from upgrading the wrong cluster. raise exceptions.Error( 'There is an existing membership, [{}], that conflicts with [{}]. ' 'Please delete it before continuing:\n\n' ' gcloud {}container memberships delete {}'.format( obj.description, args.CLUSTER_NAME, hub_util.ReleaseTrackCommandPrefix( self.ReleaseTrack()), name)) # The membership exists and has the same description. already_exists = True console_io.PromptContinue( message='A membership for [{}] already exists. Continuing will ' 'update the Connect agent deployment to use a new image (if one is ' 'available), or install the Connect agent if it is not already ' 'running.'.format(args.CLUSTER_NAME), cancel_on_no=True) # A membership exists. Attempt to update the existing agent deployment, or # install a new agent if necessary. if already_exists: obj = hub_util.GetMembership(name) hub_util.DeployConnectAgent(args, service_account_key_data, docker_credential_data, upgrade=True) return obj # No membership exists. Attempt to create a new one, and install a new # agent. try: hub_util.DeployConnectAgent(args, service_account_key_data, docker_credential_data, upgrade=False) except: hub_util.DeleteMembership(name) hub_util.DeleteMembershipResources(kube_client) raise return obj
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = kube_util.KubernetesClient(args) kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) membership_id = args.CLUSTER_NAME # Delete membership from Hub API. try: name = 'projects/{}/locations/global/memberships/{}'.format( project, membership_id) api_util.DeleteMembership(name, self.ReleaseTrack()) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership [{}] for the cluster [{}] was not found on the Hub. ' 'It may already have been deleted, or it may never have existed.' .format(name, args.CLUSTER_NAME)) # enable_workload_identity and manage_workload_identity_bucket are only # properties if we are on the alpha track if (self.ReleaseTrack() is base.ReleaseTrack.ALPHA and args.manage_workload_identity_bucket): # The issuer URL from the cluster indicates which bucket to delete. # --manage-workload-identity-bucket always uses the cluster's # built-in endpoints. openid_config_json = None try: openid_config_json = kube_client.GetOpenIDConfiguration() except exceptions.Error as e: log.status.Print( 'Cannot get the issuer URL that identifies the bucket associated ' 'with this membership. Please double check that it is possible to ' 'access the /.well-known/openid-configuration endpoint on the ' 'cluster: {}'.format(e)) if openid_config_json: issuer_url = json.loads(openid_config_json).get('issuer') if not issuer_url: log.status.Print( 'Cannot get the issuer URL that identifies the bucket associated ' 'with this membership. The OpenID Config from ' '/.well-known/openid-configuration is missing the issuer field: ' '{}'.format(openid_config_json)) try: api_util.DeleteWorkloadIdentityBucket(issuer_url) except exceptions.Error as e: log.status.Print( 'Failed to delete bucket for issuer {}: {}'.format( issuer_url, e)) # Get namespace for the connect resource label. selector = '{}={}'.format(agent_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: log.status.Print( 'There\'s no namespace for the label [{}]. ' 'If [gke-connect] is labeled with another project, ' 'You\'ll have to manually delete the namespace. ' 'You can find all namespaces by running:\n' ' `kubectl get ns -l {}`'.format( agent_util.CONNECT_RESOURCE_LABEL, agent_util.CONNECT_RESOURCE_LABEL)) # Delete in-cluster membership resources. try: exclusivity_util.DeleteMembershipResources(kube_client) except exceptions.Error as e: log.status.Print( '{} error in deleting in-cluster membership resources. ' 'You can manually delete these membership related ' 'resources from your cluster by running the command:\n' ' `kubectl delete memberships membership`.\nBy doing so, ' 'the cluster will lose its association to the Hub in ' 'project [{}] and can be registered into a different ' 'project. '.format(e, project)) # Delete the connect agent. agent_util.DeleteConnectNamespace(kube_client, args)
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) # This incidentally verifies that the kubeconfig and context args are valid. kube_client = kube_util.KubernetesClient(args) uuid = kube_util.GetClusterUUID(kube_client) gke_cluster_self_link = api_util.GKEClusterSelfLink(args) # Read the service account files provided in the arguments early, in order # to catch invalid files before performing mutating operations. try: service_account_key_data = hub_util.Base64EncodedFileContents( args.service_account_key_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( SERVICE_ACCOUNT_KEY_FILE_FLAG, e)) docker_credential_data = None if args.docker_credential_file: try: docker_credential_data = hub_util.Base64EncodedFileContents( args.docker_credential_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( DOCKER_CREDENTIAL_FILE_FLAG, e)) gke_cluster_self_link = api_util.GKEClusterSelfLink(args) # Attempt to create a membership. already_exists = False obj = None # For backward compatiblity, check if a membership was previously created # using the cluster uuid. parent = api_util.ParentRef(project, 'global') membership_id = uuid resource_name = api_util.MembershipRef(project, 'global', uuid) obj = self._CheckMembershipWithUUID(resource_name, args.CLUSTER_NAME) if obj: # The membership exists and has the same description. already_exists = True else: # Attempt to create a new membership using cluster_name. membership_id = args.CLUSTER_NAME resource_name = api_util.MembershipRef(project, 'global', args.CLUSTER_NAME) try: self._VerifyClusterExclusivity(kube_client, parent, membership_id) obj = api_util.CreateMembership(project, args.CLUSTER_NAME, args.CLUSTER_NAME, gke_cluster_self_link, uuid, self.ReleaseTrack()) 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 # The membership exists with same cluster_name. already_exists = True obj = api_util.GetMembership(resource_name, self.ReleaseTrack()) # In case of an existing membership, check with the user to upgrade the # Connect-Agent. if already_exists: console_io.PromptContinue( message='A membership for [{}] already exists. Continuing will ' 'reinstall the Connect agent deployment to use a new image (if one ' 'is available).'.format(resource_name), cancel_on_no=True) # No membership exists. Attempt to create a new one, and install a new # agent. try: self._InstallOrUpdateExclusivityArtifacts(kube_client, resource_name) agent_util.DeployConnectAgent(args, service_account_key_data, docker_credential_data, resource_name, self.ReleaseTrack()) except: # In case of a new membership, we need to clean up membership and # resources if we failed to install the Connect Agent. if not already_exists: api_util.DeleteMembership(resource_name, self.ReleaseTrack()) exclusivity_util.DeleteMembershipResources(kube_client) raise return obj
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) fleetclient = client.FleetClient(release_track=base.ReleaseTrack.ALPHA) return fleetclient.UpdateNamespace(args.NAME, project)
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) # This incidentally verifies that the kubeconfig and context args are valid. with kube_util.KubernetesClient(args) as kube_client: kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) uuid = kube_util.GetClusterUUID(kube_client) # Read the service account files provided in the arguments early, in order # to catch invalid files before performing mutating operations. try: service_account_key_data = hub_util.Base64EncodedFileContents( args.service_account_key_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( SERVICE_ACCOUNT_KEY_FILE_FLAG, e)) docker_credential_data = None if args.docker_credential_file: try: docker_credential_data = hub_util.Base64EncodedFileContents( args.docker_credential_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( DOCKER_CREDENTIAL_FILE_FLAG, e)) gke_cluster_self_link = kube_client.processor.gke_cluster_self_link issuer_url = None # public_issuer_url is only a property if we are on the alpha track if self.ReleaseTrack() is base.ReleaseTrack.ALPHA and \ args.public_issuer_url: issuer_url = args.public_issuer_url # Attempt to create a membership. already_exists = False obj = None # For backward compatiblity, check if a membership was previously created # using the cluster uuid. parent = api_util.ParentRef(project, 'global') membership_id = uuid resource_name = api_util.MembershipRef(project, 'global', uuid) obj = self._CheckMembershipWithUUID(resource_name, args.CLUSTER_NAME) if obj: # The membership exists and has the same description. already_exists = True else: # Attempt to create a new membership using cluster_name. membership_id = args.CLUSTER_NAME resource_name = api_util.MembershipRef(project, 'global', args.CLUSTER_NAME) try: self._VerifyClusterExclusivity(kube_client, parent, membership_id) obj = api_util.CreateMembership(project, args.CLUSTER_NAME, args.CLUSTER_NAME, gke_cluster_self_link, uuid, self.ReleaseTrack(), issuer_url) 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 obj = api_util.GetMembership(resource_name, self.ReleaseTrack()) if not obj.externalId: raise exceptions.Error( 'invalid membership {} does not have ' 'external_id field set. We cannot determine ' 'if registration is requested against a ' 'valid existing Membership. Consult the ' 'documentation on container hub memberships ' 'update for more information or run gcloud ' 'container hub memberships delete {} if you ' 'are sure that this is an invalid or ' 'otherwise stale Membership'.format( membership_id, membership_id)) if obj.externalId != uuid: raise exceptions.Error( 'membership {} already exists in the project' ' with another cluster. If this operation is' ' intended, please run `gcloud container ' 'hub memberships delete {}` and register ' 'again.'.format(membership_id, membership_id)) # The membership exists with same cluster_name. already_exists = True # In case of an existing membership, check with the user to upgrade the # Connect-Agent. if already_exists: console_io.PromptContinue( message= 'A membership [{}] for the cluster [{}] already exists. ' 'Continuing will reinstall the Connect agent deployment to use a ' 'new image (if one is available).'.format( resource_name, args.CLUSTER_NAME), cancel_on_no=True) else: log.status.Print( 'Created a new membership [{}] for the cluster [{}]'. format(resource_name, args.CLUSTER_NAME)) # Attempt to update the existing agent deployment, or install a new agent # if necessary. try: self._InstallOrUpdateExclusivityArtifacts( kube_client, resource_name) agent_util.DeployConnectAgent(kube_client, args, service_account_key_data, docker_credential_data, resource_name, self.ReleaseTrack()) except Exception as e: log.status.Print( 'Error in installing the Connect Agent: {}'.format(e)) # In case of a new membership, we need to clean up membership and # resources if we failed to install the Connect Agent. if not already_exists: api_util.DeleteMembership(resource_name, self.ReleaseTrack()) exclusivity_util.DeleteMembershipResources(kube_client) raise log.status.Print( 'Finished registering the cluster [{}] with the Hub.'.format( args.CLUSTER_NAME)) return obj
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = kube_util.KubernetesClient(args) kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) membership_id = args.CLUSTER_NAME # Delete membership from Hub API. try: name = 'projects/{}/locations/global/memberships/{}'.format( project, membership_id) obj = api_util.GetMembership(name, self.ReleaseTrack()) if not obj.externalId: console_io.PromptContinue( 'invalid membership {0} does not have ' 'external_id field set. We cannot determine ' 'if registration is requested against a ' 'valid existing Membership. Consult the ' 'documentation on container hub memberships ' 'update for more information or run gcloud ' 'container hub memberships delete {0} if you ' 'are sure that this is an invalid or ' 'otherwise stale Membership'.format(membership_id), cancel_on_no=True) uuid = kube_util.GetClusterUUID(kube_client) if obj.externalId != uuid: raise exceptions.Error( 'Membership [{}] is not associated with the cluster you are trying' ' to unregister. Please double check the cluster identifier that you' ' have supplied.'.format(membership_id)) api_util.DeleteMembership(name, self.ReleaseTrack()) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership [{}] for the cluster [{}] was not found on the Hub. ' 'It may already have been deleted, or it may never have existed.' .format(name, args.CLUSTER_NAME)) # enable_workload_identity and manage_workload_identity_bucket are only # properties if we are on the alpha track. if (self.ReleaseTrack() is base.ReleaseTrack.ALPHA and args.manage_workload_identity_bucket): # The issuer URL from the cluster indicates which bucket to delete. # --manage-workload-identity-bucket always uses the cluster's # built-in endpoints. openid_config_json = None try: openid_config_json = kube_client.GetOpenIDConfiguration() except exceptions.Error as e: log.status.Print( 'Cannot get the issuer URL that identifies the bucket associated ' 'with this membership. Please double check that it is possible to ' 'access the /.well-known/openid-configuration endpoint on the ' 'cluster: {}'.format(e)) if openid_config_json: issuer_url = json.loads(openid_config_json).get('issuer') if not issuer_url: log.status.Print( 'Cannot get the issuer URL that identifies the bucket associated ' 'with this membership. The OpenID Config from ' '/.well-known/openid-configuration is missing the issuer field: ' '{}'.format(openid_config_json)) try: api_util.DeleteWorkloadIdentityBucket(issuer_url) except exceptions.Error as e: log.status.Print( 'Failed to delete bucket for issuer {}: {}'.format( issuer_url, e)) # Get namespace for the connect resource label. selector = '{}={}'.format(agent_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: log.status.Print( 'There\'s no namespace for the label [{}]. ' 'If [gke-connect] is labeled with another project, ' 'You\'ll have to manually delete the namespace. ' 'You can find all namespaces by running:\n' ' `kubectl get ns -l {}`'.format( agent_util.CONNECT_RESOURCE_LABEL, agent_util.CONNECT_RESOURCE_LABEL)) # Delete in-cluster membership resources. try: parent = api_util.ParentRef(project, 'global') cr_manifest = kube_client.GetMembershipCR() res = api_util.ValidateExclusivity(cr_manifest, parent, membership_id, self.ReleaseTrack()) if res.status.code: console_io.PromptContinue( 'Error validating cluster\'s exclusivity state with the Hub under ' 'parent collection [{}]: {}. The cluster you are trying to unregister' ' is not associated with the membership [{}]. Continuing will delete' ' membership related resources from your cluster, and the cluster' ' will lose its association to the Hub in project [{}] and can be' ' registered into a different project. '.format( parent, res.status.message, membership_id, project), cancel_on_no=True) exclusivity_util.DeleteMembershipResources(kube_client) except exceptions.Error as e: log.status.Print( '{} error in deleting in-cluster membership resources. ' 'You can manually delete these membership related ' 'resources from your cluster by running the command:\n' ' `kubectl delete memberships membership`.\nBy doing so, ' 'the cluster will lose its association to the Hub in ' 'project [{}] and can be registered into a different ' 'project. '.format(e, project)) # Delete the connect agent. agent_util.DeleteConnectNamespace(kube_client, args)
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) # This incidentally verifies that the kubeconfig and context args are valid. with kube_util.KubernetesClient(args) as kube_client: kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) uuid = kube_util.GetClusterUUID(kube_client) # Read the service account files provided in the arguments early, in order # to catch invalid files before performing mutating operations. # Service Account key file is required if Workload Identity is not # enabled. # If Workload Identity is enabled, then the Connect Agent uses # a Kubernetes Service Account token instead and hence a GCP Service # Account key is not required. service_account_key_data = '' if args.service_account_key_file: try: service_account_key_data = hub_util.Base64EncodedFileContents( args.service_account_key_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( SERVICE_ACCOUNT_KEY_FILE_FLAG, e)) docker_credential_data = None if args.docker_credential_file: try: docker_credential_data = hub_util.Base64EncodedFileContents( args.docker_credential_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( DOCKER_CREDENTIAL_FILE_FLAG, e)) gke_cluster_self_link = kube_client.processor.gke_cluster_self_link issuer_url = None private_keyset_json = None if args.enable_workload_identity: # public_issuer_url can be None or given by user or gke_cluster_uri # (incase of a gke cluster). # args.public_issuer_url takes precedence over gke_cluster_uri. public_issuer_url = args.public_issuer_url or kube_client.processor.gke_cluster_uri or None try: openid_config_json = six.ensure_str( kube_client.GetOpenIDConfiguration( issuer_url=public_issuer_url), encoding='utf-8') except Exception as e: # pylint: disable=broad-except raise exceptions.Error( 'Error getting the OpenID Provider Configuration: ' '{}'.format(e)) # Extract the issuer URL from the discovery doc. issuer_url = json.loads(openid_config_json).get('issuer') if not issuer_url: raise exceptions.Error( 'Invalid OpenID Config: ' 'missing issuer: {}'.format(openid_config_json)) # Ensure public_issuer_url (only non-empty) matches what came back in # the discovery doc. if public_issuer_url and (public_issuer_url != issuer_url): raise exceptions.Error( '--public-issuer-url {} did not match issuer ' 'returned in discovery doc: {}'.format( public_issuer_url, issuer_url)) # Request the JWKS from the cluster if we need it (either for setting # up the GCS bucket or getting public keys for private issuers). In # the private issuer case, we set private_keyset_json, which is used # later to upload the JWKS in the Hub Membership. if self.ReleaseTrack() is base.ReleaseTrack.ALPHA: if args.manage_workload_identity_bucket: api_util.CreateWorkloadIdentityBucket( project, issuer_url, openid_config_json, kube_client.GetOpenIDKeyset()) elif args.has_private_issuer: private_keyset_json = kube_client.GetOpenIDKeyset() # Attempt to create a membership. already_exists = False obj = None # For backward compatiblity, check if a membership was previously created # using the cluster uuid. parent = api_util.ParentRef(project, 'global') membership_id = uuid resource_name = api_util.MembershipRef(project, 'global', uuid) obj = self._CheckMembershipWithUUID(resource_name, args.CLUSTER_NAME) if obj: # The membership exists and has the same description. already_exists = True else: # Attempt to create a new membership using cluster_name. membership_id = args.CLUSTER_NAME resource_name = api_util.MembershipRef(project, 'global', args.CLUSTER_NAME) try: self._VerifyClusterExclusivity(kube_client, parent, membership_id) obj = api_util.CreateMembership( project, args.CLUSTER_NAME, args.CLUSTER_NAME, gke_cluster_self_link, uuid, self.ReleaseTrack(), issuer_url, private_keyset_json) 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 obj = api_util.GetMembership(resource_name, self.ReleaseTrack()) if not obj.externalId: raise exceptions.Error( 'invalid membership {0} does not have ' 'external_id field set. We cannot determine ' 'if registration is requested against a ' 'valid existing Membership. Consult the ' 'documentation on container hub memberships ' 'update for more information or run gcloud ' 'container hub memberships delete {0} if you ' 'are sure that this is an invalid or ' 'otherwise stale Membership'.format(membership_id)) if obj.externalId != uuid: raise exceptions.Error( 'membership {0} already exists in the project' ' with another cluster. If this operation is' ' intended, please run `gcloud container ' 'hub memberships delete {0}` and register ' 'again.'.format(membership_id)) # The membership exists with same cluster_name. already_exists = True # In case of an existing membership, check with the user to upgrade the # Connect-Agent. if already_exists: # Update Membership when required. Scenarios that require updates: # 1. membership.authority is set, but there is now no issuer URL. # This means the user is disabling Workload Identity. # 2. membership.authority is not set, but there is now an # issuer URL. This means the user is enabling Workload Identity. # 3. membership.authority is set, but the issuer URL is different # from that set in membership.authority.issuer. This is technically # an error, but we defer to validation in the API. # 4. membership.authority.oidcJwks is set, but the private keyset # we got from the cluster differs from the keyset in the membership. # This means the user is updating the public keys, and we should # update to the latest keyset in the membership. if ( # scenario 1, disabling WI (obj.authority and not issuer_url) or # scenario 2, enabling WI (issuer_url and not obj.authority) or (obj.authority and # scenario 3, issuer changed ((obj.authority.issuer != issuer_url) or # scenario 4, JWKS changed (private_keyset_json and obj.authority.oidcJwks and (obj.authority.oidcJwks.decode('utf-8') != private_keyset_json))))): console_io.PromptContinue( message=hub_util.GenerateWIUpdateMsgString( obj, issuer_url, resource_name, args.CLUSTER_NAME), cancel_on_no=True) try: api_util.UpdateMembership( resource_name, obj, 'authority', self.ReleaseTrack(), issuer_url=issuer_url, oidc_jwks=private_keyset_json) log.status.Print( 'Updated the membership [{}] for the cluster [{}]'. format(resource_name, args.CLUSTER_NAME)) except Exception as e: raise exceptions.Error( 'Error in updating the membership [{}]:{}'.format( resource_name, e)) else: console_io.PromptContinue( message= 'A membership [{}] for the cluster [{}] already exists. ' 'Continuing will reinstall the Connect agent deployment to use a ' 'new image (if one is available).'.format( resource_name, args.CLUSTER_NAME), cancel_on_no=True) else: log.status.Print( 'Created a new membership [{}] for the cluster [{}]'. format(resource_name, args.CLUSTER_NAME)) # Attempt to update the existing agent deployment, or install a new agent # if necessary. try: self._InstallOrUpdateExclusivityArtifacts( kube_client, resource_name) agent_util.DeployConnectAgent(kube_client, args, service_account_key_data, docker_credential_data, resource_name, self.ReleaseTrack()) except Exception as e: log.status.Print( 'Error in installing the Connect Agent: {}'.format(e)) # In case of a new membership, we need to clean up membership and # resources if we failed to install the Connect Agent. if not already_exists: api_util.DeleteMembership(resource_name, self.ReleaseTrack()) exclusivity_util.DeleteMembershipResources(kube_client) raise log.status.Print( 'Finished registering the cluster [{}] with the Hub.'.format( args.CLUSTER_NAME)) return obj
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) # This incidentally verifies that the kubeconfig and context args are valid. with kube_util.KubernetesClient(args) as kube_client: kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) uuid = kube_util.GetClusterUUID(kube_client) # Read the service account files provided in the arguments early, in order # to catch invalid files before performing mutating operations. # Service Account key file is required if Workload Identity is not # enabled. # If Workload Identity is enabled, then the Connect Agent uses # a Kubernetes Service Account token instead and hence a GCP Service # Account key is not required. service_account_key_data = '' if args.service_account_key_file: try: service_account_key_data = hub_util.Base64EncodedFileContents( args.service_account_key_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( SERVICE_ACCOUNT_KEY_FILE_FLAG, e)) docker_credential_data = None if args.docker_credential_file: try: docker_credential_data = hub_util.Base64EncodedFileContents( args.docker_credential_file) except files.Error as e: raise exceptions.Error('Could not process {}: {}'.format( DOCKER_CREDENTIAL_FILE_FLAG, e)) gke_cluster_self_link = kube_client.processor.gke_cluster_self_link issuer_url = None # enable_workload_identity, public_issuer_url, and # manage_workload_identity_bucket are only properties if we are on the # alpha track if (self.ReleaseTrack() is base.ReleaseTrack.ALPHA and args.enable_workload_identity): if args.public_issuer_url: issuer_url = args.public_issuer_url # Use the user-provided public URL, and ignore the built-in endpoints. try: openid_config_json = kube_client.GetOpenIDConfiguration( issuer_url=args.public_issuer_url) except Exception as e: # pylint: disable=broad-except raise exceptions.Error( 'Please double check that --public-issuer-url was set ' 'correctly: {}'.format(e)) else: # Since the user didn't specify a public URL, try to use the cluster's # built-in endpoints. try: openid_config_json = kube_client.GetOpenIDConfiguration( ) except Exception as e: # pylint: disable=broad-except raise exceptions.Error( 'Please double check that it is possible to access the ' '/.well-known/openid-configuration endpoint on the cluster: ' '{}'.format(e)) # Extract the issuer URL from the discovery doc. issuer_url = json.loads(openid_config_json).get('issuer') if not issuer_url: raise exceptions.Error( 'Invalid OpenID Config: ' 'missing issuer: {}'.format(openid_config_json)) # If a public issuer URL was provided, ensure it matches what came back # in the discovery doc. elif args.public_issuer_url \ and args.public_issuer_url != issuer_url: raise exceptions.Error( '--public-issuer-url {} did not match issuer ' 'returned in discovery doc: {}'.format( args.public_issuer_url, issuer_url)) # Set up the GCS bucket that serves OpenID Provider Config and JWKS. if args.manage_workload_identity_bucket: openid_keyset_json = kube_client.GetOpenIDKeyset() api_util.CreateWorkloadIdentityBucket( project, issuer_url, openid_config_json, openid_keyset_json) # Attempt to create a membership. already_exists = False obj = None # For backward compatiblity, check if a membership was previously created # using the cluster uuid. parent = api_util.ParentRef(project, 'global') membership_id = uuid resource_name = api_util.MembershipRef(project, 'global', uuid) obj = self._CheckMembershipWithUUID(resource_name, args.CLUSTER_NAME) if obj: # The membership exists and has the same description. already_exists = True else: # Attempt to create a new membership using cluster_name. membership_id = args.CLUSTER_NAME resource_name = api_util.MembershipRef(project, 'global', args.CLUSTER_NAME) try: self._VerifyClusterExclusivity(kube_client, parent, membership_id) obj = api_util.CreateMembership(project, args.CLUSTER_NAME, args.CLUSTER_NAME, gke_cluster_self_link, uuid, self.ReleaseTrack(), issuer_url) 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 obj = api_util.GetMembership(resource_name, self.ReleaseTrack()) if not obj.externalId: raise exceptions.Error( 'invalid membership {} does not have ' 'external_id field set. We cannot determine ' 'if registration is requested against a ' 'valid existing Membership. Consult the ' 'documentation on container hub memberships ' 'update for more information or run gcloud ' 'container hub memberships delete {} if you ' 'are sure that this is an invalid or ' 'otherwise stale Membership'.format( membership_id, membership_id)) if obj.externalId != uuid: raise exceptions.Error( 'membership {} already exists in the project' ' with another cluster. If this operation is' ' intended, please run `gcloud container ' 'hub memberships delete {}` and register ' 'again.'.format(membership_id, membership_id)) # The membership exists with same cluster_name. already_exists = True # In case of an existing membership, check with the user to upgrade the # Connect-Agent. if already_exists: console_io.PromptContinue( message= 'A membership [{}] for the cluster [{}] already exists. ' 'Continuing will reinstall the Connect agent deployment to use a ' 'new image (if one is available).'.format( resource_name, args.CLUSTER_NAME), cancel_on_no=True) else: log.status.Print( 'Created a new membership [{}] for the cluster [{}]'. format(resource_name, args.CLUSTER_NAME)) # Attempt to update the existing agent deployment, or install a new agent # if necessary. try: self._InstallOrUpdateExclusivityArtifacts( kube_client, resource_name) agent_util.DeployConnectAgent(kube_client, args, service_account_key_data, docker_credential_data, resource_name, self.ReleaseTrack()) except Exception as e: log.status.Print( 'Error in installing the Connect Agent: {}'.format(e)) # In case of a new membership, we need to clean up membership and # resources if we failed to install the Connect Agent. if not already_exists: api_util.DeleteMembership(resource_name, self.ReleaseTrack()) exclusivity_util.DeleteMembershipResources(kube_client) raise log.status.Print( 'Finished registering the cluster [{}] with the Hub.'.format( args.CLUSTER_NAME)) return obj
def Process(unused_ref, args, req): arg_utils.SetFieldInMessage(req, api_field, arg_utils.GetFromNamespace(args, arg_name)) return req
def Run(self, args): project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True) kube_client = kube_util.KubernetesClient( gke_uri=getattr(args, 'gke_uri', None), gke_cluster=getattr(args, 'gke_cluster', None), kubeconfig=getattr(args, 'kubeconfig', None), context=getattr(args, 'context', None), public_issuer_url=getattr(args, 'public_issuer_url', None), enable_workload_identity=getattr(args, 'enable_workload_identity', False), ) location = getattr(args, 'location', 'global') if location is None: location = 'global' kube_client.CheckClusterAdminPermissions() kube_util.ValidateClusterIdentifierFlags(kube_client, args) membership_id = args.CLUSTER_NAME # Delete membership from Fleet API. try: name = 'projects/{}/locations/{}/memberships/{}'.format( project, location, membership_id) obj = api_util.GetMembership(name, self.ReleaseTrack()) if not obj.externalId: console_io.PromptContinue( 'invalid membership {0} does not have ' 'external_id field set. We cannot determine ' 'if registration is requested against a ' 'valid existing Membership. Consult the ' 'documentation on container fleet memberships ' 'update for more information or run gcloud ' 'container fleet memberships delete {0} if you ' 'are sure that this is an invalid or ' 'otherwise stale Membership'.format(membership_id), cancel_on_no=True) uuid = kube_util.GetClusterUUID(kube_client) if obj.externalId != uuid: raise exceptions.Error( 'Membership [{}] is not associated with the cluster you are trying' ' to unregister. Please double check the cluster identifier that you' ' have supplied.'.format(membership_id)) api_util.DeleteMembership(name, self.ReleaseTrack()) except apitools_exceptions.HttpUnauthorizedError as e: raise exceptions.Error( 'You are not authorized to unregister clusters from project [{}]. ' 'Underlying error: {}'.format(project, e)) except apitools_exceptions.HttpNotFoundError as e: log.status.Print( 'Membership [{}] for the cluster [{}] was not found on the Fleet. ' 'It may already have been deleted, or it may never have existed.' .format(name, args.CLUSTER_NAME)) # Get namespace for the connect resource label. selector = '{}={}'.format(agent_util.CONNECT_RESOURCE_LABEL, project) namespaces = kube_client.NamespacesWithLabelSelector(selector) if not namespaces: log.status.Print( 'There\'s no namespace for the label [{}]. ' 'If [gke-connect] is labeled with another project, ' 'You\'ll have to manually delete the namespace. ' 'You can find all namespaces by running:\n' ' `kubectl get ns -l {}`'.format( agent_util.CONNECT_RESOURCE_LABEL, agent_util.CONNECT_RESOURCE_LABEL)) # Delete in-cluster membership resources. try: parent = api_util.ParentRef(project, location) cr_manifest = kube_client.GetMembershipCR() res = api_util.ValidateExclusivity(cr_manifest, parent, membership_id, self.ReleaseTrack()) if res.status.code: console_io.PromptContinue( 'Error validating cluster\'s exclusivity state with the Fleet under ' 'parent collection [{}]: {}. The cluster you are trying to unregister' ' is not associated with the membership [{}]. Continuing will delete' ' membership related resources from your cluster, and the cluster' ' will lose its association to the Fleet in project [{}] and can be' ' registered into a different project. '.format( parent, res.status.message, membership_id, project), cancel_on_no=True) exclusivity_util.DeleteMembershipResources(kube_client) except exceptions.Error as e: log.status.Print( '{} error in deleting in-cluster membership resources. ' 'You can manually delete these membership related ' 'resources from your cluster by running the command:\n' ' `kubectl delete memberships membership`.\nBy doing so, ' 'the cluster will lose its association to the Fleet in ' 'project [{}] and can be registered into a different ' 'project. '.format(e, project)) # Delete the connect agent. agent_util.DeleteConnectNamespace(kube_client, args)