Skip to content

Instantly share code, notes, and snippets.

Created March 12, 2018 02:15
Show Gist options
  • Save anonymous/bba1ad640ab2d4b14988e8add9ce0444 to your computer and use it in GitHub Desktop.
Save anonymous/bba1ad640ab2d4b14988e8add9ce0444 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Octopus.Client;
using Octopus.Client.Model;
namespace ManualWebhook
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseKestrel(options =>
{
options.Listen(IPAddress.Any, 5000);
})
.Build();
}
public class Startup
{
public Startup(IHostingEnvironment env, IConfiguration config)
{
HostingEnvironment = env;
Configuration = config;
}
public IHostingEnvironment HostingEnvironment { get; }
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IOctopusAsyncRepository>((sp) =>
{
// API client used to query the Octopus server
var client = new OctopusClientFactory().CreateAsyncClient(new OctopusServerEndpoint("http://localhost:8080", "API-COYG6KD4TKTPYIWCOQ3W5ZI19HO"));
return client.Result.Repository;
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
[Route("octopus-webhook")]
public class OctopusWebhookController : Controller
{
readonly IOctopusAsyncRepository _repository;
public OctopusWebhookController(IOctopusAsyncRepository repository)
{
_repository = repository;
}
// This is called by the Octopus web hook. The payload it receives looks like:
//
// {
// "Payload": {
// "Event": {
// "Category": "ManualInterventionInterruptionRaised",
// "RelatedDocumentIds": [
// "Deployments-123", <-- This tells us the deployment ID
// ...
//
[HttpPost("manual-intervention")]
public async Task<ActionResult> ManualInterventionRequested([FromBody] JObject o)
{
var octopusEvent = o.Value<JObject>("Payload").Value<JObject>("Event");
var eventCategory = octopusEvent.Value<string>("Category");
// Validate that we got the event type we expected
if (eventCategory != "ManualInterventionInterruptionRaised")
return BadRequest("Unknown event category: " + eventCategory);
var relatedDocuments = octopusEvent.Value<JArray>("RelatedDocumentIds").Values<string>();
var deploymentId = relatedDocuments.First(documentId => documentId.StartsWith("Deployments-"));
var deployment = await _repository.Deployments.Get(deploymentId);
var task = await _repository.Deployments.GetTask(deployment);
if (task.State != TaskState.Queued)
{
// A deployment should be marked as queued when a manual intervention is encountered (it is queued because it is
// waiting until someone submits it).
return BadRequest("Task completed already");
}
await SubmitInterruption(deploymentId);
return Content("OK");
}
async Task SubmitInterruption(string deploymentId)
{
// Find the "interruption" object that corresponds with this deployment
var interruptions = await _repository.Interruptions.List(regardingDocumentId: deploymentId);
var interruption = interruptions.Items.First();
// The current user must first take responsibility for the interruption (so multiple people don't submit it at once)
await _repository.Interruptions.TakeResponsibility(interruption);
// Set the result
interruption.Form.Values["Result"] = "Proceed"; // Or, "Abort" to cancel
interruption.Form.Values["Notes"] = "Any other information here";
// Submit the interruption
await _repository.Interruptions.Submit(interruption);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment