/// <summary> /// TODO: Clean this up. check and errors. /// /// Should check the loadbalancer.inner.status to see if update is already in progress. /// Also should batch the queue items, add and configure multiple up configurations at once if they are in the queue. /// </summary> /// <param name="tenantDeployment"></param> /// <param name="cancellationToken"></param> /// <returns></returns> private async Task <TenantDeployment> ProcessIpDeploymentAsync(TenantDeployment tenantDeployment, CancellationToken cancellationToken) { var spId = Environment.GetEnvironmentVariable("SERVICE_PRINCIPAL_ID"); var spSecret = Environment.GetEnvironmentVariable("SERVICE_PRINCIPAL_SECRET"); var spTenantId = Environment.GetEnvironmentVariable("SERVICE_PRINCIPAL_TENANT_ID"); var subscriptionId = Environment.GetEnvironmentVariable("SUBSCRIPTION_ID"); var creds = new AzureCredentialsFactory().FromServicePrincipal(spId, spSecret, spTenantId, AzureEnvironment.AzureGlobalCloud); var azure = Azure.Authenticate(creds).WithSubscription(subscriptionId); string loadBalancerName = Environment.GetEnvironmentVariable("LOAD_BALANCER"); string backendPool = Environment.GetEnvironmentVariable("BACKENDPOOL"); string resourcegroup = Environment.GetEnvironmentVariable("RESOURCEGROUP"); string tenantname = $"deployment-{tenantDeployment.Name}"; //TODO check provisioning state of load balancer and delay if currently busy //var provisioningState = azure.ResourceGroups.GetByName(loadBalancer.ResourceGroupName).ProvisioningState; try { var loadBalancer = await azure.LoadBalancers.GetByResourceGroupAsync(resourcegroup, loadBalancerName, cancellationToken); ILoadBalancerPublicFrontend publicFrontend = loadBalancer.PublicFrontends.First().Value; var publicIpAddress = publicFrontend.GetPublicIPAddress(); await loadBalancer.Update() .DefineTcpProbe(tenantname + "_mc") .WithPort(tenantDeployment.InternalPort) .Attach() .DefineLoadBalancingRule($"{tenantname}_mc") .WithProtocol(TransportProtocol.Tcp) .FromExistingPublicIPAddress(publicIpAddress) .FromFrontendPort(tenantDeployment.InternalPort) .ToBackend(backendPool) .ToBackendPort(tenantDeployment.InternalPort) .WithProbe(tenantname + "_mc") .Attach() .DefineTcpProbe(tenantname + "_rcon") .WithPort(tenantDeployment.RconPort) .Attach() .DefineLoadBalancingRule($"{tenantname}_rcon") .WithProtocol(TransportProtocol.Tcp) .FromExistingPublicIPAddress(publicIpAddress) .FromFrontendPort(tenantDeployment.RconPort) .ToBackend(backendPool) .ToBackendPort(tenantDeployment.RconPort) .WithProbe(tenantname + "_rcon") .Attach() .ApplyAsync(cancellationToken); return(new TenantDeployment(CreationStatus.Created, tenantDeployment, publicIpAddress.Fqdn)); } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this.Context, "error provisioning ip addresses.", e.Message); return(new TenantDeployment(CreationStatus.InProcess, tenantDeployment)); } }
private async Task <TenantDeployment> ProcessTenantDeploymentAsync(TenantDeployment tenantDeploymentDeployment, CancellationToken cancellationToken) { var exists = await this.applicationOperator.ApplicationExistsAsync(tenantDeploymentDeployment.ApplicationName, cancellationToken); var serviceDefinition = new ServiceDefinition() { ServiceName = "MC", Type = "MCType", Version = "1.0.0" }; var applicationDefinition = new ApplicationDefinition() { ApplicationName = tenantDeploymentDeployment.ApplicationName, Type = "mcType", Version = "1.0.0", Services = new List <ServiceDefinition>() { serviceDefinition } }; if (exists) { string serviceName = $"{tenantDeploymentDeployment.ApplicationName}/{serviceDefinition.ServiceName}"; var serviceEndPoint = await this.applicationOperator.GetServiceEndpoint(serviceName, cancellationToken); if (serviceEndPoint.HasEndPoint) { ServiceEventSource.Current.ServiceMessage(this.Context, "Found new internal endpoint"); return(new TenantDeployment(CreationStatus.Created, serviceEndPoint.EndPoint["MCTypeEndpoint"], serviceEndPoint.EndPoint["MCrcon"], tenantDeploymentDeployment)); } // no endpoint yet leave alone. return(new TenantDeployment(CreationStatus.InProcess, tenantDeploymentDeployment)); } else { var(mcPort, rconPort) = await GetNextAvaliablePortsAsync(); serviceDefinition.Ports = new Dictionary <string, int>() { { "MCPORT", mcPort }, { "RCONPORT", rconPort } }; await this.applicationOperator.CreateApplicationAsync(applicationDefinition, cancellationToken); ServiceEventSource.Current.ServiceMessage(this.Context, "Application created"); return(new TenantDeployment(CreationStatus.New, tenantDeploymentDeployment)); } }
public async Task QueueTenantCreation(string tenantName) { var queue = await this.StateManager.GetTenantDeloymentsQueue(); using (ITransaction tx = this.StateManager.CreateTransaction()) { var tenant = TenantDeployment.CreateNew(tenantName); await queue.EnqueueAsync(tx, tenant); await tx.CommitAsync(); } }
public async Task QueueIpCreation(string tenantName, string internalIp, string rconEndpoint) { ServiceEventSource.Current.Message($"enqueue the tenant for ip address: {tenantName}, {internalIp}"); var queue = await this.StateManager.GetIpDeployments(); using (ITransaction tx = this.StateManager.CreateTransaction()) { var tenant = TenantDeployment.CreateNew(tenantName, internalIp, rconEndpoint); await queue.EnqueueAsync(tx, tenant); await tx.CommitAsync(); } }
public async Task <bool> TryDequeueAndProcessAsync(CancellationToken cancellationToken) { var queue = await this.StateManager.GetTenantDeloymentsQueue(); Stopwatch sw = Stopwatch.StartNew(); using (ITransaction tx = this.StateManager.CreateTransaction()) { ConditionalValue <TenantDeployment> workItem = await queue.TryDequeueAsync(tx, cancellationToken); if (!workItem.HasValue) { ServiceEventSource.Current.ServiceMessage(this.Context, "No new application deployment requests."); return(false); } TenantDeployment processedDeployment = await this.ProcessTenantDeploymentAsync(workItem.Value, cancellationToken); if (processedDeployment.CreationStatus == CreationStatus.Created) { //Trigger workflow ActorId actorId = new ActorId(processedDeployment.Name); ITenantWorkflowActor actor = ActorProxy.Create <ITenantWorkflowActor>(actorId, TenantHelpers.GetWorkflowActorUri()); await actor.InternalCreated(processedDeployment.InternalMineCraftEndpoint, processedDeployment.InternalRconEndpoint); ServiceEventSource.Current.ServiceMessage(this.Context, "Application Created"); } else { // The deployment hasn't completed or failed, so queue up the next stage of deployment await queue.EnqueueAsync(tx, workItem.Value, cancellationToken); ServiceEventSource.Current.ServiceMessage(this.Context, "Application enqueed again"); } await tx.CommitAsync(); } return(true); }