Files
Microsoft.SelfService.Porta…/Controllers/DeploymentController.cs

304 lines
11 KiB
C#

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add;
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get;
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit;
using Microsoft.SelfService.Portal.Core.API.Interfaces;
using Microsoft.SelfService.Portal.Core.API.Models;
using Microsoft.SelfService.Portal.Core.API.Context;
using Microsoft.SelfService.Portal.Core.API.Events.Interfaces;
using System.Reflection;
using System.Collections;
using System.Dynamic;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
namespace Microsoft.SelfService.Portal.Core.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DeploymentController : Controller
{
private readonly IDeploymentInterface _deploymentInterface;
private readonly IQueueJobService _queueJobService;
private readonly DataContext _context;
private readonly IMapper _mapper;
private readonly IEventHandlerInterface _eventHandlerInterface;
public DeploymentController(
IDeploymentInterface deploymentInterface,
IQueueJobService queueJobService,
DataContext context,
IMapper mapper,
IEventHandlerInterface eventHandlerInterface)
{
_deploymentInterface = deploymentInterface;
_queueJobService = queueJobService;
_context = context;
_mapper = mapper;
_eventHandlerInterface = eventHandlerInterface;
}
[HttpGet]
[ProducesResponseType(200, Type = typeof(IEnumerable<DeploymentModel>))]
public IActionResult GetDeployments()
{
var deployment = _mapper.Map<List<GetDeploymentDto>>(_deploymentInterface.GetDeployments());
if (!ModelState.IsValid)
return BadRequest(ModelState);
return Ok(deployment);
}
[HttpGet("{Id}")]
[ProducesResponseType(200, Type = typeof(DeploymentModel))]
[ProducesResponseType(400)]
public IActionResult GetDeploymentById(Guid Id)
{
if (!_deploymentInterface.CheckDeploymentById(Id))
return NotFound();
var deployment = _mapper.Map<GetDeploymentDetailsDto>(_deploymentInterface.GetDeploymentById(Id));
if (!ModelState.IsValid)
return BadRequest(ModelState);
return Ok(deployment);
}
[HttpPost]
[ProducesResponseType(204)]
[ProducesResponseType(400)]
public IActionResult AddDeploymentById([FromBody] AddDeploymentDto deployment)
{
if (deployment == null)
return BadRequest(ModelState);
if (!ModelState.IsValid)
return BadRequest(ModelState);
var deploymentMap = _mapper.Map<DeploymentModel>(deployment);
if (!_deploymentInterface.AddDeploymentById(deploymentMap))
{
ModelState.AddModelError("", "Something went wrong while saving");
return StatusCode(500, ModelState);
}
return Ok(deploymentMap.Id);
}
[HttpPost("Request")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
public IActionResult AddDeploymentRequest([FromBody] AddDeploymentRequestDto request)
{
if (request == null)
return BadRequest(ModelState);
if (request.VirtualMachineIds == null || request.VirtualMachineIds.Count == 0)
{
ModelState.AddModelError("", "At least one VirtualMachine must be selected.");
return BadRequest(ModelState);
}
if (!ModelState.IsValid)
return BadRequest(ModelState);
try
{
var queueJobId = _queueJobService.EnqueueDeploymentRequest(
request.DeploymentGroupId,
request.VirtualMachineIds,
request.JsonData);
return Ok(queueJobId);
}
catch (InvalidOperationException ex)
{
ModelState.AddModelError("", ex.Message);
return BadRequest(ModelState);
}
}
[HttpGet("QueueJobs")]
[ProducesResponseType(200, Type = typeof(IEnumerable<GetQueueJobDto>))]
public IActionResult GetQueueJobs()
{
var queueJobs = _context.QueueJobs
.AsNoTracking()
.Include(job => job.Targets)
.Include(job => job.Steps)
.OrderByDescending(job => job.Created)
.Select(job => new GetQueueJobDto
{
Id = job.Id,
Type = job.Type,
Status = job.Status,
Attempts = job.Attempts,
MaxAttempts = job.MaxAttempts,
Started = job.Started,
Finished = job.Finished,
ErrorMessage = job.ErrorMessage,
TargetCount = job.Targets.Count,
SucceededTargetCount = job.Targets.Count(target => target.Status == QueueJobStatus.Succeeded),
FailedTargetCount = job.Targets.Count(target => target.Status == QueueJobStatus.Failed)
})
.ToList();
return Ok(queueJobs);
}
[HttpGet("QueueJobs/{Id}")]
[ProducesResponseType(200, Type = typeof(GetQueueJobDetailsDto))]
[ProducesResponseType(404)]
public IActionResult GetQueueJobById(Guid Id)
{
var queueJob = _context.QueueJobs
.AsNoTracking()
.Include(job => job.Targets)
.Include(job => job.Steps)
.FirstOrDefault(job => job.Id == Id);
if (queueJob == null)
return NotFound();
var details = new GetQueueJobDetailsDto
{
Id = queueJob.Id,
Type = queueJob.Type,
Status = queueJob.Status,
PayloadJson = queueJob.PayloadJson,
Attempts = queueJob.Attempts,
MaxAttempts = queueJob.MaxAttempts,
Started = queueJob.Started,
Finished = queueJob.Finished,
ErrorMessage = queueJob.ErrorMessage,
MetadataJson = queueJob.MetadataJson,
RuleSnapshotJson = queueJob.RuleSnapshotJson,
Created = queueJob.Created,
CreatedBy = queueJob.CreatedBy,
Modified = queueJob.Modified,
ModifiedBy = queueJob.ModifiedBy,
Targets = queueJob.Targets.Select(target => new GetQueueJobTargetDto
{
Id = target.Id,
VirtualMachineId = target.VirtualMachineId,
DeploymentGroupId = target.DeploymentGroupId,
TemplateId = target.TemplateId,
Status = target.Status,
Attempts = target.Attempts,
ErrorMessage = target.ErrorMessage
}).ToList(),
Steps = queueJob.Steps
.OrderBy(step => step.SortOrder)
.Select(step => new GetQueueJobStepDto
{
Id = step.Id,
DependsOnQueueJobStepId = step.DependsOnQueueJobStepId,
SortOrder = step.SortOrder,
Name = step.Name,
StepType = step.StepType,
Status = step.Status,
MetadataJson = step.MetadataJson,
ApprovedAt = step.ApprovedAt,
ApprovedBy = step.ApprovedBy,
ApprovalComment = step.ApprovalComment
}).ToList()
};
return Ok(details);
}
[HttpPost("QueueJobs/{Id}/Retry")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public IActionResult RetryQueueJob(Guid Id)
{
if (!_queueJobService.RetryQueueJob(Id))
return NotFound();
return NoContent();
}
[HttpPost("QueueJobs/Steps/{stepId}/Approve")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public IActionResult ApproveQueueJobStep(Guid stepId, [FromBody] QueueJobStepApprovalDto? payload)
{
var approvedBy = payload?.ApprovedBy ?? User?.Identity?.Name ?? "System";
if (!_queueJobService.ApproveQueueJobStep(stepId, approvedBy, payload?.Comment))
return NotFound();
return NoContent();
}
[HttpPost("QueueJobs/Steps/{stepId}/Reject")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public IActionResult RejectQueueJobStep(Guid stepId, [FromBody] QueueJobStepApprovalDto? payload)
{
var approvedBy = payload?.ApprovedBy ?? User?.Identity?.Name ?? "System";
if (!_queueJobService.RejectQueueJobStep(stepId, approvedBy, payload?.Comment))
return NotFound();
return NoContent();
}
[HttpDelete("{Id}")]
[ProducesResponseType(204)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public IActionResult DeleteDeploymentById(Guid Id)
{
if (!_deploymentInterface.CheckDeploymentById(Id))
return NotFound();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var deployment = _deploymentInterface.GetDeploymentById(Id);
if (!_deploymentInterface.DeleteDeploymentById(deployment))
{
ModelState.AddModelError("", "Something went wrong while deleting");
return StatusCode(500, ModelState);
}
return NoContent();
}
[HttpPut("{Id}")]
[ProducesResponseType(204)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public IActionResult EditDeploymentById(Guid Id, [FromBody] EditDeploymentDto deployment)
{
if (deployment == null)
return BadRequest(ModelState);
if (!_deploymentInterface.CheckDeploymentById(Id))
return NotFound();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var deploymentMap = _mapper.Map<DeploymentModel>(deployment);
deploymentMap.Id = Id;
if (!_deploymentInterface.EditDeploymentById(deploymentMap))
{
ModelState.AddModelError("", "Something went wrong");
return StatusCode(500, ModelState);
}
_eventHandlerInterface.FireEvent(this.GetType().Name, MethodBase.GetCurrentMethod().Name, Id);
return NoContent();
}
}
}