diff --git a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php --- a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php +++ b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php @@ -26,6 +26,12 @@ 'JSON file with lease attributes. Use "-" to read attributes '. 'from stdin.'), ), + array( + 'name' => 'count', + 'param' => 'N', + 'default' => 1, + 'help' => pht('Lease a given number of identical resources.'), + ), )); } @@ -33,11 +39,10 @@ $viewer = $this->getViewer(); $resource_type = $args->getArg('type'); - if (!$resource_type) { + if (!phutil_nonempty_string($resource_type)) { throw new PhutilArgumentUsageException( pht( - 'Specify a resource type with `%s`.', - '--type')); + 'Specify a resource type with "--type".')); } $until = $args->getArg('until'); @@ -46,17 +51,24 @@ if ($until <= 0) { throw new PhutilArgumentUsageException( pht( - 'Unable to parse argument to "%s".', - '--until')); + 'Unable to parse argument to "--until".')); } } + $count = $args->getArgAsInteger('count'); + if ($count < 1) { + throw new PhutilArgumentUsageException( + pht( + 'Value provided to "--count" must be a nonzero, positive '. + 'number.')); + } + $attributes_file = $args->getArg('attributes'); if (phutil_nonempty_string($attributes_file)) { if ($attributes_file == '-') { echo tsprintf( "%s\n", - 'Reading JSON attributes from stdin...'); + pht('Reading JSON attributes from stdin...')); $data = file_get_contents('php://stdin'); } else { $data = Filesystem::readFile($attributes_file); @@ -67,38 +79,44 @@ $attributes = array(); } - $lease = id(new DrydockLease()) - ->setResourceType($resource_type); + $leases = array(); + for ($idx = 0; $idx < $count; $idx++) { + $lease = id(new DrydockLease()) + ->setResourceType($resource_type); - $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); - $lease->setAuthorizingPHID($drydock_phid); + $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); + $lease->setAuthorizingPHID($drydock_phid); - if ($attributes) { - $lease->setAttributes($attributes); - } + if ($attributes) { + $lease->setAttributes($attributes); + } - // TODO: This is not hugely scalable, although this is a debugging workflow - // so maybe it's fine. Do we even need `bin/drydock lease` in the long run? - $all_blueprints = id(new DrydockBlueprintQuery()) - ->setViewer($viewer) - ->execute(); - $allowed_phids = mpull($all_blueprints, 'getPHID'); - if (!$allowed_phids) { - throw new Exception( - pht( - 'No blueprints exist which can plausibly allocate resources to '. - 'satisfy the requested lease.')); - } - $lease->setAllowedBlueprintPHIDs($allowed_phids); + // TODO: This is not hugely scalable, although this is a debugging + // workflow so maybe it's fine. Do we even need `bin/drydock lease` in + // the long run? + $all_blueprints = id(new DrydockBlueprintQuery()) + ->setViewer($viewer) + ->execute(); + $allowed_phids = mpull($all_blueprints, 'getPHID'); + if (!$allowed_phids) { + throw new Exception( + pht( + 'No blueprints exist which can plausibly allocate resources to '. + 'satisfy the requested lease.')); + } + $lease->setAllowedBlueprintPHIDs($allowed_phids); - if ($until) { - $lease->setUntil($until); - } + if ($until) { + $lease->setUntil($until); + } - // If something fatals or the user interrupts the process (for example, - // with "^C"), release the lease. We'll cancel this below, if the lease - // actually activates. - $lease->setReleaseOnDestruction(true); + // If something fatals or the user interrupts the process (for example, + // with "^C"), release the lease. We'll cancel this below, if the lease + // actually activates. + $lease->setReleaseOnDestruction(true); + + $leases[] = $lease; + } // TODO: This would probably be better handled with PhutilSignalRouter, // but it currently doesn't route SIGINT. We're initializing it to setup @@ -107,29 +125,52 @@ pcntl_signal(SIGINT, array($this, 'didReceiveInterrupt')); $t_start = microtime(true); - $lease->queueForActivation(); + echo tsprintf( - "%s\n\n __%s__\n\n%s\n", - pht('Queued lease for activation:'), - PhabricatorEnv::getProductionURI($lease->getURI()), - pht('Waiting for daemons to activate lease...')); + "%s\n\n", + pht('Leases queued for activation:')); + + foreach ($leases as $lease) { + $lease->queueForActivation(); - $this->waitUntilActive($lease); + echo tsprintf( + " __%s__\n", + PhabricatorEnv::getProductionURI($lease->getURI())); + } + + echo tsprintf( + "\n%s\n\n", + pht('Waiting for daemons to activate leases...')); + + foreach ($leases as $lease) { + $this->waitUntilActive($lease); + } // Now that we've survived activation and the lease is good, make it // durable. - $lease->setReleaseOnDestruction(false); + foreach ($leases as $lease) { + $lease->setReleaseOnDestruction(false); + } + $t_end = microtime(true); echo tsprintf( - "%s\n\n %s\n\n%s\n", + "\n%s\n\n", pht( - 'Activation complete. This lease is permanent until manually '. - 'released with:'), - pht('$ ./bin/drydock release-lease --id %d', $lease->getID()), + 'Activation complete. Leases are permanent until manually '. + 'released with:')); + + foreach ($leases as $lease) { + echo tsprintf( + " %s\n", + pht('$ ./bin/drydock release-lease --id %d', $lease->getID())); + } + + echo tsprintf( + "\n%s\n", pht( - 'Lease activated in %sms.', + 'Leases activated in %sms.', new PhutilNumber((int)(($t_end - $t_start) * 1000)))); return 0; @@ -183,7 +224,8 @@ } echo tsprintf( - "<%s> %B\n", + "(Lease #%d) <%s> %B\n", + $lease->getID(), $type, $data); }