/// <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));
            }
        }
Example #2
0
        public override ILoadBalancer UpdateResource(ILoadBalancer resource)
        {
            ILoadBalancerBackend        backend        = resource.Backends.Values.First();
            ILoadBalancerInboundNatRule natRule        = resource.InboundNatRules.Values.First();
            ILoadBalancerPublicFrontend publicFrontend = (ILoadBalancerPublicFrontend)natRule.Frontend;

            IPublicIPAddress pip = resource.Manager.PublicIPAddresses.Define(loadBalancerHelper.PipNames[1])
                                   .WithRegion(loadBalancerHelper.Region)
                                   .WithExistingResourceGroup(loadBalancerHelper.GroupName)
                                   .WithLeafDomainLabel(loadBalancerHelper.PipNames[1])
                                   .Create();

            resource = resource.Update()
                       .UpdatePublicFrontend(publicFrontend.Name)
                       .WithExistingPublicIPAddress(pip)
                       .Parent()
                       .DefineBackend("backend2")
                       .Attach()
                       .WithoutBackend(backend.Name)
                       .WithoutInboundNatRule("natrule1")
                       .WithTag("tag1", "value1")
                       .WithTag("tag2", "value2")
                       .Apply();

            Assert.True(resource.Tags.ContainsKey("tag1"));

            // Verify frontends
            Assert.Equal(1, resource.Frontends.Count);
            Assert.Equal(1, resource.PublicFrontends.Count);
            Assert.Equal(0, resource.PrivateFrontends.Count);
            Assert.True(resource.Frontends.ContainsKey(publicFrontend.Name));
            var frontend = resource.Frontends[publicFrontend.Name];

            Assert.True(frontend.IsPublic);
            publicFrontend = (ILoadBalancerPublicFrontend)frontend;
            Assert.Equal(pip.Id, publicFrontend.PublicIPAddressId, ignoreCase: true);
            Assert.Equal(0, publicFrontend.LoadBalancingRules.Count);

            // Verify probes
            Assert.Equal(0, resource.TcpProbes.Count);
            Assert.Equal(0, resource.HttpProbes.Count);

            // Verify backends
            Assert.True(resource.Backends.ContainsKey("backend2"));
            Assert.True(!resource.Backends.ContainsKey(backend.Name));

            // Verify NAT rules
            Assert.Equal(0, resource.InboundNatRules.Count);

            // Verify load balancing rules
            Assert.Equal(0, resource.LoadBalancingRules.Count);

            return(resource);
        }
        // This test put multiple zonal virtual machine's NIC into backend pool of a zone-redundant load balancer.
        // There is a bug in the service, where such an attempt will fail with error
        // "error": {
        //    "code": "NetworkInterfaceAndLoadBalancerAreInDifferentAvailabilitySets",
        //    "message": "Network interface /subscriptions/<sub-id>/resourceGroups/<rg-name>/providers/Microsoft.Network/networkInterfaces/<nic-name> uses load balancer /subscriptions/<sub-id>/resourceGroups/<rg-name>/providers/Microsoft.Compute/virtualMachines/<vm-name>).",
        //    "details": []
        // }
        // Enable this test once it is fixed.
        //
        public void CanCreateZonedVMsAndAssociateThemWithSingleBackendPoolOfZoneResilientLB()
        {
            using (var context = FluentMockContext.Start(GetType().FullName))
            {
                string rgName = TestUtilities.GenerateName("rgzoned");
                try
                {
                    var    region      = Region.USEast2;
                    string networkName = TestUtilities.GenerateName("net");

                    var azure   = TestHelper.CreateRollupClient();
                    var network = azure.Networks.Define(networkName)
                                  .WithRegion(region)
                                  .WithNewResourceGroup(rgName)
                                  .WithAddressSpace("10.0.0.0/28")
                                  .WithSubnet("subnet1", "10.0.0.0/29")
                                  .WithSubnet("subnet2", "10.0.0.8/29")
                                  .Create();

                    string pipDnsLabel = TestUtilities.GenerateName("pip");

                    var subnets = network.Subnets.Values.GetEnumerator();
                    // Define first regional virtual machine
                    //
                    subnets.MoveNext();
                    var creatableVM1 = azure.VirtualMachines
                                       .Define(TestUtilities.GenerateName("vm1"))
                                       .WithRegion(region)
                                       .WithExistingResourceGroup(rgName)
                                       .WithExistingPrimaryNetwork(network)
                                       .WithSubnet(subnets.Current.Name) // Put VM in first subnet
                                       .WithPrimaryPrivateIPAddressDynamic()
                                       .WithoutPrimaryPublicIPAddress()
                                       .WithPopularLinuxImage(KnownLinuxVirtualMachineImage.UbuntuServer16_04_Lts)
                                       .WithRootUsername("Foo12")
                                       .WithRootPassword("abc!@#F0orL")
                                       // Optionals
                                       .WithAvailabilityZone(AvailabilityZoneId.Zone_1)
                                       .WithSize(VirtualMachineSizeTypes.StandardD3V2);

                    subnets.MoveNext();
                    var creatableVM2 = azure.VirtualMachines
                                       .Define(TestUtilities.GenerateName("vm2"))
                                       .WithRegion(region)
                                       .WithExistingResourceGroup(rgName)
                                       .WithExistingPrimaryNetwork(network)
                                       .WithSubnet(subnets.Current.Name) // Put VM in second subnet
                                       .WithPrimaryPrivateIPAddressDynamic()
                                       .WithoutPrimaryPublicIPAddress()
                                       .WithPopularLinuxImage(KnownLinuxVirtualMachineImage.UbuntuServer16_04_Lts)
                                       .WithRootUsername("Foo12")
                                       .WithRootPassword("abc!@#F0orL")
                                       // Optionals
                                       .WithAvailabilityZone(AvailabilityZoneId.Zone_1)
                                       .WithSize(VirtualMachineSizeTypes.StandardD3V2);

                    ICreatedResources <IVirtualMachine> createdVMs = azure.VirtualMachines.Create(creatableVM1, creatableVM2);

                    var itr = createdVMs.GetEnumerator();
                    itr.MoveNext();
                    IVirtualMachine firstVirtualMachine = itr.Current;
                    itr.MoveNext();
                    IVirtualMachine secondVirtualMachine = itr.Current;

                    var publicIPAddress = azure.PublicIPAddresses
                                          .Define(pipDnsLabel)
                                          .WithRegion(region)
                                          .WithExistingResourceGroup(rgName)
                                          .WithStaticIP()
                                                                             // Optionals
                                          .WithSku(PublicIPSkuType.Standard) //  STANDARD LB requires STANDARD PIP
                                                                             // Create PIP
                                          .Create();

                    // Creates a Internet-Facing LoadBalancer with one front-end IP configuration and
                    // two backend pool associated with this IP Config
                    //
                    var           lbName = TestUtilities.GenerateName("lb");
                    ILoadBalancer lb     = azure.LoadBalancers
                                           .Define(lbName)
                                           .WithRegion(region)
                                           .WithExistingResourceGroup(rgName)
                                           .DefineLoadBalancingRule("rule-1")
                                           .WithProtocol(TransportProtocol.Tcp)
                                           .FromFrontend("front-end-1")
                                           .FromFrontendPort(80)
                                           .ToExistingVirtualMachines(firstVirtualMachine, secondVirtualMachine)
                                           .WithProbe("tcpProbe-1")
                                           .Attach()
                                           .DefinePublicFrontend("front-end-1") // Define the frontend IP configuration used by the LB rule
                                           .WithExistingPublicIPAddress(publicIPAddress)
                                           .Attach()
                                           .DefineTcpProbe("tcpProbe-1") // Define the Probe used by the LB rule
                                           .WithPort(25)
                                           .WithIntervalInSeconds(15)
                                           .WithNumberOfProbes(5)
                                           .Attach()
                                           .WithSku(LoadBalancerSkuType.Standard) // "zone-resilient LB" which don't have the constraint that all VMs needs to be in the same availability set
                                           .Create();

                    // Zone resilient LB does not care VMs are zoned or regional, in the above cases VMs are regional.
                    //
                    // rx.Completable.merge(firstVirtualMachine.startAsync(), secondVirtualMachine.startAsync()).await();

                    // Verify frontends
                    Assert.Equal(1, lb.Frontends.Count);
                    Assert.Equal(1, lb.PublicFrontends.Count);
                    Assert.Equal(0, lb.PrivateFrontends.Count);
                    ILoadBalancerFrontend frontend = lb.Frontends.Values.First();
                    Assert.True(frontend.IsPublic);
                    ILoadBalancerPublicFrontend publicFrontend = (ILoadBalancerPublicFrontend)frontend;
                    Assert.Equal(publicIPAddress.Id, publicFrontend.PublicIPAddressId, ignoreCase: true);

                    // Verify backends
                    Assert.Equal(1, lb.Backends.Count);

                    // Verify probes
                    Assert.Equal(1, lb.TcpProbes.Count);
                    Assert.True(lb.TcpProbes.ContainsKey("tcpProbe-1"));

                    // Verify rules
                    Assert.Equal(1, lb.LoadBalancingRules.Count);
                    Assert.True(lb.LoadBalancingRules.ContainsKey("rule-1"));
                    ILoadBalancingRule rule = lb.LoadBalancingRules["rule-1"];
                    Assert.NotNull(rule.Backend);
                    Assert.Equal("tcpProbe-1", rule.Probe.Name, ignoreCase: true);
                    // Zone resilient LB does not care VMs are zoned or regional, in the above cases VMs are zoned.
                    //

                    // Note that above configuration is not possible for BASIC LB, BASIC LB has following limitation
                    // It supports VMs only in a single availability Set in a backend pool, though multiple backend pool
                    // can be associated with VMs in the single availability set, you cannot create a set of VMs in another
                    // availability set and put it in a different backend pool.
                }
                finally
                {
                    try
                    {
                        var resourceManager = TestHelper.CreateResourceManager();
                        resourceManager.ResourceGroups.DeleteByName(rgName);
                    }
                    catch { }
                }
            }
        }