Skip to content

Commit

Permalink
Runbook Command: lookup tenant by Id or name (#87)
Browse files Browse the repository at this point in the history
* lookup tenant by id or name

* Support * with tenant name or id lookup

* remove tenant lookup logging when no tenant lookup is performed
  • Loading branch information
paulegradie authored Jul 2, 2020
1 parent 830d6c9 commit 28e6e20
Showing 1 changed file with 33 additions and 21 deletions.
54 changes: 33 additions & 21 deletions source/Octopus.Cli/Commands/Runbooks/RunRunbookCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@
using Octopus.Cli.Repositories;
using Octopus.Cli.Util;
using Octopus.Client;
using Octopus.Client.Exceptions;
using Octopus.Client.Model;
using Octostache;

namespace Octopus.Cli.Commands.Runbooks
{


[Command("run-runbook", Description = "Runs a Runbook.")]
public class RunRunbookCommand : ApiCommand, ISupportFormattedOutput
{
private readonly ExecutionResourceWaiter.Factory executionResourceWaiterFactory;
private readonly Dictionary<string, string> variables = new Dictionary<string, string>();
private readonly Dictionary<string, string> Variables = new Dictionary<string, string>();

private RunbookRunResource[] runbookRuns { get; set; }
private RunbookRunResource[] RunbookRuns { get; set; }

private string ProjectNameOrId { get; set; } // required for tenant filtering with *, runbook filtering
private string RunbookNameOrId { get; set; }
Expand All @@ -33,7 +29,7 @@ public class RunRunbookCommand : ApiCommand, ISupportFormattedOutput
private List<string> ExcludedMachineIds { get; } = new List<string>();
private List<string> StepNamesToSkip { get; } = new List<string>();
private bool UseDefaultSnapshot { get; } = false;
private List<string> TenantIds { get; } = new List<string>();
private List<string> TenantNamesOrIds { get; } = new List<string>();
private List<string> TenantTagNames { get; } = new List<string>();
private DateTimeOffset? RunAt { get; set; }
private DateTimeOffset? NoRunAfter { get; set; }
Expand Down Expand Up @@ -93,7 +89,7 @@ public RunRunbookCommand(

options.Add<string>("tenant=",
"[Optional] Run a runbook on the tenant with this name or ID; specify this argument multiple times to add multiple tenants or use `*` wildcard to deploy to all tenants who are ready for this release (according to lifecycle).",
v => TenantIds.Add(v));
v => TenantNamesOrIds.Add(v));

options.Add<string>("tenantTag=",
"[Optional] Run a runbook on the tenants matching this tag; specify this argument multiple times to build a query/filter with multiple tags, just like you can in the user interface.",
Expand All @@ -116,7 +112,12 @@ public RunRunbookCommand(
options.Add<bool>("waitForRun", "[Optional] Whether to wait synchronously for deployment to finish.",
v => WaitForRun = true);

options.Add<bool>("progress", "[Optional] Show progress of the runbook run", v => { Progress = true; WaitForRun = true; NoRawLog = true; });
options.Add<bool>("progress", "[Optional] Show progress of the runbook run", v =>
{
Progress = true;
WaitForRun = true;
NoRawLog = true;
});

options.Add<TimeSpan>("runTimeout=",
"[Optional] Specifies maximum time (timespan format) that the console session will wait for the runbook run to finish (default 00:10:00). This will not stop the run. Requires --waitForRun parameter to be set.",
Expand All @@ -141,6 +142,7 @@ public async Task Request()
var project = await Repository.Projects.FindByNameOrIdOrFail(ProjectNameOrId).ConfigureAwait(false);
var runbook = await Repository.Runbooks.FindByNameOrIdOrFail(RunbookNameOrId, project).ConfigureAwait(false);
var environments = await Repository.Environments.FindByNamesOrIdsOrFail(EnvironmentNamesOrIds).ConfigureAwait(false);
var tenants = await RetrieveTenants();
LogScheduledDeployment();

var payload = new RunbookRunParameters()
Expand All @@ -155,20 +157,20 @@ public async Task Request()
ExcludedMachineIds = ExcludedMachineIds.ToArray(),
SkipActions = StepNamesToSkip.ToArray(),
UseGuidedFailure = GuidedFailure,
TenantIds = TenantIds.ToArray(),
TenantIds = tenants,
TenantTagNames = TenantTagNames.ToArray(),
QueueTime = RunAt,
QueueTimeExpiry = NoRunAfter,
FormValues = variables
FormValues = Variables
};

runbookRuns = await Repository.Runbooks.Run(runbook, payload);
RunbookRuns = await Repository.Runbooks.Run(runbook, payload);

if (runbookRuns.Any() && WaitForRun)
if (RunbookRuns.Any() && WaitForRun)
{
var waiter = executionResourceWaiterFactory(Repository, ServerBaseUrl);
await waiter.WaitForRunbookRunToComplete(
runbookRuns,
RunbookRuns,
project,
Progress,
NoRawLog,
Expand All @@ -179,6 +181,13 @@ await waiter.WaitForRunbookRunToComplete(
}
}

private async Task<string[]> RetrieveTenants()
{
return (!TenantNamesOrIds.Contains("*") && TenantNamesOrIds.Any())
? (await Repository.Tenants.FindByNamesOrIdsOrFail(TenantNamesOrIds).ConfigureAwait(false)).Select(ten => ten.Id).ToArray()
: TenantNamesOrIds.ToArray();
}

protected override Task ValidateParameters()
{
if (ProjectNameOrId == null)
Expand All @@ -197,13 +206,14 @@ protected override Task ValidateParameters()
}

if ((RunAt ?? DateTimeOffset.Now) > NoRunAfter)
throw new CommandException("The Run will expire before it has a chance to execute. Please select an expiry time that occurs after the deployment is scheduled to begin");
throw new CommandException(
"The Run will expire before it has a chance to execute. Please select an expiry time that occurs after the deployment is scheduled to begin");

CheckForIntersection(IncludedMachineIds.ToList(), ExcludedMachineIds.ToList());

if (TenantIds.Contains("*") && (TenantIds.Count > 1 || TenantTagNames.Count > 0))
if (TenantNamesOrIds.Contains("*") && (TenantNamesOrIds.Count > 1 || TenantTagNames.Count > 0))
throw new CommandException(
"When running on all tenants using the --tenantIds=* wildcard, no other tenant filters can be provided");
"When running on all tenants using the --tenant=* wildcard, no other tenant filters can be provided");

return Task.FromResult(0);
}
Expand All @@ -217,14 +227,16 @@ private static void CheckForIntersection(IEnumerable<string> included, IEnumerab
$"Cannot specify the same machine as both included and excluded: {intersection.ReadableJoin(", ")}");
}
}

private void LogScheduledDeployment()
{
if (RunAt == null) return;
var now = DateTimeOffset.UtcNow;
commandOutputProvider.Information("Runbook run will be scheduled to start in: {Duration:l}", (RunAt.Value - now).FriendlyDuration());
commandOutputProvider.Information("Runbook run will be scheduled to start in: {Duration:l}",
(RunAt.Value - now).FriendlyDuration());
}

void ParseVariable(string variable)
private void ParseVariable(string variable)
{
var index = variable.IndexOfAny(new[] {':', '='});
if (index <= 0)
Expand All @@ -233,7 +245,7 @@ void ParseVariable(string variable)
var key = variable.Substring(0, index);
var value = (index >= variable.Length - 1) ? string.Empty : variable.Substring(index + 1);

variables.Add(key, value);
Variables.Add(key, value);
}

public void PrintDefaultOutput()
Expand All @@ -242,7 +254,7 @@ public void PrintDefaultOutput()

public void PrintJsonOutput()
{
foreach (var run in runbookRuns)
foreach (var run in RunbookRuns)
{
commandOutputProvider.Json(new
{
Expand Down

0 comments on commit 28e6e20

Please sign in to comment.