Skip to content

Commit

Permalink
Merge pull request Azure#5721 from sergey-shandar/sergey-vmss-custom-…
Browse files Browse the repository at this point in the history
…image

New-AzureRmVm/Vmss: Custom image
  • Loading branch information
markcowl authored Mar 20, 2018
2 parents 64fc5ba + 5a65380 commit 1faaacd
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@
<Compile Include="INestedResourceConfig.cs" />
<Compile Include="INestedResourceConfigVisitor.cs" />
<Compile Include="INestedResourceStrategy.cs" />
<Compile Include="IResourceId.cs" />
<Compile Include="Property.cs" />
<Compile Include="ResourceId.cs" />
<Compile Include="ResourceType.cs" />
<Compile Include="SdkEngine.cs" />
<Compile Include="IEngine.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ public static IEnumerable<string> GetIdFromSubscription(this IEntityConfig confi
{
var resourceGroupId = new[]
{
ResourceType.ResourceGroups, config.GetResourceGroupName()
ResourceId.ResourceGroups, config.GetResourceGroupName()
};
return config.ResourceGroup == null
? resourceGroupId
: resourceGroupId.Concat(config.GetProvidersId());
}

internal static IEnumerable<string> GetProvidersId(this IEntityConfig config)
=> new[] { "providers" }.Concat(config.GetIdFromResourceGroup());
=> new[] { ResourceId.Providers }.Concat(config.GetIdFromResourceGroup());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------------

namespace Microsoft.Azure.Commands.Common.Strategies
{
public interface IResourceId
{
string SubscriptionId { get; }
string ResourceGroupName { get; }
ResourceType ResourceType { get; }
string Name { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------------

namespace Microsoft.Azure.Commands.Common.Strategies
{
public static class ResourceId
{
public const string Subscriptions = "subscriptions";
public const string ResourceGroups = "resourceGroups";
public const string Providers = "providers";

/// <summary>
/// Returns 'null' if the given id is not parsable.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static IResourceId TryParse(string id)
{
const int EmptyI = 0;
const int SubscriptionsI = 1;
const int SubscriptionIdI = 2;
const int ResourceGroupsI = 3;
const int ResourceGroupNameI = 4;
const int ProvidersI = 5;
const int NamespaceI = 6;
const int ProviderI = 7;
const int NameI = 8;

var parts = id.Split('/');
return parts.Length == 9
&& parts[EmptyI] == string.Empty
&& parts[SubscriptionsI] == Subscriptions
&& parts[ResourceGroupsI] == ResourceGroups
&& parts[ProvidersI] == Providers
? new Implementation(
subscriptionId: parts[SubscriptionIdI],
resourceGroupName: parts[ResourceGroupNameI],
resourceType: new ResourceType(
namespace_: parts[NamespaceI],
provider: parts[ProviderI]),
name: parts[NameI])
: null;
}

sealed class Implementation : IResourceId
{
public string Name { get; }

public string ResourceGroupName { get; }

public ResourceType ResourceType { get; }

public string SubscriptionId { get; }

public Implementation(
string subscriptionId,
string resourceGroupName,
ResourceType resourceType,
string name)
{
SubscriptionId = subscriptionId;
ResourceGroupName = resourceGroupName;
ResourceType = resourceType;
Name = name;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
namespace Microsoft.Azure.Commands.Common.Strategies
{
public sealed class ResourceType
{
public const string ResourceGroups = "resourceGroups";

{
public static ResourceType ResourceGroup { get; }
= new ResourceType(null, ResourceGroups);
= new ResourceType(null, ResourceId.ResourceGroups);

/// <summary>
/// A resource type namespace, for example 'Microsoft.Network'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Microsoft.Azure.Commands.Common.Strategies
/// Engine for REST API calls using Azure SDK.
/// </summary>
public sealed class SdkEngine : IEngine
{
{
string _SubscriptionId { get; }

public SdkEngine(string subscriptionId)
Expand All @@ -29,7 +29,7 @@ public SdkEngine(string subscriptionId)
}

public string GetId(IEntityConfig config)
=> new[] { "subscriptions", _SubscriptionId }
=> new[] { ResourceId.Subscriptions, _SubscriptionId }
.Concat(config.GetIdFromSubscription())
.IdToString();
}
Expand Down
2 changes: 2 additions & 0 deletions src/ResourceManager/Compute/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
- Additional information about change #1
-->
## Current Release
* `New-AzureRmVM` and `New-AzureRmVMSS` support data disks.
* `New-AzureRmVM` and `New-AzureRmVMSS` support custom image by name or by id.
* Log analytic feature
- Added `Export-AzureRmLogAnalyticRequestRateByInterval` cmdlet
- Added `Export-AzureRmLogAnalyticThrottledRequests` cmdlet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public string Location
public async Task<ResourceConfig<VirtualMachineScaleSet>> CreateConfigAsync()
{
ImageAndOsType = await _client.UpdateImageAndOsTypeAsync(
ImageAndOsType, _cmdlet.ImageName, Location);
ImageAndOsType, _cmdlet.ResourceGroupName, _cmdlet.ImageName, Location);

// generate a domain name label if it's not specified.
_cmdlet.DomainNameLabel = await PublicIPAddressStrategy.UpdateDomainNameLabelAsync(
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -583,4 +583,15 @@ The file needs to be a PowerShell script (.ps1 or .psm1) or a ZIP archive (.zip)
<value>Use '{0}' to connect to the VMSS instances.</value>
<comment>{0} = connection string</comment>
</data>
<data name="ComputeInvalidImageName" xml:space="preserve">
<value>Invalid image resource id '{0}'.</value>
<comment>{0} = image resource id</comment>
</data>
<data name="ComputeMismatchSubscription" xml:space="preserve">
<value>The image subscription doesn't match the current subscription.</value>
</data>
<data name="ComputeNoImageFound" xml:space="preserve">
<value>Can't find the image '{0}'.</value>
<comment>{0} = image name</comment>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace Microsoft.Azure.Commands.Compute.Strategies.ComputeRp
{
static class ComputeStrategy
{
public const string Namespace = "Microsoft.Compute";

public static ResourceStrategy<TModel> Create<TModel, TOperations>(
string provider,
Func<ComputeManagementClient, TOperations> getOperations,
Expand All @@ -30,7 +32,7 @@ public static ResourceStrategy<TModel> Create<TModel, TOperations>(
Func<TModel, int> createTime)
where TModel : Resource
=> ResourceStrategy.Create(
type: new ResourceType("Microsoft.Compute", provider),
type: new ResourceType(Namespace, provider),
getOperations: getOperations,
getAsync: getAsync,
createOrUpdateAsync: createOrUpdateAsync,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ private static int[] CreatePorts(this OperatingSystemTypes osType)
public static async Task<ImageAndOsType> UpdateImageAndOsTypeAsync(
this IClient client,
ImageAndOsType imageAndOsType,
string resourceGroupName,
string imageName,
string location)
{
Expand All @@ -44,6 +45,8 @@ public static async Task<ImageAndOsType> UpdateImageAndOsTypeAsync(
return imageAndOsType;
}

var compute = client.GetClient<ComputeManagementClient>();

if (imageName.Contains(':'))
{
if (location == null)
Expand All @@ -64,7 +67,7 @@ public static async Task<ImageAndOsType> UpdateImageAndOsTypeAsync(
Sku = imageArray[2],
Version = imageArray[3],
};
var compute = client.GetClient<ComputeManagementClient>();

if (image.Version.ToLower() == "latest")
{
var images = await compute.VirtualMachineImages.ListAsync(
Expand All @@ -81,10 +84,44 @@ public static async Task<ImageAndOsType> UpdateImageAndOsTypeAsync(
location, image.Publisher, image.Offer, image.Sku, image.Version);
return new ImageAndOsType(imageModel.OsDiskImage.OperatingSystem, image);
}
else if (imageName.Contains("/"))
{
var resourceId = ResourceId.TryParse(imageName);
if (resourceId == null
|| resourceId.ResourceType.Namespace != ComputeStrategy.Namespace
|| resourceId.ResourceType.Provider != "images")
{
throw new ArgumentException(string.Format(Resources.ComputeInvalidImageName, imageName));
}

if (compute.SubscriptionId != resourceId.SubscriptionId)
{
throw new ArgumentException(Resources.ComputeMismatchSubscription);
}

var localImage = await compute.Images.GetAsync(
resourceGroupName: resourceId.ResourceGroupName,
imageName: resourceId.Name);

return new ImageAndOsType(
localImage.StorageProfile.OsDisk.OsType,
new ImageReference { Id = localImage.Id });
}
else
{
// get image
return Images
try
{
var localImage = await compute.Images.GetAsync(resourceGroupName, imageName);
return new ImageAndOsType(
localImage.StorageProfile.OsDisk.OsType,
new ImageReference { Id = localImage.Id });
}
catch
{
}

// get generic image
var result = Images
.Instance
.SelectMany(osAndMap => osAndMap
.Value
Expand All @@ -95,6 +132,13 @@ public static async Task<ImageAndOsType> UpdateImageAndOsTypeAsync(
: OperatingSystemTypes.Linux,
nameAndImage.Value)))
.FirstOrDefault();

if (result == null)
{
throw new ArgumentException(string.Format(Resources.ComputeNoImageFound, imageName));
}

return result;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ public async Task<ResourceConfig<VirtualMachine>> CreateConfigAsync()
if (_cmdlet.DiskFile == null)
{
ImageAndOsType = await _client.UpdateImageAndOsTypeAsync(
ImageAndOsType, _cmdlet.ImageName, Location);
ImageAndOsType, _cmdlet.ResourceGroupName, _cmdlet.ImageName, Location);
}

_cmdlet.DomainNameLabel = await PublicIPAddressStrategy.UpdateDomainNameLabelAsync(
Expand Down

0 comments on commit 1faaacd

Please sign in to comment.