
    |N                        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ZdZdZ G d dej<                        Z G d dej<                        Z  ejB                  dg d      Z" G d de#      Z$d Z%d Z& G d de#      Z' G d de'      Z( G d  d!e'      Z) G d" d#ejT                        Z+ G d$ d%e#      Z,y)&z/Manage and stream build logs from Cloud Builds.    )absolute_import)division)print_function)unicode_literalsN)
exceptions)cloudbuild_util)common)log)
properties)	resources)console_attr_os)requests)encodingz
To live stream log output for this build, please ensure the grpc module is installed. Run:
  pip install grpcio
and set:
  export CLOUDSDK_PYTHON_SITEPACKAGES=1
a  
The build is running, and logs are being written to the default logs bucket.
This tool can only stream logs if you are Viewer/Owner of the project and, if applicable, allowed by your VPC-SC security policy.

The default logs bucket is always outside any VPC-SC security perimeter.
If you want your logs saved inside your VPC-SC perimeter, use your own bucket.
See https://cloud.google.com/build/docs/securing-builds/store-manage-build-logs.
c                        e Zd Z fdZ xZS )NoLogsBucketExceptionc                 0    d}t         t        |   |       y )Nz8Build does not specify logsBucket, unable to stream logs)superr   __init__)selfmsg	__class__s     -lib/googlecloudsdk/api_lib/cloudbuild/logs.pyr   zNoLogsBucketException.__init__<   s    
DC	
/4    __name__
__module____qualname__r   __classcell__r   s   @r   r   r   :   s    5 5r   r   c                        e Zd Z fdZ xZS )4DefaultLogsBucketIsOutsideSecurityPerimeterExceptionc                 4    t         t        |   t               y N)r   r!   r   6DEFAULT_LOGS_BUCKET_IS_OUTSIDE_SECURITY_PERIMETER_TEXT)r   r   s    r   r   z=DefaultLogsBucketIsOutsideSecurityPerimeterException.__init__C   s    	
>
OPr   r   r   s   @r   r!   r!   A   s    Q Qr   r!   Response)statusheadersbodyc                       e Zd ZdZd Zd Zy)RequestsLogTailerz9LogTailer transport to make HTTP requests using requests.c                 6    t        j                         | _        y r#   )creds_requests
GetSessionsessionr   s    r   r   zRequestsLogTailer.__init__N   s    !,,.DLr   c                 2   	 | j                   j                  d|ddj                  |      i      }t        |j                  |j
                  |j                        S # t        j                  j                  $ r}t        j                  d|z        d }~ww xY w)NGETRangez
bytes={0}-)r'   zFailed to connect: %s)r.   requestformatr%   status_coder'   contentr   r   RequestExceptionapi_exceptionsCommunicationError)r   urlcursorresponsees        r   RequestzRequestsLogTailer.RequestQ   s    K%%
w(;(;F(CD & Fhh**H,<,<h>N>NOO// K--.E.IJJKs   AA B9BBN)r   r   r   __doc__r   r>    r   r   r*   r*   K   s    A/Kr   r*   c                      	 ddl m}  | j                         S # t        $ r& t        j                  j                  t               Y yw xY w)zReturn a GCL LogTailer.r   tailingN)googlecloudsdk.api_lib.loggingrC   ImportErrorr
   outPrintLOG_STREAM_HELP_TEXT	LogTailerrB   s    r   GetGCLLogTailerrJ   Z   s@    6 
				 
 GGMM&'s    ,AAc                    | j                   r~| j                   j                  r)t        | j                   j                  j                        S | j                   j                  r)t        | j                   j                  j
                        S y)z/Separate CB4A requests to print different logs.F)optionsclusterboolnameanthosCluster
membership)builds    r   IsCB4ArS   g   s\    
]]}}%--'',,--		$	$%----8899	r   c                   6    e Zd ZdZdZdZd Zd ZefdZd	dZ	y)

TailerBasez"Base class for log tailer classes.z REMOTE BUILD OUTPUT -c                     t         j                  j                  j                  j	                         }|rt        j                  dd|      S |S )z2Modify output for better screen reader experience.z--->  )r   VALUESaccessibilityscreen_readerGetBoolresub)r   textr[   s      r   _ValidateScreenReaderz TailerBase._ValidateScreenReaderv   s=    %%33AAIIKMVVGR&&Kr   c                 v    | j                   r-|r*| j                   j                  |j                                yyy)z@Testing Hook: This method enables better verification of output.N)rF   rG   rstrip)r   r_   s     r   _PrintLogLinezTailerBase._PrintLogLine}   s(    xxD
hhnnT[[]# xr   c                     t        j                         \  }}| j                  |j                  || j                               y)zDPrint a pretty starting line to identify start of build output logs.Nr   GetTermSizerc   centerOUTPUT_LINE_CHARr   r   width_s       r   _PrintFirstLinezTailerBase._PrintFirstLine   s3    **,HE1szz%)>)>?@r   c                     t        j                         \  }}| j                  |j                  || j                        dz          y)z@Print a pretty ending line to identify end of build output logs.
Nre   ri   s       r   _PrintLastLinezTailerBase._PrintLastLine   s8    **,HE1szz%)>)>?$FGr   N)rX   )
r   r   r   r?   LOG_OUTPUT_BEGINrh   r`   rc   rl   ro   r@   r   r   rU   rU   q   s,    *,$
 !1 A
Hr   rU   c                   l    e Zd ZdZdej
                  dfdZeej                  fd       Z	d Z
d Zd Zy)	GCLLogTailerzBHelper class to tail logs from GCL, printing content as available.NFc                     t               | _        || _        || _        || _        || _        d| _        || _        d| _        || _	        y )N   F)
rJ   tailerbuild_id
project_id	timestamprF   buffer_window_secondslog_urlstopis_cb4a)r   buildId	projectIdrx   logUrlrF   r|   s          r   r   zGCLLogTailer.__init__   sG     "#DKDMDODNDH!"DDLDIDLr   c           
           | |j                   |j                  |j                  |j                  |t	        |            S )zBuild a GCLLogTailer from a build resource.

    Args:
      build: Build resource, The build whose logs shall be streamed.
      out: The output stream to write the logs to.

    Returns:
      GCLLogTailer, the tailer of this build's logs.
    )r}   r~   rx   r   rF   r|   )idr~   
createTimer   rS   )clsrR   rF   s      r   	FromBuildzGCLLogTailer.FromBuild   s9     //""||u r   c                 v   | j                   sy| j                  rydj                  | j                        }dj                  | j                  | j                        }| j
                  rdj                  | j                        }| j                   j                  |g|| j                        }| j                          |D ].  }| j                  |j                        }| j                  |       0 | j                  d	       | j                  r+| j                  d
j                  | j                               y)z9Tail the GCL logs and print any new bytes to the console.Nprojects/{project_id}rw   zslogName="projects/{project_id}/logs/cloudbuild" AND resource.type="build" AND resource.labels.build_id="{build_id}")rw   rv   zdlabels."k8s-pod/tekton.dev/taskRun"="{build_id}" OR labels."k8s-pod/tekton_dev/taskRun"="{build_id}")rv   )ry   z( BUILD FINISHED; TRUNCATING OUTPUT LOGS z"Logs are available at [{log_url}].)rz   )ru   r{   r4   rw   rv   r|   TailLogsry   rl   r`   text_payloadrc   ro   rz   r   parent
log_filteroutput_logsoutputr_   s         r   TailzGCLLogTailer.Tail   s,    ;;yy$++t+GF:;A6!%4== <B <J  ||
GHN!% IO I0  ++&&	*D4N4N ' PK 	''(;(;<d
  	BC||

.
5
5dll
5
KM r   c                     d| _         t        j                  | j                         | j                  r| j                  j                          yyzStop log tailing.TN)r{   timesleepry   ru   Stopr/   s    r   r   zGCLLogTailer.Stop   s7    DIJJt))*{{
kk r   c                    dj                  | j                        }dj                  | j                  | j                  | j                        }| j                  r'dj                  | j                  | j                        }t        j                  |d|      }| j                          |D ].  }| j                  |j                        }| j                  |       0 | j                          y	)
zPrint GCL logs to the console.r   r   zlogName="projects/{project_id}/logs/cloudbuild" AND resource.type="build" AND timestamp>="{timestamp}" AND resource.labels.build_id="{build_id}")rw   rx   rv   z(labels."k8s-pod/tekton.dev/taskRun"="{build_id}" OR labels."k8s-pod/tekton_dev/taskRun"="{build_id}") AND timestamp>="{timestamp}")rv   rx   asc)r   order_byr   N)r4   rw   rx   rv   r|   r	   	FetchLogsrl   r`   textPayloadrc   ro   r   s         r   rG   zGCLLogTailer.Print   s    $++t+GF	0 28nn]] 28 2$  ||
/06!%$.. 17 1J 
 ""f>K 	''(:(:;d
  	r   )r   r   r   r?   r
   r&   r   classmethodrF   r   r   r   rG   r@   r   r   rr   rr      sD    J ::"  #  $&P r   rr   c                   z    e Zd ZdZdZej                  fdZd Ze	ej                  fd       ZddZd Zd Zd	 Zy
)GCSLogTailerzBHelper class to tail a GCS logfile, printing content as available.z (possibly incomplete) c                     t               | _        | j                  ||      | _        t	        j
                  d| j                  z          d| _        || _        d| _        y )NzGCS logfile url is r   F)	r*   	transport_StorageUrlr:   r
   debugr;   rF   r{   )r   bucketobjrF   s       r   r   zGCSLogTailer.__init__  sK    &(DN,DHII#dhh./DKDHDIr   c                     d}t         j                  j                  j                  j	                         rd}|j                  ||      S )Nz-https://storage.googleapis.com/{bucket}/{obj}z2https://storage.mtls.googleapis.com/{bucket}/{obj})r   r   )r   rY   context_awareuse_client_certificater\   r4   )r   r   r   url_patterns       r   r   zGCSLogTailer._StorageUrl  s@    AK&&==EEGHkV55r   c                    |j                   s
t               |j                   }d}|j                  |      r|t        |      d }d|vr|}d}n|j	                  dd      \  }}|dz  }dj                  ||j                        } | |||      S )	aL  Build a GCSLogTailer from a build resource.

    Args:
      build: Build resource, The build whose logs shall be streamed.
      out: The output stream to write the logs to.

    Raises:
      NoLogsBucketException: If the build does not specify a logsBucket.

    Returns:
      GCSLogTailer, the tailer of this build's logs.
    zgs://N/rX      z{object}log-{id}.txt)objectr   )r   r   rF   )
logsBucketr   
startswithlensplitr4   r   )r   rR   rF   log_stripped
gcs_prefix
log_bucketlog_object_dir
log_objects           r   r   zGCSLogTailer.FromBuild  s     !## ##LJz*!#j/"23l
,jn%1%7%7Q%?"z>n'..88 / J
  r   c                 d   	 | j                   j                  | j                  | j                        }|j                  dk(  rt        j                  d       y|j                  dk(  r(t        j                  d       |r| j                          y|j                  dk(  s|j                  dk(  rt        j                  dj                  |j                  t        |j                        	             | j                  d
k(  r| j                          | xj                  t        |j                        z  c_        t        j                  |j                        }|| j!                  |      }| j#                  |j%                  d             |r| j                          y|j                  dk(  r3t        j&                  d       |r| j                  | j(                         y|j                  dk\  r[|j                  dk  rLt        j&                  dj                  |j                               |r| j                  | j(                         yt+        |j,                        }|j                  |d<   t	        j.                  ||j                  | j                        # t        j
                  $ r |r Y yw xY w)aE  Poll the GCS object and print any new bytes to the console.

    Args:
      is_last: True if this is the final poll operation.

    Raises:
      api_exceptions.HttpError: if there is trouble connecting to GCS.
      api_exceptions.CommunicationError: if there is trouble reaching the server
          and is_last=True.
    Ni  z3Reading GCS logfile: 404 (no log yet; keep polling)i  z7Reading GCS logfile: 416 (no new content; keep polling)      z0Reading GCS logfile: {code} (read {count} bytes))codecountr   rn   i  z2Reading GCS logfile: 429 (server is throttling us)i  iX  z&Reading GCS logfile: got {0}, retryingr&   )r   r>   r:   r;   r8   r9   r&   r
   r   ro   r4   r   r(   rl   r   Decoder`   rc   rb   warningLOG_OUTPUT_INCOMPLETEdictr'   	HttpError)r   is_lastresdecodedr'   s        r   PollzGCSLogTailer.PollE  s   	NN""488T[[9c zzS	iiEF
zzS	iiIJ	
zzSCJJ#-	iiBIIzzSXX J 0 1		
kkS]"k)g		,,W5
-.	 zzS	kkFG	D667
zzSSZZ#-	kk:AA#**MN	D667 3;;G

GH

"
"7CHHdhh
??q ,, 
 
s   0J J/.J/c                     | j                   s2| j                          t        j                  d       | j                   s2| j                  d       y)z;Tail the GCS object and print any new bytes to the console.r   Tr   N)r{   r   r   r   r/   s    r   r   zGCSLogTailer.Tail  s6    ii
iik
jjm ii 	IIdIr   c                     d| _         yr   )r{   r/   s    r   r   zGCSLogTailer.Stop  s	    DIr   c                 (    | j                  d       y)zPrint GCS logs to the console.Tr   N)r   r/   s    r   rG   zGCSLogTailer.Print  s    IIdIr   N)F)r   r   r   r?   r   r
   r&   r   r   r   rF   r   r   r   r   rG   r@   r   r   r   r     sO    J3&)jj 6  # % %NE@N
r   r   c                   (     e Zd ZdZ fdZd Z xZS )ThreadInterceptorz'Wrapper to intercept thread exceptions.c                 F    t         t        |           || _        d | _        y r#   )r   r   r   target	exception)r   r   r   s     r   r   zThreadInterceptor.__init__  s    	
T+-DKDNr   c                     	 | j                          y # t        j                  $ r5}|j                  dk(  rt	               | _        n|| _        Y d }~y Y d }~y d }~wt        j                  $ r}|| _        Y d }~y d }~ww xY w)Ni  )r   r8   r   r5   r!   r   r9   )r   r=   s     r   runzThreadInterceptor.run  sg    
kkm## 	
#	 NO 	 ,, dnns     A=&AA=,A88A=)r   r   r   r?   r   r   r   r   s   @r   r   r     s    /
r   r   c                   P    e Zd ZdZ	 	 	 	 ddZd Zd Zej                  fdZ	d Z
y)	CloudBuildClientzGClient for interacting with the Cloud Build API (and Cloud Build logs).Nc                     |xs t        j                         | _        |xs t        j                         | _        || _        || _        y r#   )r   GetClientInstanceclientGetMessagesModulemessagessupport_gclpolling_interval)r   r   r   r   r   s        r   r   zCloudBuildClient.__init__  s>    
 ?O==?DKC A A CDM"D,Dr   c                 L   |j                         dk(  rEt        j                  j                  d|j                  t
        j                  |j                        }| j                  j                  j                  | j                  j                  |j                                     S )zGet a Build message.

    Args:
      build_ref: Build reference. Expects a cloudbuild.projects.locations.builds
        but also supports cloudbuild.projects.builds.

    Returns:
      Build resource
    zcloudbuild.projects.buildsz$cloudbuild.projects.locations.builds)
collection
projectsIdlocationsIdbuildsId)rO   )
Collectionr   REGISTRYCreater~   r   DEFAULT_REGIONr   r   projects_locations_buildsGetr   +CloudbuildProjectsLocationsBuildsGetRequestRelativeName)r   	build_refs     r   GetBuildzCloudBuildClient.GetBuild  s     !==$$++;((%44<<	 , !i ;;0044AA'') 	B 	+, ,r   c                 4   t         j                  j                  dt        | j                        z   dz          |j                  |v r?| j                  |      }t        j                  | j                         |j                  |v r?|r|j                          |S )a  Checks whether a log tailer should be stopped.

    Args:
      build: Build object, containing build status
      build_ref: Build reference, The build whose logs shall be streamed.
      log_tailer: Specific log tailer object
      working_statuses: Valid working statuses that define we should continue
        tailing

    Returns:
      Build message, the completed or terminated build.
    z1Waiting for build to complete. Polling interval: z second(s).)	r
   r&   rG   strr   r   r   r   r   )r   rR   r   
log_tailerworking_statusess        r   ShouldStopTailerz!CloudBuildClient.ShouldStopTailer  s     JJH../02?@ A
,,*
*mmI&e
jj&&' ,,*
* ooLr   c                    | j                  |      }|j                  r|j                  j                  | j                  j                  j
                  j                  | j                  j                  j
                  j                  | j                  j                  j
                  j                  fvrt        j                  ||      }n |j                  j                  | j                  j                  j
                  j                  | j                  j                  j
                  j                  fv r\| j                  rPt        j                  dj                  |j                  j                               t        j                  ||      }n:t        j                  dj                  |j                  j                               d}| j                  j                   j"                  }|j$                  |j&                  g}d}|r&t)        |j*                        }|j-                          | j/                  ||||      }|r(|j1                          |j2                  |j2                  |S )a  Streams the logs for a build if available.

    Regardless of whether logs are available for streaming, awaits build
    completion before returning.

    Args:
      build_ref: Build reference, The build whose logs shall be streamed.
      out: The output stream to write the logs to.

    Raises:
      NoLogsBucketException: If the build is expected to specify a logsBucket
      but does not.

    Returns:
      Build message, the completed or terminated build.
    )rF   z7Streaming logs from GCL: requested logging mode is {0}.z2Not streaming logs: requested logging mode is {0}.N)r   )r   rL   loggingr   BuildOptionsLoggingValueValuesEnumNONESTACKDRIVER_ONLYCLOUD_LOGGING_ONLYr   r   r   r
   infor4   rr   BuildStatusValueValuesEnumQUEUEDWORKINGr   r   startr   joinr   )r   r   rF   rR   r   statusesr   ts           r   StreamzCloudBuildClient.Stream  s   " MM)$E==EMM11""99>>""99JJ""99LL: 
  ))%S)9j			""99JJ""99LL# 
 

	hhHOO
--

! "))%S)9j	hhCJJ
--

! "j}}""88H
 	A
:??
3aggi!!%J"24Effh	
	 kkLr   c                    | j                  |      }|j                  r|j                  j                  | j                  j                  j
                  j                  | j                  j                  j
                  j                  | j                  j                  j
                  j                  fvrt        j                  |      }n|j                  j                  | j                  j                  j
                  j                  | j                  j                  j
                  j                  fv rNt        j                  dj                  |j                  j                               t        j                  |      }n:t        j                  dj                  |j                  j                               d}|r|j                          yy)zPrint the logs for a build.

    Args:
      build_ref: Build reference, The build whose logs shall be streamed.

    Raises:
      NoLogsBucketException: If the build does not specify a logsBucket.
    z6Printing logs from GCL: requested logging mode is {0}.z.Logs not available: build logging mode is {0}.N)r   rL   r   r   r   r   r   r   r   r   r   r
   r   r4   rr   rG   )r   r   rR   r   s       r   PrintLogzCloudBuildClient.PrintLog+  sN    MM)$E==EMM11""99>>""99JJ""99LL: 
  ))%0j			""99JJ""99LL# 
 
hhGNN
--

! "))%0j	hh?FF
--

! "j r   )NNFr   )r   r   r   r?   r   r   r   r
   rF   r   r   r@   r   r   r   r     s6    O   !	-,.0 #&'' 5nr   r   )-r?   
__future__r   r   r   r   collectionsr]   	threadingr   apitools.base.pyr   r8   !googlecloudsdk.api_lib.cloudbuildr   rD   r	   googlecloudsdk.corer
   r   r   googlecloudsdk.core.consoler   googlecloudsdk.core.credentialsr   r,   googlecloudsdk.core.utilr   rH   r$   Errorr   r!   
namedtupler%   r   r*   rJ   rS   rU   rr   r   Threadr   r   r@   r   r   <module>r	     s    6 &  % '  	   9 = 1 * # * ) 7 F -  : 65J,, 5Q:;K;K Q ";!!*.KLK K
H H:w: wtV: Vr	(( .Qv Qr   