Exemplo n.º 1
0
        /// <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));
            }
        }
Exemplo n.º 2
0
        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));
            }
        }
Exemplo n.º 3
0
        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();
            }
        }
Exemplo n.º 4
0
        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();
            }
        }
Exemplo n.º 5
0
        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);
        }