From ebfa508db52d9611dbb43669b1ac5d7bfb120f31 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Fri, 13 Oct 2017 22:30:17 -0700 Subject: [PATCH] AzureObject, ResourceGroupObject, VirtualNetworkObject. --- .../AuthenticationResponse.cs | 8 ++ .../Azure.Experiments.Tests.csproj | 7 +- .../Azure.Experiments.Tests/ComputeTest.cs | 83 ++++------------- .../Azure.Experiments.Tests/Configuration.cs | 10 +++ .../Azure.Experiments.Tests/Credentials.cs | 16 ++++ .../Azure.Experiments.Tests/TokenProvider.cs | 54 ++++++++++++ .../Azure.Experiments.csproj | 2 + .../Azure.Experiments/AzureObject.cs | 88 +++++++++++++++++++ .../Azure.Experiments/AzureResource.cs | 27 ++++++ .../Azure.Experiments/Context.cs | 17 ++++ .../Azure.Experiments/ResourceGroupObject.cs | 34 +++++++ .../Azure.Experiments/VirtualNetworkObject.cs | 46 ++++++++++ 12 files changed, 325 insertions(+), 67 deletions(-) create mode 100644 experiments/Azure.Experiments/Azure.Experiments.Tests/AuthenticationResponse.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments.Tests/Configuration.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments.Tests/Credentials.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments.Tests/TokenProvider.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments/AzureObject.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments/AzureResource.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments/Context.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments/ResourceGroupObject.cs create mode 100644 experiments/Azure.Experiments/Azure.Experiments/VirtualNetworkObject.cs diff --git a/experiments/Azure.Experiments/Azure.Experiments.Tests/AuthenticationResponse.cs b/experiments/Azure.Experiments/Azure.Experiments.Tests/AuthenticationResponse.cs new file mode 100644 index 000000000000..e570fac03049 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments.Tests/AuthenticationResponse.cs @@ -0,0 +1,8 @@ +namespace Azure.Experiments.Tests +{ + internal sealed class AuthenticationResponse + { + public string token_type; + public string access_token; + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments.Tests/Azure.Experiments.Tests.csproj b/experiments/Azure.Experiments/Azure.Experiments.Tests/Azure.Experiments.Tests.csproj index 7a0f172a554c..dfed5b47f9c4 100644 --- a/experiments/Azure.Experiments/Azure.Experiments.Tests/Azure.Experiments.Tests.csproj +++ b/experiments/Azure.Experiments/Azure.Experiments.Tests/Azure.Experiments.Tests.csproj @@ -7,9 +7,10 @@ - - - + + + + diff --git a/experiments/Azure.Experiments/Azure.Experiments.Tests/ComputeTest.cs b/experiments/Azure.Experiments/Azure.Experiments.Tests/ComputeTest.cs index 8c50221277b7..0a846b7f727e 100644 --- a/experiments/Azure.Experiments/Azure.Experiments.Tests/ComputeTest.cs +++ b/experiments/Azure.Experiments/Azure.Experiments.Tests/ComputeTest.cs @@ -1,83 +1,38 @@ -using Microsoft.Rest; using Xunit; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; -using System.Net.Http; -using System; -using System.IO; -using Newtonsoft.Json; using Microsoft.Azure.Management.Compute; namespace Azure.Experiments.Tests { public class ComputeTest { - sealed class TokenProvider : ITokenProvider - { - public TokenProvider(Configuration c) - { - var parameters = new[] - { - KeyValuePair.Create("grant_type", "client_credentials"), - KeyValuePair.Create("client_id", c.applicationId), - KeyValuePair.Create("client_secret", c.clientSecret), - KeyValuePair.Create("resource", "https://management.core.windows.net/") - }; - Content = new FormUrlEncodedContent(parameters); - Uri = new Uri("https://login.microsoftonline.com/" + c.tenantId + "/oauth2/token"); - } - - public async Task GetAuthenticationHeaderAsync( - CancellationToken cancellationToken) - { - if (Header == null) - { - using (var client = new HttpClient()) - { - var response = await client - .PostAsync(Uri, Content) - .Result - .Content - .ReadAsStringAsync(); - var responseObject = JsonConvert.DeserializeObject( - response); - Header = new AuthenticationHeaderValue( - responseObject.token_type, responseObject.access_token); - } - } - return Header; - } - - private Uri Uri { get; } - - private FormUrlEncodedContent Content { get; } - - private AuthenticationHeaderValue Header { get; set; } - } - - private sealed class AuthenticationResponse + [Fact] + public async void ResourceGroupTest() { - public string token_type; - public string access_token; + var c = Credentials.Get(); + var rg = new ResourceGroupObject("My"); + var info = await rg.GetOrNullAsync(c); + var infoCreate = await rg.GetOrCreateAsync(c); + // await rg.DeleteAsync(c); } - private sealed class Configuration + [Fact] + public async void VirtualNetworkTest() { - public string applicationId; - public string tenantId; - public string clientSecret; - public string subscriptionId; + var c = Credentials.Get(); + var rg = new ResourceGroupObject("My1"); + var vn = new VirtualNetworkObject("My1", rg, "192.168.0.0/16"); + var info = await vn.GetOrNullAsync(c); + var infoCreate = await vn.GetOrCreateAsync(c); } [Fact] public async void Test1() { - var text = File.ReadAllText(@"c:\Users\sergey\Desktop\php-test.json"); - var c = JsonConvert.DeserializeObject(text); - var credentials = new TokenCredentials(new TokenProvider(c)); - var client = new ComputeManagementClient(credentials); - client.SubscriptionId = c.subscriptionId; + var c = Credentials.Get(); + var client = new ComputeManagementClient(c.Credentials) + { + SubscriptionId = c.SubscriptionId + }; var list = await client.VirtualMachines.ListAllAsync(); } } diff --git a/experiments/Azure.Experiments/Azure.Experiments.Tests/Configuration.cs b/experiments/Azure.Experiments/Azure.Experiments.Tests/Configuration.cs new file mode 100644 index 000000000000..1fc17c306c4e --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments.Tests/Configuration.cs @@ -0,0 +1,10 @@ +namespace Azure.Experiments.Tests +{ + internal sealed class Configuration + { + public string applicationId; + public string tenantId; + public string clientSecret; + public string subscriptionId; + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments.Tests/Credentials.cs b/experiments/Azure.Experiments/Azure.Experiments.Tests/Credentials.cs new file mode 100644 index 000000000000..33de6fb084e0 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments.Tests/Credentials.cs @@ -0,0 +1,16 @@ +using Microsoft.Rest; +using Newtonsoft.Json; +using System.IO; + +namespace Azure.Experiments.Tests +{ + internal static class Credentials + { + public static Context Get() + { + var text = File.ReadAllText(@"c:\Users\sergey\Desktop\php-test.json"); + var c = JsonConvert.DeserializeObject(text); + return new Context(new TokenCredentials(new TokenProvider(c)), c.subscriptionId); + } + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments.Tests/TokenProvider.cs b/experiments/Azure.Experiments/Azure.Experiments.Tests/TokenProvider.cs new file mode 100644 index 000000000000..d3839cebc64e --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments.Tests/TokenProvider.cs @@ -0,0 +1,54 @@ +using Microsoft.Rest; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Http; +using System; +using Newtonsoft.Json; + +namespace Azure.Experiments.Tests +{ + sealed class TokenProvider : ITokenProvider + { + public TokenProvider(Configuration c) + { + var parameters = new[] + { + KeyValuePair.Create("grant_type", "client_credentials"), + KeyValuePair.Create("client_id", c.applicationId), + KeyValuePair.Create("client_secret", c.clientSecret), + KeyValuePair.Create("resource", "https://management.core.windows.net/") + }; + Content = new FormUrlEncodedContent(parameters); + Uri = new Uri("https://login.microsoftonline.com/" + c.tenantId + "/oauth2/token"); + } + + public async Task GetAuthenticationHeaderAsync( + CancellationToken cancellationToken) + { + if (Header == null) + { + using (var client = new HttpClient()) + { + var response = await client + .PostAsync(Uri, Content) + .Result + .Content + .ReadAsStringAsync(); + var responseObject = JsonConvert.DeserializeObject( + response); + Header = new AuthenticationHeaderValue( + responseObject.token_type, + responseObject.access_token); + } + } + return Header; + } + + private Uri Uri { get; } + + private FormUrlEncodedContent Content { get; } + + private AuthenticationHeaderValue Header { get; set; } + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments/Azure.Experiments.csproj b/experiments/Azure.Experiments/Azure.Experiments/Azure.Experiments.csproj index 9febd4410874..0349dbc31893 100644 --- a/experiments/Azure.Experiments/Azure.Experiments/Azure.Experiments.csproj +++ b/experiments/Azure.Experiments/Azure.Experiments/Azure.Experiments.csproj @@ -6,6 +6,8 @@ + + diff --git a/experiments/Azure.Experiments/Azure.Experiments/AzureObject.cs b/experiments/Azure.Experiments/Azure.Experiments/AzureObject.cs new file mode 100644 index 000000000000..bfa530174b78 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/AzureObject.cs @@ -0,0 +1,88 @@ +using Microsoft.Rest.Azure; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace Azure.Experiments +{ + public abstract class AzureObject + { + public static IEnumerable NoDependencies { get; } + = Enumerable.Empty(); + + public string Name { get; } + + public IEnumerable Dependencies { get; } + + public abstract Task CheckOrCreateAsync(Context c); + + protected AzureObject(string name, IEnumerable dependencies) + { + Name = name; + Dependencies = dependencies; + } + } + + public abstract class AzureObject : AzureObject + where T: class + { + public async Task GetOrNullAsync(Context c) + { + if (!IsGetCalled) + { + IsGetCalled = true; + try + { + Info = await GetOrThrowAsync(CreateClient(c)); + } + catch (CloudException e) + when (e.Response.StatusCode == HttpStatusCode.NotFound) + { + } + } + return Info; + } + + public async Task GetOrCreateAsync(Context c) + { + Info = await GetOrNullAsync(c); + if (Info == null) + { + // this can be optimized by using WaitForAll and a state + // machine for `Task Info`. The state machine is required to + // avoid multiple creations of the same resource group. + foreach (var d in Dependencies) + { + await d.CheckOrCreateAsync(c); + } + Info = await CreateAsync(CreateClient(c)); + } + return Info; + } + + public Task DeleteAsync(Context c) + => DeleteAsync(CreateClient(c)); + + public override Task CheckOrCreateAsync(Context c) + => GetOrCreateAsync(c); + + protected AzureObject(string name, IEnumerable dependencies) + : base(name, dependencies) + { + } + + protected abstract C CreateClient(Context c); + + protected abstract Task GetOrThrowAsync(C c); + + protected abstract Task CreateAsync(C c); + + protected abstract Task DeleteAsync(C c); + + private bool IsGetCalled; + + private T Info; + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments/AzureResource.cs b/experiments/Azure.Experiments/Azure.Experiments/AzureResource.cs new file mode 100644 index 000000000000..1bb5769485a2 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/AzureResource.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Azure.Experiments +{ + public abstract class AzureResource : AzureObject + where T : class + { + protected string ResourceGroupName { get; } + + protected AzureResource( + string name, + ResourceGroupObject rg, + IEnumerable dependencies) + : base(name, dependencies.Concat(new[] { rg })) + { + ResourceGroupName = rg.Name; + } + + protected AzureResource( + string name, + ResourceGroupObject rg) + : this(name, rg, Enumerable.Empty()) + { + } + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments/Context.cs b/experiments/Azure.Experiments/Azure.Experiments/Context.cs new file mode 100644 index 000000000000..5b6807dce32e --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/Context.cs @@ -0,0 +1,17 @@ +using Microsoft.Rest; + +namespace Azure.Experiments +{ + public class Context + { + public Context(ServiceClientCredentials credentials, string subscriptionId) + { + Credentials = credentials; + SubscriptionId = subscriptionId; + } + + public ServiceClientCredentials Credentials { get; } + + public string SubscriptionId { get; } + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments/ResourceGroupObject.cs b/experiments/Azure.Experiments/Azure.Experiments/ResourceGroupObject.cs new file mode 100644 index 000000000000..5afafde9fa46 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/ResourceGroupObject.cs @@ -0,0 +1,34 @@ +using System.Linq; +using Microsoft.Azure.Management.ResourceManager.Models; +using Microsoft.Azure.Management.ResourceManager; +using System.Threading.Tasks; + +namespace Azure.Experiments +{ + public sealed class ResourceGroupObject : AzureObject< + ResourceGroup, IResourceGroupsOperations> + { + public ResourceGroupObject(string name) + : base(name, NoDependencies) + { + } + + protected override IResourceGroupsOperations CreateClient(Context c) + => new ResourceManagementClient(c.Credentials) + { + SubscriptionId = c.SubscriptionId + } + .ResourceGroups; + + protected override Task CreateAsync(IResourceGroupsOperations c) + => c.CreateOrUpdateAsync( + Name, + new ResourceGroup { Location = "eastus" }); + + protected override Task GetOrThrowAsync(IResourceGroupsOperations c) + => c.GetAsync(Name); + + protected override Task DeleteAsync(IResourceGroupsOperations c) + => c.DeleteAsync(Name); + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments/VirtualNetworkObject.cs b/experiments/Azure.Experiments/Azure.Experiments/VirtualNetworkObject.cs new file mode 100644 index 000000000000..d088a1e22d96 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/VirtualNetworkObject.cs @@ -0,0 +1,46 @@ +using Microsoft.Azure.Management.Network; +using Microsoft.Azure.Management.Network.Models; +using System.Threading.Tasks; + +namespace Azure.Experiments +{ + public sealed class VirtualNetworkObject : + AzureResource + { + public VirtualNetworkObject( + string name, + ResourceGroupObject rg, + string addressPrefix) + : base(name, rg, NoDependencies) + { + AddressPrefix = addressPrefix; + } + + protected override Task CreateAsync(IVirtualNetworksOperations c) + => c.CreateOrUpdateAsync( + ResourceGroupName, + Name, + new VirtualNetwork + { + Location = "eastus", + AddressSpace = new AddressSpace + { + AddressPrefixes = new[] { AddressPrefix } + } + }); + + protected override IVirtualNetworksOperations CreateClient(Context c) + => new NetworkManagementClient(c.Credentials) + { SubscriptionId = c.SubscriptionId } + .VirtualNetworks; + + protected override Task DeleteAsync(IVirtualNetworksOperations c) + => c.DeleteAsync(ResourceGroupName, Name); + + protected override Task GetOrThrowAsync( + IVirtualNetworksOperations c) + => c.GetAsync(ResourceGroupName, Name); + + private string AddressPrefix { get; } + } +}