Port Azure code from SSDT to the tools service (#477)

Porting of the vast majority of Azure-related code from SSDT. This is very large, so I want to put this out as one large "lift and shift" PR before I do the tools-service specific JSON-RPC service handlers, connect a new account handler (as the code to get necessary info from accounts and subscriptions isn't fully complete) and add tests over these

**What's in this PR**:

- Created 3 new projects:
  - Microsoft.SqlTools.ResourceProvider will host the executable that accepts requests for Azure-related actions over the JSON-RPC protocol. This must be separate from other DLLs since a direct dependency on the Azure SDK DLLs fails (they're NetStandard 1.4 and you can't reference them if you have RuntimeIdentifiers in your .csproj file)
  - Microsoft.SqlTools.ResourceProvider.Core is where all the main business logic is, including definitions and logic on how to navigate over resources and create firewall rules, etc.
  - Microsoft.SqlTools.ResourceProvider.DefaultImpl is the actual Azure implementation of the resource provider APIs. The reason for separating this is to support eventual integration back into other tools (since their Azure and Identity services will be different).
- Implemented the AzureResourceManager that connects to Azure via ARM APIs and handles creating firewall rule and querying databases. The dependent DLLs have had major breaking changes, so will need additional verification to ensure this works as expected
- Ported the unit tests for all code that was not a viewmodel. Viewmodel test code will be ported in a future update as we plumb through a service-equivalent to these. Also, the DependencyManager code which has overlap with our service provider code is commented out. Will work to uncomment in a future update as it has value to test some scenarios

**What's not in this PR**:
- Identity Services. We currently just have a stub for the interface, and even that will likely change a little
- anything JSON-RPC or registered service related. These will be adapted from the viewmodels and added in a separate PR
This commit is contained in:
Kevin Cunnane
2017-10-04 12:37:20 -07:00
committed by GitHub
parent 98f7e59f1a
commit ac64ac063b
108 changed files with 8181 additions and 21 deletions

View File

@@ -0,0 +1,81 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Net;
using System.Runtime.Serialization;
using Microsoft.SqlTools.ResourceProvider.Core;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Exception to be raised if azure resource manager operation fails
/// </summary>
public class AzureResourceFailedException : ServiceExceptionBase
{
/// <summary>
/// Initializes a new instance of the AuthenticationFailedException class.
/// </summary>
public AzureResourceFailedException()
{
}
/// <summary>
/// Initializes a new instance of the AuthenticationFailedException class with a specified error message.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param>
public AzureResourceFailedException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the AuthenticationFailedException class with a specified error message.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param>
/// <param name="httpStatusCode">The Http error code. </param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified</param>
public AzureResourceFailedException(string message, HttpStatusCode httpStatusCode, Exception innerException = null)
: base(message, httpStatusCode, innerException)
{
}
/// <summary>
/// Initializes a new instance of the AuthenticationFailedException class with a specified error message.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param>
/// <param name="httpStatusCode">The Http error code. </param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified</param>
public AzureResourceFailedException(string message, int httpStatusCode, Exception innerException = null)
: base(message, httpStatusCode, innerException)
{
}
/// <summary>
/// Initializes a new instance of the AuthenticationFailedException class with a specified error message
/// and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified</param>
public AzureResourceFailedException(string message, Exception innerException)
: base(message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the AuthenticationFailedException class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
public AzureResourceFailedException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

View File

@@ -0,0 +1,93 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Azure.Management.ResourceManager;
using Microsoft.Azure.Management.Sql;
using Microsoft.SqlTools.ResourceProvider.Core;
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// VS session used by <see cref="AzureResourceManager" />.
/// Includes all the clients that the resource management needs to get ther resources
/// </summary>
public class AzureResourceManagementSession : IAzureResourceManagementSession
{
/// <summary>
/// Creates the new session for given clients
/// </summary>
/// <param name="sqlManagementClient">Sql Management Client</param>
/// <param name="resourceManagementClient">Resource Management Client</param>
/// <param name="subscriptionContext">Subscription Context</param>
public AzureResourceManagementSession(SqlManagementClient sqlManagementClient,
ResourceManagementClient resourceManagementClient,
IAzureUserAccountSubscriptionContext subscriptionContext)
{
SqlManagementClient = sqlManagementClient;
ResourceManagementClient = resourceManagementClient;
SubscriptionContext = subscriptionContext;
}
/// <summary>
/// Disposes the session
/// </summary>
public void Dispose()
{
CloseSession();
}
/// <summary>
/// Closes the session by disposing the clients
/// </summary>
/// <returns></returns>
public bool CloseSession()
{
try
{
if (ResourceManagementClient != null)
{
ResourceManagementClient.Dispose();
}
if (SqlManagementClient != null)
{
SqlManagementClient.Dispose();
}
return true;
}
catch (Exception)
{
//TODO: trace
return false;
}
}
/// <summary>
/// Subscription Context
/// </summary>
public IAzureUserAccountSubscriptionContext SubscriptionContext
{
get;
set;
}
/// <summary>
/// Resource Management Client
/// </summary>
public ResourceManagementClient ResourceManagementClient
{
get; set;
}
/// <summary>
/// Sql Management Client
/// </summary>
public SqlManagementClient SqlManagementClient
{
get; set;
}
}
}

View File

@@ -0,0 +1,258 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Management.ResourceManager;
using Microsoft.Azure.Management.ResourceManager.Models;
using Microsoft.Azure.Management.Sql;
using Microsoft.Azure.Management.Sql.Models;
using RestFirewallRule = Microsoft.Azure.Management.Sql.Models.FirewallRule;
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
using Microsoft.SqlTools.ResourceProvider.Core.FirewallRule;
using Microsoft.SqlTools.ResourceProvider.Core.Extensibility;
using Microsoft.SqlTools.Utility;
using Microsoft.Rest;
using System.Globalization;
using Microsoft.Rest.Azure;
using Microsoft.SqlTools.ResourceProvider.Core;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Default implementation for <see cref="IAzureResourceManager" />
/// Provides functionality to get azure resources by making Http request to the Azure REST API
/// </summary>
[Exportable(
ServerTypes.SqlServer,
Categories.Azure,
typeof(IAzureResourceManager),
"Microsoft.SqlServer.ConnectionServices.Azure.Impl.VsAzureResourceManager",
1)
]
public class AzureResourceManager : ExportableBase, IAzureResourceManager
{
private readonly Uri _resourceManagementUri = new Uri("https://management.azure.com/");
public AzureResourceManager()
{
// Duplicate the exportable attribute as at present we do not support filtering using extensiondescriptor.
// The attribute is preserved in order to simplify ability to backport into existing tools
Metadata = new ExportableMetadata(
ServerTypes.SqlServer,
Categories.Azure,
"Microsoft.SqlServer.ConnectionServices.Azure.Impl.VsAzureResourceManager");
}
public async Task<IAzureResourceManagementSession> CreateSessionAsync(IAzureUserAccountSubscriptionContext subscriptionContext)
{
CommonUtil.CheckForNull(subscriptionContext, "subscriptionContext");
try
{
ServiceClientCredentials credentials = await CreateCredentialsAsync(subscriptionContext);
SqlManagementClient sqlManagementClient = new SqlManagementClient(_resourceManagementUri, credentials);
ResourceManagementClient resourceManagementClient = new ResourceManagementClient(_resourceManagementUri, credentials);
return new AzureResourceManagementSession(sqlManagementClient, resourceManagementClient, subscriptionContext);
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error, string.Format(CultureInfo.CurrentCulture, "Failed to get databases {0}", ex));
throw;
}
}
/// <summary>
/// Returns a list of azure databases given subscription resource group name and server name
/// </summary>
/// <param name="azureResourceManagementSession">Subscription Context which includes credentials to use in the resource manager</param>
/// <param name="resourceGroupName">Resource Group Name</param>
/// <param name="serverName">Server name</param>
/// <returns>The list of databases</returns>
public async Task<IEnumerable<IAzureResource>> GetAzureDatabasesAsync(
IAzureResourceManagementSession azureResourceManagementSession,
string resourceGroupName,
string serverName)
{
CommonUtil.CheckForNull(azureResourceManagementSession, "azureResourceManagerSession");
try
{
AzureResourceManagementSession vsAzureResourceManagementSession = azureResourceManagementSession as AzureResourceManagementSession;
if (vsAzureResourceManagementSession != null)
{
try
{
IEnumerable<Database> databaseListResponse = await vsAzureResourceManagementSession.SqlManagementClient.Databases.ListByServerAsync(resourceGroupName, serverName);
return databaseListResponse.Select(
x => new AzureResourceWrapper(x) { ResourceGroupName = resourceGroupName });
}
catch(HttpOperationException ex)
{
throw new AzureResourceFailedException(SR.FailedToGetAzureDatabasesErrorMessage, ex.Response.StatusCode);
}
}
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error, string.Format(CultureInfo.CurrentCulture, "Failed to get databases {0}", ex.Message));
throw;
}
return null;
}
/// <summary>
/// Returns a list of azure servers given subscription
/// </summary>
/// <param name="azureResourceManagementSession">Subscription Context which includes credentials to use in the resource manager</param>
/// <returns>The list of Sql server resources</returns>
public async Task<IEnumerable<IAzureSqlServerResource>> GetSqlServerAzureResourcesAsync(
IAzureResourceManagementSession azureResourceManagementSession)
{
CommonUtil.CheckForNull(azureResourceManagementSession, "azureResourceManagerSession");
List<IAzureSqlServerResource> sqlServers = new List<IAzureSqlServerResource>();
try
{
AzureResourceManagementSession vsAzureResourceManagementSession = azureResourceManagementSession as AzureResourceManagementSession;
if(vsAzureResourceManagementSession != null)
{
IEnumerable<ResourceGroup> resourceGroupNames = await GetResourceGroupsAsync(vsAzureResourceManagementSession);
if (resourceGroupNames != null)
{
foreach (ResourceGroup resourceGroupExtended in resourceGroupNames)
{
try
{
IServersOperations serverOperations = vsAzureResourceManagementSession.SqlManagementClient.Servers;
IPage<Server> servers = await serverOperations.ListByResourceGroupAsync(resourceGroupExtended.Name);
if (servers != null)
{
sqlServers.AddRange(servers.Select(x =>
new SqlAzureResource(x) { ResourceGroupName = resourceGroupExtended.Name }));
}
}
catch (HttpOperationException ex)
{
throw new AzureResourceFailedException(SR.FailedToGetAzureSqlServersErrorMessage, ex.Response.StatusCode);
}
}
}
}
}
catch(Exception ex)
{
TraceException(TraceEventType.Error, (int) TraceId.AzureResource, ex, "Failed to get servers");
throw;
}
return sqlServers;
}
public async Task<FirewallRuleResponse> CreateFirewallRuleAsync(
IAzureResourceManagementSession azureResourceManagementSession,
IAzureSqlServerResource azureSqlServer,
FirewallRuleRequest firewallRuleRequest)
{
CommonUtil.CheckForNull(azureResourceManagementSession, "azureResourceManagerSession");
CommonUtil.CheckForNull(firewallRuleRequest, "firewallRuleRequest");
CommonUtil.CheckForNull(azureSqlServer, "azureSqlServer");
try
{
AzureResourceManagementSession vsAzureResourceManagementSession = azureResourceManagementSession as AzureResourceManagementSession;
if (vsAzureResourceManagementSession != null)
{
try
{
var firewallRule = new RestFirewallRule()
{
EndIpAddress = firewallRuleRequest.EndIpAddress.ToString(),
StartIpAddress = firewallRuleRequest.StartIpAddress.ToString()
};
IFirewallRulesOperations firewallRuleOperations = vsAzureResourceManagementSession.SqlManagementClient.FirewallRules;
var firewallRuleResponse = await firewallRuleOperations.CreateOrUpdateAsync(
azureSqlServer.ResourceGroupName,
azureSqlServer.Name,
firewallRuleRequest.FirewallRuleName,
firewallRule);
return new FirewallRuleResponse()
{
StartIpAddress = firewallRuleResponse.StartIpAddress,
EndIpAddress = firewallRuleResponse.EndIpAddress,
Created = true
};
}
catch (HttpOperationException ex)
{
throw new AzureResourceFailedException(SR.FirewallRuleCreationFailed, ex.Response.StatusCode);
}
}
// else respond with failure case
return new FirewallRuleResponse()
{
Created = false
};
}
catch (Exception ex)
{
TraceException(TraceEventType.Error, (int) TraceId.AzureResource, ex, "Failed to get databases");
throw;
}
}
/// <summary>
/// Returns the azure resource groups for given subscription
/// </summary>
private async Task<IEnumerable<ResourceGroup>> GetResourceGroupsAsync(AzureResourceManagementSession vsAzureResourceManagementSession)
{
try
{
if (vsAzureResourceManagementSession != null)
{
try
{
IResourceGroupsOperations resourceGroupOperations = vsAzureResourceManagementSession.ResourceManagementClient.ResourceGroups;
IPage<ResourceGroup> resourceGroupList = await resourceGroupOperations.ListAsync();
if (resourceGroupList != null)
{
return resourceGroupList.AsEnumerable();
}
}
catch (HttpOperationException ex)
{
throw new AzureResourceFailedException(SR.FailedToGetAzureResourceGroupsErrorMessage, ex.Response.StatusCode);
}
}
return Enumerable.Empty<ResourceGroup>();
}
catch (Exception ex)
{
TraceException(TraceEventType.Error, (int)TraceId.AzureResource, ex, "Failed to get azure resource groups");
throw;
}
}
/// <summary>
/// Creates credential instance for given subscription
/// </summary>
private Task<ServiceClientCredentials> CreateCredentialsAsync(IAzureUserAccountSubscriptionContext subscriptionContext)
{
AzureUserAccountSubscriptionContext azureUserSubContext =
subscriptionContext as AzureUserAccountSubscriptionContext;
if (azureUserSubContext != null)
{
return Task.FromResult(azureUserSubContext.Credentials);
}
throw new NotSupportedException("This uses an unknown subscription type");
}
}
}

View File

@@ -0,0 +1,103 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Azure.Management.Sql.Models;
using Microsoft.SqlTools.ResourceProvider.Core;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureResource" /> using VS services.
/// Provides information about an Azure resource
/// </summary>
public class AzureResourceWrapper : IAzureResource
{
/// <summary>
/// Initializes the resource
/// </summary>
public AzureResourceWrapper(TrackedResource azureResource)
{
CommonUtil.CheckForNull(azureResource, nameof(azureResource));
AzureResource = azureResource;
}
/// <summary>
/// Resource name
/// </summary>
public string Name
{
get
{
return AzureResource != null ? AzureResource.Name : string.Empty;
}
set
{
throw new NotSupportedException();
}
}
/// <summary>
/// Resource type
/// </summary>
public string Type
{
get
{
return AzureResource != null ? AzureResource.Type : string.Empty;
}
set
{
throw new NotSupportedException();
}
}
/// <summary>
/// Resource id
/// </summary>
public string Id
{
get
{
return AzureResource != null ? AzureResource.Id : string.Empty;
}
set
{
throw new NotSupportedException();
}
}
/// <summary>
/// Resource Group Name
/// </summary>
public string ResourceGroupName { get; set; }
/// <summary>
/// Resource Location
/// </summary>
public string Location
{
get
{
return AzureResource != null ? AzureResource.Location : string.Empty;
}
set
{
if (AzureResource != null)
{
AzureResource.Location = value;
}
}
}
/// <summary>
/// The resource wrapped by this class
/// </summary>
protected TrackedResource AzureResource
{
get;
set;
}
}
}

View File

@@ -0,0 +1,56 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureSubscriptionContext" /> using VS services
/// Contains information about an Azure subscription
/// </summary>
public class AzureSubscriptionContext : IAzureSubscriptionContext
{
private readonly IAzureSubscriptionIdentifier _azureSubscriptionIdentifier;
/// <summary>
/// Default constructor to initialize the subscription
/// </summary>
public AzureSubscriptionContext(IAzureSubscriptionIdentifier azureSubscriptionIdentifier)
{
_azureSubscriptionIdentifier = azureSubscriptionIdentifier;
}
/// <summary>
/// Returns true if given subscription equals this class
/// </summary>
public bool Equals(IAzureSubscriptionContext other)
{
return (other == null && Subscription == null) || (other != null && other.Subscription.Equals(Subscription));
}
/// <summary>
/// Returns the wraper for the subscription identifier
/// </summary>
public IAzureSubscriptionIdentifier Subscription
{
get
{
return _azureSubscriptionIdentifier;
}
}
/// <summary>
/// Returns subscription name
/// </summary>
public string SubscriptionName
{
get
{
return _azureSubscriptionIdentifier != null ?
_azureSubscriptionIdentifier.SubscriptionId : string.Empty;
}
}
}
}

View File

@@ -0,0 +1,61 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.SqlTools.ResourceProvider.Core;
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureSubscriptionIdentifier" />
/// Contains information about an Azure subscription identifier
/// </summary>
public class AzureSubscriptionIdentifier : IAzureSubscriptionIdentifier
{
/// <summary>
/// Default constructor to initialize the subscription identifier
/// </summary>
public AzureSubscriptionIdentifier(IAzureUserAccount userAccount, string subscriptionId, Uri serviceManagementEndpoint)
{
UserAccount = userAccount;
SubscriptionId = subscriptionId;
ServiceManagementEndpoint = serviceManagementEndpoint;
}
/// <summary>
/// Returns true if given subscription identifier equals this class
/// </summary>
public bool Equals(IAzureSubscriptionIdentifier other)
{
return other != null &&
CommonUtil.SameString(SubscriptionId, other.SubscriptionId) &&
CommonUtil.SameUri(ServiceManagementEndpoint, other.ServiceManagementEndpoint);
}
public IAzureUserAccount UserAccount
{
get;
private set;
}
/// <summary>
/// Returns the endpoint url used by the identifier
/// </summary>
public Uri ServiceManagementEndpoint
{
get;
private set;
}
/// <summary>
/// Subscription id
/// </summary>
public string SubscriptionId
{
get;
private set;
}
}
}

View File

@@ -0,0 +1,93 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.SqlTools.ResourceProvider.Core;
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureUserAccount" /> using VS services
/// Contains information about an Azure account
/// </summary>
public class AzureUserAccount : IAzureUserAccount
{
private string uniqueId;
/// <summary>
/// Default constructor to initializes user session
/// </summary>
public AzureUserAccount()
{
}
/// <summary>
/// Default constructor to initializes user session
/// </summary>
public AzureUserAccount(IAzureUserAccount azureUserAccount)
{
CopyFrom(azureUserAccount);
}
private void CopyFrom(IAzureUserAccount azureUserAccount)
{
this.DisplayInfo = new AzureUserAccountDisplayInfo(azureUserAccount.DisplayInfo);
this.NeedsReauthentication = azureUserAccount.NeedsReauthentication;
this.TenantId = azureUserAccount.TenantId;
this.UniqueId = azureUserAccount.UniqueId;
}
/// <summary>
/// Returns true if given user account equals this class
/// </summary>
public bool Equals(IAzureUserAccount other)
{
return other != null &&
CommonUtil.SameString(other.UniqueId, UniqueId) &&
CommonUtil.SameString(other.TenantId, TenantId);
}
/// <summary>
/// Unique Id
/// </summary>
public string UniqueId
{
get
{
return uniqueId == null ? string.Empty : uniqueId;
}
set
{
this.uniqueId = value;
}
}
/// <summary>
/// Returns true if user needs reauthentication
/// </summary>
public bool NeedsReauthentication
{
get;
set;
}
/// <summary>
/// User display info
/// </summary>
public IAzureUserAccountDisplayInfo DisplayInfo
{
get;
set;
}
/// <summary>
/// Tenant Id
/// </summary>
public string TenantId
{
get;
set;
}
}
}

View File

@@ -0,0 +1,110 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureUserAccountDisplayInfo" /> using VS services
/// Contains information about an Azure account display info
/// </summary>
public class AzureUserAccountDisplayInfo : IAzureUserAccountDisplayInfo
{
private string userName;
private string accountDisplayName;
/// <summary>
/// Creating the instance using <see cref="IAzureUserAccountDisplayInfo" />
/// </summary>
public AzureUserAccountDisplayInfo(IAzureUserAccountDisplayInfo azureUserAccountDisplayInfo)
{
CopyFrom(azureUserAccountDisplayInfo);
}
/// <summary>
/// Creating empty instance
/// </summary>
public AzureUserAccountDisplayInfo()
{
}
private void CopyFrom(IAzureUserAccountDisplayInfo azureUserAccountDisplayInfo)
{
this.AccountDisplayName = azureUserAccountDisplayInfo.AccountDisplayName;
this.AccountLogo = azureUserAccountDisplayInfo.AccountLogo;
this.ProviderDisplayName = azureUserAccountDisplayInfo.ProviderDisplayName;
this.ProviderLogo = azureUserAccountDisplayInfo.ProviderLogo;
this.UserName = azureUserAccountDisplayInfo.UserName;
}
/// <summary>
/// Returns true if given user account equals this class
/// </summary>
public bool Equals(IAzureUserAccountDisplayInfo other)
{
return other != null &&
((other.AccountDisplayName == null && AccountDisplayName == null ) || (other.AccountDisplayName != null && other.AccountDisplayName.Equals(AccountDisplayName))) &&
((other.UserName == null && UserName == null ) || (other.UserName != null && other.UserName.Equals(UserName)));
}
/// <summary>
/// Account display name
/// </summary>
public string AccountDisplayName
{
get
{
return accountDisplayName != null ? accountDisplayName : string.Empty;
}
set
{
accountDisplayName = value;
}
}
/// <summary>
/// Account lego
/// </summary>
public byte[] AccountLogo
{
get;
set;
}
/// <summary>
/// Provider display name
/// </summary>
public string ProviderDisplayName
{
get;
set;
}
/// <summary>
/// Provider lego
/// </summary>
public byte[] ProviderLogo
{
get;
set;
}
/// <summary>
/// User name
/// </summary>
public string UserName
{
get
{
return userName != null ? userName : string.Empty;
}
set
{
userName = value;
}
}
}
}

View File

@@ -0,0 +1,92 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Rest;
using Microsoft.SqlTools.ResourceProvider.Core;
using Microsoft.SqlTools.ResourceProvider.Core.Authentication;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureUserAccountSubscriptionContext" /> using built-in services
/// Contains information about an Azure account subscription
/// </summary>
public class AzureUserAccountSubscriptionContext : IAzureUserAccountSubscriptionContext
{
/// <summary>
/// Default constructor to initializes user account and subscription
/// </summary>
public AzureUserAccountSubscriptionContext(AzureSubscriptionIdentifier subscription, ServiceClientCredentials credentials)
{
CommonUtil.CheckForNull(subscription, nameof(subscription));
CommonUtil.CheckForNull(credentials, nameof(credentials));
Subscription = subscription;
Credentials = credentials;
}
/// <summary>
/// Creates a subscription context for connecting with a known access token. This creates a <see cref="TokenCredentials"/> object for use
/// in a request
/// </summary>
public static AzureUserAccountSubscriptionContext CreateStringTokenContext(AzureSubscriptionIdentifier subscription, string accessToken)
{
CommonUtil.CheckForNull(subscription, nameof(subscription));
CommonUtil.CheckStringForNullOrEmpty(accessToken, nameof(accessToken));
TokenCredentials credentials = new TokenCredentials(accessToken);
return new AzureUserAccountSubscriptionContext(subscription, credentials);
}
public bool Equals(IAzureSubscriptionContext other)
{
return other != null && other.Equals(this);
}
/// <summary>
/// Returns the wraper for the subscription identifier
/// </summary>
public IAzureSubscriptionIdentifier Subscription
{
get;
private set;
}
/// <summary>
/// Subscription name
/// </summary>
public string SubscriptionName
{
get { return Subscription != null ? Subscription.SubscriptionId : string.Empty; }
}
/// <summary>
///
/// </summary>
public bool Equals(IAzureUserAccountSubscriptionContext other)
{
return other != null &&
CommonUtil.SameSubscriptionIdentifier(Subscription, other.Subscription) &&
CommonUtil.SameUserAccount(UserAccount, other.UserAccount);
}
/// <summary>
/// User Account
/// </summary>
public IAzureUserAccount UserAccount
{
get
{
return Subscription != null ?
new AzureUserAccount(Subscription.UserAccount) : null;
}
}
public ServiceClientCredentials Credentials
{
get;
private set;
}
}
}

View File

@@ -0,0 +1,106 @@
// WARNING:
// This file was generated by the Microsoft DataWarehouse String Resource Tool 1.37.0.0
// from information in sr.strings
// DO NOT MODIFY THIS FILE'S CONTENTS, THEY WILL BE OVERWRITTEN
//
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
using System;
using System.Reflection;
using System.Resources;
using System.Globalization;
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class SR
{
protected SR()
{ }
public static CultureInfo Culture
{
get
{
return Keys.Culture;
}
set
{
Keys.Culture = value;
}
}
public static string FailedToGetAzureDatabasesErrorMessage
{
get
{
return Keys.GetString(Keys.FailedToGetAzureDatabasesErrorMessage);
}
}
public static string FailedToGetAzureResourceGroupsErrorMessage
{
get
{
return Keys.GetString(Keys.FailedToGetAzureResourceGroupsErrorMessage);
}
}
public static string FailedToGetAzureSqlServersErrorMessage
{
get
{
return Keys.GetString(Keys.FailedToGetAzureSqlServersErrorMessage);
}
}
public static string FirewallRuleCreationFailed
{
get
{
return Keys.GetString(Keys.FirewallRuleCreationFailed);
}
}
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Keys
{
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ResourceProvider.DefaultImpl.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
static CultureInfo _culture = null;
public const string FailedToGetAzureDatabasesErrorMessage = "FailedToGetAzureDatabasesErrorMessage";
public const string FailedToGetAzureResourceGroupsErrorMessage = "FailedToGetAzureResourceGroupsErrorMessage";
public const string FailedToGetAzureSqlServersErrorMessage = "FailedToGetAzureSqlServersErrorMessage";
public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";
private Keys()
{ }
public static CultureInfo Culture
{
get
{
return _culture;
}
set
{
_culture = value;
}
}
public static string GetString(string key)
{
return resourceManager.GetString(key, _culture);
}
}
}
}

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype=">text/microsoft-resx</resheader>
<resheader name="version=">2.0</resheader>
<resheader name="reader=">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer=">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1="><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing=">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64=">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64=">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata=">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true=">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded=">
<xsd:element name="metadata=">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly=">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data=">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader=">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="FailedToGetAzureDatabasesErrorMessage" xml:space="preserve">
<value>An error occurred while getting Azure databases</value>
<comment></comment>
</data>
<data name="FailedToGetAzureResourceGroupsErrorMessage" xml:space="preserve">
<value>An error occurred while getting Azure resource groups</value>
<comment></comment>
</data>
<data name="FailedToGetAzureSqlServersErrorMessage" xml:space="preserve">
<value>An error occurred while getting Azure Sql Servers</value>
<comment></comment>
</data>
<data name="FirewallRuleCreationFailed" xml:space="preserve">
<value>An error occurred while creating a new firewall rule.</value>
<comment></comment>
</data>
</root>

View File

@@ -0,0 +1,28 @@
# String resource file
#
# When processed by the String Resource Tool, this file generates
# both a .CS and a .RESX file with the same name as the file.
# The .CS file contains a class which can be used to access these
# string resources, including the ability to format in
# parameters, which are identified with the .NET {x} format
# (see String.Format help).
#
# Comments below assume the file name is SR.strings.
#
# Lines starting with a semicolon ";" are also treated as comments, but
# in a future version they will be extracted and made available in LocStudio
# Put your comments to localizers _before_ the string they apply to.
#
# SMO build specific comment
# after generating the .resx file, run srgen on it and get the .resx file
# please remember to also check that .resx in, along with the
# .strings and .cs files
[strings]
############################################################################
# Azure Core DLL
FailedToGetAzureDatabasesErrorMessage = An error occurred while getting Azure databases
FailedToGetAzureResourceGroupsErrorMessage = An error occurred while getting Azure resource groups
FailedToGetAzureSqlServersErrorMessage = An error occurred while getting Azure Sql Servers
FirewallRuleCreationFailed = An error occurred while creating a new firewall rule.

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" original="sr.resx" source-language="en">
<body>
<trans-unit id="FailedToGetAzureDatabasesErrorMessage">
<source>An error occurred while getting Azure databases</source>
<target state="new">An error occurred while getting Azure databases</target>
<note></note>
</trans-unit>
<trans-unit id="FailedToGetAzureResourceGroupsErrorMessage">
<source>An error occurred while getting Azure resource groups</source>
<target state="new">An error occurred while getting Azure resource groups</target>
<note></note>
</trans-unit>
<trans-unit id="FailedToGetAzureSqlServersErrorMessage">
<source>An error occurred while getting Azure Sql Servers</source>
<target state="new">An error occurred while getting Azure Sql Servers</target>
<note></note>
</trans-unit>
<trans-unit id="FirewallRuleCreationFailed">
<source>An error occurred while creating a new firewall rule.</source>
<target state="new">An error occurred while creating a new firewall rule.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Microsoft.SqlTools.ResourceProvider.DefaultImpl</PackageId>
<AssemblyName>Microsoft.SqlTools.ResourceProvider.DefaultImpl</AssemblyName>
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<ApplicationIcon />
<OutputType>Library</OutputType>
<StartupObject />
<Description>Provides the default for SqlTools applications.</Description>
<Copyright><EFBFBD> Microsoft Corporation. All rights reserved.</Copyright>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Management.ResourceManager" Version="1.6.0-preview" />
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.10" />
<PackageReference Include="Microsoft.Rest.ClientRuntime.Azure" Version="3.3.10" />
<PackageReference Include="System.Data.SqlClient" Version="4.4.0" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.0.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.Composition" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.Management.Sql" Version="1.6.0-preview" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.SqlTools.ResourceProvider.Core\Microsoft.SqlTools.ResourceProvider.Core.csproj" />
<ProjectReference Include="..\Microsoft.SqlTools.Hosting\Microsoft.SqlTools.Hosting.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\sr.resx" />
<None Include="Localization\sr.strings" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,50 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.SqlTools.ResourceProvider.Core;
using Models = Microsoft.Azure.Management.Sql.Models;
namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
{
/// <summary>
/// Implementation for <see cref="IAzureSqlServerResource" /> using VS services
/// Provides information about an Azure Sql Server resource
/// </summary>
public class SqlAzureResource : AzureResourceWrapper, IAzureSqlServerResource
{
private readonly Models.Server _azureSqlServerResource;
/// <summary>
/// Initializes the resource
/// </summary>
public SqlAzureResource(Models.Server azureResource) : base(azureResource)
{
CommonUtil.CheckForNull(azureResource, nameof(azureResource));
_azureSqlServerResource = azureResource;
}
/// <summary>
/// Fully qualified domain name
/// </summary>
public string FullyQualifiedDomainName
{
get
{
return _azureSqlServerResource != null ? _azureSqlServerResource.FullyQualifiedDomainName : string.Empty;
}
}
/// <summary>
/// Administrator User
/// </summary>
public string AdministratorLogin
{
get
{
return _azureSqlServerResource != null ? _azureSqlServerResource.AdministratorLogin : string.Empty;
}
}
}
}