Refactor code structure for improved readability and maintainability
This commit is contained in:
+110
-29
@@ -11,25 +11,25 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<EventModel> Events { get; set; }
|
|
||||||
|
|
||||||
public DbSet<EnvironmentModel> Environments { get; set; }
|
public DbSet<EnvironmentModel> Environments { get; set; }
|
||||||
public DbSet<EnvironmentDomainsModel> EnvironmentDomains { get; set; }
|
public DbSet<EnvironmentDomainsModel> EnvironmentDomains { get; set; }
|
||||||
public DbSet<DomainModel> Domains { get; set; }
|
public DbSet<DomainModel> Domains { get; set; }
|
||||||
public DbSet<VirtualMachineModel> VirtualMachines { get; set; }
|
public DbSet<TargetModel> Targets { get; set; }
|
||||||
public DbSet<DeploymentModel> Deployments { get; set; }
|
public DbSet<DeploymentModel> Deployments { get; set; }
|
||||||
public DbSet<DeploymentGroupModel> DeploymentGroups { get; set; }
|
public DbSet<DeploymentGroupModel> DeploymentGroups { get; set; }
|
||||||
public DbSet<TemplateModel> Templates { get; set; }
|
public DbSet<TemplateModel> Templates { get; set; }
|
||||||
|
public DbSet<TemplateVersionModel> TemplateVersions { get; set; }
|
||||||
public DbSet<DeploymentRuleModel> DeploymentRules { get; set; }
|
public DbSet<DeploymentRuleModel> DeploymentRules { get; set; }
|
||||||
public DbSet<DeploymentRuleStepModel> DeploymentRuleSteps { get; set; }
|
public DbSet<DeploymentRuleStepModel> DeploymentRuleSteps { get; set; }
|
||||||
|
public DbSet<DeploymentTemplateSelectionModel> DeploymentTemplateSelections { get; set; }
|
||||||
|
public DbSet<DeploymentParameterValueModel> DeploymentParameterValues { get; set; }
|
||||||
|
public DbSet<DeploymentTargetAssignmentModel> DeploymentTargetAssignments { get; set; }
|
||||||
public DbSet<TemplateCategoryModel> TemplateCategories { get; set; }
|
public DbSet<TemplateCategoryModel> TemplateCategories { get; set; }
|
||||||
public DbSet<ServiceModel> Services { get; set; }
|
public DbSet<ServiceModel> Services { get; set; }
|
||||||
public DbSet<ServiceRoleDefinitionModel> ServiceRoleDefinitions { get; set; }
|
public DbSet<ServiceRoleDefinitionModel> ServiceRoleDefinitions { get; set; }
|
||||||
public DbSet<TemplateOptionModel> TemplateOptions { get; set; }
|
public DbSet<TemplateOptionModel> TemplateOptions { get; set; }
|
||||||
public DbSet<OptionModel> Options { get; set; }
|
public DbSet<OptionModel> Options { get; set; }
|
||||||
public DbSet<OptionCategoryModel> OptionCategories { get; set; }
|
public DbSet<OptionCategoryModel> OptionCategories { get; set; }
|
||||||
public DbSet<JobModel> Jobs { get; set; }
|
|
||||||
public DbSet<RunbookModel> Runbooks { get; set; }
|
|
||||||
public DbSet<QueueJobModel> QueueJobs { get; set; }
|
public DbSet<QueueJobModel> QueueJobs { get; set; }
|
||||||
public DbSet<QueueJobTargetModel> QueueJobTargets { get; set; }
|
public DbSet<QueueJobTargetModel> QueueJobTargets { get; set; }
|
||||||
public DbSet<QueueJobStepModel> QueueJobSteps { get; set; }
|
public DbSet<QueueJobStepModel> QueueJobSteps { get; set; }
|
||||||
@@ -77,6 +77,14 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
|||||||
modelBuilder.Entity<DeploymentGroupModel>()
|
modelBuilder.Entity<DeploymentGroupModel>()
|
||||||
.ToTable("DeploymentBatches");
|
.ToTable("DeploymentBatches");
|
||||||
|
|
||||||
|
modelBuilder.Entity<TargetModel>()
|
||||||
|
.Property(target => target.TargetType)
|
||||||
|
.HasMaxLength(64);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TargetModel>()
|
||||||
|
.Property(target => target.ProviderType)
|
||||||
|
.HasMaxLength(64);
|
||||||
|
|
||||||
modelBuilder.Entity<DeploymentModel>()
|
modelBuilder.Entity<DeploymentModel>()
|
||||||
.ToTable("DeploymentExecutions");
|
.ToTable("DeploymentExecutions");
|
||||||
modelBuilder.Entity<DeploymentModel>()
|
modelBuilder.Entity<DeploymentModel>()
|
||||||
@@ -105,12 +113,12 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
|||||||
.HasColumnName("DependsOnDeploymentJobStepId");
|
.HasColumnName("DependsOnDeploymentJobStepId");
|
||||||
|
|
||||||
modelBuilder.Entity<DeploymentModel>()
|
modelBuilder.Entity<DeploymentModel>()
|
||||||
.HasKey(d => new { d.VirtualMachineId, d.DeploymentGroupId });
|
.HasKey(d => new { d.TargetId, d.DeploymentGroupId });
|
||||||
|
|
||||||
modelBuilder.Entity<DeploymentModel>()
|
modelBuilder.Entity<DeploymentModel>()
|
||||||
.HasOne(d => d.VirtualMachine)
|
.HasOne(d => d.Target)
|
||||||
.WithMany(vm => vm.Deployments)
|
.WithMany(vm => vm.Deployments)
|
||||||
.HasForeignKey(d => d.VirtualMachineId);
|
.HasForeignKey(d => d.TargetId);
|
||||||
|
|
||||||
modelBuilder.Entity<DeploymentModel>()
|
modelBuilder.Entity<DeploymentModel>()
|
||||||
.HasOne(d => d.DeploymentGroup)
|
.HasOne(d => d.DeploymentGroup)
|
||||||
@@ -122,11 +130,103 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
|||||||
.WithMany(t => t.DeploymentGroups)
|
.WithMany(t => t.DeploymentGroups)
|
||||||
.HasForeignKey(dg => dg.TemplateId);
|
.HasForeignKey(dg => dg.TemplateId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentGroupModel>()
|
||||||
|
.HasOne(dg => dg.DeploymentRule)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(dg => dg.DeploymentRuleId)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTemplateSelectionModel>()
|
||||||
|
.HasOne(selection => selection.DeploymentGroup)
|
||||||
|
.WithMany(batch => batch.TemplateSelections)
|
||||||
|
.HasForeignKey(selection => selection.DeploymentGroupId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTemplateSelectionModel>()
|
||||||
|
.HasOne(selection => selection.TemplateVersion)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(selection => selection.TemplateVersionId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTemplateSelectionModel>()
|
||||||
|
.HasIndex(selection => new { selection.DeploymentGroupId, selection.SortOrder })
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentParameterValueModel>()
|
||||||
|
.HasOne(parameterValue => parameterValue.DeploymentGroup)
|
||||||
|
.WithMany(batch => batch.ParameterValues)
|
||||||
|
.HasForeignKey(parameterValue => parameterValue.DeploymentGroupId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentParameterValueModel>()
|
||||||
|
.HasOne(parameterValue => parameterValue.DeploymentTemplateSelection)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(parameterValue => parameterValue.DeploymentTemplateSelectionId)
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentParameterValueModel>()
|
||||||
|
.HasIndex(parameterValue => new { parameterValue.DeploymentGroupId, parameterValue.DeploymentTemplateSelectionId, parameterValue.Name })
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[DeploymentTemplateSelectionId] IS NOT NULL");
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentParameterValueModel>()
|
||||||
|
.HasIndex(parameterValue => new { parameterValue.DeploymentGroupId, parameterValue.Name })
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[DeploymentTemplateSelectionId] IS NULL");
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentParameterValueModel>()
|
||||||
|
.ToTable(table => table.HasCheckConstraint("CK_DeploymentParameterValues_ValueJson_IsJson", "ISJSON([ValueJson]) = 1"));
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTargetAssignmentModel>()
|
||||||
|
.HasOne(target => target.DeploymentGroup)
|
||||||
|
.WithMany(batch => batch.TargetAssignments)
|
||||||
|
.HasForeignKey(target => target.DeploymentGroupId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTargetAssignmentModel>()
|
||||||
|
.HasOne(target => target.Target)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(target => target.TargetId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTargetAssignmentModel>()
|
||||||
|
.HasIndex(target => new { target.DeploymentGroupId, target.TargetId, target.RoleKey })
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<DeploymentTargetAssignmentModel>()
|
||||||
|
.ToTable(table => table.HasCheckConstraint("CK_DeploymentTargetAssignments_NodeDataJson_IsJson", "ISJSON([NodeDataJson]) = 1"));
|
||||||
|
|
||||||
modelBuilder.Entity<TemplateModel>()
|
modelBuilder.Entity<TemplateModel>()
|
||||||
.HasOne(template => template.DeploymentRule)
|
.HasOne(template => template.DeploymentRule)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey(template => template.DeploymentRuleId);
|
.HasForeignKey(template => template.DeploymentRuleId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.HasOne(version => version.Template)
|
||||||
|
.WithMany(template => template.TemplateVersions)
|
||||||
|
.HasForeignKey(version => version.TemplateId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.HasIndex(version => new { version.TemplateId, version.Version })
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.HasIndex(version => version.TemplateId)
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[IsPublished] = 1");
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.Property(version => version.Version)
|
||||||
|
.HasMaxLength(64);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.Property(version => version.JsonHash)
|
||||||
|
.HasMaxLength(64);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.Property(version => version.SchemaVersion)
|
||||||
|
.HasMaxLength(32);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>()
|
||||||
|
.ToTable(table => table.HasCheckConstraint("CK_TemplateVersions_JsonData_IsJson", "ISJSON([JsonData]) = 1"));
|
||||||
|
|
||||||
modelBuilder.Entity<DeploymentRuleStepModel>()
|
modelBuilder.Entity<DeploymentRuleStepModel>()
|
||||||
.HasOne(step => step.DeploymentRule)
|
.HasOne(step => step.DeploymentRule)
|
||||||
.WithMany(rule => rule.Steps)
|
.WithMany(rule => rule.Steps)
|
||||||
@@ -148,28 +248,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
|||||||
.HasForeignKey(step => step.DependsOnQueueJobStepId)
|
.HasForeignKey(step => step.DependsOnQueueJobStepId)
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
modelBuilder.Entity<JobModel>()
|
|
||||||
.HasKey(j => new { j.RunbookId, j.DeploymentId });
|
|
||||||
|
|
||||||
modelBuilder.Entity<JobModel>()
|
|
||||||
.HasOne(j => j.Deployment)
|
|
||||||
.WithMany(d => d.Jobs)
|
|
||||||
.HasPrincipalKey(d => d.Id)
|
|
||||||
.HasForeignKey(j => j.DeploymentId);
|
|
||||||
|
|
||||||
modelBuilder.Entity<JobModel>()
|
|
||||||
.HasOne(j => j.Runbook)
|
|
||||||
.WithMany(r => r.Jobs)
|
|
||||||
.HasPrincipalKey(r => r.Id)
|
|
||||||
.HasForeignKey(j => j.RunbookId);
|
|
||||||
|
|
||||||
modelBuilder.Entity<EventModel>()
|
|
||||||
.HasOne(e => e.Runbook)
|
|
||||||
.WithMany(r => r.Events)
|
|
||||||
.HasPrincipalKey(e => e.Id)
|
|
||||||
.HasForeignKey(r => r.RunbookId);
|
|
||||||
|
|
||||||
OnModelCreatingAddDefaultSqlValues(modelBuilder);
|
OnModelCreatingAddDefaultSqlValues(modelBuilder);
|
||||||
|
DemoData.Seed(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnModelCreatingAddDefaultSqlValues(ModelBuilder modelBuilder)
|
private void OnModelCreatingAddDefaultSqlValues(ModelBuilder modelBuilder)
|
||||||
@@ -206,3 +286,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||||
|
{
|
||||||
|
public class DataContextFactory : IDesignTimeDbContextFactory<DataContext>
|
||||||
|
{
|
||||||
|
public DataContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var basePath = ResolveBasePath();
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(basePath)
|
||||||
|
.AddJsonFile("appsettings.json", optional: false)
|
||||||
|
.AddJsonFile("appsettings.Development.json", optional: true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var connectionString = configuration.GetConnectionString("Context")
|
||||||
|
?? throw new InvalidOperationException("Connection string 'Context' not found.");
|
||||||
|
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<DataContext>();
|
||||||
|
optionsBuilder.UseSqlServer(connectionString);
|
||||||
|
|
||||||
|
return new DataContext(optionsBuilder.Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveBasePath()
|
||||||
|
{
|
||||||
|
var currentDirectory = Directory.GetCurrentDirectory();
|
||||||
|
var projectDirectory = Path.Combine(
|
||||||
|
currentDirectory,
|
||||||
|
".Net",
|
||||||
|
"Microsoft.SelfService.Portal.Core.API");
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(currentDirectory, "appsettings.json")))
|
||||||
|
{
|
||||||
|
return currentDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(projectDirectory, "appsettings.json")))
|
||||||
|
{
|
||||||
|
return projectDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
var assemblyDirectory = AppContext.BaseDirectory;
|
||||||
|
if (File.Exists(Path.Combine(assemblyDirectory, "appsettings.json")))
|
||||||
|
{
|
||||||
|
return assemblyDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,331 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||||
|
{
|
||||||
|
internal static class DemoData
|
||||||
|
{
|
||||||
|
private static readonly DateTime Timestamp = new(2026, 7, 7, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
private const string Owner = "DemoSeed";
|
||||||
|
|
||||||
|
internal static readonly Guid EnvironmentContosoTestId = Guid.Parse("10000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid EnvironmentContosoProdId = Guid.Parse("10000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid EnvironmentM365Id = Guid.Parse("10000000-0000-0000-0000-000000000003");
|
||||||
|
|
||||||
|
internal static readonly Guid DomainCentralId = Guid.Parse("20000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid DomainResourceId = Guid.Parse("20000000-0000-0000-0000-000000000002");
|
||||||
|
|
||||||
|
internal static readonly Guid VmDc01Id = Guid.Parse("30000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid VmDc02Id = Guid.Parse("30000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid VmSql01Id = Guid.Parse("30000000-0000-0000-0000-000000000003");
|
||||||
|
internal static readonly Guid VmSp01Id = Guid.Parse("30000000-0000-0000-0000-000000000004");
|
||||||
|
internal static readonly Guid VmSp02Id = Guid.Parse("30000000-0000-0000-0000-000000000005");
|
||||||
|
internal static readonly Guid TargetM365TenantId = Guid.Parse("30000000-0000-0000-0000-000000000006");
|
||||||
|
internal static readonly Guid TargetTeamsPolicyScopeId = Guid.Parse("30000000-0000-0000-0000-000000000007");
|
||||||
|
|
||||||
|
internal static readonly Guid ServiceActiveDirectoryId = Guid.Parse("40000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid ServiceSqlServerId = Guid.Parse("40000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid ServiceSharePointId = Guid.Parse("40000000-0000-0000-0000-000000000003");
|
||||||
|
internal static readonly Guid ServiceTeamsId = Guid.Parse("40000000-0000-0000-0000-000000000004");
|
||||||
|
|
||||||
|
internal static readonly Guid CategoryActiveDirectoryId = Guid.Parse("50000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid CategorySqlServerId = Guid.Parse("50000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid CategorySharePointId = Guid.Parse("50000000-0000-0000-0000-000000000003");
|
||||||
|
internal static readonly Guid CategoryTeamsId = Guid.Parse("50000000-0000-0000-0000-000000000004");
|
||||||
|
|
||||||
|
internal static readonly Guid RuleStandardId = Guid.Parse("60000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid RuleStepValidateId = Guid.Parse("60000000-0000-0000-0000-000000000101");
|
||||||
|
internal static readonly Guid RuleStepApproveId = Guid.Parse("60000000-0000-0000-0000-000000000102");
|
||||||
|
internal static readonly Guid RuleStepDeployId = Guid.Parse("60000000-0000-0000-0000-000000000103");
|
||||||
|
|
||||||
|
internal static readonly Guid TemplateActiveDirectoryId = Guid.Parse("70000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid TemplateSqlServerId = Guid.Parse("70000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid TemplateSharePointId = Guid.Parse("70000000-0000-0000-0000-000000000003");
|
||||||
|
internal static readonly Guid TemplateTeamsId = Guid.Parse("70000000-0000-0000-0000-000000000004");
|
||||||
|
|
||||||
|
internal static readonly Guid TemplateActiveDirectoryVersionId = Guid.Parse("71000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid TemplateSqlServerVersionId = Guid.Parse("71000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid TemplateSharePointVersionId = Guid.Parse("71000000-0000-0000-0000-000000000003");
|
||||||
|
internal static readonly Guid TemplateTeamsVersionId = Guid.Parse("71000000-0000-0000-0000-000000000004");
|
||||||
|
|
||||||
|
internal static readonly Guid DeploymentBatchSharePointId = Guid.Parse("80000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid DeploymentSp01Id = Guid.Parse("81000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid DeploymentSp02Id = Guid.Parse("81000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid DeploymentSharePointTemplateSelectionId = Guid.Parse("82000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid DeploymentParameterDatabasePrefixId = Guid.Parse("83000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid DeploymentParameterFarmAccountId = Guid.Parse("83000000-0000-0000-0000-000000000002");
|
||||||
|
internal static readonly Guid DeploymentTargetSp01Id = Guid.Parse("84000000-0000-0000-0000-000000000001");
|
||||||
|
internal static readonly Guid DeploymentTargetSp02Id = Guid.Parse("84000000-0000-0000-0000-000000000002");
|
||||||
|
|
||||||
|
internal static void Seed(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<EnvironmentModel>().HasData(Environments());
|
||||||
|
modelBuilder.Entity<DomainModel>().HasData(Domains());
|
||||||
|
modelBuilder.Entity<EnvironmentDomainsModel>().HasData(EnvironmentDomains());
|
||||||
|
modelBuilder.Entity<TargetModel>().HasData(Targets());
|
||||||
|
modelBuilder.Entity<ServiceModel>().HasData(Services());
|
||||||
|
modelBuilder.Entity<ServiceRoleDefinitionModel>().HasData(ServiceRoleDefinitions());
|
||||||
|
modelBuilder.Entity<TemplateCategoryModel>().HasData(TemplateCategories());
|
||||||
|
modelBuilder.Entity<DeploymentRuleModel>().HasData(DeploymentRules());
|
||||||
|
modelBuilder.Entity<DeploymentRuleStepModel>().HasData(DeploymentRuleSteps());
|
||||||
|
modelBuilder.Entity<TemplateModel>().HasData(Templates());
|
||||||
|
modelBuilder.Entity<TemplateVersionModel>().HasData(TemplateVersions());
|
||||||
|
modelBuilder.Entity<DeploymentGroupModel>().HasData(DeploymentBatches());
|
||||||
|
modelBuilder.Entity<DeploymentModel>().HasData(Deployments());
|
||||||
|
modelBuilder.Entity<DeploymentTemplateSelectionModel>().HasData(DeploymentTemplateSelections());
|
||||||
|
modelBuilder.Entity<DeploymentParameterValueModel>().HasData(DeploymentParameterValues());
|
||||||
|
modelBuilder.Entity<DeploymentTargetAssignmentModel>().HasData(DeploymentTargetAssignments());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object[] Environments() =>
|
||||||
|
[
|
||||||
|
Base(new EnvironmentModel { Id = EnvironmentContosoTestId, Name = "Contoso Test", EnvironmentType = EnvironmentStages.Test, HostingType = EnvironmentHostingTypes.OnPrem, MetadataJson = "{\"location\":\"Datacenter A\"}" }),
|
||||||
|
Base(new EnvironmentModel { Id = EnvironmentContosoProdId, Name = "Contoso Production", EnvironmentType = EnvironmentStages.Production, HostingType = EnvironmentHostingTypes.OnPrem, MetadataJson = "{\"location\":\"Datacenter A\"}" }),
|
||||||
|
Base(new EnvironmentModel { Id = EnvironmentM365Id, Name = "Contoso M365", EnvironmentType = EnvironmentStages.Production, HostingType = EnvironmentHostingTypes.M365Tenant, ProviderType = "Microsoft365", TenantId = "11111111-1111-1111-1111-111111111111", MetadataJson = "{\"tenant\":\"contoso.onmicrosoft.com\"}" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] Domains() =>
|
||||||
|
[
|
||||||
|
Base(new DomainModel { Id = DomainCentralId, Name = "Central Management", FQDN = "corp.contoso.com", NetBIOS = "CONTOSO" }),
|
||||||
|
Base(new DomainModel { Id = DomainResourceId, Name = "Resource Domain", FQDN = "resource.contoso.com", NetBIOS = "RESOURCE" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] EnvironmentDomains() =>
|
||||||
|
[
|
||||||
|
Junction(new EnvironmentDomainsModel { EnvironmentId = EnvironmentContosoTestId, DomainId = DomainCentralId }),
|
||||||
|
Junction(new EnvironmentDomainsModel { EnvironmentId = EnvironmentContosoProdId, DomainId = DomainCentralId }),
|
||||||
|
Junction(new EnvironmentDomainsModel { EnvironmentId = EnvironmentContosoProdId, DomainId = DomainResourceId })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] Targets() =>
|
||||||
|
[
|
||||||
|
Base(new TargetModel { Id = VmDc01Id, DomainID = DomainCentralId, Name = "CT-DC-01", TargetType = "VirtualMachine", ProviderType = "OnPrem", MetadataJson = "{\"role\":\"DomainController\",\"environment\":\"Test\"}" }),
|
||||||
|
Base(new TargetModel { Id = VmDc02Id, DomainID = DomainCentralId, Name = "CT-DC-02", TargetType = "VirtualMachine", ProviderType = "OnPrem", MetadataJson = "{\"role\":\"DomainController\",\"environment\":\"Production\"}" }),
|
||||||
|
Base(new TargetModel { Id = VmSql01Id, DomainID = DomainCentralId, Name = "CT-SQL-01", TargetType = "VirtualMachine", ProviderType = "OnPrem", MetadataJson = "{\"role\":\"SqlServer\",\"environment\":\"Test\"}" }),
|
||||||
|
Base(new TargetModel { Id = VmSp01Id, DomainID = DomainCentralId, Name = "CT-SHP-01", TargetType = "VirtualMachine", ProviderType = "OnPrem", MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\"}" }),
|
||||||
|
Base(new TargetModel { Id = VmSp02Id, DomainID = DomainCentralId, Name = "CT-SHP-02", TargetType = "VirtualMachine", ProviderType = "OnPrem", MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\"}" }),
|
||||||
|
Base(new TargetModel { Id = TargetM365TenantId, Name = "contoso.onmicrosoft.com", TargetType = "Tenant", ProviderType = "Microsoft365", ExternalId = "11111111-1111-1111-1111-111111111111", MetadataJson = "{\"environment\":\"Production\",\"workload\":\"M365\"}" }),
|
||||||
|
Base(new TargetModel { Id = TargetTeamsPolicyScopeId, Name = "Teams - Standard Users", TargetType = "PolicyScope", ProviderType = "Microsoft365", ExternalId = "Teams.StandardUsers", MetadataJson = "{\"workload\":\"Teams\",\"scope\":\"StandardUsers\"}" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] Services() =>
|
||||||
|
[
|
||||||
|
Base(new ServiceModel { Id = ServiceActiveDirectoryId, Name = "Active Directory", Description = "On-premises directory and identity service.", IconKey = "network", IsCloudService = false }),
|
||||||
|
Base(new ServiceModel { Id = ServiceSqlServerId, Name = "SQL Server", Description = "Database platform for application workloads.", IconKey = "database", IsCloudService = false }),
|
||||||
|
Base(new ServiceModel { Id = ServiceSharePointId, Name = "SharePoint Server", Description = "Collaboration platform for on-premises workloads.", IconKey = "sharepoint", IsCloudService = false }),
|
||||||
|
Base(new ServiceModel { Id = ServiceTeamsId, Name = "Microsoft Teams", Description = "Cloud collaboration workload in Microsoft 365.", IconKey = "messages-square", IsCloudService = true })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] ServiceRoleDefinitions() =>
|
||||||
|
[
|
||||||
|
Base(new ServiceRoleDefinitionModel { Id = Guid.Parse("41000000-0000-0000-0000-000000000001"), ServiceId = ServiceSharePointId, Key = "Farm", Name = "Farm", Description = "SharePoint farm role." }),
|
||||||
|
Base(new ServiceRoleDefinitionModel { Id = Guid.Parse("41000000-0000-0000-0000-000000000002"), ServiceId = ServiceSharePointId, Key = "WebFrontEnd", Name = "Web Front End", Description = "SharePoint web front-end role." }),
|
||||||
|
Base(new ServiceRoleDefinitionModel { Id = Guid.Parse("41000000-0000-0000-0000-000000000003"), ServiceId = ServiceSharePointId, Key = "Application", Name = "Application", Description = "SharePoint service application role." }),
|
||||||
|
Base(new ServiceRoleDefinitionModel { Id = Guid.Parse("41000000-0000-0000-0000-000000000004"), ServiceId = ServiceSqlServerId, Key = "Database", Name = "Database", Description = "SQL Server database role." })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] TemplateCategories() =>
|
||||||
|
[
|
||||||
|
Base(new TemplateCategoryModel { Id = CategoryActiveDirectoryId, ServiceId = ServiceActiveDirectoryId, Name = "Domain Services", Description = "Templates for domain controller and domain configuration.", Color = "#2563EB", IsActive = true }),
|
||||||
|
Base(new TemplateCategoryModel { Id = CategorySqlServerId, ServiceId = ServiceSqlServerId, Name = "Database Platform", Description = "Templates for SQL Server workloads.", Color = "#16A34A", IsActive = true }),
|
||||||
|
Base(new TemplateCategoryModel { Id = CategorySharePointId, ServiceId = ServiceSharePointId, Name = "Collaboration Farm", Description = "Templates for SharePoint Server farms.", Color = "#0F766E", IsActive = true }),
|
||||||
|
Base(new TemplateCategoryModel { Id = CategoryTeamsId, ServiceId = ServiceTeamsId, Name = "Teams Policies", Description = "Templates for Teams policy configuration.", Color = "#7C3AED", IsActive = true })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] DeploymentRules() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentRuleModel { Id = RuleStandardId, Name = "Standard Provisioning", Description = "Validate input, wait for approval, then provision targets.", IsActive = true })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] DeploymentRuleSteps() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentRuleStepModel { Id = RuleStepValidateId, DeploymentRuleId = RuleStandardId, SortOrder = 10, Name = "Validate configuration", StepType = QueueJobStepType.Provision, RequiresApproval = false, MetadataJson = "{\"action\":\"validate\"}" }),
|
||||||
|
Base(new DeploymentRuleStepModel { Id = RuleStepApproveId, DeploymentRuleId = RuleStandardId, SortOrder = 20, Name = "Approve deployment", StepType = QueueJobStepType.Approval, RequiresApproval = true, MetadataJson = "{\"approverGroup\":\"Platform Owners\"}" }),
|
||||||
|
Base(new DeploymentRuleStepModel { Id = RuleStepDeployId, DeploymentRuleId = RuleStandardId, SortOrder = 30, Name = "Provision workload", StepType = QueueJobStepType.Provision, RequiresApproval = false, MetadataJson = "{\"action\":\"deploy\"}" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] Templates() =>
|
||||||
|
[
|
||||||
|
Base(new TemplateModel { Id = TemplateActiveDirectoryId, TemplateCategoryId = CategoryActiveDirectoryId, DeploymentRuleId = RuleStandardId, Name = "Contoso Active Directory Domain", Version = "1.0.0", Description = "Creates a reusable Active Directory domain baseline.", JSONData = ActiveDirectoryTemplateJson }),
|
||||||
|
Base(new TemplateModel { Id = TemplateSqlServerId, TemplateCategoryId = CategorySqlServerId, DeploymentRuleId = RuleStandardId, Name = "Contoso SQL Server", Version = "1.0.0", Description = "Creates a SQL Server baseline for application workloads.", JSONData = SqlServerTemplateJson }),
|
||||||
|
Base(new TemplateModel { Id = TemplateSharePointId, TemplateCategoryId = CategorySharePointId, DeploymentRuleId = RuleStandardId, Name = "Contoso SharePoint Server", Version = "1.0.0", Description = "Creates a SharePoint Server farm baseline.", JSONData = SharePointTemplateJson }),
|
||||||
|
Base(new TemplateModel { Id = TemplateTeamsId, TemplateCategoryId = CategoryTeamsId, DeploymentRuleId = RuleStandardId, Name = "Contoso Teams Policies", Version = "1.0.0", Description = "Creates a Microsoft Teams policy baseline.", JSONData = TeamsTemplateJson })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] TemplateVersions() =>
|
||||||
|
[
|
||||||
|
TemplateVersion(TemplateActiveDirectoryVersionId, TemplateActiveDirectoryId, ActiveDirectoryTemplateJson),
|
||||||
|
TemplateVersion(TemplateSqlServerVersionId, TemplateSqlServerId, SqlServerTemplateJson),
|
||||||
|
TemplateVersion(TemplateSharePointVersionId, TemplateSharePointId, SharePointTemplateJson),
|
||||||
|
TemplateVersion(TemplateTeamsVersionId, TemplateTeamsId, TeamsTemplateJson)
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] DeploymentBatches() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentGroupModel { Id = DeploymentBatchSharePointId, TemplateId = TemplateSharePointId, DeploymentRuleId = RuleStandardId, Status = QueueJobStatus.Pending })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] Deployments() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentModel { Id = DeploymentSp01Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp01Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"WebFrontEnd\"}" }),
|
||||||
|
Base(new DeploymentModel { Id = DeploymentSp02Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp02Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Application\"}" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] DeploymentTemplateSelections() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentTemplateSelectionModel { Id = DeploymentSharePointTemplateSelectionId, DeploymentGroupId = DeploymentBatchSharePointId, TemplateVersionId = TemplateSharePointVersionId, TemplateRole = "Service", SortOrder = 10, Alias = "SharePoint" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] DeploymentParameterValues() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentParameterValueModel { Id = DeploymentParameterDatabasePrefixId, DeploymentGroupId = DeploymentBatchSharePointId, DeploymentTemplateSelectionId = DeploymentSharePointTemplateSelectionId, Name = "DatabasePrefix", ValueJson = "{\"value\":\"SharePoint_Contoso_Test\"}", IsOverride = true, IsSecretReference = false }),
|
||||||
|
Base(new DeploymentParameterValueModel { Id = DeploymentParameterFarmAccountId, DeploymentGroupId = DeploymentBatchSharePointId, DeploymentTemplateSelectionId = DeploymentSharePointTemplateSelectionId, Name = "FarmAccount", ValueJson = "{\"provider\":\"SecretManagement\",\"vault\":\"ContosoDemo\",\"name\":\"Windows/SharePoint/FarmAccount\"}", IsOverride = true, IsSecretReference = true })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static object[] DeploymentTargetAssignments() =>
|
||||||
|
[
|
||||||
|
Base(new DeploymentTargetAssignmentModel { Id = DeploymentTargetSp01Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp01Id, RoleKey = "WebFrontEnd", SortOrder = 10, NodeDataJson = "{\"nodeName\":\"CT-SHP-01\"}" }),
|
||||||
|
Base(new DeploymentTargetAssignmentModel { Id = DeploymentTargetSp02Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp02Id, RoleKey = "Application", SortOrder = 20, NodeDataJson = "{\"nodeName\":\"CT-SHP-02\"}" })
|
||||||
|
];
|
||||||
|
|
||||||
|
private static TemplateVersionModel TemplateVersion(Guid id, Guid templateId, string jsonData)
|
||||||
|
{
|
||||||
|
return Base(new TemplateVersionModel
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
TemplateId = templateId,
|
||||||
|
Version = "1.0.0",
|
||||||
|
JsonData = jsonData,
|
||||||
|
JsonHash = TemplateVersionModel.ComputeSha256(jsonData),
|
||||||
|
SchemaVersion = "1.0",
|
||||||
|
IsPublished = true,
|
||||||
|
PublishedAt = Timestamp,
|
||||||
|
PublishedBy = Owner
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T Base<T>(T model)
|
||||||
|
where T : BaseModel
|
||||||
|
{
|
||||||
|
model.Created = Timestamp;
|
||||||
|
model.Modified = Timestamp;
|
||||||
|
model.CreatedBy = Owner;
|
||||||
|
model.ModifiedBy = Owner;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T Junction<T>(T model)
|
||||||
|
where T : BaseJunctionModel
|
||||||
|
{
|
||||||
|
model.Created = Timestamp;
|
||||||
|
model.Modified = Timestamp;
|
||||||
|
model.CreatedBy = Owner;
|
||||||
|
model.ModifiedBy = Owner;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string ActiveDirectoryTemplateJson = """
|
||||||
|
{
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"templateType": "Service",
|
||||||
|
"parameters": {
|
||||||
|
"DomainName": { "type": "string", "defaultValue": "corp.contoso.com" },
|
||||||
|
"NetBIOSName": { "type": "string", "defaultValue": "CONTOSO" }
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"DefaultSiteName": "[concat(parameters('DomainName'), '-DefaultSite')]"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"AllNodes": [
|
||||||
|
{ "NodeName": "*", "PSDscAllowPlainTextPassword": true }
|
||||||
|
],
|
||||||
|
"NonNodeData": {
|
||||||
|
"Services": {
|
||||||
|
"ActiveDirectory": {
|
||||||
|
"DomainName": "[parameters('DomainName')]",
|
||||||
|
"NetBIOSName": "[parameters('NetBIOSName')]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private const string SqlServerTemplateJson = """
|
||||||
|
{
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"templateType": "Service",
|
||||||
|
"parameters": {
|
||||||
|
"InstanceName": { "type": "string", "defaultValue": "MSSQLSERVER" },
|
||||||
|
"DatabasePrefix": { "type": "string", "defaultValue": "Contoso" }
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"ConfigDatabase": "[concat(parameters('DatabasePrefix'), '_Config')]"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"NonNodeData": {
|
||||||
|
"Services": {
|
||||||
|
"SqlServer": {
|
||||||
|
"InstanceName": "[parameters('InstanceName')]",
|
||||||
|
"ConfigDatabase": "[variables('ConfigDatabase')]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private const string SharePointTemplateJson = """
|
||||||
|
{
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"templateType": "Service",
|
||||||
|
"parameters": {
|
||||||
|
"DatabasePrefix": { "type": "string", "defaultValue": "SharePoint_Contoso_Test" },
|
||||||
|
"FarmAccount": { "type": "credential", "metadata": { "description": "Farm account resolved by the credential provider." } }
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"ConfigDbName": "[concat(parameters('DatabasePrefix'), '_Farm_Config')]",
|
||||||
|
"AdminContentDbName": "[concat(parameters('DatabasePrefix'), '_AdminContent')]"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"NonNodeData": {
|
||||||
|
"Services": {
|
||||||
|
"SharePoint": {
|
||||||
|
"Farm": {
|
||||||
|
"ConfigDatabase": "[variables('ConfigDbName')]",
|
||||||
|
"AdminContentDatabase": "[variables('AdminContentDbName')]",
|
||||||
|
"ManagedAccounts": {
|
||||||
|
"FarmAccount": "[parameters('FarmAccount')]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private const string TeamsTemplateJson = """
|
||||||
|
{
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"templateType": "Service",
|
||||||
|
"parameters": {
|
||||||
|
"CallingPolicyName": { "type": "string", "defaultValue": "Contoso-Standard-Calling" },
|
||||||
|
"MeetingPolicyName": { "type": "string", "defaultValue": "Contoso-Standard-Meetings" }
|
||||||
|
},
|
||||||
|
"variables": {},
|
||||||
|
"resources": {
|
||||||
|
"NonNodeData": {
|
||||||
|
"Services": {
|
||||||
|
"Teams": {
|
||||||
|
"CallingPolicy": "[parameters('CallingPolicyName')]",
|
||||||
|
"MeetingPolicy": "[parameters('MeetingPolicyName')]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Events.Interfaces;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|
||||||
{
|
|
||||||
public class AbstractController : Controller
|
|
||||||
{
|
|
||||||
private readonly IEventHandlerInterface _eventHandlerInterface;
|
|
||||||
|
|
||||||
private readonly string _class;
|
|
||||||
private readonly string _method;
|
|
||||||
|
|
||||||
public AbstractController( string Class, string Method)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[NonAction]
|
|
||||||
ICollection<EventModel> GetEvents()
|
|
||||||
{
|
|
||||||
return _eventHandlerInterface.GetEvents(_class, _method);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Edit;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/deployment-batches")]
|
||||||
|
[ApiController]
|
||||||
|
public class DeploymentBatchController : Controller
|
||||||
|
{
|
||||||
|
private readonly IDeploymentBatchInterface _deploymentBatchInterface;
|
||||||
|
private readonly DataContext _context;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public DeploymentBatchController(IDeploymentBatchInterface deploymentBatchInterface, DataContext context, IMapper mapper)
|
||||||
|
{
|
||||||
|
_deploymentBatchInterface = deploymentBatchInterface;
|
||||||
|
_context = context;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType(200, Type = typeof(IEnumerable<GetDeploymentBatchDto>))]
|
||||||
|
public IActionResult GetDeploymentBatches()
|
||||||
|
{
|
||||||
|
var deploymentBatches = _deploymentBatchInterface
|
||||||
|
.GetDeploymentBatches()
|
||||||
|
.Select(batch => new GetDeploymentBatchDto
|
||||||
|
{
|
||||||
|
Id = batch.Id,
|
||||||
|
TemplateId = batch.TemplateId,
|
||||||
|
DeploymentRuleId = batch.DeploymentRuleId,
|
||||||
|
Status = batch.Status,
|
||||||
|
Created = batch.Created,
|
||||||
|
CreatedBy = batch.CreatedBy,
|
||||||
|
Modified = batch.Modified,
|
||||||
|
ModifiedBy = batch.ModifiedBy
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
return Ok(deploymentBatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(DeploymentGroupModel))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
public IActionResult GetDeploymentBatchById(Guid id)
|
||||||
|
{
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var deploymentBatch = _mapper.Map<GetDeploymentBatchDetailsDto>(_deploymentBatchInterface.GetDeploymentBatchById(id));
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
return Ok(deploymentBatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
public IActionResult AddDeploymentBatch([FromBody] AddDeploymentBatchDto deploymentBatch)
|
||||||
|
{
|
||||||
|
if (deploymentBatch == null)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var deploymentBatchMap = _mapper.Map<DeploymentGroupModel>(deploymentBatch);
|
||||||
|
|
||||||
|
if (!_deploymentBatchInterface.AddDeploymentBatchById(deploymentBatchMap, deploymentBatch.TargetIds))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong while saving");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(deploymentBatchMap.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteDeploymentBatchById(Guid id)
|
||||||
|
{
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var deploymentBatch = _deploymentBatchInterface.GetDeploymentBatchById(id);
|
||||||
|
|
||||||
|
if (deploymentBatch == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!_deploymentBatchInterface.DeleteDeploymentBatchById(deploymentBatch))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong while deleting");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult EditDeploymentBatchById(Guid id, [FromBody] EditDeploymentBatchDto deploymentBatch)
|
||||||
|
{
|
||||||
|
if (deploymentBatch == null)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var deploymentBatchMap = _mapper.Map<DeploymentGroupModel>(deploymentBatch);
|
||||||
|
deploymentBatchMap.Id = id;
|
||||||
|
|
||||||
|
if (!_deploymentBatchInterface.EditDeploymentBatchById(deploymentBatchMap))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}/composition")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(GetDeploymentCompositionDto))]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult GetDeploymentComposition(Guid id)
|
||||||
|
{
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Ok(LoadComposition(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id}/template-selections")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult AddTemplateSelection(Guid id, [FromBody] AddDeploymentTemplateSelectionDto templateSelection)
|
||||||
|
{
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!_context.TemplateVersions.Any(version => version.Id == templateSelection.TemplateVersionId))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(templateSelection.TemplateVersionId), "Template version was not found.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortOrder = templateSelection.SortOrder > 0
|
||||||
|
? templateSelection.SortOrder
|
||||||
|
: GetNextTemplateSelectionSortOrder(id);
|
||||||
|
|
||||||
|
if (_context.DeploymentTemplateSelections.Any(selection => selection.DeploymentGroupId == id && selection.SortOrder == sortOrder))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(templateSelection.SortOrder), "SortOrder already exists in this deployment batch.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = _mapper.Map<DeploymentTemplateSelectionModel>(templateSelection);
|
||||||
|
model.Id = Guid.NewGuid();
|
||||||
|
model.DeploymentGroupId = id;
|
||||||
|
model.SortOrder = sortOrder;
|
||||||
|
|
||||||
|
_context.DeploymentTemplateSelections.Add(model);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return Ok(model.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}/template-selections/{selectionId}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteTemplateSelection(Guid id, Guid selectionId)
|
||||||
|
{
|
||||||
|
var selection = _context.DeploymentTemplateSelections
|
||||||
|
.FirstOrDefault(existing => existing.DeploymentGroupId == id && existing.Id == selectionId);
|
||||||
|
|
||||||
|
if (selection == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
_context.DeploymentTemplateSelections.Remove(selection);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id}/parameter-values")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult AddParameterValue(Guid id, [FromBody] AddDeploymentParameterValueDto parameterValue)
|
||||||
|
{
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (parameterValue.DeploymentTemplateSelectionId.HasValue
|
||||||
|
&& !_context.DeploymentTemplateSelections.Any(selection =>
|
||||||
|
selection.DeploymentGroupId == id
|
||||||
|
&& selection.Id == parameterValue.DeploymentTemplateSelectionId.Value))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(parameterValue.DeploymentTemplateSelectionId), "Template selection was not found in this deployment batch.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_context.DeploymentParameterValues.Any(existing =>
|
||||||
|
existing.DeploymentGroupId == id
|
||||||
|
&& existing.DeploymentTemplateSelectionId == parameterValue.DeploymentTemplateSelectionId
|
||||||
|
&& existing.Name == parameterValue.Name))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(parameterValue.Name), "Parameter value already exists in this scope.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parameterValue.ValueJson = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||||
|
parameterValue.ValueJson,
|
||||||
|
ConfigurationDocumentKind.Metadata).JsonData;
|
||||||
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(parameterValue.ValueJson), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = _mapper.Map<DeploymentParameterValueModel>(parameterValue);
|
||||||
|
model.Id = Guid.NewGuid();
|
||||||
|
model.DeploymentGroupId = id;
|
||||||
|
|
||||||
|
_context.DeploymentParameterValues.Add(model);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return Ok(model.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}/parameter-values/{parameterValueId}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteParameterValue(Guid id, Guid parameterValueId)
|
||||||
|
{
|
||||||
|
var parameterValue = _context.DeploymentParameterValues
|
||||||
|
.FirstOrDefault(existing => existing.DeploymentGroupId == id && existing.Id == parameterValueId);
|
||||||
|
|
||||||
|
if (parameterValue == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
_context.DeploymentParameterValues.Remove(parameterValue);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id}/target-assignments")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult AddTargetAssignment(Guid id, [FromBody] AddDeploymentTargetAssignmentDto targetAssignment)
|
||||||
|
{
|
||||||
|
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!_context.Targets.Any(target => target.Id == targetAssignment.TargetId))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(targetAssignment.TargetId), "Target target was not found.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_context.DeploymentTargetAssignments.Any(existing =>
|
||||||
|
existing.DeploymentGroupId == id
|
||||||
|
&& existing.TargetId == targetAssignment.TargetId
|
||||||
|
&& existing.RoleKey == targetAssignment.RoleKey))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(targetAssignment.TargetId), "Target assignment already exists for this role.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
targetAssignment.NodeDataJson = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||||
|
targetAssignment.NodeDataJson,
|
||||||
|
ConfigurationDocumentKind.Metadata).JsonData;
|
||||||
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(targetAssignment.NodeDataJson), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortOrder = targetAssignment.SortOrder > 0
|
||||||
|
? targetAssignment.SortOrder
|
||||||
|
: GetNextTargetAssignmentSortOrder(id);
|
||||||
|
|
||||||
|
var model = _mapper.Map<DeploymentTargetAssignmentModel>(targetAssignment);
|
||||||
|
model.Id = Guid.NewGuid();
|
||||||
|
model.DeploymentGroupId = id;
|
||||||
|
model.SortOrder = sortOrder;
|
||||||
|
|
||||||
|
_context.DeploymentTargetAssignments.Add(model);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return Ok(model.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}/target-assignments/{targetAssignmentId}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteTargetAssignment(Guid id, Guid targetAssignmentId)
|
||||||
|
{
|
||||||
|
var targetAssignment = _context.DeploymentTargetAssignments
|
||||||
|
.FirstOrDefault(existing => existing.DeploymentGroupId == id && existing.Id == targetAssignmentId);
|
||||||
|
|
||||||
|
if (targetAssignment == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
_context.DeploymentTargetAssignments.Remove(targetAssignment);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetDeploymentCompositionDto LoadComposition(Guid deploymentBatchId)
|
||||||
|
{
|
||||||
|
return new GetDeploymentCompositionDto
|
||||||
|
{
|
||||||
|
DeploymentBatchId = deploymentBatchId,
|
||||||
|
TemplateSelections = _mapper.Map<List<GetDeploymentTemplateSelectionDto>>(
|
||||||
|
_context.DeploymentTemplateSelections
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(selection => selection.TemplateVersion)
|
||||||
|
.Where(selection => selection.DeploymentGroupId == deploymentBatchId)
|
||||||
|
.OrderBy(selection => selection.SortOrder)
|
||||||
|
.ToList()),
|
||||||
|
ParameterValues = _mapper.Map<List<GetDeploymentParameterValueDto>>(
|
||||||
|
_context.DeploymentParameterValues
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(parameterValue => parameterValue.DeploymentGroupId == deploymentBatchId)
|
||||||
|
.OrderBy(parameterValue => parameterValue.Name)
|
||||||
|
.ToList()),
|
||||||
|
TargetAssignments = _mapper.Map<List<GetDeploymentTargetAssignmentDto>>(
|
||||||
|
_context.DeploymentTargetAssignments
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(target => target.Target)
|
||||||
|
.Where(target => target.DeploymentGroupId == deploymentBatchId)
|
||||||
|
.OrderBy(target => target.SortOrder)
|
||||||
|
.ToList())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetNextTemplateSelectionSortOrder(Guid deploymentBatchId)
|
||||||
|
{
|
||||||
|
var maxSortOrder = _context.DeploymentTemplateSelections
|
||||||
|
.Where(selection => selection.DeploymentGroupId == deploymentBatchId)
|
||||||
|
.Select(selection => (int?)selection.SortOrder)
|
||||||
|
.Max() ?? 0;
|
||||||
|
|
||||||
|
return maxSortOrder + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetNextTargetAssignmentSortOrder(Guid deploymentBatchId)
|
||||||
|
{
|
||||||
|
var maxSortOrder = _context.DeploymentTargetAssignments
|
||||||
|
.Where(target => target.DeploymentGroupId == deploymentBatchId)
|
||||||
|
.Select(target => (int?)target.SortOrder)
|
||||||
|
.Max() ?? 0;
|
||||||
|
|
||||||
|
return maxSortOrder + 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,13 +6,8 @@ using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit;
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
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;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||||
{
|
{
|
||||||
@@ -24,20 +19,17 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
private readonly IQueueJobService _queueJobService;
|
private readonly IQueueJobService _queueJobService;
|
||||||
private readonly DataContext _context;
|
private readonly DataContext _context;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
private readonly IEventHandlerInterface _eventHandlerInterface;
|
|
||||||
|
|
||||||
public DeploymentController(
|
public DeploymentController(
|
||||||
IDeploymentInterface deploymentInterface,
|
IDeploymentInterface deploymentInterface,
|
||||||
IQueueJobService queueJobService,
|
IQueueJobService queueJobService,
|
||||||
DataContext context,
|
DataContext context,
|
||||||
IMapper mapper,
|
IMapper mapper)
|
||||||
IEventHandlerInterface eventHandlerInterface)
|
|
||||||
{
|
{
|
||||||
_deploymentInterface = deploymentInterface;
|
_deploymentInterface = deploymentInterface;
|
||||||
_queueJobService = queueJobService;
|
_queueJobService = queueJobService;
|
||||||
_context = context;
|
_context = context;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
_eventHandlerInterface = eventHandlerInterface;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -83,11 +75,19 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
|
|
||||||
var deploymentMap = _mapper.Map<DeploymentModel>(deployment);
|
var deploymentMap = _mapper.Map<DeploymentModel>(deployment);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (!_deploymentInterface.AddDeploymentById(deploymentMap))
|
if (!_deploymentInterface.AddDeploymentById(deploymentMap))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("", "Something went wrong while saving");
|
ModelState.AddModelError("", "Something went wrong while saving");
|
||||||
return StatusCode(500, ModelState);
|
return StatusCode(500, ModelState);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(deployment.JsonData), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(deploymentMap.Id);
|
return Ok(deploymentMap.Id);
|
||||||
}
|
}
|
||||||
@@ -100,9 +100,9 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
if (request == null)
|
if (request == null)
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
if (request.VirtualMachineIds == null || request.VirtualMachineIds.Count == 0)
|
if (request.TargetIds == null || request.TargetIds.Count == 0)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("", "At least one VirtualMachine must be selected.");
|
ModelState.AddModelError("", "At least one Target must be selected.");
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
{
|
{
|
||||||
var queueJobId = _queueJobService.EnqueueDeploymentRequest(
|
var queueJobId = _queueJobService.EnqueueDeploymentRequest(
|
||||||
request.DeploymentGroupId,
|
request.DeploymentGroupId,
|
||||||
request.VirtualMachineIds,
|
request.TargetIds,
|
||||||
request.JsonData);
|
request.JsonData);
|
||||||
|
|
||||||
return Ok(queueJobId);
|
return Ok(queueJobId);
|
||||||
@@ -123,6 +123,11 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
ModelState.AddModelError("", ex.Message);
|
ModelState.AddModelError("", ex.Message);
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
}
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(request.JsonData), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("QueueJobs")]
|
[HttpGet("QueueJobs")]
|
||||||
@@ -187,7 +192,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
Targets = queueJob.Targets.Select(target => new GetQueueJobTargetDto
|
Targets = queueJob.Targets.Select(target => new GetQueueJobTargetDto
|
||||||
{
|
{
|
||||||
Id = target.Id,
|
Id = target.Id,
|
||||||
VirtualMachineId = target.VirtualMachineId,
|
TargetId = target.TargetId,
|
||||||
DeploymentGroupId = target.DeploymentGroupId,
|
DeploymentGroupId = target.DeploymentGroupId,
|
||||||
TemplateId = target.TemplateId,
|
TemplateId = target.TemplateId,
|
||||||
Status = target.Status,
|
Status = target.Status,
|
||||||
@@ -271,6 +276,32 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpDelete("Batch/{deploymentBatchId}/Target/{targetId}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteDeploymentExecution(Guid deploymentBatchId, Guid targetId)
|
||||||
|
{
|
||||||
|
if (!_deploymentInterface.CheckDeploymentByCompositeId(deploymentBatchId, targetId))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var deployment = _deploymentInterface.GetDeploymentByCompositeId(deploymentBatchId, targetId);
|
||||||
|
|
||||||
|
if (deployment == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!_deploymentInterface.DeleteDeploymentById(deployment))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong while deleting");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPut("{Id}")]
|
[HttpPut("{Id}")]
|
||||||
[ProducesResponseType(204)]
|
[ProducesResponseType(204)]
|
||||||
[ProducesResponseType(400)]
|
[ProducesResponseType(400)]
|
||||||
@@ -289,15 +320,22 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
var deploymentMap = _mapper.Map<DeploymentModel>(deployment);
|
var deploymentMap = _mapper.Map<DeploymentModel>(deployment);
|
||||||
deploymentMap.Id = Id;
|
deploymentMap.Id = Id;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (!_deploymentInterface.EditDeploymentById(deploymentMap))
|
if (!_deploymentInterface.EditDeploymentById(deploymentMap))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
ModelState.AddModelError("", "Something went wrong");
|
||||||
return StatusCode(500, ModelState);
|
return StatusCode(500, ModelState);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_eventHandlerInterface.FireEvent(this.GetType().Name, MethodBase.GetCurrentMethod().Name, Id);
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(deployment.jsonData), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Get;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Add;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Edit;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|
||||||
{
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class DeploymentGroupController : Controller
|
|
||||||
{
|
|
||||||
private readonly IDeploymentGroupInterface _deploymentgroupInterface;
|
|
||||||
private readonly IMapper _mapper;
|
|
||||||
|
|
||||||
public DeploymentGroupController(IDeploymentGroupInterface deploymentGroupInterface, IMapper mapper)
|
|
||||||
{
|
|
||||||
_deploymentgroupInterface = deploymentGroupInterface;
|
|
||||||
_mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(200, Type = typeof(IEnumerable<DomainModel>))]
|
|
||||||
public IActionResult GetDeploymentGroups()
|
|
||||||
{
|
|
||||||
var deploymentgroups = _mapper.Map<List<GetDeploymentGroupDto>>(_deploymentgroupInterface.GetDeploymentGroups());
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
return Ok(deploymentgroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{Id}")]
|
|
||||||
[ProducesResponseType(200, Type = typeof(DeploymentGroupModel))]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
public IActionResult GetDeploymentGroupById(Guid Id)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!_deploymentgroupInterface.CheckDeploymentGroupById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var deploymentgroup = _mapper.Map<GetDeploymentGroupDetailsDto>(_deploymentgroupInterface.GetDeploymentGroupById(Id));
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
return Ok(deploymentgroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
public IActionResult AddDeploymentGroupById([FromBody] AddDeploymentGroupDto deploymentgroup)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (deploymentgroup == null)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var deploymentgroupMap = _mapper.Map<DeploymentGroupModel>(deploymentgroup);
|
|
||||||
|
|
||||||
if (!_deploymentgroupInterface.AddDeploymentGroupById(deploymentgroupMap, deploymentgroup.VirtualMachineIds))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong while saving");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
return Ok(deploymentgroupMap.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{Id}")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
public IActionResult DeleteDeploymentGroupById(Guid Id)
|
|
||||||
{
|
|
||||||
if (!_deploymentgroupInterface.CheckDeploymentGroupById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var deploymentgroup = _deploymentgroupInterface.GetDeploymentGroupById(Id);
|
|
||||||
|
|
||||||
if (!_deploymentgroupInterface.DeleteDeploymentGroupById(deploymentgroup))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong while deleting");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{Id}")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
public IActionResult EditDeploymentGroupById(Guid Id, [FromBody] EditDeploymentGroupDto deploymentgroup)
|
|
||||||
{
|
|
||||||
if (deploymentgroup == null)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (!_deploymentgroupInterface.CheckDeploymentGroupById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var deploymentgroupMap = _mapper.Map<DeploymentGroupModel>(deploymentgroup);
|
|
||||||
deploymentgroupMap.Id = Id;
|
|
||||||
|
|
||||||
if (!_deploymentgroupInterface.EditDeploymentGroupById(deploymentgroupMap))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/deployment-rules")]
|
||||||
|
[ApiController]
|
||||||
|
public class DeploymentRuleController : Controller
|
||||||
|
{
|
||||||
|
private readonly DataContext _context;
|
||||||
|
|
||||||
|
public DeploymentRuleController(DataContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType(200, Type = typeof(IEnumerable<GetDeploymentRuleDto>))]
|
||||||
|
public IActionResult GetDeploymentRules()
|
||||||
|
{
|
||||||
|
var rules = _context.DeploymentRules
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(rule => rule.Steps)
|
||||||
|
.OrderBy(rule => rule.Name)
|
||||||
|
.Select(rule => MapRule(rule))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return Ok(rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(GetDeploymentRuleDto))]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult GetDeploymentRuleById(Guid id)
|
||||||
|
{
|
||||||
|
var rule = _context.DeploymentRules
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(entry => entry.Steps)
|
||||||
|
.FirstOrDefault(entry => entry.Id == id);
|
||||||
|
|
||||||
|
if (rule == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Ok(MapRule(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
public IActionResult AddDeploymentRule([FromBody] AddDeploymentRuleDto deploymentRule)
|
||||||
|
{
|
||||||
|
if (deploymentRule == null)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var rule = new DeploymentRuleModel
|
||||||
|
{
|
||||||
|
Name = deploymentRule.Name,
|
||||||
|
Description = deploymentRule.Description,
|
||||||
|
IsActive = deploymentRule.IsActive
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.DeploymentRules.Add(rule);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
foreach (var (step, index) in deploymentRule.Steps.Select((value, idx) => (value, idx)))
|
||||||
|
{
|
||||||
|
_context.DeploymentRuleSteps.Add(new DeploymentRuleStepModel
|
||||||
|
{
|
||||||
|
DeploymentRuleId = rule.Id,
|
||||||
|
SortOrder = step.SortOrder > 0 ? step.SortOrder : index + 1,
|
||||||
|
Name = step.Name,
|
||||||
|
StepType = string.IsNullOrWhiteSpace(step.StepType) ? QueueJobStepType.Provision : step.StepType,
|
||||||
|
RequiresApproval = step.RequiresApproval,
|
||||||
|
MetadataJson = step.MetadataJson
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.SaveChanges();
|
||||||
|
return Ok(rule.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult EditDeploymentRule(Guid id, [FromBody] AddDeploymentRuleDto deploymentRule)
|
||||||
|
{
|
||||||
|
var existingRule = _context.DeploymentRules
|
||||||
|
.Include(rule => rule.Steps)
|
||||||
|
.FirstOrDefault(rule => rule.Id == id);
|
||||||
|
|
||||||
|
if (existingRule == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
existingRule.Name = deploymentRule.Name;
|
||||||
|
existingRule.Description = deploymentRule.Description;
|
||||||
|
existingRule.IsActive = deploymentRule.IsActive;
|
||||||
|
|
||||||
|
var existingSteps = _context.DeploymentRuleSteps.Where(step => step.DeploymentRuleId == id).ToList();
|
||||||
|
if (existingSteps.Count > 0)
|
||||||
|
{
|
||||||
|
_context.DeploymentRuleSteps.RemoveRange(existingSteps);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (step, index) in deploymentRule.Steps.Select((value, idx) => (value, idx)))
|
||||||
|
{
|
||||||
|
_context.DeploymentRuleSteps.Add(new DeploymentRuleStepModel
|
||||||
|
{
|
||||||
|
DeploymentRuleId = id,
|
||||||
|
SortOrder = step.SortOrder > 0 ? step.SortOrder : index + 1,
|
||||||
|
Name = step.Name,
|
||||||
|
StepType = string.IsNullOrWhiteSpace(step.StepType) ? QueueJobStepType.Provision : step.StepType,
|
||||||
|
RequiresApproval = step.RequiresApproval,
|
||||||
|
MetadataJson = step.MetadataJson
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.SaveChanges();
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteDeploymentRule(Guid id)
|
||||||
|
{
|
||||||
|
var existingRule = _context.DeploymentRules.FirstOrDefault(rule => rule.Id == id);
|
||||||
|
if (existingRule == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var linkedTemplates = _context.Templates.Where(template => template.DeploymentRuleId == id).ToList();
|
||||||
|
foreach (var template in linkedTemplates)
|
||||||
|
{
|
||||||
|
template.DeploymentRuleId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var steps = _context.DeploymentRuleSteps.Where(step => step.DeploymentRuleId == id).ToList();
|
||||||
|
if (steps.Count > 0)
|
||||||
|
{
|
||||||
|
_context.DeploymentRuleSteps.RemoveRange(steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.DeploymentRules.Remove(existingRule);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GetDeploymentRuleDto MapRule(DeploymentRuleModel rule)
|
||||||
|
{
|
||||||
|
return new GetDeploymentRuleDto
|
||||||
|
{
|
||||||
|
Id = rule.Id,
|
||||||
|
Name = rule.Name,
|
||||||
|
Description = rule.Description,
|
||||||
|
IsActive = rule.IsActive,
|
||||||
|
Created = rule.Created,
|
||||||
|
CreatedBy = rule.CreatedBy,
|
||||||
|
Modified = rule.Modified,
|
||||||
|
ModifiedBy = rule.ModifiedBy,
|
||||||
|
Steps = rule.Steps
|
||||||
|
.OrderBy(step => step.SortOrder)
|
||||||
|
.Select(step => new GetDeploymentRuleStepDto
|
||||||
|
{
|
||||||
|
Id = step.Id,
|
||||||
|
SortOrder = step.SortOrder,
|
||||||
|
Name = step.Name,
|
||||||
|
StepType = step.StepType,
|
||||||
|
RequiresApproval = step.RequiresApproval,
|
||||||
|
MetadataJson = step.MetadataJson,
|
||||||
|
Created = step.Created,
|
||||||
|
CreatedBy = step.CreatedBy,
|
||||||
|
Modified = step.Modified,
|
||||||
|
ModifiedBy = step.ModifiedBy
|
||||||
|
})
|
||||||
|
.ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -210,16 +210,16 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{Id}/VirtualMachines")]
|
[HttpGet("{Id}/Targets")]
|
||||||
[ProducesResponseType(200, Type = typeof(DomainModel))]
|
[ProducesResponseType(200, Type = typeof(DomainModel))]
|
||||||
[ProducesResponseType(400)]
|
[ProducesResponseType(400)]
|
||||||
public IActionResult GetVirtualMachinesByDomainId(Guid Id)
|
public IActionResult GetTargetsByDomainId(Guid Id)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!_domainInterface.CheckDomainById(Id))
|
if (!_domainInterface.CheckDomainById(Id))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
var domain = _mapper.Map<GetDomainVirtualMachineDetailsDto>(_domainInterface.GetVirtualMachinesByDomainId(Id));
|
var domain = _mapper.Map<GetDomainTargetDetailsDto>(_domainInterface.GetTargetsByDomainId(Id));
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
@@ -228,3 +228,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,10 +63,16 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
|
|
||||||
if (_environmentInterface.CheckEnvironmentByName(environment.Name))
|
if (_environmentInterface.CheckEnvironmentByName(environment.Name))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("", "Domain already exists");
|
ModelState.AddModelError("", "Environment already exists");
|
||||||
return StatusCode(422, ModelState);
|
return StatusCode(422, ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsValidEnvironmentStage(environment.EnvironmentType) || !IsValidHostingType(environment.HostingType))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Invalid Environment Stage or Hosting Type.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
@@ -118,6 +124,12 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (!IsValidEnvironmentStage(environment.EnvironmentType) || !IsValidHostingType(environment.HostingType))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Invalid Environment Stage or Hosting Type.");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
var environmentMap = _mapper.Map<EnvironmentModel>(environment);
|
var environmentMap = _mapper.Map<EnvironmentModel>(environment);
|
||||||
environmentMap.Id = Id;
|
environmentMap.Id = Id;
|
||||||
|
|
||||||
@@ -130,6 +142,21 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsValidEnvironmentStage(string? stage)
|
||||||
|
{
|
||||||
|
return stage == EnvironmentStages.Development
|
||||||
|
|| stage == EnvironmentStages.Test
|
||||||
|
|| stage == EnvironmentStages.QA
|
||||||
|
|| stage == EnvironmentStages.Production;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidHostingType(string? hostingType)
|
||||||
|
{
|
||||||
|
return hostingType == EnvironmentHostingTypes.OnPrem
|
||||||
|
|| hostingType == EnvironmentHostingTypes.AzureTenant
|
||||||
|
|| hostingType == EnvironmentHostingTypes.M365Tenant;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("{Id}/Domains")]
|
[HttpGet("{Id}/Domains")]
|
||||||
[ProducesResponseType(200, Type = typeof(EnvironmentModel))]
|
[ProducesResponseType(200, Type = typeof(EnvironmentModel))]
|
||||||
[ProducesResponseType(400)]
|
[ProducesResponseType(400)]
|
||||||
@@ -161,3 +188,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Get;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Add;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class RunbookController : Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
private readonly IRunbookInterface _runbookInterface;
|
|
||||||
private readonly IMapper _mapper;
|
|
||||||
|
|
||||||
public RunbookController(IRunbookInterface runbookInterface, IMapper mapper)
|
|
||||||
{
|
|
||||||
_runbookInterface = runbookInterface;
|
|
||||||
_mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(200, Type = typeof(IEnumerable<RunbookModel>))]
|
|
||||||
public IActionResult GetRunbooks()
|
|
||||||
{
|
|
||||||
var runbooks = _mapper.Map<List<GetRunbookDto>>(_runbookInterface.GetRunbooks());
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
return Ok(runbooks);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{Id}")]
|
|
||||||
[ProducesResponseType(200, Type = typeof(RunbookModel))]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
public IActionResult GetRunbookById(Guid Id)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!_runbookInterface.CheckRunbookById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var runbook = _mapper.Map<GetRunbookDetailsDto>(_runbookInterface.GetRunbookById(Id));
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
return Ok(runbook);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
public IActionResult AddRunbookById([FromBody] AddRunbookDto runbook)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (runbook == null)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (_runbookInterface.CheckRunbookByName(runbook.Name))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Runbook already exists");
|
|
||||||
return StatusCode(422, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
|
|
||||||
var runbookMap = _mapper.Map<RunbookModel>(runbook);
|
|
||||||
|
|
||||||
if (!_runbookInterface.AddRunbookById(runbookMap))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong while saving");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok("Successfully created");
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{Id}")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
public IActionResult EditRunbookById(Guid Id, [FromBody] GetRunbookDetailsDto runbook)
|
|
||||||
{
|
|
||||||
if (runbook == null)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (Id != runbook.Id)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (!_runbookInterface.CheckRunbookById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var runbookMap = _mapper.Map<RunbookModel>(runbook);
|
|
||||||
|
|
||||||
if (_runbookInterface.EditRunbookById(runbookMap))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit;
|
||||||
@@ -240,3 +240,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Edit;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class TargetController : Controller
|
||||||
|
{
|
||||||
|
private readonly ITargetInterface _targetInterface;
|
||||||
|
private readonly IDomainInterface _domainInterface;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public TargetController(ITargetInterface targetInterface, IDomainInterface domainInterface, IMapper mapper)
|
||||||
|
{
|
||||||
|
_targetInterface = targetInterface;
|
||||||
|
_domainInterface = domainInterface;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType(200, Type = typeof(IEnumerable<TargetModel>))]
|
||||||
|
public IActionResult GetTargets()
|
||||||
|
{
|
||||||
|
var targets = _mapper.Map<List<GetTargetDto>>(_targetInterface.GetTargets());
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
return Ok(targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{Id}")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(TargetModel))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
public IActionResult GetTargetById(Guid Id)
|
||||||
|
{
|
||||||
|
if (!_targetInterface.CheckTargetById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var target = _mapper.Map<GetTargetDetailsDto>(_targetInterface.GetTargetById(Id));
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
return Ok(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(200)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
public IActionResult AddTargetById([FromBody] AddTargetDto target)
|
||||||
|
{
|
||||||
|
if (target == null)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (_targetInterface.CheckTargetByName(target.Name))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Target already exists");
|
||||||
|
return StatusCode(422, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.DomainID.HasValue && !_domainInterface.CheckDomainById(target.DomainID.Value))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Domain does not exist");
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var targetMap = _mapper.Map<TargetModel>(target);
|
||||||
|
|
||||||
|
if (!_targetInterface.AddTargetById(targetMap))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong while saving");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(targetMap.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{Id}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult EditTargetById(Guid Id, [FromBody] EditTargetDto target)
|
||||||
|
{
|
||||||
|
if (target == null)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (!_targetInterface.CheckTargetById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var existingTarget = _targetInterface.GetTargetById(Id);
|
||||||
|
if (existingTarget == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
existingTarget.Name = target.Name;
|
||||||
|
existingTarget.TargetType = target.TargetType;
|
||||||
|
existingTarget.ProviderType = target.ProviderType;
|
||||||
|
existingTarget.ExternalId = target.ExternalId;
|
||||||
|
existingTarget.MetadataJson = target.MetadataJson;
|
||||||
|
|
||||||
|
if (!_targetInterface.EditTargetById(existingTarget))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{Id}/Domain/{domainId}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
[ProducesResponseType(409)]
|
||||||
|
public IActionResult LinkTargetToDomain(Guid Id, Guid domainId)
|
||||||
|
{
|
||||||
|
if (!_targetInterface.CheckTargetById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!_domainInterface.CheckDomainById(domainId))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var existingTarget = _targetInterface.GetTargetById(Id);
|
||||||
|
if (existingTarget == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (existingTarget.DomainID.HasValue)
|
||||||
|
return Conflict("Target is already linked to a domain. Unlink it first.");
|
||||||
|
|
||||||
|
existingTarget.DomainID = domainId;
|
||||||
|
|
||||||
|
if (!_targetInterface.EditTargetById(existingTarget))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{Id}/Domain")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult UnlinkTargetFromDomain(Guid Id)
|
||||||
|
{
|
||||||
|
if (!_targetInterface.CheckTargetById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var existingTarget = _targetInterface.GetTargetById(Id);
|
||||||
|
if (existingTarget == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!existingTarget.DomainID.HasValue)
|
||||||
|
return NoContent();
|
||||||
|
|
||||||
|
existingTarget.DomainID = null;
|
||||||
|
|
||||||
|
if (!_targetInterface.EditTargetById(existingTarget))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{Id}")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult DeleteTargetById(Guid Id)
|
||||||
|
{
|
||||||
|
if (!_targetInterface.CheckTargetById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
var target = _targetInterface.GetTargetById(Id);
|
||||||
|
|
||||||
|
if (!_targetInterface.DeleteTargetById(target))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong while deleting");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit;
|
||||||
@@ -128,3 +128,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||||
@@ -73,11 +76,19 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
|
|
||||||
var templateMap = _mapper.Map<TemplateModel>(template);
|
var templateMap = _mapper.Map<TemplateModel>(template);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (!_templateInterface.AddTemplateById(templateMap))
|
if (!_templateInterface.AddTemplateById(templateMap))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("", "Something went wrong while saving");
|
ModelState.AddModelError("", "Something went wrong while saving");
|
||||||
return StatusCode(500, ModelState);
|
return StatusCode(500, ModelState);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(template.JSONData), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(templateMap.Id);
|
return Ok(templateMap.Id);
|
||||||
}
|
}
|
||||||
@@ -102,11 +113,19 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
var templateMap = _mapper.Map<TemplateModel>(template);
|
var templateMap = _mapper.Map<TemplateModel>(template);
|
||||||
templateMap.Id = Id;
|
templateMap.Id = Id;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (!_templateInterface.EditTemplateById(templateMap))
|
if (!_templateInterface.EditTemplateById(templateMap))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
ModelState.AddModelError("", "Something went wrong");
|
||||||
return StatusCode(500, ModelState);
|
return StatusCode(500, ModelState);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(template.JSONData), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.Equals(existingTemplate.JSONData, template.JSONData, StringComparison.Ordinal))
|
if (!string.Equals(existingTemplate.JSONData, template.JSONData, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
@@ -138,5 +157,82 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{Id}/Versions")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(IEnumerable<GetTemplateVersionDto>))]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult GetTemplateVersions(Guid Id)
|
||||||
|
{
|
||||||
|
if (!_templateInterface.CheckTemplateById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var versions = _mapper.Map<List<GetTemplateVersionDto>>(_templateInterface.GetTemplateVersions(Id));
|
||||||
|
return Ok(versions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{Id}/Versions/{VersionId}")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(GetTemplateVersionDto))]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult GetTemplateVersionById(Guid Id, Guid VersionId)
|
||||||
|
{
|
||||||
|
var version = _templateInterface.GetTemplateVersionById(Id, VersionId);
|
||||||
|
if (version == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Ok(_mapper.Map<GetTemplateVersionDto>(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{Id}/Versions")]
|
||||||
|
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||||
|
[ProducesResponseType(400)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult AddTemplateVersion(Guid Id, [FromBody] AddTemplateVersionDto templateVersion)
|
||||||
|
{
|
||||||
|
if (templateVersion == null)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (!_templateInterface.CheckTemplateById(Id))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
if (_templateInterface.CheckTemplateVersionByVersion(Id, templateVersion.Version))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(templateVersion.Version), "Template version already exists");
|
||||||
|
return StatusCode(422, ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var version = _mapper.Map<TemplateVersionModel>(templateVersion);
|
||||||
|
version.PublishedBy = templateVersion.PublishedBy ?? User?.Identity?.Name ?? "System";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_templateInterface.AddTemplateVersion(Id, version, templateVersion.Publish))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("", "Something went wrong while saving template version");
|
||||||
|
return StatusCode(500, ModelState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ConfigurationDocumentValidationException ex)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(templateVersion.JsonData), ex.Message);
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(version.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{Id}/Versions/{VersionId}/Publish")]
|
||||||
|
[ProducesResponseType(204)]
|
||||||
|
[ProducesResponseType(404)]
|
||||||
|
public IActionResult PublishTemplateVersion(Guid Id, Guid VersionId)
|
||||||
|
{
|
||||||
|
if (!_templateInterface.PublishTemplateVersion(Id, VersionId, User?.Identity?.Name ?? "System"))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,200 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Add;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Edit;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class VirtualMachineController : Controller
|
|
||||||
{
|
|
||||||
private readonly IVirtualMachineInterface _virtualmachineInterface;
|
|
||||||
private readonly IDomainInterface _domainInterface;
|
|
||||||
private readonly IMapper _mapper;
|
|
||||||
|
|
||||||
public VirtualMachineController(IVirtualMachineInterface virtualmachineInterface, IDomainInterface domainInterface, IMapper mapper)
|
|
||||||
{
|
|
||||||
_virtualmachineInterface = virtualmachineInterface;
|
|
||||||
_domainInterface = domainInterface;
|
|
||||||
_mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(200, Type = typeof(IEnumerable<VirtualMachineModel>))]
|
|
||||||
public IActionResult GetVirtualMachines()
|
|
||||||
{
|
|
||||||
var virtualMachines = _mapper.Map<List<GetVirtualMachineDto>>(_virtualmachineInterface.GetVirtualMachines());
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
return Ok(virtualMachines);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{Id}")]
|
|
||||||
[ProducesResponseType(200, Type = typeof(VirtualMachineModel))]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
public IActionResult GetVirtualMachineById(Guid Id)
|
|
||||||
{
|
|
||||||
if (!_virtualmachineInterface.CheckVirtualMachineById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var virtualMachine = _mapper.Map<GetVirtualMachineDetailsDto>(_virtualmachineInterface.GetVirtualMachineById(Id));
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
return Ok(virtualMachine);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[ProducesResponseType(200)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
public IActionResult AddVirtualMachineById([FromBody] AddVirtualMachineDto virtualMachine)
|
|
||||||
{
|
|
||||||
if (virtualMachine == null)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (_virtualmachineInterface.CheckVirtualMachineByName(virtualMachine.Name))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "VirtualMachine already exists");
|
|
||||||
return StatusCode(422, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virtualMachine.DomainID.HasValue && !_domainInterface.CheckDomainById(virtualMachine.DomainID.Value))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Domain does not exist");
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var virtualMachineMap = _mapper.Map<VirtualMachineModel>(virtualMachine);
|
|
||||||
|
|
||||||
if (!_virtualmachineInterface.AddVirtualMachineById(virtualMachineMap))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong while saving");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(virtualMachineMap.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{Id}")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
public IActionResult EditVirtualMachineById(Guid Id, [FromBody] EditVirtualMachineDto virtualMachine)
|
|
||||||
{
|
|
||||||
if (virtualMachine == null)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
if (!_virtualmachineInterface.CheckVirtualMachineById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var existingVirtualMachine = _virtualmachineInterface.GetVirtualMachineById(Id);
|
|
||||||
if (existingVirtualMachine == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
existingVirtualMachine.Name = virtualMachine.Name;
|
|
||||||
existingVirtualMachine.ExternalId = virtualMachine.ExternalId;
|
|
||||||
existingVirtualMachine.MetadataJson = virtualMachine.MetadataJson;
|
|
||||||
|
|
||||||
if (!_virtualmachineInterface.EditVirtualMachineById(existingVirtualMachine))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{Id}/Domain/{domainId}")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
[ProducesResponseType(409)]
|
|
||||||
public IActionResult LinkVirtualMachineToDomain(Guid Id, Guid domainId)
|
|
||||||
{
|
|
||||||
if (!_virtualmachineInterface.CheckVirtualMachineById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!_domainInterface.CheckDomainById(domainId))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var existingVirtualMachine = _virtualmachineInterface.GetVirtualMachineById(Id);
|
|
||||||
if (existingVirtualMachine == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (existingVirtualMachine.DomainID.HasValue)
|
|
||||||
return Conflict("VirtualMachine is already linked to a domain. Unlink it first.");
|
|
||||||
|
|
||||||
existingVirtualMachine.DomainID = domainId;
|
|
||||||
|
|
||||||
if (!_virtualmachineInterface.EditVirtualMachineById(existingVirtualMachine))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{Id}/Domain")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
public IActionResult UnlinkVirtualMachineFromDomain(Guid Id)
|
|
||||||
{
|
|
||||||
if (!_virtualmachineInterface.CheckVirtualMachineById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var existingVirtualMachine = _virtualmachineInterface.GetVirtualMachineById(Id);
|
|
||||||
if (existingVirtualMachine == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!existingVirtualMachine.DomainID.HasValue)
|
|
||||||
return NoContent();
|
|
||||||
|
|
||||||
existingVirtualMachine.DomainID = null;
|
|
||||||
|
|
||||||
if (!_virtualmachineInterface.EditVirtualMachineById(existingVirtualMachine))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{Id}")]
|
|
||||||
[ProducesResponseType(204)]
|
|
||||||
[ProducesResponseType(400)]
|
|
||||||
[ProducesResponseType(404)]
|
|
||||||
public IActionResult DeleteVirtualMachineById(Guid Id)
|
|
||||||
{
|
|
||||||
if (!_virtualmachineInterface.CheckVirtualMachineById(Id))
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
var virtualMachine = _virtualmachineInterface.GetVirtualMachineById(Id);
|
|
||||||
|
|
||||||
if (!_virtualmachineInterface.DeleteVirtualMachineById(virtualMachine))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Something went wrong while deleting");
|
|
||||||
return StatusCode(500, ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,559 @@
|
|||||||
|
# Deployment Model Architecture
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
The portal should become a generic configuration composition platform. It must support on-premises workloads such as Active Directory, SQL Server, SharePoint, and Exchange, as well as cloud workloads such as Teams, Azure, and M365.
|
||||||
|
|
||||||
|
The database should not know SharePoint-specific concepts such as farm accounts or service application pools. Those details belong inside versioned template documents. The database should know how templates, environments, domains, targets, deployments, jobs, and artifacts relate to each other.
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
The model separates reusable catalog data from concrete execution data:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Catalog:
|
||||||
|
Environment
|
||||||
|
Domain
|
||||||
|
Service
|
||||||
|
Target
|
||||||
|
Template
|
||||||
|
TemplateVersion
|
||||||
|
|
||||||
|
Design:
|
||||||
|
DeploymentGroup
|
||||||
|
Deployment
|
||||||
|
DeploymentTemplateSelection
|
||||||
|
DeploymentParameterValue
|
||||||
|
DeploymentTarget
|
||||||
|
|
||||||
|
Execution:
|
||||||
|
QueueJob
|
||||||
|
QueueJobStep
|
||||||
|
QueueJobTarget
|
||||||
|
DeploymentArtifact
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment
|
||||||
|
|
||||||
|
An environment is a logical target context, for example `Prod A`, `Test A`, `Prod B`, `Test B`, or `QA B`.
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `Key`
|
||||||
|
- `Name`
|
||||||
|
- `Stage`, for example `Development`, `Test`, `QA`, `Production`
|
||||||
|
- `HostingType`, for example `OnPrem`, `Azure`, `M365`, `Hybrid`
|
||||||
|
- `ProviderType`
|
||||||
|
- `TenantId`
|
||||||
|
- `SubscriptionId`
|
||||||
|
- `MetadataJson`
|
||||||
|
|
||||||
|
### Domain
|
||||||
|
|
||||||
|
A domain is reusable catalog data and configuration. A domain can be linked to multiple environments.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Central-Management
|
||||||
|
-> Test A
|
||||||
|
-> Prod A
|
||||||
|
-> QA B
|
||||||
|
```
|
||||||
|
|
||||||
|
The goal is to change the Central-Management domain configuration once and then decide which linked environments should consume the new version.
|
||||||
|
|
||||||
|
Suggested relationship:
|
||||||
|
|
||||||
|
```text
|
||||||
|
EnvironmentDomain
|
||||||
|
- EnvironmentId
|
||||||
|
- DomainId
|
||||||
|
- Role
|
||||||
|
- SortOrder
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service
|
||||||
|
|
||||||
|
A service represents a workload family, for example:
|
||||||
|
|
||||||
|
- `active-directory`
|
||||||
|
- `sql-server`
|
||||||
|
- `sharepoint`
|
||||||
|
- `exchange`
|
||||||
|
- `teams`
|
||||||
|
- `azure-network`
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `Key`
|
||||||
|
- `Name`
|
||||||
|
- `Description`
|
||||||
|
- `WorkloadType`, for example `OnPrem`, `Azure`, `M365`, `Hybrid`
|
||||||
|
- `IconKey`
|
||||||
|
- `IsActive`
|
||||||
|
|
||||||
|
### Target
|
||||||
|
|
||||||
|
A target is anything a deployment can act on. It should not be limited to virtual machines.
|
||||||
|
|
||||||
|
Suggested target types:
|
||||||
|
|
||||||
|
- `VirtualMachine`
|
||||||
|
- `Tenant`
|
||||||
|
- `Subscription`
|
||||||
|
- `ResourceGroup`
|
||||||
|
- `User`
|
||||||
|
- `Group`
|
||||||
|
- `Site`
|
||||||
|
- `PolicyScope`
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `Name`
|
||||||
|
- `TargetType`
|
||||||
|
- `EnvironmentId`
|
||||||
|
- `DomainId`
|
||||||
|
- `ExternalId`
|
||||||
|
- `MetadataJson`
|
||||||
|
|
||||||
|
For current VM usage, `VirtualMachineModel` can either remain as a specialized target table during migration or be folded into a generic target model later.
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
### Template
|
||||||
|
|
||||||
|
`Template` should be the stable catalog entry. It should not contain mutable deployment content.
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `Key`, for example `service.sharepoint.default`
|
||||||
|
- `Name`
|
||||||
|
- `TemplateType`, for example `Domain`, `Environment`, `Service`, `Stage`, `TargetSet`, `Policy`
|
||||||
|
- `WorkloadType`, for example `OnPrem`, `Azure`, `M365`, `Hybrid`
|
||||||
|
- `ServiceId`
|
||||||
|
- `TemplateCategoryId`
|
||||||
|
- `DeploymentRuleId`
|
||||||
|
- `IsActive`
|
||||||
|
|
||||||
|
`Template` is mutable catalog metadata. It can be renamed, categorized, activated, or deactivated without changing the immutable template document history.
|
||||||
|
|
||||||
|
### TemplateVersion
|
||||||
|
|
||||||
|
`TemplateVersion` should contain the immutable template document.
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `TemplateId`
|
||||||
|
- `Version`
|
||||||
|
- `JsonData`
|
||||||
|
- `JsonHash`
|
||||||
|
- `SchemaVersion`
|
||||||
|
- `IsPublished`
|
||||||
|
- `PublishedAt`
|
||||||
|
- `PublishedBy`
|
||||||
|
- `Created`
|
||||||
|
- `CreatedBy`
|
||||||
|
|
||||||
|
Recommended constraints:
|
||||||
|
|
||||||
|
- Unique: `TemplateId + Version`
|
||||||
|
- Optional unique filtered index: `TemplateId` where `IsPublished = true`, if only one current published version should exist.
|
||||||
|
|
||||||
|
Template version content is immutable after publication. If the document changes, create a new `TemplateVersion`.
|
||||||
|
|
||||||
|
## JsonData Strategy
|
||||||
|
|
||||||
|
Keep `JsonData` as text in SQL Server, but do not treat it as an unstructured dumping ground.
|
||||||
|
The canonical document shapes and validation rules are defined in `Docs/Architecture/JsonDocumentContract.md`.
|
||||||
|
|
||||||
|
Database storage:
|
||||||
|
|
||||||
|
```text
|
||||||
|
JsonData nvarchar(max)
|
||||||
|
JsonHash nvarchar(64)
|
||||||
|
SchemaVersion nvarchar(32)
|
||||||
|
```
|
||||||
|
|
||||||
|
EF model storage can remain a string:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public string JsonData { get; private set; } = "{}";
|
||||||
|
public string JsonHash { get; private set; } = string.Empty;
|
||||||
|
public string SchemaVersion { get; set; } = "1.0";
|
||||||
|
```
|
||||||
|
|
||||||
|
API DTOs should expose real JSON instead of escaped JSON strings where practical:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public JsonElement JsonData { get; set; }
|
||||||
|
```
|
||||||
|
|
||||||
|
The service layer should canonicalize JSON, validate it, calculate the hash, and store it as a string.
|
||||||
|
|
||||||
|
Recommended approach:
|
||||||
|
|
||||||
|
1. Store the canonical template/deployment document as JSON.
|
||||||
|
2. Version every template document.
|
||||||
|
3. Validate JSON before saving.
|
||||||
|
4. Store a content hash beside the document.
|
||||||
|
5. Store schema version beside the document.
|
||||||
|
6. Project frequently queried values into normal columns or helper tables.
|
||||||
|
|
||||||
|
Do not store binary .NET serialization, base64 payloads, or provider-specific object graphs. The stored document should remain plain JSON so it can be returned by the API, diffed, hashed, migrated, and rendered to DSC v3 documents later.
|
||||||
|
|
||||||
|
This gives us flexibility for DSC v2, DSC v3, and cloud workloads without turning every possible parameter/resource into relational tables.
|
||||||
|
|
||||||
|
### Why Keep JSON?
|
||||||
|
|
||||||
|
The configuration document is naturally hierarchical:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Metadata
|
||||||
|
Parameters
|
||||||
|
Variables
|
||||||
|
Resources
|
||||||
|
```
|
||||||
|
|
||||||
|
Trying to fully normalize this would make the database rigid and painful for new services. SharePoint, Exchange, Teams, and Azure do not share the same resource shape.
|
||||||
|
|
||||||
|
### What Should Be Normalized?
|
||||||
|
|
||||||
|
Normalize stable catalog and workflow data:
|
||||||
|
|
||||||
|
- templates
|
||||||
|
- template versions
|
||||||
|
- environments
|
||||||
|
- domains
|
||||||
|
- services
|
||||||
|
- targets
|
||||||
|
- deployment groups
|
||||||
|
- deployments
|
||||||
|
- template selections
|
||||||
|
- parameter overrides
|
||||||
|
- jobs
|
||||||
|
- artifacts
|
||||||
|
|
||||||
|
Keep service-specific configuration inside `JsonData`.
|
||||||
|
|
||||||
|
### Optional Projection Tables
|
||||||
|
|
||||||
|
For GUI performance and validation, create projection tables derived from `JsonData`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
TemplateParameters
|
||||||
|
- TemplateVersionId
|
||||||
|
- Name
|
||||||
|
- Type
|
||||||
|
- Required
|
||||||
|
- Sensitive
|
||||||
|
- Sealed
|
||||||
|
- DescriptionJson
|
||||||
|
- AllowedValuesJson
|
||||||
|
```
|
||||||
|
|
||||||
|
The source of truth stays `TemplateVersion.JsonData`. Projection tables can be rebuilt when a template version changes.
|
||||||
|
|
||||||
|
## Deployments
|
||||||
|
|
||||||
|
### DeploymentGroup
|
||||||
|
|
||||||
|
A deployment group represents a deployable environment composition, for example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Contoso Test A Full Farm
|
||||||
|
- AD Deployment
|
||||||
|
- SQL Deployment
|
||||||
|
- SharePoint Deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `EnvironmentId`
|
||||||
|
- `Name`
|
||||||
|
- `Status`
|
||||||
|
- `DeploymentRuleId`
|
||||||
|
- `Created`
|
||||||
|
- `CreatedBy`
|
||||||
|
|
||||||
|
In the current model, `DeploymentGroupModel` maps to the `DeploymentBatches` table and still has a direct `TemplateId`. In the target model this direct `TemplateId` becomes legacy. The selected templates move to `DeploymentTemplateSelection`.
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
|
||||||
|
A deployment is one deployable workload slice inside a group.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- `AD`
|
||||||
|
- `SQL`
|
||||||
|
- `SharePoint`
|
||||||
|
- `Exchange`
|
||||||
|
- `Teams Policies`
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `DeploymentGroupId`
|
||||||
|
- `ServiceId`
|
||||||
|
- `Name`
|
||||||
|
- `SortOrder`
|
||||||
|
- `Status`
|
||||||
|
- `DeploymentDataJson`
|
||||||
|
- `MergedConfigurationDataJson`
|
||||||
|
- `ResolvedPreviewJson`
|
||||||
|
- `RendererTarget`, for example `PowerShellDscV2`, `DscV3Json`, `CloudApi`
|
||||||
|
|
||||||
|
In the current model, `DeploymentModel` maps to `DeploymentExecutions` and is keyed by `VirtualMachineId + DeploymentGroupId`. This is closer to a target execution than to a design-level deployment. During migration, keep it as compatibility data and introduce the new composition tables beside it.
|
||||||
|
|
||||||
|
### DeploymentTemplateSelection
|
||||||
|
|
||||||
|
A deployment selects multiple template versions.
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `DeploymentId`
|
||||||
|
- `TemplateVersionId`
|
||||||
|
- `TemplateRole`, for example `Domain`, `Environment`, `Service`, `Stage`, `TargetSet`, `Policy`
|
||||||
|
- `SortOrder`
|
||||||
|
- `Alias`
|
||||||
|
|
||||||
|
Example SharePoint deployment:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Domain/Central-Management
|
||||||
|
Environment/Test A
|
||||||
|
Service/SharePoint/Contoso
|
||||||
|
Stage/Install
|
||||||
|
Targets/SharePointNodes
|
||||||
|
```
|
||||||
|
|
||||||
|
### DeploymentParameterValue
|
||||||
|
|
||||||
|
User overrides should be stored separately from the generated full deployment document.
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `DeploymentId`
|
||||||
|
- `DeploymentTemplateSelectionId`
|
||||||
|
- `Name`
|
||||||
|
- `ValueJson`
|
||||||
|
- `IsSecretReference`
|
||||||
|
- `IsOverride`
|
||||||
|
|
||||||
|
### DeploymentTarget
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `DeploymentId`
|
||||||
|
- `TargetId`
|
||||||
|
- `RoleKey`, for example `DomainController`, `SqlServer`, `SharePointServer`, `TeamsPolicyScope`
|
||||||
|
- `SortOrder`
|
||||||
|
- `NodeDataJson`
|
||||||
|
|
||||||
|
## Queue And Worker
|
||||||
|
|
||||||
|
The existing `QueueJobModel`, `QueueJobStepModel`, and `QueueJobTargetModel` are a good foundation.
|
||||||
|
|
||||||
|
Recommended additions:
|
||||||
|
|
||||||
|
- `CorrelationId`
|
||||||
|
- `Priority`
|
||||||
|
- `ScheduledAt`
|
||||||
|
- `HeartbeatAt`
|
||||||
|
- `WorkerName`
|
||||||
|
- `RowVersion`
|
||||||
|
|
||||||
|
Recommended indexes:
|
||||||
|
|
||||||
|
- `(Status, LockedUntil, Created)`
|
||||||
|
- `(Type, Status)`
|
||||||
|
- `(CorrelationId)`
|
||||||
|
|
||||||
|
The worker should claim jobs atomically and update `LockedBy`, `LockedUntil`, and `HeartbeatAt`.
|
||||||
|
|
||||||
|
The existing queue tables can remain. The first improvements should be additive so the current Web/API flow keeps working.
|
||||||
|
|
||||||
|
## Artifacts
|
||||||
|
|
||||||
|
Generated output should be stored as artifacts.
|
||||||
|
|
||||||
|
Suggested fields:
|
||||||
|
|
||||||
|
- `Id`
|
||||||
|
- `DeploymentId`
|
||||||
|
- `QueueJobId`
|
||||||
|
- `ArtifactType`, for example `MergedJson`, `ResolvedPreviewJson`, `PowerShellDataFile`, `Mof`, `DscV3Json`, `Log`
|
||||||
|
- `Path`
|
||||||
|
- `ContentHash`
|
||||||
|
- `ContentJson`
|
||||||
|
- `ContentText`
|
||||||
|
- `Created`
|
||||||
|
|
||||||
|
## Worker Pipeline
|
||||||
|
|
||||||
|
Current DSC v2 flow:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Load template versions
|
||||||
|
Convert JSON to ordered PowerShell hashtables
|
||||||
|
Merge-DSCConfigurationData
|
||||||
|
Resolve-DSCConfigurationData
|
||||||
|
Render PowerShell DSC v2
|
||||||
|
Compile MOF
|
||||||
|
Store artifacts and status
|
||||||
|
```
|
||||||
|
|
||||||
|
Future DSC v3 flow:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Load template versions
|
||||||
|
Merge/resolve
|
||||||
|
Render DSC v3 JSON/YAML document
|
||||||
|
dsc config test/set
|
||||||
|
Store artifacts and status
|
||||||
|
```
|
||||||
|
|
||||||
|
The worker should therefore have a renderer abstraction:
|
||||||
|
|
||||||
|
- `PowerShellDscV2Renderer`
|
||||||
|
- `DscV3JsonRenderer`
|
||||||
|
- future cloud/action renderers
|
||||||
|
|
||||||
|
## Migration Strategy
|
||||||
|
|
||||||
|
1. Add `TemplateVersions` while keeping `Templates.JSONData`.
|
||||||
|
2. Create one initial `TemplateVersion` per existing `Template`.
|
||||||
|
3. Update API reads to expose the current published version.
|
||||||
|
4. Add deployment composition tables next to the existing deployment batch/execution model.
|
||||||
|
5. Migrate Web and Worker to the new model.
|
||||||
|
6. Remove legacy fields only after the new flow is stable.
|
||||||
|
|
||||||
|
## Current Model Mapping
|
||||||
|
|
||||||
|
The current model maps to the target model as follows:
|
||||||
|
|
||||||
|
```text
|
||||||
|
TemplateModel
|
||||||
|
-> Template
|
||||||
|
-> TemplateVersion
|
||||||
|
|
||||||
|
TemplateCategoryModel
|
||||||
|
-> TemplateCategory
|
||||||
|
|
||||||
|
ServiceModel
|
||||||
|
-> Service
|
||||||
|
|
||||||
|
EnvironmentModel
|
||||||
|
-> Environment
|
||||||
|
|
||||||
|
DomainModel
|
||||||
|
-> Domain
|
||||||
|
|
||||||
|
EnvironmentDomainsModel
|
||||||
|
-> EnvironmentDomain
|
||||||
|
|
||||||
|
VirtualMachineModel
|
||||||
|
-> Target where TargetType = VirtualMachine
|
||||||
|
|
||||||
|
DeploymentGroupModel / DeploymentBatches
|
||||||
|
-> DeploymentGroup
|
||||||
|
|
||||||
|
DeploymentModel / DeploymentExecutions
|
||||||
|
-> legacy deployment target/execution record
|
||||||
|
-> later replaced or complemented by Deployment + DeploymentTarget
|
||||||
|
|
||||||
|
QueueJobModel / DeploymentJobs
|
||||||
|
-> QueueJob
|
||||||
|
|
||||||
|
QueueJobStepModel / DeploymentJobSteps
|
||||||
|
-> QueueJobStep
|
||||||
|
|
||||||
|
QueueJobTargetModel / DeploymentJobTargets
|
||||||
|
-> QueueJobTarget
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compatibility Rules
|
||||||
|
|
||||||
|
During migration:
|
||||||
|
|
||||||
|
- Keep existing endpoints working.
|
||||||
|
- Keep `TemplateModel.JSONData` until API reads and writes use `TemplateVersion`.
|
||||||
|
- New code should prefer `TemplateVersion.JsonData`.
|
||||||
|
- Existing `DeploymentGroup.TemplateId` remains legacy and should be populated for old clients.
|
||||||
|
- New deployments should use `DeploymentTemplateSelection`.
|
||||||
|
- Do not remove old database columns until Web and Worker are migrated.
|
||||||
|
- Worker code should be written against the target composition model as soon as the new tables exist.
|
||||||
|
|
||||||
|
## Planned API Shape
|
||||||
|
|
||||||
|
Initial compatibility endpoint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /api/Template/{id}
|
||||||
|
```
|
||||||
|
|
||||||
|
should continue to return the existing DTO shape, but its `JsonData` should come from the current published `TemplateVersion` when available.
|
||||||
|
|
||||||
|
New endpoints:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /api/templates/{templateId}/versions
|
||||||
|
GET /api/templates/{templateId}/versions/{versionId}
|
||||||
|
POST /api/templates/{templateId}/versions
|
||||||
|
POST /api/templates/{templateId}/versions/{versionId}/publish
|
||||||
|
```
|
||||||
|
|
||||||
|
Deployment composition endpoints later:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /api/deployment-groups/{id}/composition
|
||||||
|
POST /api/deployment-groups/{id}/deployments
|
||||||
|
POST /api/deployments/{id}/template-selections
|
||||||
|
POST /api/deployments/{id}/targets
|
||||||
|
POST /api/deployments/{id}/parameter-values
|
||||||
|
```
|
||||||
|
|
||||||
|
## First Database Change
|
||||||
|
|
||||||
|
The first concrete database change should be additive:
|
||||||
|
|
||||||
|
```text
|
||||||
|
TemplateVersions
|
||||||
|
- Id
|
||||||
|
- TemplateId
|
||||||
|
- Version
|
||||||
|
- JsonData
|
||||||
|
- JsonHash
|
||||||
|
- SchemaVersion
|
||||||
|
- IsPublished
|
||||||
|
- PublishedAt
|
||||||
|
- PublishedBy
|
||||||
|
- Modified
|
||||||
|
- ModifiedBy
|
||||||
|
- Created
|
||||||
|
- CreatedBy
|
||||||
|
```
|
||||||
|
|
||||||
|
`TemplateVersions.TemplateId` references `Templates.Id`.
|
||||||
|
|
||||||
|
For existing data, create one version per current template:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Version = Templates.Version
|
||||||
|
JsonData = Templates.JSONData
|
||||||
|
IsPublished = true
|
||||||
|
SchemaVersion = '1.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
After this step, new code can begin reading from `TemplateVersions` while old code can still read `Templates.JSONData`.
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# JSON Document Contract
|
||||||
|
|
||||||
|
The API stores configuration documents as JSON strings, but treats them as typed contracts.
|
||||||
|
Workers can convert those documents to ordered PowerShell hashtables for DSC v2, while future DSC v3 renderers can consume JSON directly.
|
||||||
|
|
||||||
|
## Template Document
|
||||||
|
|
||||||
|
Template documents are versioned through `TemplateVersionModel.JsonData`.
|
||||||
|
Every stored template version must be a JSON object with this shape:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"templateType": "Service",
|
||||||
|
"parameters": {},
|
||||||
|
"variables": {},
|
||||||
|
"resources": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
|
||||||
|
- `schemaVersion`: Contract version. Currently supported: `1.0`.
|
||||||
|
- `templateType`: One of `Environment`, `Domain`, `Landscape`, `Service`, `Stage`, or `Deployment`.
|
||||||
|
- `parameters`: Object with user-facing inputs and metadata.
|
||||||
|
- `variables`: Object with derived values and expressions.
|
||||||
|
- `resources`: Object with configuration blocks that can be merged and rendered.
|
||||||
|
|
||||||
|
Template documents are normalized and validated before a `TemplateVersion` is persisted.
|
||||||
|
The API calculates `JsonHash` from the normalized document and stores the effective `SchemaVersion`.
|
||||||
|
|
||||||
|
## Deployment Override Document
|
||||||
|
|
||||||
|
Deployment override documents are stored on deployment executions and queue jobs.
|
||||||
|
They are currently intentionally permissive so legacy requests like this remain valid:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"role": "WebFrontEnd"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The canonical shape for new deployments should be:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"parameters": {},
|
||||||
|
"variables": {},
|
||||||
|
"resources": {},
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Step 4 will make this stricter when deployments can reference multiple immutable template versions.
|
||||||
|
|
||||||
|
## Metadata Documents
|
||||||
|
|
||||||
|
Fields such as `MetadataJson` and `RuleSnapshotJson` are metadata documents.
|
||||||
|
They must be valid JSON objects when explicitly validated, but they do not need the full template contract.
|
||||||
|
|
||||||
|
## Validation Rules
|
||||||
|
|
||||||
|
- The root value must be a JSON object.
|
||||||
|
- Template documents must contain the required fields listed above.
|
||||||
|
- Unsupported `schemaVersion` values are rejected.
|
||||||
|
- Unsupported `templateType` values are rejected.
|
||||||
|
- If a client submits `SchemaVersion` for a template version, it must match the document's `schemaVersion`.
|
||||||
|
|
||||||
|
## Queryable Fields
|
||||||
|
|
||||||
|
For now, the API projects these fields into columns:
|
||||||
|
|
||||||
|
- `TemplateVersion.SchemaVersion`
|
||||||
|
- `TemplateVersion.JsonHash`
|
||||||
|
- `TemplateVersion.Version`
|
||||||
|
- `TemplateVersion.IsPublished`
|
||||||
|
|
||||||
|
Additional document fields should only become relational columns when the GUI or worker needs filtering, sorting, or joins over that field.
|
||||||
@@ -6,3 +6,4 @@
|
|||||||
public Guid DomainId { get; set; }
|
public Guid DomainId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,3 +27,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto
|
|||||||
public string CreatedBy { get; set; } = "System";
|
public string CreatedBy { get; set; } = "System";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
public class AddDeploymentDto
|
public class AddDeploymentDto
|
||||||
{
|
{
|
||||||
public Guid DeploymentGroupId { get; set; }
|
public Guid DeploymentGroupId { get; set; }
|
||||||
public Guid VirtualMachineId { get; set; }
|
public Guid TargetId { get; set; }
|
||||||
|
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public string JsonData { get; set; }
|
public string JsonData { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add
|
||||||
{
|
{
|
||||||
public class AddDeploymentRequestDto
|
public class AddDeploymentRequestDto
|
||||||
{
|
{
|
||||||
public Guid DeploymentGroupId { get; set; }
|
public Guid DeploymentGroupId { get; set; }
|
||||||
public ICollection<Guid> VirtualMachineIds { get; set; } = new List<Guid>();
|
public ICollection<Guid> TargetIds { get; set; } = new List<Guid>();
|
||||||
public string JsonData { get; set; } = "{}";
|
public string JsonData { get; set; } = "{}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add
|
||||||
{
|
{
|
||||||
public class QueueJobStepApprovalDto
|
public class QueueJobStepApprovalDto
|
||||||
{
|
{
|
||||||
@@ -6,3 +6,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add
|
|||||||
public string? ApprovedBy { get; set; }
|
public string? ApprovedBy { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit
|
|||||||
public string jsonData { get; set; }
|
public string jsonData { get; set; }
|
||||||
|
|
||||||
[Column(Order = 1)]
|
[Column(Order = 1)]
|
||||||
public Guid VirtualMachineId { get; set; }
|
public Guid TargetId { get; set; }
|
||||||
[Column(Order = 1)]
|
[Column(Order = 1)]
|
||||||
public Guid DeploymentGroupId { get; set; }
|
public Guid DeploymentGroupId { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
||||||
{
|
{
|
||||||
public class GetDeploymentDetailsDto : BaseDetailsDto
|
public class GetDeploymentDetailsDto : BaseDetailsDto
|
||||||
{
|
{
|
||||||
public Guid VirtualMachineId { get; set; }
|
public Guid TargetId { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public string JSONData { get; set; }
|
public string JSONData { get; set; }
|
||||||
|
|
||||||
public GetVirtualMachineDetailsDto VirtualMachine { get; set; }
|
public GetTargetDetailsDto Target { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
|||||||
public class GetDeploymentDto : BaseDto
|
public class GetDeploymentDto : BaseDto
|
||||||
{
|
{
|
||||||
public Guid DeploymentGroupId { get; set; }
|
public Guid DeploymentGroupId { get; set; }
|
||||||
public Guid VirtualMachineId { get; set; }
|
public Guid TargetId { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public string JSONData { get; set; }
|
public string JSONData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
||||||
{
|
{
|
||||||
public class GetQueueJobDetailsDto : BaseDetailsDto
|
public class GetQueueJobDetailsDto : BaseDetailsDto
|
||||||
{
|
{
|
||||||
@@ -16,3 +16,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
|||||||
public ICollection<GetQueueJobStepDto> Steps { get; set; } = new List<GetQueueJobStepDto>();
|
public ICollection<GetQueueJobStepDto> Steps { get; set; } = new List<GetQueueJobStepDto>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
||||||
{
|
{
|
||||||
public class GetQueueJobDto : BaseDto
|
public class GetQueueJobDto : BaseDto
|
||||||
{
|
{
|
||||||
@@ -14,3 +14,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
|||||||
public int FailedTargetCount { get; set; }
|
public int FailedTargetCount { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
||||||
{
|
{
|
||||||
public class GetQueueJobStepDto : BaseDto
|
public class GetQueueJobStepDto : BaseDto
|
||||||
{
|
{
|
||||||
@@ -13,3 +13,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
|||||||
public string? ApprovalComment { get; set; }
|
public string? ApprovalComment { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
||||||
{
|
{
|
||||||
public class GetQueueJobTargetDto : BaseDto
|
public class GetQueueJobTargetDto : BaseDto
|
||||||
{
|
{
|
||||||
public Guid VirtualMachineId { get; set; }
|
public Guid TargetId { get; set; }
|
||||||
public Guid DeploymentGroupId { get; set; }
|
public Guid DeploymentGroupId { get; set; }
|
||||||
public Guid TemplateId { get; set; }
|
public Guid TemplateId { get; set; }
|
||||||
public string Status { get; set; } = string.Empty;
|
public string Status { get; set; } = string.Empty;
|
||||||
@@ -10,3 +10,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get
|
|||||||
public string? ErrorMessage { get; set; }
|
public string? ErrorMessage { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Add
|
||||||
|
{
|
||||||
|
public class AddDeploymentBatchDto
|
||||||
|
{
|
||||||
|
[Column(Order = 1)]
|
||||||
|
public Guid TemplateId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 2)]
|
||||||
|
public Guid? DeploymentRuleId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 3)]
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Column(Order = 4)]
|
||||||
|
public ICollection<Guid>? TargetIds { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Edit
|
||||||
|
{
|
||||||
|
public class EditDeploymentBatchDto
|
||||||
|
{
|
||||||
|
[Column(Order = 1)]
|
||||||
|
public Guid TemplateId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 2)]
|
||||||
|
public Guid? DeploymentRuleId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 3)]
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentBatchDetailsDto : BaseDto
|
||||||
|
{
|
||||||
|
public Guid? DeploymentRuleId { get; set; }
|
||||||
|
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public GetTemplateDetailsDto Template { get; set; } = null!;
|
||||||
|
|
||||||
|
public ICollection<GetDeploymentDetailsDto> Deployments { get; set; } = new List<GetDeploymentDetailsDto>();
|
||||||
|
public ICollection<GetDeploymentTemplateSelectionDto> TemplateSelections { get; set; } = new List<GetDeploymentTemplateSelectionDto>();
|
||||||
|
public ICollection<GetDeploymentParameterValueDto> ParameterValues { get; set; } = new List<GetDeploymentParameterValueDto>();
|
||||||
|
public ICollection<GetDeploymentTargetAssignmentDto> TargetAssignments { get; set; } = new List<GetDeploymentTargetAssignmentDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentBatchDto : BaseDetailsDto
|
||||||
|
{
|
||||||
|
public Guid TemplateId { get; set; }
|
||||||
|
|
||||||
|
public Guid? DeploymentRuleId { get; set; }
|
||||||
|
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Add
|
||||||
|
{
|
||||||
|
public class AddDeploymentParameterValueDto
|
||||||
|
{
|
||||||
|
public Guid? DeploymentTemplateSelectionId { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string ValueJson { get; set; } = "{}";
|
||||||
|
public bool IsSecretReference { get; set; }
|
||||||
|
public bool IsOverride { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Add
|
||||||
|
{
|
||||||
|
public class AddDeploymentTargetAssignmentDto
|
||||||
|
{
|
||||||
|
public Guid TargetId { get; set; }
|
||||||
|
public string RoleKey { get; set; } = "Node";
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
public string NodeDataJson { get; set; } = "{}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Add
|
||||||
|
{
|
||||||
|
public class AddDeploymentTemplateSelectionDto
|
||||||
|
{
|
||||||
|
public Guid TemplateVersionId { get; set; }
|
||||||
|
public string TemplateRole { get; set; } = "Service";
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
public string? Alias { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentCompositionDto
|
||||||
|
{
|
||||||
|
public Guid DeploymentBatchId { get; set; }
|
||||||
|
public ICollection<GetDeploymentTemplateSelectionDto> TemplateSelections { get; set; } = new List<GetDeploymentTemplateSelectionDto>();
|
||||||
|
public ICollection<GetDeploymentParameterValueDto> ParameterValues { get; set; } = new List<GetDeploymentParameterValueDto>();
|
||||||
|
public ICollection<GetDeploymentTargetAssignmentDto> TargetAssignments { get; set; } = new List<GetDeploymentTargetAssignmentDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentParameterValueDto : BaseDto
|
||||||
|
{
|
||||||
|
public Guid DeploymentGroupId { get; set; }
|
||||||
|
public Guid? DeploymentTemplateSelectionId { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string ValueJson { get; set; } = "{}";
|
||||||
|
public bool IsSecretReference { get; set; }
|
||||||
|
public bool IsOverride { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentTargetAssignmentDto : BaseDto
|
||||||
|
{
|
||||||
|
public Guid DeploymentGroupId { get; set; }
|
||||||
|
public Guid TargetId { get; set; }
|
||||||
|
public string RoleKey { get; set; } = string.Empty;
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
public string NodeDataJson { get; set; } = "{}";
|
||||||
|
public GetTargetDto? Target { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Get;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentTemplateSelectionDto : BaseDto
|
||||||
|
{
|
||||||
|
public Guid DeploymentGroupId { get; set; }
|
||||||
|
public Guid TemplateVersionId { get; set; }
|
||||||
|
public string TemplateRole { get; set; } = string.Empty;
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
public string? Alias { get; set; }
|
||||||
|
public GetTemplateVersionDto? TemplateVersion { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Add
|
|
||||||
{
|
|
||||||
public class AddDeploymentGroupDto
|
|
||||||
{
|
|
||||||
[Column(Order = 1)]
|
|
||||||
public Guid TemplateId { get; set; }
|
|
||||||
[Column(Order = 2)]
|
|
||||||
public string Status { get; set; }
|
|
||||||
[Column(Order = 3)]
|
|
||||||
public ICollection<Guid>? VirtualMachineIds { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Edit
|
|
||||||
{
|
|
||||||
public class EditDeploymentGroupDto
|
|
||||||
{
|
|
||||||
[Column(Order = 1)]
|
|
||||||
public Guid TemplateId { get; set; }
|
|
||||||
[Column(Order = 2)]
|
|
||||||
public string Status { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Get
|
|
||||||
{
|
|
||||||
public class GetDeploymentGroupDetailsDto : BaseDto
|
|
||||||
{
|
|
||||||
public string Status { get; set; }
|
|
||||||
|
|
||||||
public GetTemplateDetailsDto Template { get; set; }
|
|
||||||
|
|
||||||
public ICollection <GetDeploymentDetailsDto> Deployments { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Get
|
|
||||||
{
|
|
||||||
public class GetDeploymentGroupDto
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
public string Status { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Add
|
||||||
|
{
|
||||||
|
public class AddDeploymentRuleDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public ICollection<AddDeploymentRuleStepDto> Steps { get; set; } = new List<AddDeploymentRuleStepDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Add
|
||||||
|
{
|
||||||
|
public class AddDeploymentRuleStepDto
|
||||||
|
{
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string StepType { get; set; }
|
||||||
|
public bool RequiresApproval { get; set; }
|
||||||
|
public string? MetadataJson { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentRuleDto : BaseDetailsDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
public ICollection<GetDeploymentRuleStepDto> Steps { get; set; } = new List<GetDeploymentRuleStepDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Get
|
||||||
|
{
|
||||||
|
public class GetDeploymentRuleStepDto : BaseDetailsDto
|
||||||
|
{
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string StepType { get; set; }
|
||||||
|
public bool RequiresApproval { get; set; }
|
||||||
|
public string? MetadataJson { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -12,3 +12,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Add
|
|||||||
public string NetBIOS { get; set; }
|
public string NetBIOS { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Edit
|
|||||||
public string NetBIOS { get; set; }
|
public string NetBIOS { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
|||||||
public ICollection<GetDomainEnvironmentDetailsDto> EnvironmentDomains { get; set; }
|
public ICollection<GetDomainEnvironmentDetailsDto> EnvironmentDomains { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -1,10 +1,10 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
||||||
{
|
{
|
||||||
public class GetDomainVirtualMachineDetailsDto : BaseDetailsDto
|
public class GetDomainTargetDetailsDto : BaseDetailsDto
|
||||||
{
|
{
|
||||||
|
|
||||||
[Column(Order = 1)]
|
[Column(Order = 1)]
|
||||||
@@ -15,6 +15,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get
|
|||||||
public string NetBIOS { get; set; }
|
public string NetBIOS { get; set; }
|
||||||
|
|
||||||
[Column(Order = 4)]
|
[Column(Order = 4)]
|
||||||
public ICollection<GetVirtualMachineDto> VirtualMachines { get; set; }
|
public ICollection<GetTargetDto> Targets { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,18 +8,22 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Add
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Column(Order = 2)]
|
[Column(Order = 2)]
|
||||||
public string EnvironmentType { get; set; } = "OnPrem";
|
public string EnvironmentType { get; set; } = "Test";
|
||||||
|
|
||||||
[Column(Order = 3)]
|
[Column(Order = 3)]
|
||||||
public string? ProviderType { get; set; }
|
public string HostingType { get; set; } = "OnPrem";
|
||||||
|
|
||||||
[Column(Order = 4)]
|
[Column(Order = 4)]
|
||||||
public string? TenantId { get; set; }
|
public string? ProviderType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 5)]
|
[Column(Order = 5)]
|
||||||
public string? SubscriptionId { get; set; }
|
public string? TenantId { get; set; }
|
||||||
|
|
||||||
[Column(Order = 6)]
|
[Column(Order = 6)]
|
||||||
|
public string? SubscriptionId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 7)]
|
||||||
public string? MetadataJson { get; set; }
|
public string? MetadataJson { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,22 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Edit
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Column(Order = 2)]
|
[Column(Order = 2)]
|
||||||
public string EnvironmentType { get; set; } = "OnPrem";
|
public string EnvironmentType { get; set; } = "Test";
|
||||||
|
|
||||||
[Column(Order = 3)]
|
[Column(Order = 3)]
|
||||||
public string? ProviderType { get; set; }
|
public string HostingType { get; set; } = "OnPrem";
|
||||||
|
|
||||||
[Column(Order = 4)]
|
[Column(Order = 4)]
|
||||||
public string? TenantId { get; set; }
|
public string? ProviderType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 5)]
|
[Column(Order = 5)]
|
||||||
public string? SubscriptionId { get; set; }
|
public string? TenantId { get; set; }
|
||||||
|
|
||||||
[Column(Order = 6)]
|
[Column(Order = 6)]
|
||||||
|
public string? SubscriptionId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 7)]
|
||||||
public string? MetadataJson { get; set; }
|
public string? MetadataJson { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,19 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
|||||||
public string EnvironmentType { get; set; }
|
public string EnvironmentType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 3)]
|
[Column(Order = 3)]
|
||||||
public string? ProviderType { get; set; }
|
public string HostingType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 4)]
|
[Column(Order = 4)]
|
||||||
public string? TenantId { get; set; }
|
public string? ProviderType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 5)]
|
[Column(Order = 5)]
|
||||||
public string? SubscriptionId { get; set; }
|
public string? TenantId { get; set; }
|
||||||
|
|
||||||
[Column(Order = 6)]
|
[Column(Order = 6)]
|
||||||
|
public string? SubscriptionId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 7)]
|
||||||
public string? MetadataJson { get; set; }
|
public string? MetadataJson { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@@ -32,3 +32,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
||||||
@@ -9,6 +9,24 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Column(Order = 2)]
|
[Column(Order = 2)]
|
||||||
|
public string EnvironmentType { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 3)]
|
||||||
|
public string HostingType { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 4)]
|
||||||
|
public string? ProviderType { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 5)]
|
||||||
|
public string? TenantId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 6)]
|
||||||
|
public string? SubscriptionId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 7)]
|
||||||
|
public string? MetadataJson { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 8)]
|
||||||
public ICollection<GetEnvironmentDomainDetailsDto> EnvironmentDomains { get; set; }
|
public ICollection<GetEnvironmentDomainDetailsDto> EnvironmentDomains { get; set; }
|
||||||
|
|
||||||
public static GetEnvironmentDomainDto FromModel(EnvironmentModel environment)
|
public static GetEnvironmentDomainDto FromModel(EnvironmentModel environment)
|
||||||
@@ -17,6 +35,12 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
|||||||
{
|
{
|
||||||
Id = environment.Id,
|
Id = environment.Id,
|
||||||
Name = environment.Name,
|
Name = environment.Name,
|
||||||
|
EnvironmentType = environment.EnvironmentType,
|
||||||
|
HostingType = environment.HostingType,
|
||||||
|
ProviderType = environment.ProviderType,
|
||||||
|
TenantId = environment.TenantId,
|
||||||
|
SubscriptionId = environment.SubscriptionId,
|
||||||
|
MetadataJson = environment.MetadataJson,
|
||||||
Created = environment.Created,
|
Created = environment.Created,
|
||||||
CreatedBy = environment.CreatedBy,
|
CreatedBy = environment.CreatedBy,
|
||||||
Modified = environment.Modified,
|
Modified = environment.Modified,
|
||||||
@@ -29,3 +53,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,16 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get
|
|||||||
public string EnvironmentType { get; set; }
|
public string EnvironmentType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 3)]
|
[Column(Order = 3)]
|
||||||
public string? ProviderType { get; set; }
|
public string HostingType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 4)]
|
[Column(Order = 4)]
|
||||||
public string? TenantId { get; set; }
|
public string? ProviderType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 5)]
|
[Column(Order = 5)]
|
||||||
|
public string? TenantId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 6)]
|
||||||
public string? SubscriptionId { get; set; }
|
public string? SubscriptionId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Add
|
|
||||||
{
|
|
||||||
public class AddRunbookDto
|
|
||||||
{
|
|
||||||
[Column(Order = 1)]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[Column(Order = 2)]
|
|
||||||
public string Description { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Get
|
|
||||||
{
|
|
||||||
public class GetRunbookDetailsDto : BaseDetailsDto
|
|
||||||
{
|
|
||||||
[Column(Order = 1)]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[Column(Order = 2)]
|
|
||||||
public string Decription { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Get
|
|
||||||
{
|
|
||||||
public class GetRunbookDto : BaseDto
|
|
||||||
{
|
|
||||||
[Column(Order = 1)]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[Column(Order = 2)]
|
|
||||||
public string Decription { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Add
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Add
|
||||||
{
|
{
|
||||||
@@ -17,3 +17,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Add
|
|||||||
public string? IconKey { get; set; }
|
public string? IconKey { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit
|
||||||
{
|
{
|
||||||
@@ -17,3 +17,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit
|
|||||||
public string? IconKey { get; set; }
|
public string? IconKey { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Get
|
|||||||
public string? IconKey { get; set; }
|
public string? IconKey { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.Get
|
|||||||
public string? IconKey { get; set; }
|
public string? IconKey { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.RoleDefinition
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.RoleDefinition
|
||||||
{
|
{
|
||||||
public class AddServiceRoleDefinitionDto
|
public class AddServiceRoleDefinitionDto
|
||||||
{
|
{
|
||||||
@@ -7,3 +7,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.RoleDefinition
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.RoleDefinition
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.RoleDefinition
|
||||||
{
|
{
|
||||||
public class EditServiceRoleDefinitionDto
|
public class EditServiceRoleDefinitionDto
|
||||||
{
|
{
|
||||||
@@ -7,3 +7,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Service.RoleDefinition
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Target.Add
|
||||||
|
{
|
||||||
|
public class AddTargetDto
|
||||||
|
{
|
||||||
|
public Guid? DomainID { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string TargetType { get; set; } = "VirtualMachine";
|
||||||
|
public string ProviderType { get; set; } = "OnPrem";
|
||||||
|
public string? ExternalId { get; set; }
|
||||||
|
public string? MetadataJson { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Target.Edit
|
||||||
|
{
|
||||||
|
public class EditTargetDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string TargetType { get; set; } = "VirtualMachine";
|
||||||
|
public string ProviderType { get; set; } = "OnPrem";
|
||||||
|
public string? ExternalId { get; set; }
|
||||||
|
public string? MetadataJson { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+10
-3
@@ -2,9 +2,9 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Target.Get
|
||||||
{
|
{
|
||||||
public class GetVirtualMachineDetailsDto : BaseDetailsDto
|
public class GetTargetDetailsDto : BaseDetailsDto
|
||||||
{
|
{
|
||||||
|
|
||||||
[Column(Order = 1)]
|
[Column(Order = 1)]
|
||||||
@@ -14,11 +14,18 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Column(Order = 3)]
|
[Column(Order = 3)]
|
||||||
public string? ExternalId { get; set; }
|
public string TargetType { get; set; }
|
||||||
|
|
||||||
[Column(Order = 4)]
|
[Column(Order = 4)]
|
||||||
|
public string ProviderType { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 5)]
|
||||||
|
public string? ExternalId { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 6)]
|
||||||
public string? MetadataJson { get; set; }
|
public string? MetadataJson { get; set; }
|
||||||
|
|
||||||
public GetDomainDto? Domain { get; set; }
|
public GetDomainDto? Domain { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Target.Get
|
||||||
{
|
{
|
||||||
public class GetVirtualMachineDto : BaseDto
|
public class GetTargetDto : BaseDto
|
||||||
{
|
{
|
||||||
[Column(Order = 1)]
|
[Column(Order = 1)]
|
||||||
public Guid? DomainID { get; set; }
|
public Guid? DomainID { get; set; }
|
||||||
@@ -11,7 +11,14 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Column(Order = 3)]
|
[Column(Order = 3)]
|
||||||
|
public string TargetType { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 4)]
|
||||||
|
public string ProviderType { get; set; }
|
||||||
|
|
||||||
|
[Column(Order = 5)]
|
||||||
public string? ExternalId { get; set; }
|
public string? ExternalId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Template.Add
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Template.Add
|
||||||
{
|
{
|
||||||
@@ -20,3 +20,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Template.Add
|
|||||||
public string JSONData { get; set; }
|
public string JSONData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit
|
||||||
{
|
{
|
||||||
@@ -20,3 +20,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit
|
|||||||
public string JSONData { get; set; }
|
public string JSONData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,3 +10,4 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,4 @@
|
|||||||
public string JSONData { get; set; }
|
public string JSONData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add
|
||||||
{
|
{
|
||||||
public class AddTemplateCategoryDto
|
public class AddTemplateCategoryDto
|
||||||
{
|
{
|
||||||
@@ -9,3 +9,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add
|
|||||||
public string? Color { get; set; }
|
public string? Color { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit
|
||||||
{
|
{
|
||||||
public class EditTemplateCategoryDto
|
public class EditTemplateCategoryDto
|
||||||
{
|
{
|
||||||
@@ -9,3 +9,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit
|
|||||||
public string? Color { get; set; }
|
public string? Color { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get
|
||||||
{
|
{
|
||||||
public class GetTemplateCategoryDetailsDto : BaseDetailsDto
|
public class GetTemplateCategoryDetailsDto : BaseDetailsDto
|
||||||
{
|
{
|
||||||
@@ -9,3 +9,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get
|
|||||||
public string? Color { get; set; }
|
public string? Color { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get
|
||||||
{
|
{
|
||||||
public class GetTemplateCategoryDto : BaseDto
|
public class GetTemplateCategoryDto : BaseDto
|
||||||
{
|
{
|
||||||
@@ -9,3 +9,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get
|
|||||||
public string? Color { get; set; }
|
public string? Color { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Add
|
||||||
|
{
|
||||||
|
public class AddTemplateVersionDto
|
||||||
|
{
|
||||||
|
public string Version { get; set; } = "1.0.0";
|
||||||
|
public string JsonData { get; set; } = "{}";
|
||||||
|
public string SchemaVersion { get; set; } = "1.0";
|
||||||
|
public bool Publish { get; set; }
|
||||||
|
public string? PublishedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Get
|
||||||
|
{
|
||||||
|
public class GetTemplateVersionDto : BaseDetailsDto
|
||||||
|
{
|
||||||
|
public Guid TemplateId { get; set; }
|
||||||
|
public string Version { get; set; } = string.Empty;
|
||||||
|
public string JsonData { get; set; } = "{}";
|
||||||
|
public string JsonHash { get; set; } = string.Empty;
|
||||||
|
public string SchemaVersion { get; set; } = "1.0";
|
||||||
|
public bool IsPublished { get; set; }
|
||||||
|
public DateTime? PublishedAt { get; set; }
|
||||||
|
public string? PublishedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Add
|
|
||||||
{
|
|
||||||
public class AddVirtualMachineDto
|
|
||||||
{
|
|
||||||
public Guid? DomainID { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string? ExternalId { get; set; }
|
|
||||||
public string? MetadataJson { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Edit
|
|
||||||
{
|
|
||||||
public class EditVirtualMachineDto
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string? ExternalId { get; set; }
|
|
||||||
public string? MetadataJson { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Events.Interfaces;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Helper;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Events
|
|
||||||
{
|
|
||||||
public class AbstractEventHandler : IEventHandlerInterface
|
|
||||||
{
|
|
||||||
private readonly DataContext _context;
|
|
||||||
|
|
||||||
public AbstractEventHandler(DataContext context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
new APIHelper();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICollection<EventModel> GetEvents(string Class, string Method)
|
|
||||||
{
|
|
||||||
return _context.Events
|
|
||||||
.Where(e => e.Class == Class && e.Method == Method)
|
|
||||||
.Include(r => r.Runbook)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void FireEvent(string Class, string Method, Guid parameters)
|
|
||||||
{
|
|
||||||
var events = GetEvents(Class, Method);
|
|
||||||
|
|
||||||
foreach (EventModel @event in events){
|
|
||||||
|
|
||||||
APIHelper.SetUrl(@event.RunbookId, @event.RestEndpointOperation);
|
|
||||||
APIHelper.SetRequestBody(parameters);
|
|
||||||
|
|
||||||
var response = await APIHelper.ApiClient.PostAsync(APIHelper.GetUrl(), APIHelper.SetRequestHeaders("application/json;odata=verbose;charset=utf-8"));
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new HttpRequestException(response.ReasonPhrase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Events.Interfaces
|
|
||||||
{
|
|
||||||
public interface IEventHandlerInterface
|
|
||||||
{
|
|
||||||
ICollection<EventModel> GetEvents(string Class, string Method);
|
|
||||||
void FireEvent(string Class, string Method, Guid parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,3 +11,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Handlers
|
|
||||||
{
|
|
||||||
public class DomainEditedHandler
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Helper
|
|
||||||
{
|
|
||||||
public class APIHelper
|
|
||||||
{
|
|
||||||
public static HttpClient ApiClient { get; set; } = new HttpClient();
|
|
||||||
|
|
||||||
public static String _Url;
|
|
||||||
public static String _Body;
|
|
||||||
|
|
||||||
public APIHelper()
|
|
||||||
{
|
|
||||||
ApiClient = new HttpClient();
|
|
||||||
ApiClient.BaseAddress = new Uri("http://rz1vcmsma001.cm.p01s01.ccis.svc.intranetbw.de:8080");
|
|
||||||
ApiClient.DefaultRequestHeaders.Accept.Clear();
|
|
||||||
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
|
|
||||||
|
|
||||||
ApiClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(
|
|
||||||
Encoding.UTF8.GetBytes("CCIS-P01S01-CM\\ASA_Administrator:UQp7AurAkH4M")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetUrl(Guid RunbookId, String RestEndpointMethod)
|
|
||||||
{
|
|
||||||
_Url = string.Format("/00000000-0000-0000-0000-000000000000/Runbooks(guid'{0}')/{1}", RunbookId, RestEndpointMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetUrl()
|
|
||||||
{
|
|
||||||
return _Url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StringContent SetRequestHeaders(String ContentType)
|
|
||||||
{
|
|
||||||
MediaTypeHeaderValue JsonMediaType = null;
|
|
||||||
MediaTypeHeaderValue.TryParse(ContentType, out JsonMediaType);
|
|
||||||
|
|
||||||
return new StringContent(_Body, Encoding.UTF8, JsonMediaType); ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetRequestBody(Guid parameters)
|
|
||||||
{
|
|
||||||
var obj = new
|
|
||||||
{
|
|
||||||
parameters = new[]
|
|
||||||
{
|
|
||||||
new
|
|
||||||
{
|
|
||||||
__metadata = new
|
|
||||||
{
|
|
||||||
type = "Orchestrator.ResourceModel.NameValuePair"
|
|
||||||
},
|
|
||||||
Name = "deploymentId",
|
|
||||||
Value = parameters
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_Body = JsonSerializer.Serialize(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String GetRequestBody()
|
|
||||||
{
|
|
||||||
return _Body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,23 +3,26 @@ using Microsoft.SelfService.Portal.Core.API.Models;
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Dto;
|
using Microsoft.SelfService.Portal.Core.API.Dto;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Get;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Runbook.Add;
|
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.VirtualMachine.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Target.Edit;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Edit;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Edit;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentGroup.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Edit;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Add;
|
||||||
|
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Get;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Get;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add;
|
||||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit;
|
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit;
|
||||||
@@ -40,8 +43,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper
|
|||||||
CreateMap<GetDomainDetailsDto, DomainModel>();
|
CreateMap<GetDomainDetailsDto, DomainModel>();
|
||||||
CreateMap<DomainModel, GetDomainEnvironmentDto>();
|
CreateMap<DomainModel, GetDomainEnvironmentDto>();
|
||||||
CreateMap<GetDomainEnvironmentDto, DomainModel>();
|
CreateMap<GetDomainEnvironmentDto, DomainModel>();
|
||||||
CreateMap<DomainModel, GetDomainVirtualMachineDetailsDto>();
|
CreateMap<DomainModel, GetDomainTargetDetailsDto>();
|
||||||
CreateMap<GetDomainVirtualMachineDetailsDto, DomainModel>();
|
CreateMap<GetDomainTargetDetailsDto, DomainModel>();
|
||||||
CreateMap<DomainModel, AddDomainDto>();
|
CreateMap<DomainModel, AddDomainDto>();
|
||||||
CreateMap<AddDomainDto, DomainModel>();
|
CreateMap<AddDomainDto, DomainModel>();
|
||||||
CreateMap<DomainModel, EditDomainDto>();
|
CreateMap<DomainModel, EditDomainDto>();
|
||||||
@@ -67,41 +70,50 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper
|
|||||||
CreateMap<EnvironmentDomainsModel, AddEnvironmentDomainDto>();
|
CreateMap<EnvironmentDomainsModel, AddEnvironmentDomainDto>();
|
||||||
CreateMap<AddEnvironmentDomainDto, EnvironmentDomainsModel>();
|
CreateMap<AddEnvironmentDomainDto, EnvironmentDomainsModel>();
|
||||||
|
|
||||||
/** Virtual Machine Model **/
|
/** Target Model **/
|
||||||
CreateMap<VirtualMachineModel, GetVirtualMachineDto>();
|
CreateMap<TargetModel, GetTargetDto>();
|
||||||
CreateMap<GetVirtualMachineDto, VirtualMachineModel>();
|
CreateMap<GetTargetDto, TargetModel>();
|
||||||
CreateMap<VirtualMachineModel, GetVirtualMachineDetailsDto>();
|
CreateMap<TargetModel, GetTargetDetailsDto>();
|
||||||
CreateMap<GetVirtualMachineDetailsDto, VirtualMachineModel>();
|
CreateMap<GetTargetDetailsDto, TargetModel>();
|
||||||
CreateMap<VirtualMachineModel, AddVirtualMachineDto>();
|
CreateMap<TargetModel, AddTargetDto>();
|
||||||
CreateMap<AddVirtualMachineDto, VirtualMachineModel>();
|
CreateMap<AddTargetDto, TargetModel>();
|
||||||
CreateMap<VirtualMachineModel, EditVirtualMachineDto>();
|
CreateMap<TargetModel, EditTargetDto>();
|
||||||
CreateMap<EditVirtualMachineDto, VirtualMachineModel>();
|
CreateMap<EditTargetDto, TargetModel>();
|
||||||
|
|
||||||
/** Runbook Model **/
|
|
||||||
CreateMap<RunbookModel, GetRunbookDto>();
|
|
||||||
CreateMap<GetRunbookDto, RunbookModel>();
|
|
||||||
CreateMap<RunbookModel, GetRunbookDetailsDto>();
|
|
||||||
CreateMap<GetRunbookDetailsDto, RunbookModel>();
|
|
||||||
CreateMap<RunbookModel, AddRunbookDto>();
|
|
||||||
CreateMap<AddRunbookDto, RunbookModel>();
|
|
||||||
|
|
||||||
/** Deployment Model **/
|
/** Deployment Model **/
|
||||||
CreateMap<DeploymentModel, GetDeploymentDto>();
|
CreateMap<DeploymentModel, GetDeploymentDto>();
|
||||||
CreateMap<GetDeploymentDto, DeploymentModel>();
|
CreateMap<GetDeploymentDto, DeploymentModel>();
|
||||||
CreateMap<DeploymentModel, GetDeploymentDetailsDto>();
|
CreateMap<DeploymentModel, GetDeploymentDetailsDto>();
|
||||||
CreateMap<GetDeploymentDetailsDto, DeploymentModel>();
|
CreateMap<GetDeploymentDetailsDto, DeploymentModel>();
|
||||||
CreateMap<DeploymentModel, AddDeploymentDto>();
|
CreateMap<DeploymentModel, AddDeploymentDto>()
|
||||||
CreateMap<AddDeploymentDto, DeploymentModel>();
|
.ForMember(destination => destination.JsonData, option => option.MapFrom(source => source.JSONData));
|
||||||
CreateMap<DeploymentModel, EditDeploymentDto>();
|
CreateMap<AddDeploymentDto, DeploymentModel>()
|
||||||
CreateMap<EditDeploymentDto, DeploymentModel>();
|
.ForMember(destination => destination.JSONData, option => option.MapFrom(source => source.JsonData));
|
||||||
|
CreateMap<DeploymentModel, EditDeploymentDto>()
|
||||||
|
.ForMember(destination => destination.jsonData, option => option.MapFrom(source => source.JSONData));
|
||||||
|
CreateMap<EditDeploymentDto, DeploymentModel>()
|
||||||
|
.ForMember(destination => destination.JSONData, option => option.MapFrom(source => source.jsonData));
|
||||||
|
|
||||||
/** Deployment Group Model **/
|
/** Deployment Group Model **/
|
||||||
CreateMap<DeploymentGroupModel, GetDeploymentGroupDto>();
|
CreateMap<DeploymentGroupModel, GetDeploymentBatchDto>();
|
||||||
CreateMap<GetDeploymentGroupDto, DeploymentGroupModel>();
|
CreateMap<GetDeploymentBatchDto, DeploymentGroupModel>();
|
||||||
CreateMap<DeploymentGroupModel, GetDeploymentGroupDetailsDto>();
|
CreateMap<DeploymentGroupModel, GetDeploymentBatchDetailsDto>();
|
||||||
CreateMap<GetDeploymentGroupDetailsDto, DeploymentGroupModel>();
|
CreateMap<GetDeploymentBatchDetailsDto, DeploymentGroupModel>();
|
||||||
CreateMap<DeploymentGroupModel, AddDeploymentGroupDto>();
|
CreateMap<DeploymentGroupModel, AddDeploymentBatchDto>();
|
||||||
CreateMap<AddDeploymentGroupDto, DeploymentGroupModel>();
|
CreateMap<AddDeploymentBatchDto, DeploymentGroupModel>();
|
||||||
|
CreateMap<DeploymentGroupModel, EditDeploymentBatchDto>();
|
||||||
|
CreateMap<EditDeploymentBatchDto, DeploymentGroupModel>();
|
||||||
|
|
||||||
|
/** Deployment Composition Model **/
|
||||||
|
CreateMap<DeploymentTemplateSelectionModel, GetDeploymentTemplateSelectionDto>();
|
||||||
|
CreateMap<GetDeploymentTemplateSelectionDto, DeploymentTemplateSelectionModel>();
|
||||||
|
CreateMap<AddDeploymentTemplateSelectionDto, DeploymentTemplateSelectionModel>();
|
||||||
|
CreateMap<DeploymentParameterValueModel, GetDeploymentParameterValueDto>();
|
||||||
|
CreateMap<GetDeploymentParameterValueDto, DeploymentParameterValueModel>();
|
||||||
|
CreateMap<AddDeploymentParameterValueDto, DeploymentParameterValueModel>();
|
||||||
|
CreateMap<DeploymentTargetAssignmentModel, GetDeploymentTargetAssignmentDto>();
|
||||||
|
CreateMap<GetDeploymentTargetAssignmentDto, DeploymentTargetAssignmentModel>();
|
||||||
|
CreateMap<AddDeploymentTargetAssignmentDto, DeploymentTargetAssignmentModel>();
|
||||||
|
|
||||||
/** Template Model **/
|
/** Template Model **/
|
||||||
CreateMap<TemplateModel, GetTemplateDto>();
|
CreateMap<TemplateModel, GetTemplateDto>();
|
||||||
@@ -113,6 +125,12 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper
|
|||||||
CreateMap<TemplateModel, EditTemplateDto>();
|
CreateMap<TemplateModel, EditTemplateDto>();
|
||||||
CreateMap<EditTemplateDto, TemplateModel>();
|
CreateMap<EditTemplateDto, TemplateModel>();
|
||||||
|
|
||||||
|
/** Template Version Model **/
|
||||||
|
CreateMap<TemplateVersionModel, GetTemplateVersionDto>();
|
||||||
|
CreateMap<GetTemplateVersionDto, TemplateVersionModel>();
|
||||||
|
CreateMap<TemplateVersionModel, AddTemplateVersionDto>();
|
||||||
|
CreateMap<AddTemplateVersionDto, TemplateVersionModel>();
|
||||||
|
|
||||||
/** Service Model **/
|
/** Service Model **/
|
||||||
CreateMap<ServiceModel, GetServiceDto>();
|
CreateMap<ServiceModel, GetServiceDto>();
|
||||||
CreateMap<GetServiceDto, ServiceModel>();
|
CreateMap<GetServiceDto, ServiceModel>();
|
||||||
@@ -135,3 +153,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
|
||||||
{
|
|
||||||
public interface IAbstractInterface
|
|
||||||
{
|
|
||||||
bool SaveChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||||
|
|
||||||
|
namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
||||||
|
{
|
||||||
|
public interface IDeploymentBatchInterface
|
||||||
|
{
|
||||||
|
ICollection<DeploymentGroupModel> GetDeploymentBatches();
|
||||||
|
|
||||||
|
DeploymentGroupModel? GetDeploymentBatchById(Guid id);
|
||||||
|
|
||||||
|
bool AddDeploymentBatchById(DeploymentGroupModel deploymentBatch, ICollection<Guid>? targetIds);
|
||||||
|
|
||||||
|
bool DeleteDeploymentBatchById(DeploymentGroupModel deploymentBatch);
|
||||||
|
|
||||||
|
bool EditDeploymentBatchById(DeploymentGroupModel deploymentBatch);
|
||||||
|
|
||||||
|
bool CheckDeploymentBatchById(Guid id);
|
||||||
|
|
||||||
|
bool SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
|
||||||
|
|
||||||
namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
|
||||||
{
|
|
||||||
public interface IDeploymentGroupInterface
|
|
||||||
{
|
|
||||||
ICollection<DeploymentGroupModel> GetDeploymentGroups();
|
|
||||||
|
|
||||||
DeploymentGroupModel GetDeploymentGroupById(Guid Id);
|
|
||||||
bool AddDeploymentGroupById(DeploymentGroupModel deploymentgroup, ICollection<Guid>? virtualMachineIds);
|
|
||||||
bool DeleteDeploymentGroupById(DeploymentGroupModel deploymentgroup);
|
|
||||||
bool EditDeploymentGroupById(DeploymentGroupModel deploymentgroup);
|
|
||||||
|
|
||||||
bool CheckDeploymentGroupById(Guid Id);
|
|
||||||
|
|
||||||
bool SaveChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,8 +10,11 @@ namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
|||||||
bool AddDeploymentById(DeploymentModel deployment);
|
bool AddDeploymentById(DeploymentModel deployment);
|
||||||
bool DeleteDeploymentById(DeploymentModel deployment);
|
bool DeleteDeploymentById(DeploymentModel deployment);
|
||||||
bool EditDeploymentById(DeploymentModel deployment);
|
bool EditDeploymentById(DeploymentModel deployment);
|
||||||
|
DeploymentModel GetDeploymentByCompositeId(Guid deploymentGroupId, Guid targetId);
|
||||||
|
bool CheckDeploymentByCompositeId(Guid deploymentGroupId, Guid targetId);
|
||||||
|
|
||||||
bool CheckDeploymentById(Guid Id);
|
bool CheckDeploymentById(Guid Id);
|
||||||
bool SaveChanges();
|
bool SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
|||||||
bool EditDomainById(DomainModel domain);
|
bool EditDomainById(DomainModel domain);
|
||||||
|
|
||||||
DomainModel GetDomainByIdInEnvironments(Guid Id);
|
DomainModel GetDomainByIdInEnvironments(Guid Id);
|
||||||
DomainModel GetVirtualMachinesByDomainId(Guid Id);
|
DomainModel GetTargetsByDomainId(Guid Id);
|
||||||
|
|
||||||
bool LinkDomainByIdToEnvironment(EnvironmentDomainsModel environmentDomain);
|
bool LinkDomainByIdToEnvironment(EnvironmentDomainsModel environmentDomain);
|
||||||
bool UnlinkDomainByIdFromEnvironment(EnvironmentDomainsModel environmentDomain);
|
bool UnlinkDomainByIdFromEnvironment(EnvironmentDomainsModel environmentDomain);
|
||||||
@@ -23,3 +23,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
|||||||
bool SaveChanges();
|
bool SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
|||||||
bool SaveChanges();
|
bool SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user