Skip to content

Commit b6e25ef

Browse files
committed
Common code changes
1 parent 915e926 commit b6e25ef

File tree

7 files changed

+352
-42
lines changed

7 files changed

+352
-42
lines changed

src/Common/Commands.Common/Extensions/CmdletExtensions.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Collections.Generic;
1919
using System.Collections.ObjectModel;
2020
using System.IO;
21+
using System.Linq.Expressions;
2122
using System.Management.Automation;
2223
using System.Reflection;
2324
using System.Text;
@@ -256,7 +257,7 @@ public static string ResolvePath(this PSCmdlet psCmdlet, string path)
256257
}
257258

258259
/// <summary>
259-
/// Execute the given cmdlet in powershell usign the given pipeline parameters.
260+
/// Execute the given cmdlet in powershell usign the given pipeline parameters.
260261
/// </summary>
261262
/// <typeparam name="T">The output type for the cmdlet</typeparam>
262263
/// <param name="cmdlet">The cmdlet to execute</param>
@@ -353,6 +354,13 @@ public static List<T> ExecuteScript<T>(this PSCmdlet cmdlet, string contents)
353354

354355
return output;
355356
}
357+
358+
public static bool IsParameterBound<TPSCmdlet, TProp>(this TPSCmdlet cmdlet, Expression<Func<TPSCmdlet, TProp>> propertySelector) where TPSCmdlet : PSCmdlet
359+
{
360+
var propName = ((MemberExpression)propertySelector.Body).Member.Name;
361+
return cmdlet.MyInvocation.BoundParameters.ContainsKey(propName);
362+
}
363+
356364
#region PowerShell Commands
357365

358366
public static void RemoveModule(this PSCmdlet cmdlet, string moduleName)
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
namespace Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters
16+
{
17+
using Commands.Common.Authentication;
18+
using Commands.Common.Authentication.Abstractions;
19+
using Management.Internal.Resources;
20+
using Management.Internal.Resources.Models;
21+
using Properties;
22+
using Rest.Azure;
23+
using System;
24+
using System.Collections.Concurrent;
25+
using System.Collections.Generic;
26+
using System.Linq;
27+
using System.Management.Automation;
28+
29+
/// <summary>
30+
/// This attribute will allow the user to autocomplete the -ResourceType parameter of a cmdlet with valid resource types
31+
/// </summary>
32+
public class ResourceTypeCompleterAttribute : PSCompleterBaseAttribute
33+
{
34+
private static IDictionary<int, IList<String>> _resourceTypesDictionary = new ConcurrentDictionary<int, IList<string>>();
35+
private static readonly object _lock = new object();
36+
public static int _timeout = 3;
37+
38+
protected static IList<String> ResourceTypes
39+
{
40+
get
41+
{
42+
lock (_lock)
43+
{
44+
IAzureContext context = AzureRmProfileProvider.Instance.Profile.DefaultContext;
45+
var contextHash = HashContext(context);
46+
if (!_resourceTypesDictionary.ContainsKey(contextHash))
47+
{
48+
var tempResourceTypeList = new List<string>();
49+
try
50+
{
51+
var instance = AzureSession.Instance;
52+
var client = instance.ClientFactory.CreateCustomArmClient<ResourceManagementClient>(
53+
context.Environment.GetEndpointAsUri(AzureEnvironment.Endpoint.ResourceManager),
54+
instance.AuthenticationFactory.GetServiceClientCredentials(context, AzureEnvironment.Endpoint.ResourceManager),
55+
instance.ClientFactory.GetCustomHandlers());
56+
client.SubscriptionId = context.Subscription.Id;
57+
// Retrieve only the first page of resource types to display to the user
58+
var resourceTypes = client.Providers.ListAsync();
59+
if (resourceTypes.Wait(TimeSpan.FromSeconds(_timeout)))
60+
{
61+
tempResourceTypeList = CreateResourceTypeList(resourceTypes.Result);
62+
if (resourceTypes.Result != null)
63+
{
64+
_resourceTypesDictionary[contextHash] = tempResourceTypeList;
65+
}
66+
}
67+
#if DEBUG
68+
else
69+
{
70+
throw new InvalidOperationException("client.Providers.ListAsync() call timed out");
71+
}
72+
#endif
73+
}
74+
75+
catch (Exception ex)
76+
{
77+
if (ex == null) { }
78+
#if DEBUG
79+
throw ex;
80+
#endif
81+
}
82+
83+
return tempResourceTypeList;
84+
}
85+
86+
else
87+
{
88+
return _resourceTypesDictionary[contextHash];
89+
}
90+
}
91+
}
92+
}
93+
94+
/// <summary>
95+
/// This class will provide a list of resource groups that are available to the user (with default resource group first if it exists). This will then be available to the user to tab through.
96+
/// Example: [Parameter(ParameterSetName = ListByNameInTenantParameterSet, ValueFromPipelineByPropertyName = true, Mandatory = false), ResourceGroupCompleter()]
97+
/// </summary>
98+
/// <param name="resourceTypes"></param>
99+
public ResourceTypeCompleterAttribute()
100+
{
101+
}
102+
103+
public override string[] GetCompleterValues()
104+
{
105+
return GetResourceTypes();
106+
}
107+
108+
public static string[] GetResourceTypes(int timeout)
109+
{
110+
_timeout = timeout;
111+
return GetResourceTypes();
112+
}
113+
114+
public static string[] GetResourceTypes()
115+
{
116+
return ResourceTypes.ToArray();
117+
}
118+
119+
private static ScriptBlock CreateScriptBlock()
120+
{
121+
string script = "param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)\n" +
122+
"$locations = [Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters.ResourceTypeCompleterAttribute]::GetResourceTypes()\n" +
123+
"$locations | Where-Object { $_ -Like \"$wordToComplete*\" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }";
124+
ScriptBlock scriptBlock = ScriptBlock.Create(script);
125+
return scriptBlock;
126+
}
127+
128+
private static int HashContext(IAzureContext context)
129+
{
130+
return (context.Account.Id + context.Environment.Name + context.Subscription.Id + context.Tenant.Id).GetHashCode();
131+
}
132+
133+
public static List<string> CreateResourceTypeList(IPage<Provider> result)
134+
{
135+
var tempResourceTypeList = new List<string>();
136+
if (result != null)
137+
{
138+
foreach (Provider provider in result)
139+
{
140+
foreach (ProviderResourceType resourceType in provider.ResourceTypes)
141+
{
142+
var type = provider.NamespaceProperty + "/" + resourceType.ResourceType;
143+
tempResourceTypeList.Add(type);
144+
}
145+
}
146+
}
147+
#if DEBUG
148+
else
149+
{
150+
throw new Exception("Result from client.ResourceGroups is null");
151+
}
152+
#endif
153+
return tempResourceTypeList;
154+
}
155+
}
156+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
namespace Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters
16+
{
17+
using Commands.Common.Authentication;
18+
using Commands.Common.Authentication.Abstractions;
19+
using Management.Internal.Resources;
20+
using Management.Internal.Resources.Models;
21+
using Properties;
22+
using Rest.Azure;
23+
using System;
24+
using System.Collections.Concurrent;
25+
using System.Collections.Generic;
26+
using System.Linq;
27+
using System.Management.Automation;
28+
29+
public class ScopeCompleterAttribute : PSCompleterBaseAttribute
30+
{
31+
public static IDictionary<int, IList<string>> _scopeDictionary = new ConcurrentDictionary<int, IList<string>>();
32+
private static readonly object _lock = new object();
33+
public static int _timeout = 3;
34+
35+
protected static IList<String> Scopes
36+
{
37+
get
38+
{
39+
lock (_lock)
40+
{
41+
IAzureContext context = AzureRmProfileProvider.Instance.Profile.DefaultContext;
42+
var contextHash = HashContext(context);
43+
if (!_scopeDictionary.ContainsKey(contextHash))
44+
{
45+
var tempScopeList = new List<string>();
46+
try
47+
{
48+
var instance = AzureSession.Instance;
49+
var client = instance.ClientFactory.CreateCustomArmClient<ResourceManagementClient>(
50+
context.Environment.GetEndpointAsUri(AzureEnvironment.Endpoint.ResourceManager),
51+
instance.AuthenticationFactory.GetServiceClientCredentials(context, AzureEnvironment.Endpoint.ResourceManager),
52+
instance.ClientFactory.GetCustomHandlers());
53+
client.SubscriptionId = context.Subscription.Id;
54+
// Retrieve only the first page of ResourceGroups to display to the user
55+
var resourceGroups = client.ResourceGroups.ListAsync();
56+
if (resourceGroups.Wait(TimeSpan.FromSeconds(_timeout)))
57+
{
58+
tempScopeList = CreateScopeList(resourceGroups.Result, context.Subscription.Id);
59+
_scopeDictionary[contextHash] = tempScopeList;
60+
}
61+
#if DEBUG
62+
else
63+
{
64+
throw new InvalidOperationException("client.ResourceGroups call timed out");
65+
}
66+
#endif
67+
}
68+
69+
catch (Exception ex)
70+
{
71+
if (ex == null) { }
72+
#if DEBUG
73+
throw ex;
74+
#endif
75+
}
76+
77+
return tempScopeList;
78+
}
79+
80+
else
81+
{
82+
return _scopeDictionary[contextHash];
83+
}
84+
}
85+
}
86+
}
87+
88+
public override string[] GetCompleterValues()
89+
{
90+
return GetScopes();
91+
}
92+
93+
public static string[] GetScopes(int timeout)
94+
{
95+
_timeout = timeout;
96+
return GetScopes();
97+
}
98+
99+
public static string[] GetScopes()
100+
{
101+
return Scopes.ToArray();
102+
}
103+
104+
private static ScriptBlock CreateScriptBlock()
105+
{
106+
string script = "param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)\n" +
107+
"$scopes = [Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters.ScopeCompleterAttribute]::GetScopes()\n" +
108+
"$scopes | Where-Object { $_ -Like \"$wordToComplete*\" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }";
109+
ScriptBlock scriptBlock = ScriptBlock.Create(script);
110+
return scriptBlock;
111+
}
112+
113+
private static int HashContext(IAzureContext context)
114+
{
115+
return (context.Account.Id + context.Environment.Name + context.Subscription.Id + context.Tenant.Id).GetHashCode();
116+
}
117+
118+
public static List<string> CreateScopeList(IPage<ResourceGroup> result, string subscriptionId)
119+
{
120+
var tempScopeList = new List<string> { string.Format("/subscriptions/{0}", subscriptionId) };
121+
if (result != null)
122+
{
123+
foreach (ResourceGroup resourceGroup in result)
124+
{
125+
tempScopeList.Add(string.Format("/subscriptions/{0}/resourceGroups/{1}", subscriptionId, resourceGroup.Name));
126+
}
127+
}
128+
#if DEBUG
129+
else
130+
{
131+
throw new Exception("Result from client.ResourceGroups is null");
132+
}
133+
#endif
134+
return tempScopeList;
135+
}
136+
}
137+
}

src/ResourceManager/Common/Commands.ResourceManager.Common/Commands.ResourceManager.Common.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
<ItemGroup>
5757
<Compile Include="AccessTokenExtensions.cs" />
5858
<Compile Include="ArgumentCompleters\PSArgumentCompleter.cs" />
59+
<Compile Include="ArgumentCompleters\ResourceTypeCompleter.cs" />
60+
<Compile Include="ArgumentCompleters\ScopeCompleter.cs" />
5961
<Compile Include="AzureRmCmdlet.cs" />
6062
<Compile Include="AzureRmLongRunningCmdlet.cs" />
6163
<Compile Include="Generated\DeploymentOperations.cs" />
@@ -117,8 +119,8 @@
117119
<Compile Include="Generated\Models\ManagementLockOwner.cs" />
118120
<Compile Include="Generated\Models\Page.cs" />
119121
<Compile Include="Generated\Models\Page1.cs" />
120-
<Compile Include="Generated\Models\PageEnumerable.cs" />
121-
<Compile Include="Generated\Models\PageEnumerator.cs" />
122+
<Compile Include="Paging\PageEnumerable.cs" />
123+
<Compile Include="Paging\PageEnumerator.cs" />
122124
<Compile Include="Generated\Models\ParametersLink.cs" />
123125
<Compile Include="Generated\Models\Plan.cs" />
124126
<Compile Include="Generated\Models\PolicyAssignment.cs" />

src/ResourceManager/Common/Commands.ResourceManager.Common/Generated/SubscriptionsOperationsExtensions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for
33
// license information.
4-
//
4+
//
55
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
66
// Changes may cause incorrect behavior and will be lost if the code is
77
// regenerated.
@@ -16,6 +16,7 @@ namespace Microsoft.Azure.Internal.Subscriptions
1616
using Microsoft.Rest;
1717
using Microsoft.Rest.Azure;
1818
using Models;
19+
using Commands.ResourceManager.Common.Paging;
1920

2021
/// <summary>
2122
/// Extension methods for SubscriptionsOperations.
@@ -167,9 +168,9 @@ public static IPage<Subscription> ListNext(this ISubscriptionsOperations operati
167168
/// <returns>
168169
/// PageEnumerable object containing all of the subscriptions for the given tenant used in the client.
169170
/// </returns>
170-
public static PageEnumerable ListAll(this ISubscriptionClient client)
171+
public static PageEnumerable<Subscription> ListAll(this ISubscriptionClient client)
171172
{
172-
return new PageEnumerable(client);
173+
return new PageEnumerable<Subscription>(client.Subscriptions.List, client.Subscriptions.ListNext, ulong.MaxValue, 0);
173174
}
174175
}
175176
}

0 commit comments

Comments
 (0)