Create remote file browser service (#448)

* code refactoring

* Add filebrowser service and tests

* change dataset reference

* Address pr comments

* add more tests

* address pr comments

* address pr comments and added more tests

* minor change

* minor fix

* Fix test break and add dataset result check
This commit is contained in:
Kate Shin
2017-09-08 13:57:56 -07:00
committed by GitHub
parent 784f4c5d05
commit 14ec5be961
29 changed files with 1942 additions and 59 deletions

View File

@@ -0,0 +1,162 @@
//
// 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.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Globalization;
using System.IO;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
{
/// <summary>
/// Validate selected file paths for backup/restore operations
/// </summary>
public static class DisasterRecoveryFileValidator
{
internal const string LocalSqlServer = "(local)";
internal const string LocalMachineName = ".";
public static bool ValidatePaths(FileBrowserValidateEventArgs args, out string errorMessage)
{
errorMessage = string.Empty;
bool result = true;
SqlConnection connection = null;
if (args != null)
{
ConnectionInfo connInfo;
ConnectionService.Instance.TryFindConnection(args.OwnerUri, out connInfo);
if (connInfo != null)
{
DbConnection dbConnection = null;
connInfo.TryGetConnection(Connection.ConnectionType.Default, out dbConnection);
if (dbConnection != null)
{
connection = ReliableConnectionHelper.GetAsSqlConnection(dbConnection);
}
}
if (connection != null)
{
bool isLocal = false;
if (string.Compare(GetMachineName(connection.DataSource), Environment.MachineName, StringComparison.OrdinalIgnoreCase) == 0)
{
isLocal = true;
}
foreach (string filePath in args.FilePaths)
{
bool isFolder;
bool existing = IsPathExisting(connection, filePath, out isFolder);
if (existing)
{
if (isFolder)
{
errorMessage = string.Format(SR.BackupPathIsFolderError, filePath);
result = false;
break;
}
}
else
{
// If the file path doesn't exist, check if the folder exists
string folderPath = PathWrapper.GetDirectoryName(filePath);
if (isLocal)
{
if (!string.IsNullOrEmpty(folderPath) && !Directory.Exists(folderPath))
{
errorMessage = string.Format(SR.InvalidBackupPathError, folderPath);
result = false;
break;
}
}
else
{
bool isFolderOnRemote;
bool existsOnRemote = IsPathExisting(connection, folderPath, out isFolderOnRemote);
if (!existsOnRemote)
{
errorMessage = string.Format(SR.InvalidBackupPathError, folderPath);
result = false;
break;
}
}
}
}
}
else
{
result = false;
}
}
else
{
result = false;
}
return result;
}
#region private methods
internal static bool IsPathExisting(SqlConnection connection, string path, out bool isFolder)
{
Request req = new Request
{
Urn = "Server/File[@FullName='" + Urn.EscapeString(path) + "']",
Fields = new[] { "IsFile" }
};
Enumerator en = new Enumerator();
bool isExisting = false;
isFolder = false;
using (DataSet ds = en.Process(connection, req))
{
if (FileBrowserBase.IsValidDataSet(ds))
{
isFolder = !(Convert.ToBoolean(ds.Tables[0].Rows[0]["IsFile"], CultureInfo.InvariantCulture));
isExisting = true;
}
}
return isExisting;
}
internal static string GetMachineName(string sqlServerName)
{
string machineName = string.Empty;
if (sqlServerName != null)
{
string serverName = sqlServerName.ToLowerInvariant().Trim();
if ((serverName == LocalSqlServer) || (serverName == LocalMachineName))
{
machineName = System.Environment.MachineName;
}
else
{
machineName = sqlServerName;
if (sqlServerName.Trim().Length != 0)
{
// [0] = machine, [1] = instance
return sqlServerName.Split('\\')[0];
}
}
}
return machineName;
}
#endregion
}
}

View File

@@ -9,12 +9,11 @@ using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Admin;
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using System.Threading;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation;
using System.Globalization;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation;
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
{
@@ -26,6 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
private static readonly Lazy<DisasterRecoveryService> instance = new Lazy<DisasterRecoveryService>(() => new DisasterRecoveryService());
private static ConnectionService connectionService = null;
private SqlTaskManager sqlTaskManagerInstance = null;
private FileBrowserService fileBrowserService = null;
private RestoreDatabaseHelper restoreDatabaseService = new RestoreDatabaseHelper();
/// <summary>
@@ -78,6 +78,25 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
}
}
/// <summary>
/// Gets or sets the current filebrowser service instance
/// </summary>
internal FileBrowserService FileBrowserServiceInstance
{
get
{
if (fileBrowserService == null)
{
fileBrowserService = FileBrowserService.Instance;
}
return fileBrowserService;
}
set
{
fileBrowserService = value;
}
}
/// <summary>
/// Initializes the service instance
/// </summary>
@@ -89,14 +108,18 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
// Create backup
serviceHost.SetRequestHandler(BackupRequest.Type, HandleBackupRequest);
// Create respore task
// Create restore task
serviceHost.SetRequestHandler(RestoreRequest.Type, HandleRestoreRequest);
// Create respore plan
// Create restore plan
serviceHost.SetRequestHandler(RestorePlanRequest.Type, HandleRestorePlanRequest);
// Create respore config
// Create restore config
serviceHost.SetRequestHandler(RestoreConfigInfoRequest.Type, HandleRestoreConfigInfoRequest);
// Register file path validation callbacks
FileBrowserServiceInstance.RegisterValidatePathsCallback(FileValidationServiceConstants.Backup, DisasterRecoveryFileValidator.ValidatePaths);
FileBrowserServiceInstance.RegisterValidatePathsCallback(FileValidationServiceConstants.Restore, DisasterRecoveryFileValidator.ValidatePaths);
}
/// <summary>