
    +?                     `   d Z ddlmZ ddlmZ ddlm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dlmZ  G d dej.                        Z G d dej.                        Z G d de      Zd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$y)z-Utilities for dealing with version resources.    )absolute_import)division)unicode_literalsN)
exceptions)env)metric_names)operations_util)log)metrics)retry)text)times)mapc                       e Zd Zy)VersionValidationErrorN__name__
__module____qualname__     .lib/googlecloudsdk/api_lib/app/version_util.pyr   r   &       r   r   c                       e Zd Zy)VersionsDeleteErrorNr   r   r   r   r   r   *   r   r   r   c                   r    e Zd ZdZdZdZdZ	 	 	 	 	 ddZed        Z	ed        Z
d	 Zd
 Zd Zd Zd Zd Zy)VersionzValue class representing a version resource.

  This wrapper around appengine_<API-version>_messages.Version is necessary
  because Versions don't have traffic split, project, or last_deployed_time as a
  datetime object.
  g-C6?   zFapps/(?P<project>.*)/services/(?P<service>.*)/versions/(?P<version>.*)Nc	                 t    || _         || _        || _        || _        || _        || _        || _        || _        y N)projectserviceidversiontraffic_splitlast_deployed_timeenvironmentservice_account)	selfr!   r"   
version_idr%   r&   r'   version_resourcer(   s	            r   __init__zVersion.__init__B   s@     DLDLDG#DL&D0D"D*Dr   c                     |j                  d      }dt        |      cxk  r| j                  k  st        d       t        d      d g| j                  t        |      z
  z  |z   } | | S )N/r   zJ[{0}] is not a valid resource path. Expected <project>/<service>/<version>)splitlen_RESOURCE_PATH_PARTSr   )clspathpartss      r   FromResourcePathzVersion.FromResourcePathT   s    JJsOEs5z5S555" $L M M 6" $L M M Fc..U;<uDE;r   c           	      ^   t        j                  | j                  |j                        j	                         \  }}}|xr& |j
                  j                  |j                  d      }d}	 |j                  rDt        j                  |j                        j                  d      }t        j                  |      }|j                  dk(  rt        j                  }	n-|j                   rt        j"                  }	nt        j$                  }	 | |||j                  |||	|      S # t        $ r Y qw xY w)zFConvert appengine_<API-version>_messages.Version into wrapped Version.g        Nr   )microsecondflexible)r%   r&   r'   r+   )rematch_VERSION_NAME_PATTERNnamegroupsr/   getr#   
createTimer   ParseDateTimereplaceLocalizeDateTime
ValueErrorr   FLEXvmMANAGED_VMSSTANDARD)
r2   r$   r"   r!   
service_id_r%   last_deployedlast_deployed_dtr'   s
             r   FromVersionResourcezVersion.FromVersionResource^   s     XXc&?&?&-ll44:FH GZB 1 1'**c BMM			 ..w/A/ABJJ K ../?@ {{j HHk	OOkLLkw
GJJm"/[ ') )  
s   *AD   	D,+D,c                 L    t        | j                  dz
        | j                  k  S )Ng      ?)absr%   _ALL_TRAFFIC_EPSILONr)   s    r   IsReceivingAllTrafficzVersion.IsReceivingAllTrafficv   s#    t!!C'(4+D+DDDr   c           	         | j                   sh	 |j                  | j                  | j                        | _         | j                   s$t	        j
                  dj                  |              | j                   S | j                   S # t        j                  $ r`}t	        j                  dj                  t        j                  |       t        j                  |                   Y d}~| j                   S d}~ww xY w)aG  Attempts to load the Version resource for this version.

    Returns the cached Version resource if it exists. Otherwise, attempts to
    load it from the server. Errors are logged and ignored.

    Args:
      api_client: An AppengineApiClient.

    Returns:
      The Version resource, or None if it could not be loaded.
    z-Failed to retrieve resource for version [{0}]z,Error retrieving Version resource [{0}]: {1}N)r$   GetVersionResourcer"   r#   r
   infoformatapitools_exceptionsErrorwarningsix	text_type)r)   
api_clientes      r   rS   zVersion.GetVersionResourcey   s     <<	D!44T\\477K||
((BII$O
P <<4<< !&& D 	BVCMM$/q1AB	D 	D<<Ds   AB C4AC//C4c                     t        |      t        u xrO | j                  |j                  k(  xr4 | j                  |j                  k(  xr | j                  |j                  k(  S r    )typer   r!   r"   r#   r)   others     r   __eq__zVersion.__eq__   sT    K7"  LLEMM) LLEMM)  GGuxx!r   c                     | |k(   S r    r   r_   s     r   __ne__zVersion.__ne__   s    u}r   c                     t        | j                  | j                  | j                  f|j                  |j                  |j                  f      S r    )cmpr!   r"   r#   r_   s     r   __cmp__zVersion.__cmp__   s:    dllDGG4u}}ehh79 9r   c                 d    dj                  | j                  | j                  | j                        S )Nz{0}/{1}/{2})rU   r!   r"   r#   rP   s    r   __str__zVersion.__str__   s#    dllDGGDDr   )NNNNN)r   r   r   __doc__rO   r1   r;   r,   classmethodr5   rL   rQ   rS   ra   rc   rf   rh   r   r   r   r   r   .   s{     6 ""& $#+$   ) ).E2!9Er   r   c                    | D ]  }|j                   |D cg c]  }|j                    c}vr$t        dj                  |j                               ||vsRt        dj                  |j                   |j                               yc c}w )aX  Validate that each version in filtered_versions is also in all_versions.

  Args:
    filtered_versions: list of Version representing a filtered subset of
      all_versions.
    all_versions: list of Version representing all versions in the current
      project.

  Raises:
    VersionValidationError: If a service or version is not found.
  Service [{0}] not found.zVersion [{0}/{1}] not found.Nr"   r   rU   r#   )filtered_versionsall_versionsr$   vs       r   _ValidateServicesAreSubsetrq      s     #g,?,Qqyy,??"
$
+
+GOO
<> >l""
(
/
/07

<= = #?s   Bc                     t        t        t        j                  |             }|D ]R  }|j                  s|j
                  st        d      |j                  r|j                  |k7  rt        d      ||_        T |S )aE  Parse the list of resource paths specifying versions.

  Args:
    paths: The list of resource paths by which to filter.
    project: The current project. Used for validation.

  Returns:
    list of Version

  Raises:
    VersionValidationError: If not all versions are valid resource paths for the
      current project.
  zTIf you provide a resource path as an argument, all arguments must be resource paths.z,All versions must be in the current project.)listr   r   r5   r!   r"   r   )pathsr!   versionsr$   s       r   ParseVersionResourcePathsrv      sv     #g..67(gOOw" $, - - 7??g5"
8: :GO  
/r   c                    | }|rU|| D cg c]  }|j                    c}vrt        dj                  |            | D cg c]  }|j                   |k(  s| }}|r|D cg c]  }|j                  |v s| }}|S c c}w c c}w c c}w )a  Return a list of versions to act on based on user arguments.

  Args:
    all_versions: list of Version representing all services in the project.
    versions: list of string, version names to filter for.
      If empty, match all versions.
    service: string or None, service name. If given, only match versions in the
      given service.

  Returns:
    list of matching Version

  Raises:
    VersionValidationError: If an improper combination of arguments is given.
  rl   rm   )ro   ru   r"   rn   rp   s        r   GetMatchingVersionsrx      s      #,7,Qqyy,77"#=#D#DW#MNN$0ILqAII4HLI$5J$5q9I$5J	 8I Ks   A<BB B4Bc                    i }|D ]^  }dj                  |j                  |j                        }	 t        j                  | j
                  |j                  |j                         ` |ri }|j                         D ]  \  }}dj                  ||      ||<    t        dj                  t        j                  t        |      d      dj                  t        |j!                                           dj                  t        |j#                                     z         y# t        j                  $ r#}t        j                  |      ||<   Y d}~Kd}~ww xY w)z/Delete the given version of the given services.z{0}/{1}Nz
[{0}]: {1}zIssue deleting {0}: [{1}]

r$   z, z

)rU   r"   r#   r	   CallAndCollectOpErrorsDeleteVersionMiscOperationErrorrY   rZ   itemsr   r   	Pluralizer0   joinrs   keysvalues)r[   ru   errorsr$   version_patherrprintable_errors	error_msgs           r   DeleteVersionsr      s.   &g##GOOWZZ@L0,,

"
"GOOWZZA  #)<<>i'3':':<;D(F|$ $2 '..NN3/0)<IId+00234	6 	D)00234	56 6  -- 0 ]]3/f\0s   5DE2EEc                    d}|rt        | ||      }|j                  |      }|j                  j                  j                  }|ro|j
                  |j                  k(  rVt        j                  j                  dj                  |             |j                  |j                  |j                  d       t        ||       |rt        |||       yy)a  Promote the new version to receive all traffic.

  First starts the new version if it is not running.

  Additionally, stops the previous version if stop_previous_version is True and
  it is possible to stop the previous version.

  Args:
    all_services: {str, Service}, A mapping of service id to Service objects
      for all services in the app.
    new_version: Version, The version to promote.
    api_client: appengine_api_client.AppengineApiClient to use to make requests.
    stop_previous_version: bool, True to stop the previous version which was
      receiving all traffic, if any.
    wait_for_stop_version: bool, indicating whether to wait for stop operation
    to finish.
  Nz+Starting version [{0}] before promoting it.T)block)_GetPreviousVersionrS   messagesr   ServingStatusValueValuesEnumservingStatusSTOPPEDr
   statusPrintrU   StartVersionr"   r#   _SetDefaultVersion_StopPreviousVersionIfApplies)all_servicesnew_versionr[   stop_previous_versionwait_for_stop_versionold_default_versionnew_version_resourcestatus_enums           r   PromoteVersionr     s    &  .k:/ %77
C##++HH+((K,?,??JJBf[)+K//tL[*-!"5z"79 r   c                 .    | j                   j                  S r    )r$   
versionUrl)r$   s    r   GetUrir   3  s    		#	##r   c                     | j                  |j                  d      }|sy|j                  |g      D ]0  }|j                         s|j                  |j                  k7  s.|c S  y)a  Get the previous default version of which new_version is replacing.

  If there is no such version, return None.

  Args:
    all_services: {str, Service}, A mapping of service id to Service objects
      for all services in the app.
    new_version: Version, The version to promote.
    api_client: appengine_api_client.AppengineApiClient, The client for talking
      to the App Engine Admin API.

  Returns:
    Version, The previous version or None.
  N)r>   r"   ListVersionsrQ   r#   )r   r   r[   r"   old_versions        r   r   r   7  s]     [00$7'	,,gY7k 	))++..( 8r   c                    t        j                  t        j                         d }	 t	        j
                  dd      }|j                  |j                  | j                  | j                  g|d       t        j                  t        j                         y	# t        j                  $ rM}|j                  \  }}|rt        j                  |d   |d          nt        j                         Y d	}~d	}~ww xY w)
zSets the given version as the default.

  Args:
    new_version: Version, The version to promote.
    api_client: appengine_api_client.AppengineApiClient to use to make requests.
  c                 6    t        | t        j                        S r    )
issubclassrV   	HttpError)exc_typeunused_exc_valueunused_tracebackunused_states       r   ShouldRetryz'_SetDefaultVersion.<locals>.ShouldRetry[  s    h 3 = =>>r   r      )max_retrialsexponential_sleep_multiplieri  )should_retry_ifsleep_ms   )tbN)r   CustomTimedEventr   SET_DEFAULT_VERSION_API_STARTr   RetryerRetryOnExceptionSetDefaultVersionr"   r#   MaxRetrialsExceptionlast_resultr   reraiseInternalErrorSET_DEFAULT_VERSION_API)r   r[   r   retryerr\   unused_resultexc_infos          r   r   r   R  s     
<EEF?'mmKG$${':':KNN&K#d  4 
<??@ 
	#	# ' !]H!!5 $$&&	 6's   AB C8+AC33C8c           	         | j                   }|j                  j                  j                  }|j                  |j
                  k7  r%t        j                  dj                  |              y|j                  xs  |j                  dk(  xs |j                  dk(   }|r=|j                  s1|j                  s%t        j                  dj                  |              yt        j                  j                  dj                  |              	 t        j                   |j"                  | j$                  | j&                  |       |s/t        j                  j                  dj                  |              yy# t        j(                  $ rf}t        j*                  d	j                  | t-        j.                  |                   t        j*                  d
j                  |              Y d}~yd}~ww xY w)a!  Stop the previous default version if applicable.

  Cases where a version will not be stopped:

  * If the previous default version is not serving, there is no need to stop it.
  * If the previous default version is an automatically scaled standard
    environment app, it cannot be stopped.

  Args:
    old_default_version: Version, The old default version to stop.
    api_client: appengine_api_client.AppengineApiClient to use to make requests.
    wait_for_stop_version: bool, indicating whether to wait for stop operation
    to finish.
  z?Previous default version [{0}] not serving, so not stopping it.Nflexr8   zgPrevious default version [{0}] is an automatically scaled standard environment app, so not stopping it.zStopping version [{0}].)service_namer*   r   zSent request to stop version [{0}]. This operation may take some time to complete. If you would like to verify that it succeeded, run:
  $ gcloud app versions describe -s {0.service} {0.id}
until it shows that the version has stopped.z!Error stopping version [{0}]: {1}zVersion [{0}] is still running and you must stop or delete it yourself in order to turn it off. (If you do not, you may be charged.))r$   r   r   r   r   SERVINGr
   rT   rU   rE   r   basicScalingmanualScalingr   r   r	   rz   StopVersionr"   r#   r|   rX   rY   rZ   )r   r[   r   version_objectr   is_standardr   s          r   r   r   n  s     '...##++HH+!![%8%88HH	f()+ #&& 6.*<*<*F 6#'':57+.55

&
&HH	88>9!" **,334GHI$ **(00&))#	% ! 
jj9 :@!:#	$ ! 
	+	+ 9KK3::;N;>==;MO PKK "F#679 99s   7E1 1G*AG%%G*)%ri   
__future__r   r   r   r9   apitools.base.pyr   rV   googlecloudsdk.api_lib.appr   r   r	   googlecloudsdk.corer
   r   googlecloudsdk.core.utilr   r   r   rY   	six.movesr   rW   r   r   objectr   rq   rv   rx   r   r   r   r   r   r   r   r   r   <module>r      s     4 &  ' 	 > * 3 6 * # ' * ) * 
 Z-- *** rEf rEj=,886.(9V$6A8<$r   