
    m                     D   d 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dl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Z)dZ*dZ+dZ, G d dejZ                        Z. G d dejZ                        Z/d Z0d Z1d  Z2 G d! d"e3      Z4 G d# d$e3      Z5 G d% d&ejl                        Z7 G d' d(e3      Z8 G d) d*e3      Z9 G d+ d,e3      Z:d- Z;d. Z<d/ Z=y)0z5Utils for Kubernetes Operations for GKE Hub commands.    )absolute_import)division)print_function)unicode_literalsN)api_adapter)
kubeconfig)util)waiter)
exceptions)format_util)gke_util)execution_utils)log)
properties)requests)encoding)files)client)config)urljoini i:  i  c                       e Zd ZdZy)	RBACErrorz,Class for errors raised by GKE Hub commands.N__name__
__module____qualname____doc__     ;lib/googlecloudsdk/command_lib/container/fleet/kube_util.pyr   r   4   s    4r   r   c                       e Zd ZdZy)KubectlErrorz5Class for errors raised when shelling out to kubectl.Nr   r   r   r    r"   r"   8   s    =r   r"   c                 $    | j                  d      S )aH  Gets the UUID of the kube-system namespace.

  Args:
    kube_client: A KubernetesClient.

  Returns:
    the namespace UID

  Raises:
    exceptions.Error: If the UID cannot be acquired.
    calliope_exceptions.MinimumArgumentException: if a kubeconfig file cannot be
      deduced from the command line flags or environment
  zkube-system)GetNamespaceUIDkube_clients    r    GetClusterUUIDr'   <   s     
	$	$]	33r   c                 "    | j                         S )ad  Gets the UUID of the kube-system namespace.

  Args:
    kube_client: A KubernetesClient.

  Returns:
    the cluster server version

  Raises:
    exceptions.Error: If the cluster server version cannot be acquired.
    calliope_exceptions.MinimumArgumentException: if a kubeconfig file cannot be
      deduced from the command line flags or environment
  )GetServerVersionr%   s    r    GetClusterServerVersionr*   M   s     
	%	%	''r   c           	         | j                  |      ry	 t        j                  t               t	        ||       dj                  |      t        t        t        t              \  }}|s%t        j                  dj                  ||            yy# t        j                  $ r% t        j                  dj                  |            w xY w)zDelete a namespace from the cluster.

  Args:
    kube_client: The KubernetesClient towards the cluster.
    namespace: the namespace of connect agent deployment.

  Raises:
    exceptions.Error: if failed to delete the namespace.
  z&Deleting namespace [{}] in the clusterpre_start_sleep_msmax_wait_mswait_ceiling_mssleep_msz-Could not delete namespace [{}] from cluster.z7Could not delete namespace [{}] from cluster. Error: {}N)NamespaceExistsr
   WaitForKubernetesPollerNamespaceDeleteOperationformat"NAMESPACE_DELETION_INITIAL_WAIT_MSNAMESPACE_DELETION_TIMEOUT_MS'NAMESPACE_DELETION_MAX_POLL_INTERVAL_MS+NAMESPACE_DELETION_INITIAL_POLL_INTERVAL_MSTimeoutErrorr   Error)r&   	namespace	succeedederrors       r    DeleteNamespacer?   ^   s       +


"9k
:
2
9
9)
D?3A>i  
C
J
J  % ,   
9
@
@
K s   AB 8Cc                   *    e Zd ZdZdZdZd Zd Zd Zy)MembershipCRDCreationOperationz;An operation that waits for a membership CRD to be created.	unchanged
configuredc                 J    || _         d| _        d| _        d | _        || _        y NF)r&   doner=   r>   membership_crd_manifest)selfr&   rG   s      r    __init__z'MembershipCRDCreationOperation.__init__   s'    "DDIDNDJ#:D r   c                      y)Nz<creating membership CRD>r   rH   s    r    __str__z&MembershipCRDCreationOperation.__str__   s    &r   c                     | j                   j                  | j                        \  }}|rd| _        || _        y| j
                  |v s| j                  |v rd| _        d| _        yy)zBUpdates this operation with the latest membership creation status.TN)r&   CreateMembershipCRDrG   rF   r>   CREATED_KEYWORDCONFIGURED_KEYWORDr=   rH   outerrs      r    Updatez%MembershipCRDCreationOperation.Update   si    33$$HC didj 
			$(?(?3(Fdidn )Gr   N)	r   r   r   r   rO   rP   rI   rL   rT   r   r   r    rA   rA      s    C/#;'r   rA   c                   $    e Zd ZdZd Zd ZddZy)KubeconfigProcessorz?A helper class that processes kubeconfig and context arguments.c	                     || _         || _        || _        || _        || _        || _        || _        || _        t        j                         st        j                  d      d| _        d| _        y)a8  Constructor for KubeconfigProcessor.

    Args:
      api_adapter: the GKE api adapter used for running kubernetes commands
      gke_uri: the URI of the GKE cluster; for example,
        'https://container.googleapis.com/v1/projects/my-project/locations/us-central1-a/clusters/my-cluster'
      gke_cluster: the "location/name" of the GKE cluster. The location can be a
        zone or a region for e.g `us-central1-a/my-cluster`
      kubeconfig: the kubeconfig path
      internal_ip: whether to persist the internal IP of the endpoint.
      cross_connect_subnetwork: full path of the cross connect subnet whose
        endpoint to persist (optional)
      private_endpoint_fqdn: whether to persist the private fqdn.
      context: the context to use

    Raises:
      exceptions.Error: if kubectl is not installed
    zkubectl not installed.N)r   gke_urigke_clusterr   internal_ipcross_connect_subnetworkprivate_endpoint_fqdncontextc_utilCheckKubectlInstalledr   r;   gke_cluster_self_linkgke_cluster_uri)	rH   r   rX   rY   r   rZ   r[   r\   r]   s	            r    rI   zKubeconfigProcessor.__init__   so    < #DDL"D DO"D$<D!!6DDL'')566!%DDr   c           
      4   | j                   s| j                  rd}| j                   r$t        j                  | j                         \  }}}nTt        j
                  j                  j                  j                         }t        j                  | j                        \  }}t        j                  |||      \  | _        | _        t        | j                  ||||| j                  | j                   | j"                        dfS | j$                  sIt'        j(                  t*        j,                  d      r%t'        j(                  t*        j,                  d      ry| j$                  xs( t'        j(                  t*        j,                  d      xs d}t/        j0                  |      }|st3        j4                  dgd      t6        j8                  j;                  |      }| j<                  }||j>                  vr%tA        jB                  d	jE                  ||            ||fS )
a  Gets the kubeconfig, cluster context and resource link from arguments and defaults.

    Args:
      temp_kubeconfig_dir: a TemporaryDirectoryObject.

    Returns:
      the kubeconfig filepath and context name

    Raises:
      calliope_exceptions.MinimumArgumentException: if a kubeconfig file cannot
        be deduced from the command line flags or environment
      exceptions.Error: if the context does not exist in the deduced kubeconfig
        file
    NKUBERNETES_SERVICE_PORTKUBERNETES_SERVICE_HOSTNN
KUBECONFIGz~/.kube/config--kubeconfigzoPlease specify --kubeconfig, set the $KUBECONFIG environment variable, or ensure that $HOME/.kube/config existsz.context [{}] does not exist in kubeconfig [{}])#rX   rY   r   ParseGKEURIr   VALUEScoreproject	GetOrFailParseGKECluster%ConstructGKEClusterResourceLinkAndURIr`   ra   _GetGKEKubeconfigr   rZ   r[   r\   r   r   GetEncodedValueosenvironr   ExpandHomeDircalliope_exceptionsMinimumArgumentExceptionkconfig
KubeconfigLoadFromFiler]   contextsr   r;   r5   )	rH   temp_kubeconfig_dircluster_projectlocationnamekubeconfig_filer   kccontext_names	            r    GetKubeconfigAndContextz+KubeconfigProcessor.GetKubeconfigAndContext   s   " ||t''o	*2*>*>t||*L'4$++0088BBD!11$2B2BC$ 
8
8x 7d $"6 !++((	  ( OO$$RZZ1JK$$RZZ1JK 	 	##BJJ=	  $$_5J88
? 
 
			(	(	4B<<L2;;&
:
A
AJ  |##r   Nc                     |+t        j                  ||       t        j                         S t        j                          t        j                         S )a  Gets a client derived from the kubeconfig and context.

    Args:
      kubeconfig: path to a kubeconfig file, None if in-cluster config.
      context: the kubeconfig context to use, None if in-cluster config.

    Returns:
      kubernetes.client.ApiClient
    )config_filer]   )kube_client_configload_kube_configkube_client_lib	ApiClientload_incluster_config)rH   r   r]   s      r    GetKubeClientz!KubeconfigProcessor.GetKubeClient#  sI     )) ' &&((..0&&((r   re   )r   r   r   r   rI   r   r   r   r   r    rV   rV      s    G* XP$d)r   rV   c                   "    e Zd ZdZd Zd Zd Zy)r3   zGAn OperationPoller that polls operations targeting Kubernetes clusters.c                     |j                   S N)rF   rH   	operations     r    IsDonezKubernetesPoller.IsDone=  s    >>r   c                 &    |j                          |S r   )rT   )rH   operation_refs     r    PollzKubernetesPoller.Poll@  s    r   c                 2    |j                   |j                  fS r   )r=   r>   r   s     r    	GetResultzKubernetesPoller.GetResultD  s    11r   N)r   r   r   r   r   r   r   r   r   r    r3   r3   :  s    O2r   r3   c                       e Zd ZdZ	 	 	 	 	 	 	 	 	 	 d%dZd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd&dZ d&d Z!d&d!Z"d&d"Z#d'd#Z$d&d$Z%y)(KubernetesClientz6A client for accessing a subset of the Kubernetes API.Nc           
         d| _         d| _        |s|rt        j                         | _        t	        ||||||||      | _        | j
                  j                  | j                        \  | _        | _        |	s|
r| j
                  j                  ry|
r6| j
                  j                  | j                  | j                        | _        yy)a=  Constructor for KubernetesClient.

    Args:
      api_adapter: the GKE api adapter used for running kubernetes commands
      gke_uri: the URI of the GKE cluster; for example,
        'https://container.googleapis.com/v1/projects/my-project/locations/us-central1-a/clusters/my-cluster'
      gke_cluster: the "location/name" of the GKE cluster. The location can be a
        zone or a region for e.g `us-central1-a/my-cluster`
      kubeconfig: the kubeconfig path
      internal_ip: whether to persist the internal IP of the endpoint.
      cross_connect_subnetwork: full path of the cross connect subnet whose
        endpoint to persist (optional)
      private_endpoint_fqdn: whether to persist the private fqdn.
      context: the context to use
      public_issuer_url: the public issuer url
      enable_workload_identity: whether to enable workload identity

    Raises:
      exceptions.Error: if the client cannot be configured
      calliope_exceptions.MinimumArgumentException: if a kubeconfig file
        cannot be deduced from the command line flags or environment
    20sN)r   rX   rY   r   rZ   r[   r\   r]   )kubectl_timeoutrz   r   TemporaryDirectoryrV   	processorr   r   r]   ra   r   r&   )rH   r   rX   rY   r   rZ   r[   r\   r]   public_issuer_urlenable_workload_identitys              r    rI   zKubernetesClient.__init__K  s    F !D#D +!&!9!9!;d(!93	DN %)NN$J$J  %!DOT\  T^^%C%C55
//4<<d  r   c                     | S r   r   rK   s    r    	__enter__zKubernetesClient.__enter__  s    Kr   c                 R    | j                   | j                   j                          y y r   )rz   Close)rH   _s     r    __exit__zKubernetesClient.__exit__  s%    +
$$& ,r   c                     | j                  g dd      \  }}|rt        dj                  |            d|vrt        d      y)zCheck to see if the user can perform all the actions in any namespace.

    Raises:
      KubectlError: if failing to get check for cluster-admin permissions.
      RBACError: if cluster-admin permissions are not found.
    )authzcan-i*r   z--all-namespacesNz2Failed to check if the user is a cluster-admin: {}yesae  Missing cluster-admin RBAC role: The cluster-admin role-based accesscontrol (RBAC) ClusterRole grants you the cluster permissions necessary to connect your clusters back to Google. 
To create a ClusterRoleBinding resource in the cluster, run the following command:

kubectl create clusterrolebinding [BINDING_NAME]  --clusterrole cluster-admin --user [USER])_RunKubectlr"   r5   r   rQ   s      r    CheckClusterAdminPermissionsz-KubernetesClient.CheckClusterAdminPermissions  s^     7HC 
>
E
Ec
J  C(  r   c                     | j                  dd|ddgd       \  }}|r$t        j                  dj                  |            |j	                  dd      S )Ngetr<   -ozjsonpath='{.metadata.uid}'z(Failed to get the UID of the cluster: {}' )r   r   r;   r5   replacerH   r<   rR   rS   s       r    r$   z KubernetesClient.GetNamespaceUID  sa    	Y.JKHC 
4
;
;C
@  ;;sBr   c                     | j                  g dd      \  }}|r$t        j                  dj                  |            t	        j
                  |      }|d   d   dz   |d   d   z   }|S )zGet server version of the cluster.

    Raises:
      exceptions.Error: if failing to get namespaces.

    Returns:
      Server version of the cluster in major.minor format (e.g. 1.21)
    )versionr   jsonNz3Failed to get the server version of the cluster: {}serverVersionmajor.minor)r   r   r;   r5   r   loads)rH   rR   rS   version_strs       r    r)   z!KubernetesClient.GetServerVersion  s|      94@HC

?
F
Fs
K  **S/COW%+c/.B7.KK  r   c                 j    | j                  ddd|z   dgd      \  }}|rt        j                         |S )z!Get k8s events for the namespace.r   eventsz--namespace=z--sort-by='{.lastTimestamp}'N)r   r   r;   r   s       r    	GetEventszKubernetesClient.GetEvents  sJ    Y&*		
 	HC Jr   c                 Z   | j                  ddd|ddgd      \  }}|r$t        j                  dj                  |            |dk(  rg S | j                  ddd|dd	gd      \  }}|r$t        j                  dj                  |            |r|j	                         j                  d
      S g S )zGet the Connect Agent namespace by label.

    Args:
      label: the label used for namespace selection

    Raises:
      exceptions.Error: if failing to get namespaces.

    Returns:
      The first namespace with the label selector.
    r   
namespacesz
--selectorr   zjsonpath={.items}Nz,Failed to list namespaces in the cluster: {}z[]z"jsonpath={.items[0].metadata.name} )r   r   r;   r5   stripsplit)rH   labelrR   rS   s       r    NamespacesWithLabelSelectorz,KubernetesClient.NamespacesWithLabelSelector  s     	lE49LMHC 
8
?
?
D  d{i0	
 	
HC 
8
?
?
D  &)399;S!0b0r   c                 2    | j                  g d      \  }}|S )N)delete
membershipr   r   rH   r   rS   s      r    DeleteMembershipz!KubernetesClient.DeleteMembership  s    DEFAsJr   c                    t        j                  d      }t        j                  d      }|j                  |j                               rA| j	                  dd|ddg      \  }}|r$t        j                  dj                  |            |S |j                  |j                               rA| j	                  dd|ddg      \  }}|r$t        j                  dj                  |            |S y	)
)Get the RBAC cluster role binding policy.^clusterrole/^role/r   clusterrolebindingr   yaml Error retrieving RBAC policy: {}rolebindingN)recompilematchlowerr   r   r;   r5   )rH   rbac_policy_namerolecluster_patternnamespace_patternrR   r>   s          r    GetRbacPermissionPolicyz(KubernetesClient.GetRbacPermissionPolicy  s    jj1O

8,TZZ\*##&(8$
Gjc5 
.556FG
 	
 jtzz|,##-!14
@jc5 
.556FG
 	
 j -r   c                 f   |D ]  }|d   }|d   }| j                  d||gd      \  }}|rXd|v r0t        j                  j                  dj	                  ||             [t        j                  dj	                  |            t        j                  j                  dj	                  |              y	)
z.Clean up the RBAC cluster role binding policy.r      r   NNotFoundz!{} for RBAC policy: {} not exist.zError deleting RBAC policy: {}z{}T)r   r   statusPrintr5   r   r;   )rH   rbac_to_checkrbac_policy_pair	rbac_type	rbac_namerR   rS   s          r    CleanUpRbacPolicyz"KubernetesClient.CleanUpRbacPolicy-  s    )"1%i"1%i!!8Y	"BDIhc3	
**

188IN   !A!H!H!MN
N

S)* * r   c                 :    | j                  dd|gd       \  }}||fS )Ndiff-f)_RunKubectlDiff)rH   rbac_policy_filerR   rS   s       r    GetRbacPolicyDiffz"KubernetesClient.GetRbacPolicyDiff?  s)    ##VT3C$DdKHC8Or   c                     d}|D ]Q  }|d   }|d   }| j                  d||g      \  }}|r+d|v rd}-t        j                  dj                  |             y |ryy)	r   Fr   r   r   r   Tr   Nr   r   r;   r5   )rH   r   	not_foundr   r   r   r   rS   s           r    GetRbacPolicyzKubernetesClient.GetRbacPolicyE  s~    I)"1%i"1%i	9 =>fa	)  !C!J!J3!OP
P *  r   c                 p   t        j                  d      }t        j                  d      }g }	|rE|	j                  dt        j                  d||||      fdt        j                  d||||      fg       |r,|	j                  dt        j                  d||||      f       |	S |j                  |j                               r,|	j                  dt        j                  d||||      f       |	S |j                  |j                               r*|	j                  dt        j                  d||||      f       |	S )	z$Get the formatted RBAC policy names.r   r   clusterroleimpersonater   anthos
permissionr   )r   r   extendr   RbacPolicyNameappendr   r   )
rH   r   r   
project_ididentityis_useranthos_supportr   r   r   s
             r    GetRBACForOperationsz%KubernetesClient.GetRBACForOperationsV  sV    jj1O

8,M((Z7 #((Z7 	 


$
$
J' 	.  
		tzz|	,


$
$J
Hg 	  
	 	 	.


$
$J
Hg 	 r   c                     | j                  g dd      \  }}|r)d|v ryt        j                  dj                  |            y)z:Returns a boolean indicating if the Membership CRD exists.)r   .customresourcedefinitions.apiextensions.k8s.iomemberships.hub.gke.ioNr   Fz#Error retrieving Membership CRD: {}Tr   r   s      r    MembershipCRDExistsz$KubernetesClient.MembershipCRDExists  sP    	

 	FAs 	s	BII#NOOr   c                     | j                  g dd      \  }}|r)d|v ryt        j                  dj                  |            |S )z1Get the YAML representation of the Membership CR.)r   r   r   r   r   Nr   r   z"Error retrieving membership CR: {}r   rQ   s      r    GetMembershipCRz KubernetesClient.GetMembershipCR  sM    94HC 	s	AHHMNNJr   c                     | j                  g dd      \  }}|r)d|v ryt        j                  dj                  |            |S )z2Get the YAML representation of the Membership CRD.)r   r   r   r   r   Nr   r   z#Error retrieving membership CRD: {}r   rQ   s      r    GetMembershipCRDz!KubernetesClient.GetMembershipCRD  sR    	
 		HC 	s	BII#NOOJr   c                     | j                         sy| j                  g dd      \  }}|r)d|v ryt        j                  dj	                  |            |S )z7Looks up the owner id field in the Membership resource.N)r   r   r   r   zjsonpath={.spec.owner.id}r   z"Error retrieving membership id: {})r   r   r   r;   r5   rQ   s      r    GetMembershipOwnerIDz%KubernetesClient.GetMembershipOwnerID  s]    ##%NHC 	s	AHHMNNJr   c                 $    | j                  |      S r   )Apply)rH   rG   s     r    rN   z$KubernetesClient.CreateMembershipCRD  s    ::-..r   c                 N   |rft        j                  t               t        | |      t        t
        t        t              \  }}|r$t        j                  dj                  |            |r;| j                  |      \  }}|r$t        j                  dj                  |            yy)zApply membership resources.r,   z.Membership CRD creation failed to complete: {}z,Failed to apply Membership CR to cluster: {}N)r
   r2   r3   rA   r6   r7   r8   r9   r   r;   r5   r  )rH   rG   membership_cr_manifestr   r>   rS   s         r    ApplyMembershipz KubernetesClient.ApplyMembership  s    


(/F
G?3A>ha 
<CCEJ
 	
 zz01fa	:AA#F
 	
 
 r   c                 x    | j                  |      \  }}|r$t        j                  dj                  |            y)z Applying RBAC policy to Cluster.z/Failed to apply rbac policy file to cluster: {}N)	ApplyRbacr   r;   r5   )rH   r   r   rS   s       r    ApplyRbacPolicyz KubernetesClient.ApplyRbacPolicy  s>    ^^,-FAs

;
B
B3
G  r   c                 8    | j                  dd|g      \  }}|d u S )Nr   r<   r   rH   r<   r   rS   s       r    r1   z KubernetesClient.NamespaceExists  s'    uk9=>FAs$;r   c                 8    | j                  dd|gd      \  }}|S )Nr   r<   z	--timeout)timeout_flagr   r  s       r    r?   z KubernetesClient.DeleteNamespace  s.    	;	*  FAs Jr   c                 |    |rd|gng }|j                  d|ddj                  |      g       | j                  |      S )a  Returns the value of a field on a Kubernetes resource.

    Args:
      namespace: the namespace of the resource, or None if this resource is
        cluster-scoped
      resource: the resource, in the format <resourceType>/<name>; e.g.,
        'configmap/foo', or <resourceType> for a list of resources
      json_path: the JSONPath expression to filter with

    Returns:
      The field value (which could be empty if there is no such field), or
      the error printed by the command if there is an error.
    -nr   r   zjsonpath={{{}}})r   r5   r   )rH   r<   resource	json_pathcmds        r    GetResourceFieldz!KubernetesClient.GetResourceField  sD      )4
bCJJx'8'?'?	'JKLC  r   c                 :    | j                  dd|gd       \  }}||fS )Napplyr   r   )rH   rbac_policyrR   rS   s       r    r  zKubernetesClient.ApplyRbac  s(    $ <dCHC8Or   c                 :    | j                  g d|      \  }}||fS )N)r  r   -stdinr   )rH   manifestrR   rS   s       r    r  zKubernetesClient.Apply  s%     4HEHC8Or   c                 6    | j                  g d|      \  }}|S )N)r   r   r  r  r   )rH   r  r   rS   s       r    DeletezKubernetesClient.Delete	  s!    38DFAsJr   c                 ,    | j                  dd||g      S )a?  Gets logs from a workload in the cluster.

    Args:
      namespace: the namespace from which to collect logs.
      log_target: the target for the logs command. Any target supported by
        'kubectl logs' is supported here.

    Returns:
      The logs, or an error if there was an error gathering these logs.
    logsr  r   )rH   r<   
log_targets      r    LogszKubernetesClient.Logs  s     VT9jABBr   c                     t        j                         j                  |||      }|j                  }|dk\  r/t	        j
                  dj                  ||j                              |j                  S )a  Internal method to make requests against web URLs.

    Args:
      method: request method, e.g. GET
      url: request URL
      headers: dictionary of request headers

    Returns:
      Response body as a string

    Raises:
      Error: If the response has a status code >= 400.
    headersi  zstatus: {}, reason: {})	r   
GetSessionrequeststatus_coder   r;   r5   reasoncontent)rH   methodurlr(  rr   s         r    _WebRequestzKubernetesClient._WebRequest  sa     	%%fc7%CA]]F}5<<VQXXNOO99r   c                    |i }| j                   j                  |ddg       t        | j                   j                  j                  |      }| j                   j
                  j                  |||      }|j                  S )aJ  Internal method to make requests against the target cluster.

    Args:
      method: request method, e.g. GET
      api_path: path to request against the API server
      headers: dictionary of request headers

    Returns:
      Response body as a string.

    Raises:
      Error: If the response has a status code >= 400.
    NBearerToken)r(  querysauth_settingsr'  )r&   update_params_for_authr   configurationhostrest_clientr*  data)rH   r.  api_pathr(  r/  r0  s         r    _ClusterRequestz KubernetesClient._ClusterRequest.  s~     g 	++]O ,  $""0055x
@C$$,,VS',JA66Mr   c                     ddi}d}	 |(|j                  d      dz   }| j                  d||      S d}| j                  d||      S # t        $ r*}t	        j
                  dj                  ||            d}~ww xY w)	aA  Get the OpenID Provider Configuration for the K8s API server.

    Args:
      issuer_url: string, the issuer URL to query for the OpenID Provider
        Configuration. If None, queries the custer's built-in endpoint.

    Returns:
      The JSON response as a string.

    Raises:
      Error: If the query failed.
    Content-Typezapplication/jsonN/z!/.well-known/openid-configurationGETr'  z7Failed to get OpenID Provider Configuration from {}: {})rstripr1  r<  	Exceptionr   r;   r5   )rH   
issuer_urlr(  r/  es        r    GetOpenIDConfigurationz'KubernetesClient.GetOpenIDConfigurationN  s     	*G C		$'JJsG<<1##E3#@@ 
C
J
J1 s   )A A 	A;%A66A;c                     ddi}d}	 ||}| j                  d||      S d}| j                  d||      S # t        $ r*}t        j                  dj                  ||            d}~ww xY w)a$  Get the JSON Web Key Set for the K8s API server.

    Args:
      jwks_uri: string, the JWKS URI to query for the JSON Web Key Set. If None,
        queries the cluster's built-in endpoint.

    Returns:
      The JSON response as a string.

    Raises:
      Error: If the query failed.
    r>  zapplication/jwk-set+jsonNr@  r'  z/openid/v1/jwksz*Failed to get JSON Web Key Set from {}: {})r1  r<  rB  r   r;   r5   )rH   jwks_urir(  r/  rD  s        r    GetOpenIDKeysetz KubernetesClient.GetOpenIDKeysetm  s     	2G C
		sG<<##E3#@@ 
6
=
=c1
E s   6 6 	A)%A$$A)c                    t        j                         g}| j                  r|j                  d| j                  g       | j                  r|j                  d| j                  g       |j                  || j
                  g       |j                  |       t        j                         }t        j                         }t        j                  |d|j                  |j                  |      }|dk7  r0|j                         s |j                  dj                  |             |dk(  r|j                         nd|dk7  r|j                         fS dfS )a  Runs a kubectl command with the cluster referenced by this client.

    Args:
      args: command line arguments to pass to kubectl
      stdin: text to be passed to kubectl via stdin
      timeout_flag: kubectl command flag used to set timeout

    Returns:
      The contents of stdout if the return code is 0, stderr (or a fabricated
      error if stderr is empty) otherwise
    	--contextrg   Tno_exitout_funcerr_funcin_strr   z"kubectl exited with return code {}N)r^   r_   r]   r   r   r   ioStringIOr   Execwritegetvaluer5   )rH   argsr  r  r  rR   rS   
returncodes           r    r   zKubernetesClient._RunKubectl  s    '')
*C||	jj+t||,-	jj.$//23JJd2234JJt
++-C
++-C %%TCII		%J Qs||~	ii4;;JGH %/t$/ /3 r   c                 6   t        j                         g}| j                  r|j                  d| j                  g       | j                  r|j                  d| j                  g       |j                  d| j
                  g       |j                  |       t        j                         }t        j                         }t        j                  |d|j                  |j                  |      }|dk(  r|j                         nd|dkD  r|j                         fS dfS )a4  Runs a kubectl diff command with the specified args.

    Args:
      args: command line arguments to pass to kubectl
      stdin: text to be passed to kubectl via stdin

    Returns:
      The contents of stdout if the return code is 1, stderr (or a fabricated
      error if stderr is empty) otherwise
    rJ  rg   --request-timeoutTrK  r   N)r^   r_   r]   r   r   r   rP  rQ  r   rR  rS  rT  )rH   rU  r  r  rR   rS   rV  s          r    r   z KubernetesClient._RunKubectlDiff  s     '')
*C||	jj+t||,-	jj.$//23JJ#T%9%9:;JJt
++-C
++-C %%TCII		%J %/t$q. .2 r   )
NNNNFNNNNFr   )NrX  )&r   r   r   r   rI   r   r   r   r$   r)   r   r   r   r   r   r   r   r   r   r  r  r  rN   r
  r  r1   r?   r  r  r  r!  r%  r1  r<  rE  rH  r   r   r   r   r    r   r   H  s    > # $HT'
4	 .&1P
0$"0d 	$/
,!$C(@>:!Fr   r   c                   "    e Zd ZdZd Zd Zd Zy) DeploymentPodsAvailableOperationzGAn operation that tracks whether a Deployment's Pods are all available.c                 f    || _         || _        || _        || _        d| _        d| _        d | _        y rE   )r<   deployment_nameimager&   rF   r=   r>   )rH   r<   r\  r]  r&   s        r    rI   z)DeploymentPodsAvailableOperation.__init__  s5    DN*DDJ"DDIDNDJr   c                 N    dj                  | j                  | j                        S )Nz<Pod availability for {}/{}>)r5   r<   r\  rK   s    r    rL   z(DeploymentPodsAvailableOperation.__str__  s$    )00,, r   c                     dj                   j                        } fd} j                  j                   j                  |d      \  }}|r	 ||       y| j
                  k7  ry j                  j                   j                  |d      \  }}|r	 ||       y j                  j                   j                  |d      \  }}|r	 ||       y j                  j                   j                  |d      \  }}|r	 ||       y j                  j                   j                  |d      \  }}|r	 ||       y||k  ry||kD  ry||k  ryd	 _        d	 _        y)
zFUpdates this operation with the latest Deployment availability status.zdeployment/{}c                 :    d| v ryd_         d_        | _        y)z-Updates the operation for the provided error.r   NTF)rF   r=   r>   )rS   rH   s    r    
_HandleErrz;DeploymentPodsAvailableOperation.Update.<locals>._HandleErr  s'     
s	 didndjr   z'.spec.template.spec.containers[0].imageNz.spec.replicasz.status.replicasz.status.availableReplicasz.status.updatedReplicasT)r5   r\  r&   r  r<   r]  r=   rF   )	rH   deployment_resourcera  deployment_imagerS   spec_replicasstatus_replicasavailable_replicasupdated_replicass	   `        r    rT   z'DeploymentPodsAvailableOperation.Update  sy   )001E1EF	 !,,==1c
 o4::%))::+-=M3 o++<<+-?OS o"..??+-H o ,,==+-Fc o
 -')),,DNDIr   Nr   r   r   r   rI   rL   rT   r   r   r    rZ  rZ    s    O
Er   rZ  c                   "    e Zd ZdZd Zd Zd Zy)r4   z6An operation that waits for a namespace to be deleted.c                 J    || _         || _        d| _        d| _        d | _        y rE   )r<   r&   rF   r=   r>   )rH   r<   r&   s      r    rI   z!NamespaceDeleteOperation.__init__+  s&    DN"DDIDNDJr   c                 8    dj                  | j                        S )Nz<deleting namespace {}>)r5   r<   rK   s    r    rL   z NamespaceDeleteOperation.__str__2  s    $++DNN;;r   c                     | j                   j                  | j                        }|syd|v rd| _        d| _        y|| _        y)zAUpdates this operation with the latest namespace deletion status.Nr   T)r&   r?   r<   rF   r=   r>   )rH   rS   s     r    rT   zNamespaceDeleteOperation.Update5  sC    



*
*4>>
:C  Sdidndjr   Nrh  r   r   r    r4   r4   (  s    ><r   r4   c                    t         j                  j                  |j                  d      }t        j                  t         j
                  d      }		 t        j                  t         j
                  d|       | t        j                  d      } | j                  |||      }
| j                  |
      }|j                  }|xr |j                  xr |j                  }|sLt        j                  j!                         s.t        j"                  dj%                  |
j&                              t        j                  j)                  ||
j&                  |||       |	r't        j                  t         j
                  d|	       |S t         j
                  d= |S # |	r&t        j                  t         j
                  d|	       w t         j
                  d= w xY w)a  The kubeconfig of GKE Cluster is fetched using the GKE APIs.

  The 'KUBECONFIG' value in `os.environ` will be temporarily updated with
  the temporary kubeconfig's path if the kubeconfig arg is not None.
  Consequently, subprocesses started with
  googlecloudsdk.core.execution_utils.Exec will see the temporary KUBECONFIG
  environment variable.

  Using GKE APIs the GKE cluster is validated, and the ClusterConfig object, is
  persisted in the temporarily updated 'KUBECONFIG'.

  Args:
    api_adapter: the GKE api adapter used for running kubernetes commands
    project: string, the project id of the cluster for which kube config is to
      be fetched
    location_id: string, the id of the location to which the cluster belongs
    cluster_id: string, the id of the cluster
    temp_kubeconfig_dir: TemporaryDirectory object
    internal_ip: whether to persist the internal IP of the endpoint.
    cross_connect_subnetwork: full path of the cross connect subnet whose
      endpoint to persist (optional)
    private_endpoint_fqdn: whether to persist the private fqdn.

  Raises:
    Error: If unable to get credentials for kubernetes cluster.

  Returns:
    the path to the kubeconfig file
  r   rf   v1zGUnable to get cluster credentials. User must have edit permission on {})rq   pathjoinr   rp   rr   SetEncodedValuegke_api_adapterNewAPIAdapterParseCluster
GetCluster
masterAuthclientCertificate	clientKeyr^   ClusterConfigUseGCPAuthProviderr;   r5   	projectIdPersist)r   rk   location_id
cluster_idrz   rZ   r[   r\   r   old_kubeconfigcluster_refclusterr   valid_credss                 r    ro   ro   F  sv   N ww||/44lC*++BJJE.#RZZzB#11$7k**:{GLK$$[1GDD411DdnnK v33FFHLL#VK$9$9:      rzz<H 
 **\
"		 rzz<H
**\
"s   DF ;Gc                     t        |       }|j                  r|rt        j                  dd      |j                  r|st        j                  dd      |j
                  r|st        j                  dd      yy)a}  Validates if --gke-cluster | --gke-uri is supplied for GKE cluster, and --context for non GKE clusters.

  Args:
    kube_client: A Kubernetes client for the cluster to be registered.
    args: An argparse namespace. All arguments that were provided to this
      command invocation.

  Raises:
    calliope_exceptions.ConflictingArgumentsException: --context, --gke-uri,
    --gke-cluster are conflicting arguments.
    calliope_exceptions.ConflictingArgumentsException is raised if more than
    one of these arguments is set.

    calliope_exceptions.InvalidArgumentException is raised if --context is set
    for non GKE clusters.
  rJ  z]--context cannot be used for GKE clusters. Either --gke-uri | --gke-cluster must be specifiedz	--gke-uriz#use --context for non GKE clusters.z--gke-clusterN)IsGKEClusterr]   rt   InvalidArgumentExceptionrX   rY   )r&   rU  is_gke_clusters      r    ValidateClusterIdentifierFlagsr    s    "  ,.	\\n

6
6	=  
\\.

6
6:  
n

6
6>  -r   c                     | j                   r| j                   j                  ry| j                  ddd      \  }}|r$t        j                  dj                  |            |syy)a  Returns true if the cluster to be registered is a GKE cluster.

  There is no straightforward way to obtain this information from the cluster
  API server directly. This method uses metadata on the Kubernetes nodes to
  determine the instance ID. The instance ID field is unique to GKE clusters:
  Kubernetes-on-GCE clusters do not have this field. This test doesn't work in
  identifing a GKE cluster with zero nodes.

  Args:
    kube_client: A Kubernetes client for the cluster to be registered.

  Raises:
      exceptions.Error: if failing there's a permission error or for invalid
      command.

  Returns:
    bool: True if kubeclient communicates with a GKE Cluster, false otherwise.
  TNnodeszE.items[*].metadata.annotations.container\.googleapis\.com/instance_idz)kubectl returned non-zero status code: {}F)r   r`   r  r   r;   r5   )r&   vm_instance_idrS   s      r    r  r    sm    , {44JJ#44
O.# 	


3::3?  
	r   )>r   
__future__r   r   r   r   rP  r   rq   r    googlecloudsdk.api_lib.containerr   rr  r   rv   r	   r^   googlecloudsdk.api_lib.utilr
   googlecloudsdk.callioper   rt   *googlecloudsdk.command_lib.container.fleetr   6googlecloudsdk.command_lib.container.fleet.membershipsr   googlecloudsdk.corer   r   r   r   googlecloudsdk.core.utilr   r   
kubernetesr   r   r   r   six.moves.urllib.parser   r6   r7   r8   r9   r;   r   r"   r'   r*   r?   objectrA   rV   OperationPollerr3   r   rZ  r4   ro   r  r  r   r   r    <module>r     s   < &  % ' 	  	 	 K B ; . E B K * / # * ( - * 0 3 * &' " - *3 '.6 +5
   5>:## >4"("!HV @U)& U)p2v-- 2D
v D
NVv Vrv <DN!H&r   