
    aj                        d 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#ejH                  jJ                  diZ& G d dejN                        Z(d Z)d Z*ejH                  jJ                  fdZ+ G d de,      Z-y)z@Common utility functions for Developer Connect Insights Configs.    N)
exceptions)projects_api)common)discover_apphub)discover_artifact_configs)folders)serviceusage)apis)waiter)basename)iam_util)util)log)	resources)
console_io)z$roles/developerconnect.insightsAgentzroles/cloudasset.owneri N  v1c                       e Zd ZdZy)!InsightsConfigInitializationErrorz9Error initializing the Developer Connect Insights Config.N)__name__
__module____qualname____doc__     Plib/googlecloudsdk/api_lib/developer_connect/insights_configs/insights_config.pyr   r   2   s    Ar   r   c                 8    t        j                  | |      }|d   S )a\  Gets the P4SA for the given project and location.

  If the P4SA does not exist for this project, it will be created. Otherwise,
  the email address of the existing P4SA will be returned.

  Args:
    project: The project to get the P4SA for.
    service_name: The service name to get the P4SA for.

  Returns:
    The email address of the P4SA.
  email)r	   GenerateServiceIdentity)projectservice_nameresponses      r   _GetP4SAr$   6   s!     11'<H(	'	r   c                 R    | t         j                  k(  xs | t         j                  k(  S )a  Whether to retry the request when receiving errors.

  Args:
    exc_type: type of the raised exception.
    unused_exc_value: the instance of the raise the exception.
    unused_exc_traceback: Traceback, traceback encapsulating the call stack at
      the point where the exception occurred.
    unused_state: RetryerState, state of the retryer.

  Returns:
    True if exception and is due to NOT_FOUND or INVALID_ARGUMENT.
  )apitools_exceptionsHttpBadRequestErrorHttpNotFoundError)exc_typeunused_exc_valueunused_exc_tracebackunused_states       r   _ShouldRetryHttpErrorr-   G   s,     )==
= <
);;
;=r   c                 X    t         j                  |       }t        j                  d|      S )Ndeveloperconnect)VERSION_MAPgetr
   GetMessagesModule)release_trackapi_versions     r   r2   r2   [   s$    .+			 2K	@@r   c                       e 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 Zd Zd ej0                  d      fdZy)InsightsConfigClientz2Wrapper for Developer Connect Insights API client.c                    t         j                  |      }|| _        t        j                  d|      | _        t        j                         | _        | j                  j                  dd       t        |      | _        || _        d | _        y )Nr/   r   )r0   r1   r3   r
   GetClientInstanceclientr   Registry_resource_parserRegisterApiByNamer2   messagesr4   
p4sa_email)selfr3   r4   s      r   __init__zInsightsConfigClient.__init__c   sp    //-0K&D(();[IDK%..0D++,>E%m4DM"DDOr   c           
      "   t        j                  |      }|j                         |j                  k(  }t	        |j                               |j                  k(  }|s,|s*t        d|j                          d|j                   d      t        j                  |      }| j                  ||      \  }}	| j                  |	      }
| j                  |
|      }| j                  ||
      \  }}|j                  |       |r| j                  |j                  |d       | j                  j                  |j!                         j#                         |j$                  | j                  j'                  |j#                         |j)                         |            }	 | j*                  j,                  j/                  |      S # t0        j2                  $ r> t5        j6                  d	|j$                   d
|j                   d|j8                   d      w xY w)zCreates the insight config.z'Mismatch: App Hub application project [zM] must be the same as the project where the insight config is being created [].Fmanagement_project)r   appHubApplicationartifactConfigs)parentinsightsConfigIdinsightsConfigrequestInsights Config [z] already exists in project [] location [)r   parse_app_hub_application_uri
project_id
projectsIdstrproject_numberr   parse_artifact_configs%FindGkeWorkloadsAndGrantSAPermissionsGetArtifactConfigsFromCAISMergeArtifactConfigsBuildArtifactConfigsupdateInitServiceAccountr=   =DeveloperconnectProjectsLocationsInsightsConfigsCreateRequestParentRelativeNameinsightsConfigsIdInsightsConfigresource_namer9   "projects_locations_insightsConfigsCreater&   HttpConflictErrorr   ErrorlocationsId)r?   insight_config_refapp_hubuser_artifact_configsapp_hub_applicationare_projects_id_equalare_project_numbers_equaluser_artifact_configs_dictdependent_projectsgke_workloadscais_artifact_configs_dictmerged_artifact_configs_dictartifact_projectsartifact_configscreate_requests                  r   ra   zInsightsConfigClient.Createm   sJ   <<WE 	&&(,>,I,II  	..01((	)  !)B-"--/0 1!,,-R1  "&!<!<" 	22 3	
 &
 "&!@!@!O#'#<#<"$>$  +/*C*C$&@+'' /0


'
'
"  
 ]]``!((*779+==}}33#0021??A, 4 
 a N	[[;;BB  C   00 0BBC D!!3!>!> ? @!--.b2 s   %F= =AHc                     i }|r|j                         D ]
  \  }}|||<    |s|S |j                         D ]?  \  }}| j                  j                  || j                  j                  |            ||<   A |S )zMerges artifact configs from CAIS and user provided configs user provided configs will overwrite configs extracted from CAIS if URIs match.
    	projectIdurigoogleArtifactAnalysis)itemsr=   ArtifactConfigGoogleArtifactAnalysis)r?   artifact_configs_dictuser_provided_artifact_configsro   rw   
config_msgbuild_projects          r   rV   z)InsightsConfigClient.MergeArtifactConfigs   s    
 $& 288:/#z,6$S) ; *))<BBD]*.--*F*F!%!E!E% "F " +G +"3' E ('r   c                     | j                  |j                               \  }}t        j                  |j	                               s||fS | j                  ||       t               |fS )a  Finds the GKE workloads and grants SA permissions at the folder level for management project or returns the dependent projects for non-management projects.

    Args:
      insight_config_ref: The insight config reference.
      app_hub_application: The app hub application.

    Returns:
      A tuple of dependent projects(based on if it is a management project or
      not) and gke workloads.
    )GetRuntimesr_   r   is_management_projectrO   AssignManagementPermissionsset)r?   re   rh   rl   rm   s        r   rT   z:InsightsConfigClient.FindGkeWorkloadsAndGrantSAPermissions   sl     )-(8(8))+)% %%&9&D&D&FG.. 	$$%79LM5-r   c           	      Z   i }|D ]  }t        j                  |      }t        j                  |      }|D ]r  }t        j                  |      }|s|j                         }| j                  j                  || j                  j                  |j                                     ||<   t  |S )zQueries CAIS for artifacts associated with the gke workloads in the resources scope.

    Args:
      gke_workloads: A list of GKE workloads.

    Returns:
      A dict of artifact configs IC type.
    rt   rv   )
discover_artifactsQueryCaisForAssetsGetArtifactURIsFromAssetsr   validate_artifact_uribase_urir=   rz   r{   rO   )	r?   rm   r|   gke_workloadassetsartifact_urisartifactvalidated_artifact_urir   s	            r   rU   z/InsightsConfigClient.GetArtifactConfigsFromCAIS   s     %!44\Bf(BB6Jm#(!%!;!;H!E%
)224*.--*F*F#'==#G#G0;;= $H $ +G +
h' $ & ! r   c                    t               }|s#t        j                  j                  d       |g fS |r|j	                         D ]  }|j
                  j                  }t        j                  j                  d| d|j                   d       t        j                         xr t        j                  dd      }|r| j                  |j                        }| j                  j                  |j                  | j                  j                  |      	      ||j                  <    t        |j	                               }|j!                  d
 |D               ||fS )ay  Builds the artifact configs and returns the dependent projects and artifact configs.

    Args:
      merged_artifact_configs_dict: A combined dict of artifact configs IC type
        from CAIS and user provided configs.
      cais_artifact_configs_dict: A dict of artifact configs IC type from CAIS.

    Returns:
      A tuple of dependent projects and artifact configs.
    z*No existing artifact configurations found.z
Build project [z?] will be used to extract provenance information for artifact []z+Would you like to change the build project?F)prompt_stringdefaultrt   rv   c              3   H   K   | ]  }|j                   j                    y w)N)rx   ru   ).0r   s     r   	<genexpr>z<InsightsConfigClient.BuildArtifactConfigs.<locals>.<genexpr>6  s$      (H 	''11(s    ")r   r   statusPrintvaluesrx   ru   rw   r   	CanPromptPromptContinuePromptForBuildProjectr=   rz   r{   listrX   )r?   ro   rn   rl   artifact_configr   change_build_projectrq   s           r   rW   z)InsightsConfigClient.BuildArtifactConfigs  sa    '	jjCD## "9@@B/'>>HH

   $$%Q(	
   " ))K 	  44_5H5HI- MM((#'''+}}'K'K+ (L ( )  	%_%8%89% C8 8??AB  (  ///r   c                    d}d}|s4t        j                  d| d      }	 t        j                  |       d}|s4|S # t        j
                  $ r1 t        j                  j                  dj                  |             Y Ht        j                  $ r1 t        j                  j                  dj                  |             Y t        j                  $ r%}t        j                  d| d|        Y d}~d}~ww xY w)	z'Prompts the user for the build project.FNz2Please enter the build project for your artifact [z]: TzPermission denied when checking build project [{}]. Please ensure your account has necessary permissions or that the project exists.z^Invalid build project ID [{}]. Please ensure it is a valid project ID (e.g., "my-project-123")z Error validating build project [)r   PromptResponser   validate_build_projectr&   HttpForbiddenErrorr   r   r   formatr'   r   rc   warning)r?   artifact_urifoundr   es        r   r   z*InsightsConfigClient.PromptForBuildProject<  s    EM //nC!m
N##M2 .  !33 


* VM"		
 !44 


3396-3H	
  N6}oSLMMNs#   = AC9 A C9C9C44C9c                    t               }g }t        j                         }|j                  d|      }|D ]  }|j                  r|j                  j
                  s&t        j                  |j                  j
                        }|sR|j                  t        j                  |j                  j                  j                        j                         |j                  |        ||fS )zGets the runtime configs.

    Args:
      app_hub: The app hub application.

    Returns:
      A tuple of runtime configs projects and gke workloads associated with the
      app hub application.
    d   )	page_sizerG   )r   r   DiscoveredWorkloadsClientListworkloadReferencerw   r   parse_gke_deployment_uriaddProjectgke_namespacegke_clusterr!   rO   append)r?   rf   runtime_configs_projectsrm   r9   	workloadsworkloadr   s           r   r   z InsightsConfigClient.GetRuntimesY  s      #uM668F  I
  ''x/I/I/M/M22

$
$
(
(l 
 	!$$LL**66>>j	

 	\*# $ $]22r   c                     t        j                  t        j                  |j	                                     j
                  j                  }|g}| j                  |j                  |d       y)zBAssigns permissions to at the folder level for management project.TrC   N)	r   Getprojects_utilParseProjectrO   rG   idrY   rP   )r?   re   rf   folder_numberdependent_folders        r   r   z0InsightsConfigClient.AssignManagementPermissions  sm     !$$"" 	
 fRR	 
 &%%  
 r   c                 2   |r|r| j                  |||      }n| j                  |      }t        j                  t        j                  |j
                              s0| j                  |      }| j                  |j                  |d       nzt        j                  t        j                  t        j                  |j
                                    j                  j                  }|g}| j                  |j                  |d       | j                  |      }	|r/| j                   j"                  j$                  j&                  |	_        | j                   j+                  |	|j-                               }
| j.                  j0                  j3                  |
      S )zUpdates the insight config.FrC   T)rI   r   rJ   )HandleArtifactConfigsGetExistingInsightsConfigr   r   extract_projectrE   GetDependentProjectsrY   rP   r   r   r   r   rG   r   InsightsConfigMessageTyper=   r^   StateValueValuesEnumPENDINGstate<DeveloperconnectProjectsLocationsInsightsConfigsPatchRequestr\   r9   r`   Patch)r?   re   	discoveryr   r   old_insights_configrl   r   r   new_insights_configupdate_requests              r   UpdatezInsightsConfigClient.Update  s     66
lM !::;MN%%0BBC  445HI


'
'
"   #&&

$
$""#6#H#HI 	rr	 
 (


'
'
!   889LM
--
&
&
;
;
C
C  ]]__*,,. ` N ;;99?? @  r   c                 R   t        j                  |      }|st        j                  d| d      	 t        j                  |       | j                  |      }t        |j                        D ]^  \  }}|j                  |k(  s| j                  j!                  || j                  j#                  |            }	|	|j                  |<   |c S  |j                  j%                  | j                  j!                  || j                  j#                  |                   |S # t
        j                  $ r8 t        j                  dj                  |t        j                                     t
        j                  $ r*}t        j                  dj                  ||            d}~ww xY w)zHandles the artifact config.zInvalid artifact URI: z`. Artifact URI must be in the format {location}-docker.pkg.dev/{project}/{repository}/{package}.zPermission denied when checking build project [{}]. Please ensure the account [{}] has necessary permissions (e.g., resourcemanager.projects.get) or that the project exists.z{Invalid build project ID [{}]: {}. Please ensure it is a valid project ID (e.g., "my-project-123") and not an artifact URI.Nrt   rv   )r   r   r   rc   r   r&   r   r   r   GetAuthenticatedAccountr'   r   	enumeraterF   rw   r=   rz   r{   r   )
r?   insights_refr   r   artifact_projectr   icindexr   updated_artifacts
             r   r   z*InsightsConfigClient.HandleArtifactConfigs  s   11,?"<. 1H H 
!!-0" 
	'	'	5B"+B,>,>"?				,==77#'==#G#G' $H $ 8 
 %55!	 #@ $$#'==#G#G' $H $ 	% 	
 IG 11 G 6-!A!A!CD	  22 J6-# s   D   AF&<%F!!F&c                 d    | j                   j                  |j                  |j                        S )z+Creates a new insights config message type.)r   rF   )r=   r^   r   rF   )r?   current_insights_configs     r   r   z.InsightsConfigClient.InsightsConfigMessageType  s0    ==''%++/?? (  r   c           
      H   	 | j                   j                  j                  | j                  j	                  |j                                     S # t        j                  $ r> t        j                  d|j                   d|j                   d|j                   d      w xY w)zGets the insight config.r   rJ   rL   z] not found in project [rM   rB   )r9   r`   r   r=   :DeveloperconnectProjectsLocationsInsightsConfigsGetRequestr\   r&   r(   r   rc   r]   rP   rd   )r?   re   s     r   r   z.InsightsConfigClient.GetExistingInsightsConfig  s    [[;;??--ZZ%224 [  @  
 00 0BBC D,778 9!--.b2 s   AA AB!c                 ~   t               }|j                  t        j                  |j                               |j
                  D ]  }|j                  r@t        j                  |j                        }|r|j                  |j                                |j                  s\|j                  j                  ss|j                  |j                  j                          |j                  D ]=  }|j                  s|j                  t        j                  |j                               ? t        t        |            S )z.Gets the P4SA projects for the insight config.)r   r   r   r   rE   rF   rw   r   rO   rx   ru   runtimeConfigssortedr   )r?   insights_configprojectsr   r   runtime_configs         r   r   z)InsightsConfigClient.GetDependentProjects
  s    uHLL%%o&G&GHI*::			11/2E2EF
,,|..0
1

0
044>>_;;EEF ; *88			T)).*<*<=> 9 $x.!!r   c                    t        j                  | j                        }| j                  t	        ||      | _        | j                  st        dj                  |            |rEt        |      dk(  r!| j                  | j                  |d   d       yt        j                  d       y|D ]4  }t        j                  |      }| j                  | j                  |d       6 y)a  Get the Developer Connect P4SA, and grant IAM roles to it.

    1) First, get the P4SA for the project.
    Args:
      p4sa_project: The project to get the P4SA for.
      dependent_resources: The resources to grant the P4SA permissions to.
      management_project: Whether the resource is a management project.

    2) Then grant necessary roles needed to the P4SA for updating an insight
      config.

    3) If the app hub application is a management project, grant the P4SA
      permissions on the folder.

    4) If the app hub application is a non management project, grant the P4SA
      permissions on the dependent projects.

    Raises:
      InsightsConfigInitializationError: P4SA failed to be created.
    Nz"Failed to get P4SA for project {}.   r   Tz\Could not find folder number for the management project.Skipping permissions checks/binding.F)r   GetApiServiceNamer4   r>   r$   r   r   lenBindRolesToServiceAccountr   r   r   r   )r?   p4sa_projectdependent_resourcesrD   r"   r!   project_refs          r   rY   z'InsightsConfigClient.InitServiceAccount  s    . ++D,<,<=L |<do??-
.
5
5l
C  	 	!Q	&&&OO03T	
 	3	

 )'#009&&tUK )r   c                 F    t         D ]  }| j                  ||||d        y)zBinds roles to the provided service account.

    Args:
      sa_email: str, the service account to bind roles to.
      resource_ref: str, the resource to bind roles to.
      management_project: bool, whether the resource is a management project.
    z8required to update the Developer Connect Insights Config)reasonN)_ROLESPromptToBindRoleIfMissing)r?   sa_emailresource_refrD   roles        r   r   z.InsightsConfigClient.BindRolesToServiceAccountJ  s0     
$$



K %  r   c                 >   dj                  |      }	 |rt        j                  |      }nt        j                  |      }| j	                  |||      ryt
        j                  j                  dj                  |||             t        j                         xr& t        j                  dj                  ||            }|st        j                  d       y|rMt        j                         }	t        j                  |	j                  |||       t        j                   ||       nt        j"                  |||       t
        j                  j                  dj                  ||             y# t$        j&                  $ r t        j                  d|||       Y yw xY w)	a  Prompts to bind the role to the service account in project level if missing.

    If the console cannot prompt, a warning is logged instead.

    Args:
      sa_email: The service account email to bind the role to.
      resource_ref: The resource to bind the role to.
      role: The role to bind if missing.
      management_project: Whether the resource is a management project.
      reason: Extra information to print explaining why the binding is
        necessary.
    serviceAccount:{}Nz2
Service account [{}] is missing the role [{}].
{}z,
Bind the role [{}] to service account [{}]?)r   z0Manual binding of above role will be necessary.
z8Successfully bound the role [{}] to service account [{}]zYour account does not have permission to check or bind IAM policies to resource [%s]. If the deployment fails, ensure [%s] has the role [%s] before retrying.)r   r   GetIamPolicyr   HasRoleBindingr   r   r   r   r   r   r   FoldersMessagesr   AddBindingToIamPolicyBindingSetIamPolicyAddIamPolicyBindingr&   r   )
r?   r   r   r   rD   r   member
iam_policybindr=   s
             r   r   z.InsightsConfigClient.PromptToBindRoleIfMissing]  sl    !''1F/	)),7
!..|<
			Z4	8	jj
@
G
Gf !!# 
(A(AGNNH)d
 GH	**,&&j&$	
 	\:6((vtD	jj
D
K
KH
 11 
	kk4 

	
s    A E. BE. BE. .+FFc                 D    t        fd|j                  D              S )zReturns whether the given SA has the given role bound in given policy.

    Args:
      iam_policy: The IAM policy to check.
      sa_email: The service account to check.
      role: The role to check for.
    c              3   z   K   | ]2  }d j                        |j                  v xr |j                  k(   4 yw)r   N)r   membersr   )r   br   r   s     r   r   z6InsightsConfigClient.HasRoleBinding.<locals>.<genexpr>  s=      $A 	""8,		9LaffnL$s   8;)anybindings)r?   r   r   r   s     ``r   r   z#InsightsConfigClient.HasRoleBinding  s%      $$  r   c                 N    | j                   j                  |j                  d      S )zKConverts an operation to a resource that can be used with `waiter.WaitFor`.z1securesourcemanager.projects.locations.operations)r;   ParseRelativeNamer   )r?   	operations     r   GetOperationRefz$InsightsConfigClient.GetOperationRef  s'      22KM Mr   TiX  )secondsc                 "   |r?t        j                  | j                  j                  | j                  j                        }n)t        j
                  | j                  j                        }t        j                  ||||j                  dz        S )a  Waits for a Developer Connect operation to complete.

      Polls the Developer Connect Insights Operation service until the operation
      completes, fails, or max_wait_seconds elapses.

    Args:
      operation_ref: a resource reference created by GetOperationRef describing
        the operation.
      message: a message to display to the user while they wait.
      has_result: If True, the function will return the target of the operation
        (i.e. the InsightConfig) when it completes. If False, nothing will be
        returned (useful for Delete operations).
      max_wait: The time to wait for the operation to complete before returning.

    Returns:
      A resource reference to the target of the operation if has_result is True,
      otherwise None.
    i  )max_wait_ms)r   CloudOperationPollerr9   r`   projects_locations_operationsCloudOperationPollerNoResourcesWaitForr  )r?   operation_refmessage
has_resultmax_waitpollers         r   WaitForOperationz%InsightsConfigClient.WaitForOperation  sw    2 **
++
8
8
++
3
3f
 55
++
3
3f >>wH4D4Dt4K r   N) )r   r   r   r   r@   ra   rV   rT   rU   rW   r   r   r   r   r   r   r   r   rY   r   r   r   r  datetime	timedeltar  r   r   r   r6   r6   `   s    :BH(2 6!890v:$3L 1f0d"&+LZ( FH?BM !x!!#.%r   r6   ).r   r  apitools.base.pyr   r&   +googlecloudsdk.api_lib.cloudresourcemanagerr   (googlecloudsdk.api_lib.developer_connectr   9googlecloudsdk.api_lib.developer_connect.insights_configsr   r   r   'googlecloudsdk.api_lib.resource_managerr   googlecloudsdk.api_lib.servicesr	   googlecloudsdk.api_lib.utilr
   r   googlecloudsdk.callioper   ,googlecloudsdk.command_lib.developer_connectr   googlecloudsdk.command_lib.iamr   #googlecloudsdk.command_lib.projectsr   r   googlecloudsdk.corer   r   googlecloudsdk.core.consoler   r   _MAX_WAIT_TIME_IN_MSReleaseTrackALPHAr0   InternalErrorr   r$   r-   r2   objectr6   r   r   r   <module>r(     s     G  > D ; U u ; 8 , . ( = 3 E * # ) 2

 ! T
B
(@(@ B"=( %)$5$5$;$; A
u	6 u	r   