Renaming ARMClient to ARMLib, changing auth behavior, adding ConfigureLogin and Query
This commit is contained in:
Родитель
7056b04214
Коммит
7182c14beb
|
@ -15,7 +15,7 @@ namespace ARMClient.Library.Runner
|
|||
|
||||
private static async Task Run()
|
||||
{
|
||||
var armClient = ARMClient.GetDynamicClient(apiVersion: "2014-04-01", authHelper: new AuthHelper(AzureEnvironments.Prod));
|
||||
var armClient = ARMLib.GetDynamicClient(apiVersion: "2014-11-01").ConfigureLogin(LoginType.Upn, "userName", "password");
|
||||
|
||||
var resrouceGroups = await armClient.Subscriptions["{subscriptionId}"]
|
||||
.ResourceGroups
|
||||
|
@ -31,7 +31,6 @@ namespace ARMClient.Library.Runner
|
|||
|
||||
if (sites.Length == 0)
|
||||
{
|
||||
Console.WriteLine("ResrouceGroup: {0} Doesn't contain any websites!", resrouceGroup.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ARMClient.cs" />
|
||||
<Compile Include="ARMLib.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,216 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ARMClient.Authentication;
|
||||
using ARMClient.Authentication.AADAuthentication;
|
||||
using ARMClient.Authentication.Contracts;
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
|
||||
namespace ARMClient.Library
|
||||
{
|
||||
public class ARMClient : DynamicObject
|
||||
{
|
||||
private string _url = null;
|
||||
private string _authorizationHeader;
|
||||
private readonly string _apiVersion;
|
||||
private readonly IAuthHelper _authHelper;
|
||||
private readonly AzureEnvironments _azureEnvironment;
|
||||
|
||||
public static dynamic GetDynamicClient(string apiVersion, IAuthHelper authHelper = null,
|
||||
AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
|
||||
{
|
||||
return new ARMClient(apiVersion, authHelper, azureEnvironment, url);
|
||||
}
|
||||
|
||||
private ARMClient(string apiVersion, IAuthHelper authHelper = null,
|
||||
AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
|
||||
{
|
||||
this._apiVersion = apiVersion;
|
||||
this._authHelper = authHelper ?? new AuthHelper(azureEnvironment);
|
||||
this._azureEnvironment = azureEnvironment;
|
||||
this._url = url ?? Constants.CSMUrls[(int)azureEnvironment];
|
||||
}
|
||||
|
||||
private ARMClient(string apiVersion, string authorizationHeader, string url)
|
||||
{
|
||||
this._authorizationHeader = authorizationHeader;
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
public async Task InitializeToken(string subscriptionId = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(subscriptionId))
|
||||
{
|
||||
var match = Regex.Match(_url, ".*\\/subscriptions\\/(.*?)\\/", RegexOptions.IgnoreCase);
|
||||
subscriptionId = match.Success ? match.Groups[1].ToString() : string.Empty;
|
||||
}
|
||||
|
||||
if (!this._authHelper.IsCacheValid())
|
||||
{
|
||||
await this._authHelper.AcquireTokens().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
TokenCacheInfo cacheInfo = await this._authHelper.GetToken(subscriptionId, Constants.CSMResource).ConfigureAwait(false);
|
||||
this._authorizationHeader = cacheInfo.CreateAuthorizationHeader();
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
return TryHandleDynamicCall(binder.Name, out result);
|
||||
}
|
||||
|
||||
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
|
||||
{
|
||||
return TryHandleDynamicCall(indexes[0].ToString(), out result);
|
||||
}
|
||||
|
||||
private bool TryHandleDynamicCall(string name, out object result)
|
||||
{
|
||||
var url = string.Format("{0}/{1}", _url, name);
|
||||
|
||||
result = string.IsNullOrEmpty(this._authorizationHeader)
|
||||
? new ARMClient(this._apiVersion, this._authHelper, this._azureEnvironment, url)
|
||||
: new ARMClient(this._apiVersion, this._authorizationHeader, url);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public T Get<T>()
|
||||
{
|
||||
return Task.Run(() => GetAsync<T>()).Result;
|
||||
}
|
||||
|
||||
public async Task<T> GetAsync<T>()
|
||||
{
|
||||
var httpResponse = await InvokeAsyncDynamicMember("Get", Enumerable.Empty<object>().ToArray());
|
||||
return await httpResponse.Content.ReadAsAsync<T>();
|
||||
}
|
||||
|
||||
public T Post<T>(params object[] args)
|
||||
{
|
||||
return Task.Run(() => PostAsync<T>(args)).Result;
|
||||
}
|
||||
|
||||
public async Task<T> PostAsync<T>(params object[] args)
|
||||
{
|
||||
var httpResponse = await InvokeAsyncDynamicMember("Post", args);
|
||||
return await httpResponse.Content.ReadAsAsync<T>();
|
||||
}
|
||||
|
||||
public T Put<T>(params object[] args)
|
||||
{
|
||||
return Task.Run(() => PutAsync<T>(args)).Result;
|
||||
}
|
||||
|
||||
public async Task<T> PutAsync<T>(params object[] args)
|
||||
{
|
||||
var httpResponse = await InvokeAsyncDynamicMember("Put", args);
|
||||
return await httpResponse.Content.ReadAsAsync<T>();
|
||||
}
|
||||
|
||||
public T Delete<T>()
|
||||
{
|
||||
return Task.Run(() => DeleteAsync<T>()).Result;
|
||||
}
|
||||
|
||||
public async Task<T> DeleteAsync<T>()
|
||||
{
|
||||
var httpResponse = await InvokeAsyncDynamicMember("Delete", Enumerable.Empty<object>().ToArray());
|
||||
return await httpResponse.Content.ReadAsAsync<T>();
|
||||
}
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
result = InvokeDynamicMember(binder.Name, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
private object InvokeDynamicMember(string memberName, object[] args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(this._authorizationHeader))
|
||||
{
|
||||
InitializeToken().Wait();
|
||||
}
|
||||
|
||||
var isAsync = memberName.EndsWith("async", StringComparison.OrdinalIgnoreCase);
|
||||
memberName = isAsync
|
||||
? memberName.Substring(0, memberName.IndexOf("async", StringComparison.OrdinalIgnoreCase))
|
||||
: memberName;
|
||||
|
||||
|
||||
|
||||
object result = HttpInvoke(memberName, args);
|
||||
|
||||
return isAsync ? result : Task.Run(() => (Task<HttpResponseMessage>)result).Result;
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> InvokeAsyncDynamicMember(string memberName, object[] args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_authorizationHeader))
|
||||
{
|
||||
await InitializeToken();
|
||||
}
|
||||
|
||||
if ((String.Equals(memberName, "get", StringComparison.OrdinalIgnoreCase)
|
||||
|| String.Equals(memberName, "delete", StringComparison.OrdinalIgnoreCase)
|
||||
|| String.Equals(memberName, "put", StringComparison.OrdinalIgnoreCase)
|
||||
|| String.Equals(memberName, "post", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return await HttpInvoke(memberName, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeBinderException(string.Format("'ARMClient' does not contain a http definition for '{0}'", memberName));
|
||||
}
|
||||
}
|
||||
|
||||
private Task<HttpResponseMessage> HttpInvoke(string httpVerb, object[] args)
|
||||
{
|
||||
var uri = string.Format("{0}?api-version={1}", this._url, this._apiVersion);
|
||||
return HttpInvoke(new Uri(uri), httpVerb, args.Length > 0 ? args[0].ToString() : string.Empty);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> HttpInvoke(Uri uri, string verb, string payload)
|
||||
{
|
||||
using (var client = new HttpClient(new HttpClientHandler()))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Authorization", this._authorizationHeader);
|
||||
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
|
||||
client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);
|
||||
client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.GetAsync(uri).ConfigureAwait(false);
|
||||
}
|
||||
else if (String.Equals(verb, "delete", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.DeleteAsync(uri).ConfigureAwait(false);
|
||||
}
|
||||
else if (String.Equals(verb, "post", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.PostAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
|
||||
}
|
||||
else if (String.Equals(verb, "put", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.PutAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Invalid http verb '{0}'!", verb));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ARMClient.Authentication;
|
||||
using ARMClient.Authentication.AADAuthentication;
|
||||
using ARMClient.Authentication.Contracts;
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ARMClient.Library
|
||||
{
|
||||
public class ARMLib : DynamicObject
|
||||
{
|
||||
private string _url = null;
|
||||
private TokenCacheInfo _tokenCacheInfo;
|
||||
private readonly string _apiVersion;
|
||||
private readonly IAuthHelper _authHelper;
|
||||
private readonly AzureEnvironments _azureEnvironment;
|
||||
private LoginType _loginType;
|
||||
private string _tenantId;
|
||||
private string _appId;
|
||||
private string _appKey;
|
||||
private string _userName;
|
||||
private string _password;
|
||||
private string _query;
|
||||
|
||||
public static dynamic GetDynamicClient(string apiVersion, AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
|
||||
{
|
||||
return new ARMLib(apiVersion, azureEnvironment, url);
|
||||
}
|
||||
|
||||
private ARMLib(string apiVersion, AzureEnvironments azureEnvironment, string url)
|
||||
{
|
||||
this._apiVersion = apiVersion;
|
||||
this._authHelper = new AuthHelper(azureEnvironment);
|
||||
this._azureEnvironment = azureEnvironment;
|
||||
this._url = url ?? Constants.CSMUrls[(int)azureEnvironment];
|
||||
this._query = string.Empty;
|
||||
}
|
||||
|
||||
private ARMLib(ARMLib oldClient, string url, string query)
|
||||
{
|
||||
this._loginType = oldClient._loginType;
|
||||
this._apiVersion = oldClient._apiVersion;
|
||||
this._appId = oldClient._appId;
|
||||
this._appKey = oldClient._appKey;
|
||||
this._authHelper = oldClient._authHelper;
|
||||
this._tokenCacheInfo = oldClient._tokenCacheInfo;
|
||||
this._azureEnvironment = oldClient._azureEnvironment;
|
||||
this._loginType = oldClient._loginType;
|
||||
this._password = oldClient._password;
|
||||
this._tenantId = oldClient._tenantId;
|
||||
this._userName = oldClient._userName;
|
||||
this._query = query;
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
return TryHandleDynamicCall(binder.Name.FirstLetterToLowerCase(), out result);
|
||||
}
|
||||
|
||||
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
|
||||
{
|
||||
return TryHandleDynamicCall(indexes[0].ToString(), out result);
|
||||
}
|
||||
|
||||
private bool TryHandleDynamicCall(string name, out object result)
|
||||
{
|
||||
var url = string.Format("{0}/{1}", _url, name);
|
||||
result = new ARMLib(this, url, this._query);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<T> GetAsync<T>()
|
||||
{
|
||||
var httpResponse = await HttpInvoke("Get", Enumerable.Empty<object>().ToArray()).ConfigureAwait(false);
|
||||
httpResponse.EnsureSuccessStatusCode();
|
||||
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<T> PostAsync<T>(params object[] args)
|
||||
{
|
||||
var httpResponse = await HttpInvoke("Post", args).ConfigureAwait(false);
|
||||
httpResponse.EnsureSuccessStatusCode();
|
||||
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<T> PutAsync<T>(params object[] args)
|
||||
{
|
||||
var httpResponse = await HttpInvoke("Put", args).ConfigureAwait(false);
|
||||
httpResponse.EnsureSuccessStatusCode();
|
||||
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<T> DeleteAsync<T>()
|
||||
{
|
||||
var httpResponse = await HttpInvoke("Delete", Enumerable.Empty<object>().ToArray()).ConfigureAwait(false);
|
||||
httpResponse.EnsureSuccessStatusCode();
|
||||
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
if (binder.Name.Equals("ConfigureLogin", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
this._loginType = (LoginType) args[0];
|
||||
switch (this._loginType)
|
||||
{
|
||||
case LoginType.Spn:
|
||||
this._tenantId = args[1].ToString();
|
||||
this._appId = args[2].ToString();
|
||||
this._appKey = args[3].ToString();
|
||||
break;
|
||||
case LoginType.Upn:
|
||||
this._userName = args[1].ToString();
|
||||
this._password = args[2].ToString();
|
||||
break;
|
||||
}
|
||||
result = this;
|
||||
}
|
||||
else if (binder.Name.Equals("Query", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var query = this._query + "&" + args[0];
|
||||
result = new ARMLib(this, this._url, query);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = InvokeDynamicMember(binder.Name, args);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private object InvokeDynamicMember(string memberName, object[] args)
|
||||
{
|
||||
var isAsync = memberName.EndsWith("async", StringComparison.OrdinalIgnoreCase);
|
||||
memberName = isAsync
|
||||
? memberName.Substring(0, memberName.IndexOf("async", StringComparison.OrdinalIgnoreCase))
|
||||
: memberName;
|
||||
return HttpInvoke(memberName, args);
|
||||
}
|
||||
|
||||
private Task<HttpResponseMessage> HttpInvoke(string httpVerb, object[] args)
|
||||
{
|
||||
var uri = string.Format("{0}?api-version={1}{2}", this._url, this._apiVersion, this._query);
|
||||
return HttpInvoke(new Uri(uri), httpVerb, args.Length > 0 ? args[0] : string.Empty);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> HttpInvoke(Uri uri, string verb, object objectPayload)
|
||||
{
|
||||
var payload = JsonConvert.SerializeObject(objectPayload);
|
||||
using (var client = new HttpClient(new HttpClientHandler()))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Authorization", await GetAuthorizationHeader());
|
||||
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
|
||||
client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);
|
||||
client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.GetAsync(uri).ConfigureAwait(false);
|
||||
}
|
||||
else if (String.Equals(verb, "delete", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.DeleteAsync(uri).ConfigureAwait(false);
|
||||
}
|
||||
else if (String.Equals(verb, "post", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.PostAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
|
||||
}
|
||||
else if (String.Equals(verb, "put", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
response = await client.PutAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Invalid http verb '{0}'!", verb));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> GetAuthorizationHeader()
|
||||
{
|
||||
var match = Regex.Match(_url, ".*\\/subscriptions\\/(.*?)\\/", RegexOptions.IgnoreCase);
|
||||
var subscriptionId = match.Success ? match.Groups[1].ToString() : null;
|
||||
|
||||
if (this._tokenCacheInfo == null || this._tokenCacheInfo.ExpiresOn <= DateTimeOffset.UtcNow)
|
||||
{
|
||||
switch (this._loginType)
|
||||
{
|
||||
case LoginType.Interactive:
|
||||
await this._authHelper.AcquireTokens().ConfigureAwait(false);
|
||||
|
||||
break;
|
||||
case LoginType.Spn:
|
||||
await this._authHelper.GetTokenBySpn(this._tenantId, this._appId, this._appKey).ConfigureAwait(false);
|
||||
break;
|
||||
case LoginType.Upn:
|
||||
await this._authHelper.GetTokenByUpn(this._userName, this._password).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
this._tokenCacheInfo = await this._authHelper.GetToken(subscriptionId, Constants.CSMResource).ConfigureAwait(false);
|
||||
}
|
||||
return this._tokenCacheInfo.CreateAuthorizationHeader();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class StringExtension
|
||||
{
|
||||
public static string FirstLetterToLowerCase(this string value)
|
||||
{
|
||||
return Char.ToLowerInvariant(value[0]) + value.Substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
public enum LoginType
|
||||
{
|
||||
Upn,
|
||||
Spn,
|
||||
Interactive
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче