/// <summary>
 /// Create ubuntu server 16.04 LTS vm
 /// </summary>
 public static Task <IVirtualMachineResource> CreateXenialAsync(
     this IVirtualMachineFactory service, IResourceGroupResource resourceGroup,
     string name = null, INetworkResource network = null, string customData = null)
 {
     return(service.CreateAsync(resourceGroup, name, network, KnownImages.Ubuntu_16_04_lts,
                                customData));
 }
        /// <summary>
        /// Get or create new vm in a resource group.
        /// </summary>
        /// <param name="service"></param>
        /// <param name="resourceGroup"></param>
        /// <param name="name"></param>
        /// <param name="network"></param>
        /// <param name="image"></param>
        /// <returns></returns>
        public static async Task <IVirtualMachineResource> GetOrCreateAsync(
            this IVirtualMachineFactory service, IResourceGroupResource resourceGroup,
            string name, INetworkResource network = null, VirtualMachineImage image = null)
        {
            var resource = await Try.Async(() => service.GetAsync(resourceGroup, name));

            if (resource == null)
            {
                resource = await service.CreateAsync(resourceGroup, name, network, image, null);
            }
            return(resource);
        }
        /// <inheritdoc/>
        public async Task <IVirtualMachineResource> CreateAsync(
            IResourceGroupResource resourceGroup, string name,
            INetworkResource netres, VirtualMachineImage image,
            string customData)
        {
            if (resourceGroup == null)
            {
                throw new ArgumentNullException(nameof(resourceGroup));
            }

            var client = await CreateClientAsync(resourceGroup);

            name = await client.VirtualMachines.SelectResourceNameAsync(resourceGroup.Name,
                                                                        "vm", name);

            var user = VirtualMachineResource.kDefaultUser;
            var pw   = "Vm$" + name.ToSha1Hash().Substring(0, 3);

            if (image == null)
            {
                image = KnownImages.Ubuntu_16_04_lts;
            }

            var      attempt = 0;
            INetwork network = null;

            if (netres != null)
            {
                network = await client.Networks.GetByResourceGroupAsync(
                    resourceGroup.Name, netres.Name);

                if (network == null)
                {
                    throw new ArgumentException(nameof(netres));
                }
            }

            var originalRegion = await resourceGroup.Subscription.GetRegionAsync();

            while (true)
            {
                var regionAndVmSize = await SelectRegionAndVmSizeAsync(
                    resourceGroup, client);

                if (regionAndVmSize == null)
                {
                    throw new ExternalDependencyException(
                              "No sizes available.");
                }
                var region = regionAndVmSize.Item1;
                var vmSize = regionAndVmSize.Item2;
                try {
                    var nicDefine = client.NetworkInterfaces
                                    .Define(name)
                                    .WithRegion(region)
                                    .WithExistingResourceGroup(resourceGroup.Name);
                    var nic = nicDefine
                              .WithNewPrimaryNetwork(client.Networks
                                                     .Define(name)
                                                     .WithRegion(region)
                                                     .WithExistingResourceGroup(resourceGroup.Name)
                                                     .WithAddressSpace("172.16.0.0/16"))
                              .WithPrimaryPrivateIPAddressDynamic();

                    var ipName = await client.PublicIPAddresses.SelectResourceNameAsync(
                        resourceGroup.Name, "ip");

                    var publicIP = client.PublicIPAddresses
                                   .Define(ipName)
                                   .WithRegion(region)
                                   .WithExistingResourceGroup(resourceGroup.Name);

                    if (network != null && originalRegion == region)
                    {
                        nic = nicDefine
                              .WithExistingPrimaryNetwork(network)
                              .WithSubnet(netres.Subnet)
                              .WithPrimaryPrivateIPAddressDynamic();
                    }

                    nic = nic.WithNewPrimaryPublicIPAddress(
                        client.PublicIPAddresses
                        .Define(name)
                        .WithRegion(region)
                        .WithExistingResourceGroup(resourceGroup.Name));

                    var withOs = client.VirtualMachines
                                 .Define(name)
                                 .WithRegion(region)
                                 .WithExistingResourceGroup(resourceGroup.Name)
                                 .WithNewPrimaryNetworkInterface(nic);

                    IWithFromImageCreateOptionsManaged machine;
                    if (image.IsLinux)
                    {
                        machine = withOs
                                  .WithLatestLinuxImage(image.Publisher,
                                                        image.Offer, image.Sku)
                                  .WithRootUsername(user)
                                  .WithRootPassword(pw);
                    }
                    else
                    {
                        machine = withOs
                                  .WithLatestWindowsImage(image.Publisher,
                                                          image.Offer, image.Sku)
                                  .WithAdminUsername(user)
                                  .WithAdminPassword(pw);
                    }

                    _logger.Info($"Trying to create vm {name} on {vmSize}...");

                    IVirtualMachine vm = null;
                    if (!string.IsNullOrEmpty(customData))
                    {
                        vm = await machine
                             .WithCustomData(customData)
                             .WithSize(vmSize)
                             .CreateAsync();

                        _logger.Info($"Starting vm {name} ...");
                        // Restart for changes to go into effect
                        await vm.RestartAsync();
                    }
                    else
                    {
                        vm = await machine.WithSize(vmSize).CreateAsync();
                    }
                    _logger.Info($"Created vm {name}.");
                    return(new VirtualMachineResource(this, resourceGroup, vm,
                                                      user, pw, _logger));
                }
                catch (Exception ex) {
                    _logger.Info(
                        $"#{attempt} failed creating VM {name} as {vmSize}...",
                        () => ex);
                    await TryDeleteResourcesAsync(resourceGroup, name);

                    if (++attempt == 3)
                    {
                        throw ex;
                    }
                }
            }
        }
 /// <summary>
 /// Get or create new ubuntu server 16.04 LTS vm in a resource group.
 /// </summary>
 /// <param name="service"></param>
 /// <param name="resourceGroup"></param>
 /// <param name="name"></param>
 /// <param name="network"></param>
 /// <returns></returns>
 public static Task <IVirtualMachineResource> GetOrCreateBionicAsync(
     this IVirtualMachineFactory service, IResourceGroupResource resourceGroup,
     string name, INetworkResource network = null) =>
 service.GetOrCreateAsync(resourceGroup, name, network, KnownImages.Ubuntu_18_04_lts);
 /// <summary>
 /// Create a new linux virtual machine
 /// </summary>
 public static Task <IVirtualMachineResource> CreateAsync(
     this IVirtualMachineFactory service, IResourceGroupResource resourceGroup,
     string name = null, INetworkResource network = null, string customData = null) =>
 service.CreateAsync(resourceGroup, name, network, null, customData);