
    F                       S r SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKrSSKJ	r	J
r
  SS	KJr   \R                  r " S
 S\R                   5      rSrSS jrS rS rS rS rS r " S S\R2                  5      rg! \ a    \r NKf = f)z.Wrapper for Cloud Run TrafficTargets messages.    )absolute_import)annotations)division)print_function)unicode_literalsN)	ContainerMapping)
exceptionsc                      \ rS rSrSrSrg) InvalidTrafficSpecificationError"   z3Error to indicate an invalid traffic specification. N)__name__
__module____qualname____firstlineno____doc____static_attributes__r       )lib/googlecloudsdk/api_lib/run/traffic.pyr   r   "   s    ;r   r   LATESTc                ^    U[         :X  a  U R                  SX#S9nU$ U R                  XUS9nU$ )aN  Creates a new TrafficTarget.

Args:
  messages: The message module that defines TrafficTarget.
  key: The key for the traffic target in the TrafficTargets mapping.
  percent: Optional percent of traffic to assign to the traffic target.
  tag: Optional tag to assign to the traffic target.

Returns:
  The newly created TrafficTarget.
T)latestRevisionpercenttag)revisionNamer   r   )LATEST_REVISION_KEYTrafficTarget)messageskeyr   r   results        r   NewTrafficTargetr"   -   sJ     	##W $ F
 
- ##3#OF	-r   c                H    U R                   (       a  [        $ U R                  $ )zReturns the key for a TrafficTarget.

Args:
  target: TrafficTarget, the TrafficTarget to check

Returns:
  LATEST_REVISION_KEY if target is for the latest revison or
  target.revisionName if not.
)r   r   r   )targets    r   GetKeyr%   B   s     !' 5 5	N6;N;NNr   c                .    U [         :X  a  SU 4nU$ SU 4nU$ )ah  Sorted key function  to order TrafficTarget keys.

TrafficTargets keys are one of:
o revisionName
o LATEST_REVISION_KEY

Note LATEST_REVISION_KEY is not a str so its ordering with respect
to revisionName keys is hard to predict.

Args:
  key: Key for a TrafficTargets dictionary.

Returns:
  A value that sorts by revisionName with LATEST_REVISION_KEY
  last.
      )r   )r    r!   s     r   SortKeyFromKeyr)   O   s-    " 	XF 
- XF	-r   c                .    [        U 5      n[        U5      $ )zSorted key function to order TrafficTarget objects by key.

Args:
  target: A TrafficTarget.

Returns:
  A value that sorts by revisionName with LATEST_REVISION_KEY
  last.
)r%   r)   )r$   r    s     r   SortKeyFromTargetr+   g   s     	v#		r   c                    U R                   (       a  U R                   OSnU R                  (       a  U R                  OSnX4$ )zBKey function for sorting TrafficTarget objects during __getitem__.r    )r   r   )r$   r   r   s      r   _GetItemSortKeyr.   u   s.     %nnFNN!'jj

b#	r   c                D    U u  pSU[        U5      -
  -
  U[        U5      /$ )a  Returns object that sorts in the order we correct traffic rounding errors.

The caller specifies explicit traffic percentages for some revisions and
this module scales traffic for remaining revisions that are already
serving traffic up or down to assure that 100% of traffic is assigned.
This scaling can result in non integrer percentages that Cloud Run
does not supprt. We correct by:
  - Trimming the decimal part of float_percent, int(float_percent)
  - Adding an extra 1 percent traffic to enough revisions that have
    had their traffic reduced to get us to 100%

The returned value sorts in the order we correct revisions:
  1) Revisions with a bigger loss due are corrected before revisions with
     a smaller loss. Since 0 <= loss < 1 we sort by the value:  1 - loss.
  2) In the case of ties revisions with less traffic are corrected before
     revisions with more traffic.
  3) In case of a tie revisions with a smaller key are corrected before
     revisions with a larger key.

Args:
  key_and_percent: tuple with (key, float_percent)

Returns:
  An value that sorts with respect to values returned for
  other revisions in the order we correct for rounding
  errors.
r(   )intr)   )key_and_percentr    float_percents      r   NewRoundingCorrectionPrecedencer3      s3    8 '#=3}--.S
 r   c                      \ rS rSrSrS rS rS rS rS r	S r
S	 r\S
 5       rS rS rS rS rS rS rS rS rS rS rS rSS jrS rS r      SS jrSrg)TrafficTargets   aW  Wraps a repeated TrafficTarget message and provides dict-like access.

The dictionary key is one of
   LATEST_REVISION_KEY for the latest revision
   TrafficTarget.revisionName for TrafficTargets with a revision name.

The dictionary value is a list of all traffic targets referencing the same
revision, either by name or the latest revision.
c                R    Xl         X l        U R                   R                  U l        g)a  Constructs a new TrafficTargets instance.

The TrafficTargets instance wraps the to_wrap argument, which is a repeated
proto message. Operations that mutate to_wrap will usually occur through
this class, but that is not a requirement. Callers can directly mutate
to_wrap by accessing the proto directly.

Args:
  messages_module: The message module that defines TrafficTarget.
  to_wrap: The traffic targets to wrap.
N)	_messages_mr   _traffic_target_cls)selfmessages_moduleto_wraps      r   __init__TrafficTargets.__init__   s      %NG#~~;;Dr   c                p   ^ [        U4S jU R                   5       [        S9nU(       d  [        T5      eU$ )av  Gets a sorted list of traffic targets associated with the given key.

Allows accessing traffic targets based on the revision they reference
(either directly by name or the latest ready revision by specifying
"LATEST" as the key).

Returns a sorted list of traffic targets to support comparison operations on
TrafficTargets objects which should be independent of the order of the
traffic targets for a given key.

Args:
  key: A revision name or "LATEST" to get the traffic targets for.

Returns:
  A sorted list of traffic targets associated with the given key.

Raises:
  KeyError: If this object does not contain the given key.
c              3  J   >#    U  H  n[        U5      T:X  d  M  Uv   M     g 7fNr%   ).0tr    s     r   	<genexpr>-TrafficTargets.__getitem__.<locals>.<genexpr>   s     0GqvayC/Gs   #	#r    )sortedr9   r.   KeyError)r;   r    r!   s    ` r   __getitem__TrafficTargets.__getitem__   s1    ( 0DGG0oF SMMr   c                h    U R                    Vs/ s H  n[        U5      U:w  d  M  UPM     sn$ s  snf )z1Gets all targets that do not match the given key.r9   r%   )r;   r    rE   s      r   _OtherTargetsTrafficTargets._OtherTargets   s)    ww3w!&)s"2Aw333s   //c                    X;  a  U R                   R                  U5        gU R                  U5      U-   U R                   SS& g)z/Implements evaluation of `self[key] = targets`.N)r9   extendrO   )r;   r    new_targetss      r   __setitem__TrafficTargets.__setitem__   s4    

ggnn[!%%c*[8dggajr   c           	     r   U R                  U5      nU(       ak  U Vs/ s H4  nUR                  (       d  M  [        U R                  XR                  S9PM6     nnUR	                  [        U R                  X5      5        XPU'   gU R
                  R	                  [        U R                  X5      5        gs  snf )zSet the given percent in the traffic targets.

Moves any tags on existing targets with the specified key to zero percent
targets.

Args:
  key: Name of the revision (or "LATEST") to set the percent for.
  percent: Percent of traffic to set.
r   N)getr   r"   r8   appendr9   )r;   r    r   existingrE   rS   s         r   
SetPercentTrafficTargets.SetPercent   s     xx}H aUU ;
4>>3EE
:  
 )$..#GH3i
ggnn%dnncCDs
   B4"B4c                `    X;  a  [        U5      eU R                  U5      U R                  SS& g)z)Implements evaluation of `del self[key]`.N)rJ   rO   r9   )r;   r    s     r   __delitem__TrafficTargets.__delitem__   s)    
SM##C(DGGAJr   c                L    U R                    H  nU[        U5      :X  d  M    g   g)z(Implements evaluation of `item in self`.TFrN   )r;   r    r$   s      r   __contains__TrafficTargets.__contains__  s$    ''	v	  r   c                :    [        S U R                   5       5      $ )z$A set containing the mapping's keys.c              3  8   #    U  H  n[        U5      v   M     g 7frB   rC   )rD   rE   s     r   rF   *TrafficTargets._key_set.<locals>.<genexpr>  s     *'Qvayy'   )setr9   r;   s    r   _key_setTrafficTargets._key_set  s     *$''***r   c                ,    [        U R                  5      $ )z%Implements evaluation of `len(self)`.)lenri   rh   s    r   __len__TrafficTargets.__len__  s    t}}r   c                ,    [        U R                  5      $ )z1Returns an iterator over the traffic target keys.)iterri   rh   s    r   __iter__TrafficTargets.__iter__  s    r   c                    U R                   $ rB   )r9   rh   s    r   MakeSerializableTrafficTargets.MakeSerializable  s    77Nr   c                X    SR                  S U R                  5        5       5      nSU-  $ )Nz, c              3  H   #    U  H  u  pS R                  X5      v   M     g7f)z{}: {}N)format)rD   kvs      r   rF   *TrafficTargets.__repr__.<locals>.<genexpr>  s     G,$!--,s    "z[%s])joinitems)r;   contents     r   __repr__TrafficTargets.__repr__  s'    iiG$**,GGGGr   c           	     v   / n0 nU R                    H  n[        U5      nUR                  (       a-  UR                  [	        U R
                  XCR                  S95        UR                  (       d  M_  UR                  U[	        U R
                  US5      5      =R                  UR                  -  sl        M     X!4$ )a  Returns normalized targets, split into percent and tags targets.

Moves all tags to 0% targets. Combines all targets with a non-zero percent
that reference the same revision into a single target. Drops 0% targets
without tags. Does not modify the underlying repeated message field.

Returns:
  A tuple of (percent targets, tag targets), where percent targets is a
  dictionary mapping key to traffic target for all targets with percent
  greater than zero, and tag targets is a list of traffic targets with
  tags and percent equal to zero.
rW   r   )r9   r%   r   rY   r"   r8   r   
setdefault)r;   tag_targetspercent_targetsr$   r    s        r   _GetNormalizedTraffic$TrafficTargets._GetNormalizedTraffic  s     KO''6Nc	T^^SjjA	
 
""!$..#q9	
 	
'V^^	$
  ''r   c                    SnU H  nX#R                   -  nM     US:w  a  [        SU-  5      eU H:  nUR                   S:  d  M  [        S[        U5      < SUR                   < S35      e   g)z!Validate current traffic targets.r   d   z3Current traffic allocation of %s is not 100 percentzCurrent traffic for target z is negative ()N)r   
ValueErrorr%   )r;   existing_percent_targetsr   r$   s       r   _ValidateCurrentTraffic&TrafficTargets._ValidateCurrentTraffic7  sr    G*g + #~
?'
I  +	!	f~v~~/
 	
 +r   c                    0 nU R                    H,  n[        U5      nUR                  (       d  M!  XA;  d  M(  X2U'   M.     U$ )z7Get TrafficTargets with traffic not in new_percentages.)r9   r%   r   )r;   new_percentagesr!   r$   r    s        r   _GetUnassignedTargets$TrafficTargets._GetUnassignedTargetsI  s:    F''6Nc	C6s  Mr   c                    [        UR                  5       5      nUS:  a  [        S5      eU H)  nX   S:  d
  X   S:  d  M  [        SU< SX   < S35      e   U(       d  US:  a  [        S5      egg)	z8Validate the new traffic percentages the user specified.r   z"Over 100% of traffic is specified.r   zNew traffic for target z is z, not between 0 and 100zPEvery target with traffic is updated but 100% of traffic has not been specified.N)sumvaluesr   )r;   r   unspecified_targetsspecified_percentr    s        r   _ValidateNewPercentages&TrafficTargets._ValidateNewPercentagesR  s    O22453,
.  			!_%9C%?.O(*
 	
  #4s#:,,  $;r   c                >    [        UR                  5       5      nSU-
  $ )zAReturns percentage of traffic not explicitly specified by caller.r   )r   r   )r;   r   r   s      r   _GetPercentUnspecifiedTraffic,TrafficTargets._GetPercentUnspecifiedTrafficg  s"    O2245"""r   c                @   U Vs0 s H  o"[        X   5      _M     nn[        [        [        UR                  5       5      5      5      [        UR                  5       5      -
  n[	        UR                  5       [        S9nUSU  H  u  pgX6==   S-  ss'   M     U$ s  snf )z$Returns rounded integer percentages.rH   Nr(   )r0   roundr   r   rI   r}   r3   )r;   float_percentagesry   rounded_percentageslosscorrection_precedencer    _s           r   _IntPercentagesTrafficTargets._IntPercentagesl  s     /@.?3 #$$.?   uS*113456""$: D #!'F (.!# /s   Bc                    U R                  U5      nUS:X  a  0 $ [        S UR                  5        5       5      n0 nU H"  nX&   R                  [	        U5      -  U-  XV'   M$     U$ )Nr   c              3  8   #    U  H  oR                   v   M     g 7frB   )r   )rD   r$   s     r   rF   9TrafficTargets._GetAssignedPercentages.<locals>.<genexpr>  s      !%@6%@rf   )r   r   r   r   float)r;   r   unassigned_targetspercent_to_assignpercent_to_assign_fromassigned_percentagesry   s          r   _GetAssignedPercentages&TrafficTargets._GetAssignedPercentages{  s    ::?KAi  !%7%>%>%@!  


'
'#$%"#     r   c                   U R                  5       u  p#U R                  UR                  5       5        UR                  5       nU R	                  U5      nU R                  XE5        UR                  U R                  XE5      5        U R                  U5      n/ nU HO  nX;   a
  X   S:X  a  M  X;   a  X(   n	Xh   U	l	        O[        U R                  XU   5      n	UR                  U	5        MQ     [        U[        S9nU R                  SS2	 U R                  R!                  U5        U R                  R!                  U5        g)a  Update traffic percent assignments.

The updated traffic percent assignments will include assignments explicitly
specified by the caller. If the caller does not assign 100% of
traffic explicitly this function will scale traffic for targets
the user does not specify with an existing percent greater than zero up or
down based on the provided assignments as needed.

This method normalizes the traffic targets while updating the traffic
percent assignments. Normalization merges all targets referencing the same
revision without tags into a single target with the combined percent.
Normalization also moves any tags referencing a revision to zero percent
targets.

The update removes targets with 0% traffic unless:
 o The user explicitly specifies under 100% of total traffic
 o The user does not explicitly specify 0% traffic for the target.
 o The 0% target has a tag.

Args:
  new_percentages: Map from revision to percent traffic for the revision.
    'LATEST' means the latest rev.

Raises:
  ValueError: If the current traffic for the service is invalid.
  InvalidTrafficSpecificationError: If the caller attempts to set
    the traffic for the service to an incorrect state.
r   rH   N)r   r   r   copyr   r   updater   r   r   r"   r8   rY   rI   r+   r9   rR   )
r;   r   r   r   updated_percentagesr   int_percentagesnew_percent_targetsr    r$   s
             r   UpdateTrafficTrafficTargets.UpdateTraffic  s)   : -1,F,F,H)  !9!@!@!BC)..0334GH  !4I$$%8M **+>?O		O$8A$=*).(-!$..#s7KL  (  !!4:KL
GGNN&'GGNN;r   c                T   U R                  5       u  p#[        U;   a  UR                  [        5      nX;   a"  X!   =R                  UR                  -  sl        O"[	        U R
                  XR                  5      X!'   [        UR                  5       [        S9nXS-   U R                  SS& gg)z;Reasign traffic from LATEST to the current latest revision.rH   N)
r   r   popr   r"   r8   rI   r   r+   r9   )r;   latest_ready_revision_namer   r   latestsorted_percent_targetss         r   ZeroLatestTraffic TrafficTargets.ZeroLatestTraffic  s    #'#=#=#? Oo-""#67f	#	63;;v~~M;6FNN67
3  &

 
 
"(9  *7dggaj .r   c                    U R                    Vs0 s H+  oR                  (       d  M  UR                  [        U5      _M-     sn$ s  snf rB   )r9   r   r%   )r;   r$   s     r   TagToKeyTrafficTargets.TagToKey  s2    59WWKW6

&FJJv&WKKKs
   AAc           	        / nU R                   (       d)  [        U R                  [        S5      /U R                   SS& U R                    Hf  nU(       d   UR                  U;   d  UR                  U;   a  SUl        UR
                  (       d  UR                  (       d  MU  UR                  U5        Mh     [        UR                  5       5       H(  u  pgUR                  [        U R                  XvS95        M*     X@R                   SS& g)a  Update traffic tags.

Removes and/or clears existing traffic tags as requested. Always adds new
tags to zero percent targets for the specified revision. Treats a tag
update as a remove and add.

Args:
  to_update: A dictionary mapping tag to revision name or 'LATEST' for the
    latest ready revision.
  to_remove: A list of tags to remove.
  clear_others: A boolean indicating whether to clear tags not specified in
    to_update.
r   NrW   )	r9   r"   r8   r   r   r   rY   rI   r}   )r;   	to_update	to_removeclear_othersrS   r$   r   revision_keys           r   
UpdateTagsTrafficTargets.UpdateTags  s    & K 77$T^^5H#NOdggaj''	y0FJJ)4K
	6:::6"	 
 $IOO$56
4>><
A 7 GGAJr   )r9   r8   r:   N)r   zMapping[str, int])r   zMapping[str, str]r   zContainer[str]r   bool)r   r   r   r   r   r>   rK   rO   rT   r[   r^   ra   propertyri   rm   rq   rt   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r5   r5      s    < 649E,) + +(6
$*#
 84 l8 L"""  " 	"r   r5   )NN)r   
__future__r   r   r   r   r   collectionscollections.abcr   r	   googlecloudsdk.corer
   abccollections_abcAttributeErrorErrorr   r   r"   r%   r)   r+   r.   r3   MutableMappingr5   r   r   r   <module>r      s    5 & "  % '  . * OO/
z'7'7   *
O0!H^_33 ^M   / s   B BB