
    ԁ                     f   d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlmZ	 ddl
mZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlm Z  ddl!m"Z" ddl#m$Z$ ddl%Z%dZ&dZ'd Z(ejR                   G d dejT                               Z+y)z?The register command for registering a clusters with the fleet.    )absolute_import)division)unicode_literalsN)
exceptions)api_adapter)base)flags)
agent_util)api_util)exclusivity_util)	kube_util)	resources)util)gke_util)	arg_utils)log)
console_io)filesz--service-account-key-filez--docker-credential-filec                 h    t        | dd      }| j                  s|st        j                  dd      y y )Nenable_workload_identityFz5--enable-workload-identity --service-account-key-fileztOne of (--enable-workload-identity | --service-account-key-file) must be specified for Connect agent authentication.)getattrservice_account_key_filer   Error)argsr   s     3lib/surface/container/fleet/memberships/register.py$_ValidateConnectAgentCredentialFlagsr   /   sB    $T+EuM		&	&/G


?	>? ? 0H	&    c                   >    e Zd ZdZed        Zd Zd Zd Zd Z	d Z
y)	Registera7  Register a cluster with a fleet.

  This command registers a cluster with the fleet by:

    1. Creating a Fleet Membership resource corresponding to the cluster.
    2. Adding in-cluster Kubernetes Resources that make the cluster exclusive
       to one fleet.
    3. Installing the Connect agent into this cluster (optional for GKE).

  A successful registration implies that the cluster is now exclusive to a
  single Fleet. If the cluster is already registered to another Fleet, the
  registration will not be successful.

  To register a GKE cluster, use `--gke-cluster` or `--gke-uri` flag (no
  `--kubeconfig` flag is required). Connect agent will not be installed by
  default for GKE clusters. To install it, specify `--install-connect-agent`.
  The default value for `--location` is the same as the cluster's region or zone,
  can be specified as `global`.

  Anthos clusters on VMware, bare metal, AWS, and Azure are registered
  with a fleet when the clusters are created. To register Amazon EKS
  clusters, see
  [Attach your EKS cluster](https://cloud.google.com/anthos/clusters/docs/multi-cloud/attached/eks/how-to/attach-cluster).
  To regiser Microsoft Azure clusters, see
  [Attach your AKS cluster](https://cloud.google.com/anthos/clusters/docs/multi-cloud/attached/aks/how-to/attach-cluster).

  To register a third-party cluster, use --context flag (with an optional
  --kubeconfig flag). Connect agent will always be installed for these
  clusters.

  If Connect agent is to be installed, its authentication needs to be configured
  by `--enable-workload-identity` or `--service-account-key-file`. For the
  latter case, the corresponding service account must have been granted
  `gkehub.connect` permissions. For more information about Connect agent, go to:
  https://cloud.google.com/anthos/multicluster-management/connect/overview/

  Rerunning this command against the same cluster with the same MEMBERSHIP_NAME
  and target fleet is successful, and will upgrade the Connect agent if it is
  supposed to be installed and a newer version is available. Rerunning with
  `--enable-workload-identity` ensures that Workload Identity is enabled on the
  cluster.

  ## EXAMPLES

    Register a non-GKE cluster referenced from a specific
    kubeconfig file, and install the Connect agent:

      $ {command} my-cluster \
        --context=my-cluster-context \
        --kubeconfig=/home/user/custom_kubeconfig \
        --service-account-key-file=/tmp/keyfile.json

    Register a non-GKE cluster referenced from the default
    kubeconfig file, and install the Connect agent:

      $ {command} my-cluster \
        --context=my-cluster-context \
        --service-account-key-file=/tmp/keyfile.json

    Register a non-GKE cluster, and install a specific version
    of the Connect agent:

      $ {command} my-cluster \
        --context=my-cluster-context \
        --version=gkeconnect_20190802_02_00 \
        --service-account-key-file=/tmp/keyfile.json

    Register a non-GKE cluster and output a manifest that can be used to
    install the Connect agent by kubectl:

      $ {command} my-cluster \
        --context=my-cluster-context \
        --manifest-output-file=/tmp/manifest.yaml \
        --service-account-key-file=/tmp/keyfile.json

    Register a GKE cluster referenced from a GKE URI:

      $ {command} my-cluster \
        --gke-uri=my-cluster-gke-uri

    Register a GKE cluster referenced from a GKE URI, and install the Connect
    agent using service account key file:

      $ {command} my-cluster \
        --gke-uri=my-cluster-gke-uri \
        --install-connect-agent \
        --service-account-key-file=/tmp/keyfile.json

    Register a GKE cluster and output a manifest that can be used to
    install the Connect agent by kubectl:

      $ {command} my-cluster \
        --gke-uri=my-cluster-gke-uri \
        --enable-workload-identity \
        --install-connect-agent \
        --manifest-output-file=/tmp/manifest.yaml

    Register a GKE cluster first, and install the Connect agent later.

      $ {command} my-cluster \
        --gke-cluster=my-cluster-region-or-zone/my-cluster

      $ {command} my-cluster \
        --gke-cluster=my-cluster-region-or-zone/my-cluster \
        --install-connect-agent \
        --enable-workload-identity

    Register a GKE cluster, and install a specific version of the Connect
    agent:

      $ {command} my-cluster \
        --gke-cluster=my-cluster-region-or-zone/my-cluster \
        --install-connect-agent \
        --version=20220819-00-00 \
        --service-account-key-file=/tmp/keyfile.json

    Register a GKE cluster and output a manifest that can be used to install the
    Connect agent:

      $ {command} my-cluster \
        --gke-uri=my-cluster-gke-uri \
        --install-connect-agent \
        --manifest-output-file=/tmp/manifest.yaml \
        --service-account-key-file=/tmp/keyfile.json
  c                 D   t        j                  |t        j                  d      t        j                  d      dd       t	        j
                  |       |j                  ddt        j                  d      d	       |j                  d
t        t        j                  d             |j                  dt        t        j                  d             |j                  dt        dt        j                  d             |j                  t        t        dt        j                  d             |j                  dt        dt        j                  d             |j                  ddd       | j                         t        j                  j                  ur*|j                  ddd       |j                  dddd d       |j                         }|j                  t        t        t        j                  d             |j                  d       }|j                  d!ddt        j                  d"      #       |j                  d$      }|j                  d%t        t        j                  d&             |j                  d'dt        j                  d(      )       y )*Nz          The membership name that you choose to uniquely represents the cluster
          being registered in the fleet.
        z          The location for the membership resource, e.g. `us-central1`.
          If not specified, defaults to `global`. Not supported for GKE clusters,
          whose membership location will be the location of the cluster.
        T)membership_helplocation_helpmembership_required
positionalz--install-connect-agent
store_truez          If set to True for a GKE cluster, Connect agent will be installed in
          the cluster. No-op for Non-GKE clusters, where Connect agent will
          always be installed.
          F)actionhelpdefaultz--manifest-output-fileaC              The full path of the file into which the Connect agent installation
            manifest should be stored. If this option is provided, then the
            manifest will be written to this file and will not be deployed into
            the cluster by gcloud, and it will need to be deployed manually.
          )typer'   z--proxyz            The proxy address in the format of http[s]://{hostname}. The proxy
            must support the HTTP CONNECT method in order for this connection to
            succeed.
          z	--versionz{          The version of the Connect agent to install/upgrade if not using the
          latest connect version.
          )r)   hiddenr'   z          The credentials to be used if a private registry is provided and auth
          is required. The contents of the file will be stored into a Secret and
          referenced from the imagePullSecrets of the Connect agent workload.
          z--docker-registryz_        The registry to pull GKE Connect agent image if not using gcr.io/gkeconnect.
          z--internal-ipz?Whether to use the internal IP address of the cluster endpoint.)r'   r&   z--cross-connect-subnetworkz;full path of cross connect subnet whose endpoint to persist)r*   r'   z--private-endpoint-fqdnz#whether to persist the private fqdn)r'   r*   r(   r&   a              The JSON file of a Google Cloud service account private key. This
            service account key is stored as a secret named ``creds-gcp'' in
            gke-connect namespace. To update the ``creds-gcp'' secret in
            gke-connect namespace with a new service account key file, run the
            following command:

            kubectl delete secret creds-gcp -n gke-connect

            kubectl create secret generic creds-gcp -n gke-connect --from-file=creds-gcp.json=/path/to/file
         zWorkload Identity)r'   z--enable-workload-identitya            Enable Workload Identity when registering the cluster with a fleet.
          Ensure that GKE Workload Identity is enabled on your GKE cluster, it
          is a requirement for using Workload Identity with memberships. Refer
          to the `Enable GKE Workload Identity` section in
          https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable
          --service_account_key_file flag should not be set if this is set.
          )requiredr&   r'   )mutexz--public-issuer-urlat            Skip auto-discovery and register the cluster with this issuer URL.
          Use this option when the OpenID Provider Configuration and associated
          JSON Web Key Set for validating the cluster's service account JWTs
          are served at a public endpoint different from the cluster API server.
          Requires --enable-workload-identity.
          z--has-private-issueraE            Set to true for clusters where no publicly-routable OIDC discovery
          endpoint for the Kubernetes service account token issuer exists.

          When set to true, the gcloud command-line tool will read the
          private issuer URL and JSON Web Key Set (JWKS) (public keys) for
          validating service account tokens from the cluster's API server
          and upload both when creating the Membership. Google Cloud Platform
          will then use the JWKS, instead of a public OIDC endpoint,
          to validate service account tokens issued by this cluster.
          Note the JWKS establishes the uniqueness of issuers in this
          configuration, but issuer claims in tokens are still compared to the
          issuer URL associated with the Membership when validating tokens.

          Note the cluster's OIDC discovery endpoints
          (https://[KUBE-API-ADDRESS]/.well-known/openid-configuration and
          https://[KUBE-API-ADDRESS]/openid/v1/jwks) must still be
          network-accessible to the gcloud client running this command.
          )r&   r'   )r   AddMembershipResourceArgtextwrapdedenthub_utilAddClusterConnectionCommonArgsadd_argumentstrDOCKER_CREDENTIAL_FILE_FLAGReleaseTrackr   GAadd_mutually_exclusive_groupSERVICE_ACCOUNT_KEY_FILE_FLAG	add_group)clsparsercredentialsworkload_identityworkload_identity_mutexs        r   ArgszRegister.Args   s   &&  )  oo ' 
 ! ++F3
!__  
   	  __    	 __     __  	   #__  	  	 __  	   N   !2!2!5!55
&L  N 
#4   557K%__ 
 
  & $--3F-G""$__  	 #  0999E((__   ) 
 ((__   ) r   c                    t        j                  |dd      }| j                         t        j                  j                  u s*| j                         t        j                  j
                  u rt        j                  d      }nt        j                  d      }d}|j                  r|j                  }n*t        j                  |      rt        j                  |      }t        j                  |j                  d      |j                  d      	      \  }}|j                  d
      }|r(|r&|j                  d      st        j                  d      |r&|j                  d      s| j!                  |||||      S t#        |       t%        j&                  |t)        |dd       t)        |dd       t)        |dd       t)        |dd      t)        |dd       t)        |dd       t)        |dd       t)        |dd       t)        |dd      
      5 }|j+                          t%        j,                  ||       | j                         t        j                  j.                  urt1        j2                  |       t%        j4                  |      }	d}
|j6                  r 	 t        j8                  |j6                        }
d }|j@                  rJ	 t;        jB                  t;        jD                  |j@                              }tG        jH                  |d      }|jL                  jN                  }d }d }|jP                  r|jR                  xs |jL                  jT                  xs d }	 tG        jH                  |jW                  |      d      }t[        j\                  |      j_                  d      }|s$t        j                  dj=                  |            |r*||k7  r%t        j                  dj=                  ||            |j`                  r|jc                         }d}te        jf                  ||      }te        jh                  |||	      }| jk                  ||jl                        }t%        jn                  |      }|rd}n|jl                  }te        jh                  |||jl                        }	 | jq                  |||       te        jr                  ||jl                  |||	| j                         |||	      }| ju                  ||       |ra|j                  r|rt|r|j                  rf|j                  r|j                  j                  |k7  s@|r|j                  j                  r|j                  j                  j                  d      |k7  rt        j                  t        j                  ||||jl                        d"       	 te        j                  ||d#| j                         ||$       | ju                  ||       t        j                  j                  d%j=                  ||jl                               nkt        j                  d'j=                  ||jl                        d"       n9t        j                  j                  d(j=                  ||jl                               	 t        j                  |||
||| j                                t        j                  j                  d*j=                  |jl                               |cd d d        S # t:        j                  $ r.}t        j                  dj=                  t>        |            d }~ww xY w# t:        j                  $ r.}t        j                  dj=                  tJ        |            d }~ww xY w# tX        $ r)}t        j                  dj=                  |            d }~ww xY w# tv        jx                  $ r}t{        j|                  |      }|j~                  dk7  r te        j                  || j                               }|j                  s$t        j                  d j=                  |            |j                  |	k7  r$t        j                  d!j=                  |            d}Y d }~d }~ww xY w# tX        $ r*}t        j                  d&j=                  ||            d }~ww xY w# tX        $ ro}t        j                  j                  d)j=                  |             |s9te        j                  || j                                t        j                  |        d }~ww xY w# 1 sw Y   y xY w)+Nz	--projectT)use_defaultsv1beta1v1globalgke_urigke_cluster)rE   rF   manifest_output_fileinstall_connect_agentzfFor GKE clusters,  "manifest-output-file" should be specified together with "install-connect-agent".  
kubeconfiginternal_ipFcross_connect_subnetworkprivate_endpoint_fqdncontextpublic_issuer_urlr   )
r   rE   rF   rI   rJ   rK   rL   rM   rN   r    zCould not process {}: {}zutf-8)encoding)
issuer_urlz3Error getting the OpenID Provider Configuration: {}issuerz)Invalid OpenID Config: missing issuer: {}zI--public-issuer-url {} did not match issuer returned in discovery doc: {}ALREADY_EXISTSaa  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 Membershipzmembership {0} already exists in the project with another cluster. If this operation is intended, please run `gcloud container fleet memberships delete {0}` and register again.)messagecancel_on_no	authority)rQ   	oidc_jwksz0Updated the membership [{}] for the cluster [{}]z(Error in updating the membership [{}]:{}zA membership [{}] for the cluster [{}] already exists. Continuing will reinstall the Connect agent deployment to use a new image (if one is available).z2Created a new membership [{}] for the cluster [{}]z)Error in installing the Connect agent: {}z5Finished registering the cluster [{}] with the fleet.)Rr   GetFromNamespacer5   r   BETAALPHAgke_api_adapterNewAPIAdapterlocationr0   LocationFromGKEArgsr   GetGKEClusterResoureLinkAndURIGetValuer   r   _RegisterGKEWithoutConnectAgentr   r   KubernetesClientr   CheckClusterAdminPermissionsValidateClusterIdentifierFlagsr6   r	   VerifyGetCredentialsFlagsGetClusterUUIDr   Base64EncodedFileContentsr   formatr8   docker_credential_fileReadBinaryFileContentsExpandHomeDirsix
ensure_strr4   	processorgke_cluster_self_linkr   rN   gke_cluster_uriGetOpenIDConfiguration	Exceptionjsonloadsgethas_private_issuerGetOpenIDKeysetr   	ParentRefMembershipRef_CheckMembershipWithUUIDMEMBERSHIP_NAMEGetClusterServerVersion_VerifyClusterExclusivityCreateMembership$_InstallOrUpdateExclusivityArtifactsapitools_exceptionsHttpConflictErrorcore_api_exceptionsHttpErrorPayloadstatus_descriptionGetMembership
externalIdrV   rR   oidcJwksdecoder   PromptContinueGenerateWIUpdateMsgStringUpdateMembershipr   statusPrintr
   DeployConnectAgentDeleteMembershipr   DeleteMembershipResources)selfr   projectr   r]   gke_cluster_resource_linkrp   manifest_pathkube_clientuuidservice_account_key_dataedocker_credential_datafile_contentro   rQ   private_keyset_jsonrN   openid_config_jsonalready_existsparentresource_nameobjapi_server_versionmembership_iderrors                             r   RunzRegister.RunV  sp   (({NGd//4448I8I 9				 	 9!#11)<k#11$7kH }}h		%	%d	+--d3h191X1Xi(MM-022. MM"89M!566  !7N)O11
#_gx  ).		#	#i.D-64t4D-7!(/I)-"/%d,CTJi.!$(;TB!(/I)."0
 
..0..{DA				D$5$5$8$8	8''-%%k2d "$		&	&	1%-%G%G++&-
"  $		$	$	/55!!$"="=>@,#&>>W$.
  *33IIj 		&	&
 "" $$44 		"~~00<M0N  
 ZZ 2377A
  ##)6*<#=? ?
 "3z"A   "AAG%6
BDE E "" + ; ; =
 n !!'84f,,WhEm))-9M9MNc %<<[I	 ,, ..w/3/C/CE#	 

(
(fm
L))'43G3G*24I4*.*;*;*=z*=*<	># 
3
3K
O> 
 ]]:]]}}##z1"s}}'='=&&--g6:MM

#
#88z=$2F2FH!'%%!!#%-/ 55k6CEJJBII!4#7#79: 
#
#1178<8L8L2N! 	

@GGt335	6%%k4&>&<m&*&7&7&9	; 
jj
A
H
H""$% {
 
> {{ 	1  !;!B!B+Q"0 1 1	1 {{ 	/  !;!B!B)1". / /	/*  	  6!9 	h #44 	 %66q9%%%)99&&}d6G6G6IJ#""- .4VM-B	D 	D ^^t#""  .0 0  .5	 P  '"":AA!1&' ''.  

DKKANO 

#
#M43D3D3F
G

4
4[
Ae
 
s   B	e\.e=A	]Ae'^<D$e!A_;B<e8A4b,A,e(c9e])]  ]e^	)^^		e	^>$^99^>>ebB.bebe	c%b>>ce	d>A*d99d>>ee
c           
      b   d}	 t        j                  || j                               }t        |d      ra|j                  |k7  rRt        j                  dj                  |j                  |t        j                  | j                               |            |S # t        j                  $ r Y |S w xY w)a  Checks for an existing Membership with UUID.

    In the past, by default we used Cluster UUID to create a membership. Now
    we use user supplied membership_name. This check ensures that we don't
    reregister a cluster.

    Args:
      resource_name: The full membership resource name using the cluster uuid.
      membership_name: User supplied membership_name.

    Returns:
     The Membership resource or None.

    Raises:
      exceptions.Error: If it fails to getMembership.
    NdescriptionzThere is an existing membership, [{}], that conflicts with [{}]. Please delete it before continuing:

  gcloud {}container fleet memberships delete {})r   r   r5   hasattrr   r   r   rh   r0   ReleaseTrackCommandPrefixr   HttpNotFoundError)r   r   membership_namer   s       r   rz   z!Register._CheckMembershipWithUUID_  s    " C""=$2C2C2EFc
#}
%#//_*L ??Ev2243D3D3FG@  	  J	 00  J	s   BB B.-B.c                 2   d}|j                         r|j                         }t        j                  |||| j	                               }|j
                  j                  r9t        j                  dj                  ||j
                  j                              y)a  Verifies that the cluster can be registered to the project.

    Args:
      kube_client: a KubernetesClient
      parent: the parent collection the user is attempting to register the
        cluster with.
      membership_id: the ID of the membership to be created for the cluster.

    Raises:
      apitools.base.py.HttpError: if the API request returns an HTTP error.
      exceptions.Error: if the cluster is in an invalid exclusivity state.
    rO   zError validating cluster's exclusivity state with the Fleet under parent collection [{}]: {}. Cannot proceed with the cluster registration.N)MembershipCRDExistsGetMembershipCRr   ValidateExclusivityr5   r   coder   r   rh   rT   )r   r   r   r   cr_manifestress         r   r}   z"Register._VerifyClusterExclusivity  s     K&&(//1k

&
&{FM'+'8'8':<C zz::@&cjj((;*+ + r   c                     |j                         }|r|j                         nd}t        j                  |||      }|j	                  |j
                  |j                         y)a  Install the exclusivity artifacts for the cluster.

    Update the exclusivity artifacts if a new version is available if the
    cluster has already being registered.

    Args:
      kube_client: a KubernetesClient
      membership_ref: the full resource name of the membership the cluster is
        registered with.

    Raises:
      apitools.base.py.HttpError: if the API request returns an HTTP error.
      exceptions.Error: if the kubectl interation with the cluster failed.
    rO   N)GetMembershipCRDr   r   GenerateExclusivityManifestApplyMembershipcrdManifest
crManifest)r   r   membership_refcrd_manifestr   r   s         r   r   z-Register._InstallOrUpdateExclusivityArtifacts  sS     //1L3?+--/RK

.
.|[/=?C@r   c                    d}|j                   r|}	 t        j                  ||j                  ||d| j	                         |dd	      }t        j                   j#                  d
       |S # t
        j                  $ r}t        j                  |      }	|	j                  dk7  r t        j                  |||j                        }
t        j                  |
| j	                               }|j                  j                  j                  |k(  r"t        j                   j#                  dj%                  |
|j                  j                  j                               |r|j&                  r|j&                  j(                  |k7  r	 t        j*                  |
|d|d| j	                                t        j                   j#                  dj%                  |j                  j                  j                               ny# t,        $ r*}t/        j0                  dj%                  |
|            d}~ww xY wt/        j0                  d	j%                  |
|j                  j                  j                              Y d}~.d}~ww xY w)z8Register a GKE cluster without installing Connect agent.N)	r   r   r]   ro   external_idrelease_trackrQ   rW   r   rS   zFMembership [{}] already registered with the cluster [{}] in the Fleet.rV   )name
membershipupdate_maskrQ   rW   r   z.Enabled Workload Identity for the cluster [{}]z)Error in updating the membership [{}]: {}zmembership [{}] already exists in the Fleet with another cluster link [{}]. If this operation is intended, please delete the membership and register again.z"Finished registering to the Fleet.)r   r   r~   r{   r5   r   r   r   r   r   ry   r   endpoint
gkeClusterresourceLinkr   r   r   rh   rV   rR   r   rr   r   r   )r   r   rp   r   r]   r   rQ   r   
create_excr   r   
update_excs               r   ra   z(Register._RegisterGKEWithoutConnectAgent  s1    J$$"j3C%%,, 9))+!	#ch JJ9:JW 00 (C!22:>e		!	!%5	5,,Wh-1-A-ACm""=$2C2C2EFc		 	 	-	-1J	J

fs||66CC	
  3==#7#7:#E2''$ )'  $ 1 1 35 jjBIIll--::<=  2$$=DD#Z12 22
  VMLL33@@B	C 	CG(Cs>   6A) )I;=DI6A5G76I67	H* %H%%H**AI66I;N)__name__
__module____qualname____doc__classmethodr?   r   rz   r}   r   ra    r   r   r   r   8   s=    || [ [zGR%N+:A*=r   r   ),r   
__future__r   r   r   rs   r.   apitools.base.pyr   r    googlecloudsdk.api_lib.containerr   r[   googlecloudsdk.api_lib.utilr   googlecloudsdk.callioper   $googlecloudsdk.command_lib.containerr	   *googlecloudsdk.command_lib.container.fleetr
   r   r   r   r   r   r0   6googlecloudsdk.command_lib.container.fleet.membershipsr   $googlecloudsdk.command_lib.util.apisr   googlecloudsdk.corer   googlecloudsdk.core.consoler   googlecloudsdk.core.utilr   rl   r8   r4   r   DefaultUniverseOnlyCreateCommandr   r   r   r   <module>r      s    F &  '   > K I ( 6 A ? G @ @ G K : * # 2 * 
 < 8 ? |
t!! |
 |
r   