Qc@s-dZddkZddkZddkZddkZddkZddkZddkZddkl Z ddkl Z ddk Z ddk lZddk lZddk lZddk lZeiZd Zd Zd eifd YZd efd YZdefdYZdZdS(s7Commands for moving resources from one zone to another.iN(tapp(t appcommands(t command_base(tgcutil_logging(tutils(tversionidtMoveInstancesBasecBseZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZddZddZdZRS(s%The base class for the move commands.cCsOtt|i||tidtdd|tidtdd|dS(Ntforces!Override the confirmation prompt.t flag_valuestkeep_snapshotss8Do not delete snapshots that were created for the disks.(tsuperRt__init__tflagstDEFINE_booleantFalse(tselftnameR((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyR .scCs^|i|_|i|_|i|_|i|_|i|_ |i |_ dS(N( tdiskst _disks_apit instancest_instances_apit machineTypest_machine_type_apitprojectst _projects_apit snapshotst_snapshots_apitzonest _zones_api(Rtapi((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pytSetApi=s cOs]|idptidn|iid|ii|_|i||dGHdS(sThe point of entry to the command. This dispatches the subclass' HandleMove method. Raises: UsageError: If the service version is not v1beta14 or higher. The dependency on the version is due to the fact that snapshots were introduced in v1beta14. tv1beta14s;This command requires using API version v1beta14 or higher.tprojects The move completed successfully.N( t_IsUsingAtLeastApiVersionRt UsageErrorRtgett_projecttexecutet_project_resourcet HandleMove(Rtargstkwargs((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pytHandleEs   cCsB|p tdg}|D]%}|di|o ||qq~ p tdg}|D]%}|di|o ||qaqa~|jp td|o%d|GHtid|DGHnd|GHtid|DGH|od |GHti|GHn|ii o!ti otid nd S( sDisplays what is about to happen and prompts the user to proceed. Args: instances_to_mv: The instances that will be moved. instances_to_ignore: Instances that will not be moved because they're already in the destination zone. disks_to_mv: A list of the disk names that will be moved. dest_zone: The destination zone. Raises: CommandError: If the user declines to proceed. s6Cannot confirm move if there are no instances to move.tzonesCSome instances in the move set are already in the destination zone.s8Not all instances in ignore set are in destination zone.s8These instances are already in %s and will not be moved:cssx|]}|dVqWdS(RN((t.0ti((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys qs s,The following instances will be moved to %s:cssx|]}|dVqWdS(RN((R,R-((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys ts s(The following disks will be moved to %s:s Move aborted.N( tAssertionErrortendswithRt ListStringst_flagsRtProceedRt CommandError(Rtinstances_to_mvtinstances_to_ignoret disks_to_mvt dest_zonet_[1]R-t_[2]((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_ConfirmWs$ >6   c Cs|pdSdGHg}x=|D]5}|i|iid|id|d|dqW|i|dd\}}|o tid ti|n|i |i |d dS( sDeletes the given instances. Args: instances: A list of instance resources. zone: The zone to which the instances belong. Raises: CommandError: If one or more of the deletions fail. NsDeleting instances...R R+tinstanceRtcollection_nameRs3Aborting due to errors while deleting instances: %st operationList( tappendRtdeleteR$tExecuteRequestsRR3RR0t_CheckForErrorsInOpstMakeListResult(RRR+trequestsR;tresultst exceptions((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_DeleteInstances}s"  c CsE|pdSd|GHt|iidg}|i||g}x|D]}|i|id||dRtinsertR@RR3RR0RARB( RRtsrc_zoneR7t ip_addressesRCR;tdiskRDRE((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_CreateInstancess0     cCs|i|\}}g}xy|pgD]j}d|joWd|djoF|ddo7|dddid}|o|i|qq)q)W|o tidti|ndS(sCRaises CommandError if any operations in results contains an error.terrorterrorsitmessagesEncountered errors: %sN(t_PartitionResultsR#R>RR3RR0(RRDt_topsRTtopRS((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRAs-cCs{xt|D]l}xc|idgD]O}xF|idgD]2}d|jo|d|jod|dRRNR@RR3RR0RARBRotvalues( Rtsnapshot_mappingsROR7RCt disk_namet snapshot_nametsnapshot_resourceRDRE((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_CreateSnapshotss,  cCs| p |iiodSdGHg}x3|D]+}|i|iid|id|q,W|i|dd\}}|o tidt i |n|i |i |ddS( sDeletes the given snapshots. Args: snapshot_names: A list of snapshot names to delete. zone: The zones to which the snapshots belong. NsDeleting snapshots...R tsnapshotR<Rs3Aborting due to errors while deleting snapshots: %sR=( R1R R>RR?R$R@RR3RR0RARB(Rtsnapshot_namesR+RCRRDRE((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_DeleteSnapshots sc Cs|pdSdGHg}xk|iD]]\}}h|d6|i|id|d6}|i|iid|id|d|q$W|i|d d \}}|o tid t i |n|i |i |d dS( sCreates disks in the destination zone from the given snapshots. Args: snapshot_mappings: A dict of disk names to snapshot names. Disks are created in the destination zone from the given snapshot names. The disks will assume their previous names as indicated by the key-value pairs. dest_zone: The zone in which the disks will be created. Ns"Recreating disks from snapshots...RRtsourceSnapshotR RIR+R<Rs2Aborting due to errors while re-creating disks: %sR=( RrtNormalizeGlobalResourceNameR$R>RRNR@RR3RR0RARB( RRuR7RCRvRwt disk_resourceRDRE((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_CreateDisksFromSnapshots%s&  c Cs|pdSdGHg}x9|D]1}|i|iid|id|d|qW|i|dd\}}|o tidti|n|i |i |d dS( sDeletes the given disks. Args: disk_names: A list of disk names to delete. zone: The zone to which the disks belong. NsDeleting disks...R RQR+R<Rs/Aborting due to errors while deleting disks: %sR=( R>RR?R$R@RR3RR0RARB(Rt disk_namesR+RCRRDRE((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt _DeleteDisksDscsOti|ii|id}td|Dtfd|DS(s:Calculates the amount of CPUs used by the given instances.R`css'x |]}|d|dfVqWdS(tselfLinkt guestCpusN((R,tm((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys as c3s'x |]}t|dVqWdS(t machineTypeN(tfloat(R,R-(tnum_cpus(s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys bs (RRfRRgR$tdicttsum(RR4tmachines((Rs^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_CalculateNumCpus\s  cCs{t|}ti|ii|id|d}g}|D],}|d|jo|t|dq<q<~}t|S(s-Calculates the total size of the given disks.R+R`RtsizeGb(RJRRfRRgR$RR(RRR+RR8tdt disk_sizes((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_CalculateTotalDisksSizeGbds    @cCshht|d6|i|d6t|d6|i||d6|dj o t|n t|d6S(s@Generates a mapping between resource type to the quota required.t INSTANCEStCPUStDISKStDISKS_TOTAL_GBt SNAPSHOTSN(tlenRRR](RR4R6ROtsnapshots_to_create((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_CreateQuotaRequirementsDictns  c CsdGH|iid|id|i}|i|||d|}|i|iidg|idg|}tid|tid|xT|i D]F\} } |i| d| djot i d | |fqqWd S( sFRaises a CommandError if the quota to perform the move does not exist.s/Checking project and destination zone quotas...R R+RtquotassRequired quota for move is: %ssAvailable quota is: %sis:You do not have enough quota for %s in %s or your project.N( RR#R$R%Rt_ExtractAvailableQuotaR&RhtdebugRrRR3( RR4R6ROR7Rtdest_zone_resourcet requirementst availabletmetrictrequired((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt _CheckQuotaszs"    cCst|i}h}xs|D]k}|id}||joI|id|id||<|djo||c||7 ... cCsOtt|i||tidddd|tidddd|dS(s&Constructs a new MoveInstances object.t source_zones3The source zone from which instances will be moved.Rtdestination_zones0The zone to which the instances should be moved.N(R RR R t DEFINE_stringR](RRR((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyR scCsp|iiptidn|iiptidn|ii|iijotidndS(s;Raises a UsageError if there is any problem with the flags.s>You must specify a source zone through the --source_zone flag.sHYou must specify a destination zone through the --destination_zone flag.s1The destination and source zones cannot be equal.N(R1RRR"R(R((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_ValidateFlagss   cGsh|i|ptidn|i|ii|i_|id|iidi|fGHt i |i i |i dt i|d|iid}t i |i i |i dt i|d|iid}|i||t i |i i |i dt i|ddd|iid}d GH|i|}|i|||i|||ii|ii|i|g||ii|i}|i|}|i||||i||ii|i||ii|ii|i||ii|i||ii|i||ii|ii|i|i|iiti|d S( sHandles the actual move. Args: *instance_regexes: The sequence of name regular expressions used for filtering. s:You must specify at least one regex for instances to move.s*Retrieving instances in %s matching: %s...t tfilterR+R`RYtnesChecking disk preconditions...N( RRR"tDenormalizeResourceNameR1Rt_CheckDestinationZoneRtjoinRRfRRgR$tRegexesToFilterExpressiont_CheckInstancePreconditionst_GetPersistentDiskNamest_CheckDiskPreconditionsRR:t_GenerateLogPatht_GenerateSnapshotNamest _WriteLogRFRyRRRRR|Rttostremove(Rtinstance_regexesR4tinstances_in_destR5R6tlog_pathRu((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyR's`                     cCstd|DS(sReturns a dict mapping each disk name to a random UUID. The UUID will be used as the disk's snapshot name. UUID's are valid Compute resource names. Further, UUID collisions are improbable, so using them is a great way for generating resource names (e.g., we avoid network communication to check if the name we choose already exists). Args: disk_names: A list of disk_names for which snapshot names should be generated. Returns: A dict with the mapping. css/x(|]!}|dttifVqWdS(s snapshot-N(tstrtuuidtuuid4(R,R((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys Ks (R(RR((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyR;sc Cs|ptidnt|tjotidtng}|D]}||dqO~}g}|D]}||dqt~}t|t|@}|o tidti|ndS(Ns!No matching instances were found.sMAt most %s instances can be moved at a time. Refine your query and try again.RssEncountered name collisions. Instances with the following names exist in both the source and destination zones: %s(RR3RtMAX_INSTANCES_TO_MOVERJRR0( RR4RR8R-t src_namesR9t dest_namest common_names((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRMs%%cCst|tjotidtn|i||}|oZg}|D]&\}}|d|di|fqN~}tidti|ndS(NsIAt most %s disks can be moved at a time. Refine your query and try again.s%s: %ss, sSome of the instances you'd like to move have disks that are in use by other instances: (Offending instance: disks attached) %s(RtMAX_DISKS_TO_MOVERR3t#_CheckForDisksInUseByOtherInstancesRRR0(RR5RtresR8R;Rtoffending_instances((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyR`s 3cCsh}t|}x|D]}|d}x|idgD]r}|ddjoq<n|didd}||jo0||jog||tsortedRr(RRRRR;t instance_nameRQRv((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRps     cCskg}x^|D]V}xM|idgD]9}|ddjo"|i|diddq&q&Wq W|S(NRRRRHRi(R#R>R(RRRR;RQ((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRs*cCs1dGH|iid|id|iiidS(s9Raises an exception if the destination zone is not valid.sChecking destination zone...R R+N(RR#R$R1RR%(R((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRscCsdGHd|GHt|dii}zU|~}htid6|iid6|iid6|d6|d6}ti ||Wd QXd S( s?Logs the instances that will be moved and the destination zone.s/If the move fails, you can re-attempt it using:s gcutil resumemove %stwRR7RORRuN( topent__exit__t __enter__Rt __version__R1RRtjsontdump(RRR4RuR8tftcontents((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRs &    cCs;tiiid}tiitiidd|S(s>Generates a file path in the form ~/.gcutil.move.YYmmddHHMMSS.s %Y%m%d%H%M%St~s .gcutil.move.(tdatetimetutcnowtstrftimeRtpathRt expanduser(Rt timestamp((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRs(RRRtpositional_argsR RR'RRRRRRRR(((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyRs  M       t ResumeMovecBsJeZdZdZdZdZdZdZdZdZ RS(sResume a previously-failed move. The moveinstances subcommand produces a log file that can be used to re-attempt a move that fails. This is intended to help complete moves that are interrupted by the user or by transient network failures. WARNING: Instances that are moved will lose ALL of their ephemeral state (i.e., ephemeral disks, ephemeral IP addresses, and memory). s cCs6tt|i||tidtdd|dS(Nt keep_log_files>If true, the log file is not deleted at the end of the resume.R(R RR R R R(RRR((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyR s cCsJtd|D}g}|D]"}|d|jo ||q!q!~S(s:set(resources1) & set(resources2) based on the name field.cssx|]}|dVqWdS(RN((R,tr((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys s R(RJ(Rt resources1t resources2tnames1R8R((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt _IntersectscCsJtd|D}g}|D]"}|d|jo ||q!q!~S(s:set(resources1) - set(resources2) based on the name field.cssx|]}|dVqWdS(RN((R,R((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pys s R(RJ(RRRtnames2R8R((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt _SubtractscCs=|i|}|djotidt|n|S(s@Returns log[key] or raises a CommandError if key does not exist.s&The log file did not contain a %s key.N(R#R]RR3trepr(Rtlogtkeytvalue((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt_GetKeys  cCsAdGHt|ii}z|~}ti|}WdQX|S(s;Loads the JSON contents of the file pointed to by log_path.sParsing log file...N(RRRRtload(RRR8Rtresult((s^/Users/riccardo/git/gcloud/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.pyt _ParseLogs#c Cs2tii|ptid|n|i|}|i|d}d|GH|i|d}d|GH|i|d}|i|d}ti|i i |i d|d }ti|i i |i d|d }|i ||} |i ||}|ptid |ntti|ii |i d|} tti|ii |i d|} t|i| @} |i ||} h}| odti|ii |i }xF|iD]4\}}|| jo||jo|||s,