aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Azure
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-02-06 18:20:21 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-02-06 18:20:21 +0200
commit0baf31baf01a291b6d2c6f5d45fb15fbbc146198 (patch)
tree96d6fc1b4a5f1385ce2224233ea076d85972ee0d /Software/Visual_Studio/Azure
parent258399bb206839cdb7cd276839675fa14910bc36 (diff)
downloadTango-0baf31baf01a291b6d2c6f5d45fb15fbbc146198.tar.gz
Tango-0baf31baf01a291b6d2c6f5d45fb15fbbc146198.zip
Working on Azure Utils.
Diffstat (limited to 'Software/Visual_Studio/Azure')
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs14
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs8
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs45
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml17
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml.cs5
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs92
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsComponentBase.cs13
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsStage.cs20
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs339
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs464
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/UpgradeConfiguration.cs33
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/CreateEnvironmentConfiguration.cs28
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs374
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentSettings.cs34
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/UpgradeEnvironmentConfiguration.cs19
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/FTP/FtpManager.cs119
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs183
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj14
18 files changed, 1169 insertions, 652 deletions
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs
index a522d62cc..196848e95 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Tango.AzureUtils.UI.Managers;
using Tango.AzureUtils.UI.ViewModels;
+using Tango.Core;
using Tango.Core.DI;
namespace Tango.AzureUtils.UI
@@ -13,11 +14,16 @@ namespace Tango.AzureUtils.UI
{
static ViewModelLocator()
{
- TangoIOC.Default.Register<MainViewVM>();
- TangoIOC.Default.Register<EnvironmentUpgradeViewVM>();
- TangoIOC.Default.Register<EnvironmentCreationViewVM>();
+ ExtendedObject obj = new ExtendedObject();
- TangoIOC.Default.Register<IStatusManager, DefaultStatusManager>();
+ if (!obj.DesignMode)
+ {
+ TangoIOC.Default.Register<MainViewVM>();
+ TangoIOC.Default.Register<EnvironmentUpgradeViewVM>();
+ TangoIOC.Default.Register<EnvironmentCreationViewVM>();
+
+ TangoIOC.Default.Register<IStatusManager, DefaultStatusManager>();
+ }
}
public static MainViewVM MainViewVM
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs
index 74995c16d..fe585191d 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs
@@ -68,6 +68,8 @@ namespace Tango.AzureUtils.UI.ViewModels
public override void OnApplicationReady()
{
Email = "roy@twine-s.com";
+ SlotName = "ROY";
+ Password = "1Creativity";
}
public override void OnAuthenticated(IAzure azure, List<IWebAppBase> apps)
@@ -100,7 +102,11 @@ namespace Tango.AzureUtils.UI.ViewModels
if (!Validate()) return;
IsFree = false;
- await _environmentManager.CreateDeploymentSlot(_machineServiceApp as IWebApp, SelectedDeploymentSlot, SlotName, Email, Password);
+ await _environmentManager.CreateEnvironment(_machineServiceApp as IWebApp, SelectedDeploymentSlot, SlotName, new CreateEnvironmentConfiguration()
+ {
+ Email = Email,
+ Password = Password
+ });
}
catch (Exception ex)
{
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs
index 56228e1c5..695ef9d4f 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.AzureUtils.Deployment;
+using Tango.AzureUtils.Environment;
using Tango.Core.Commands;
using Tango.SharedUI;
@@ -34,11 +35,11 @@ namespace Tango.AzureUtils.UI.ViewModels
set { _selectedTargetAPp = value; RaisePropertyChangedAuto(); }
}
- private DeploymentManager _deploymentManager;
- public DeploymentManager DeploymentManager
+ private EnvironmentManager _environmentManager;
+ public EnvironmentManager EnvironmentManager
{
- get { return _deploymentManager; }
- set { _deploymentManager = value; RaisePropertyChangedAuto(); }
+ get { return _environmentManager; }
+ set { _environmentManager = value; RaisePropertyChangedAuto(); }
}
private bool _canUpgrade;
@@ -48,11 +49,23 @@ namespace Tango.AzureUtils.UI.ViewModels
set { _canUpgrade = value; RaisePropertyChangedAuto(); }
}
+ private UpgradeEnvironmentConfiguration _config;
+ public UpgradeEnvironmentConfiguration Config
+ {
+ get { return _config; }
+ set { _config = value; RaisePropertyChangedAuto(); }
+ }
+
+
public RelayCommand ValidateUpgradeCommand { get; set; }
+ public RelayCommand UpgradeEnvironmentCommand { get; set; }
+
public EnvironmentUpgradeViewVM()
{
+ Config = new UpgradeEnvironmentConfiguration();
ValidateUpgradeCommand = new RelayCommand(() => ValidateUpgrade());
+ UpgradeEnvironmentCommand = new RelayCommand(() => UpgradeEnvironment());
}
public override void OnAuthenticated(IAzure azure, List<IWebAppBase> apps)
@@ -62,9 +75,8 @@ namespace Tango.AzureUtils.UI.ViewModels
SelectedSourceApp = Apps.FirstOrDefault();
SelectedTargetApp = Apps.FirstOrDefault();
- DeploymentManager = new DeploymentManager(azure);
- DeploymentManager.Progress += (x, e) => StatusManager.UpdateStatus(e);
- DeploymentManager.UpgradeConfiguration.PropertyChanged += (x, e) => CanUpgrade = false;
+ EnvironmentManager = new EnvironmentManager(azure);
+ EnvironmentManager.Progress += (x, e) => StatusManager.UpdateStatus(e);
}
private async void ValidateUpgrade()
@@ -78,7 +90,7 @@ namespace Tango.AzureUtils.UI.ViewModels
{
IsFree = false;
StatusManager.UpdateStatus(AzureUtilsStage.Validating, "Validating configuration...", true);
- await DeploymentManager.ValidateUpgrade(SelectedSourceApp, SelectedTargetApp);
+ await EnvironmentManager.ValidateEnvironmentUpgrade(SelectedSourceApp, SelectedTargetApp, Config);
CanUpgrade = true;
StatusManager.UpdateStatus(AzureUtilsStage.Ready, "Configuration validated successfully.");
}
@@ -92,5 +104,22 @@ namespace Tango.AzureUtils.UI.ViewModels
IsFree = true;
}
}
+
+ private async void UpgradeEnvironment()
+ {
+ try
+ {
+ IsFree = false;
+ await EnvironmentManager.UpgradeEnvironment(SelectedSourceApp, SelectedTargetApp, Config);
+ }
+ catch (Exception ex)
+ {
+ StatusManager.UpdateStatus(ex);
+ }
+ finally
+ {
+ IsFree = true;
+ }
+ }
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml
index 67eaa52e2..6653653d0 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml
@@ -38,21 +38,20 @@
<StackPanel>
<GroupBox Header="Upgrade Configuration" Padding="10">
<StackPanel>
- <CheckBox IsChecked="{Binding DeploymentManager.UpgradeConfiguration.UpgradeMachineStudio}" >Upgrade Machine Studio</CheckBox>
- <CheckBox Margin="0 5 0 0" IsChecked="{Binding DeploymentManager.UpgradeConfiguration.UpgradePPC}" >Upgrade PPC</CheckBox>
- <CheckBox Margin="0 5 0 0" IsChecked="{Binding DeploymentManager.UpgradeConfiguration.UpgradeMachineService}" >Upgrade Machine Service</CheckBox>
+ <CheckBox Click="OnConfigChanged" IsChecked="{Binding Config.SynchronizeDatabaseSchema}" >Upgrade Database Schema</CheckBox>
+ <CheckBox Click="OnConfigChanged" Margin="0 5 0 0" IsChecked="{Binding Config.SynchronizeDatabaseData}" >Upgrade Database Static Collections</CheckBox>
+ <CheckBox Click="OnConfigChanged" Margin="0 5 0 0" IsChecked="{Binding Config.CopyMachineStudioStorageBlobs}" >Upgrade Machine Studio Blob Storage</CheckBox>
+ <CheckBox Click="OnConfigChanged" Margin="0 5 0 0" IsChecked="{Binding Config.CopyPPCStorageBlobs}" >Upgrade PPC Blob Storage</CheckBox>
+ <CheckBox Click="OnConfigChanged" Margin="0 5 0 0" IsChecked="{Binding Config.UpgradeMachineStudioDatabaseVersion}" >Upgrade Machine Studio Database Version</CheckBox>
+ <CheckBox Click="OnConfigChanged" Margin="0 5 0 0" IsChecked="{Binding Config.UpgradePPCDatabaseVersion}" >Upgrade PPC Database Version</CheckBox>
+ <CheckBox Click="OnConfigChanged" Margin="0 5 0 0" IsChecked="{Binding Config.CopyMachineServiceFiles}" >Upgrade Machine Service</CheckBox>
</StackPanel>
</GroupBox>
<StackPanel Margin="0 20 0 0">
<Button Padding="20" Command="{Binding ValidateUpgradeCommand}">Validate</Button>
<StackPanel Margin="0 20 0 0" IsEnabled="{Binding CanUpgrade}">
- <Button Padding="20">Upgrade Database Schema</Button>
- <Button Margin="0 10 0 0" Padding="20">Upgrade Database Static Collections</Button>
- <Button Margin="0 10 0 0" Padding="20">Upgrade Machine Studio</Button>
- <Button Margin="0 10 0 0" Padding="20">Upgrade PPC</Button>
- <Button Margin="0 10 0 0" Padding="20">Upgrade Machine Service</Button>
- <Button Margin="0 10 0 0" Padding="20">Full Upgrade</Button>
+ <Button Margin="0 10 0 0" Padding="20" Command="{Binding UpgradeEnvironmentCommand}">Full Upgrade</Button>
</StackPanel>
</StackPanel>
</StackPanel>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml.cs
index f904a2aef..3c3ad9b28 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentUpgradeView.xaml.cs
@@ -24,5 +24,10 @@ namespace Tango.AzureUtils.UI.Views
{
InitializeComponent();
}
+
+ private void OnConfigChanged(object sender, RoutedEventArgs e)
+ {
+ (DataContext as ViewModels.EnvironmentUpgradeViewVM).CanUpgrade = false;
+ }
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs
index 4527a1f53..fe5934fa9 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs
@@ -12,50 +12,82 @@ namespace Tango.AzureUtils.ActiveDirectory
public class ActiveDirectoryManager : AzureUtilsComponentBase
{
private AuthenticationResult _authResult;
- private AzureUtilsCredentials _credentials;
private ActiveDirectoryClient _adClient;
- public ActiveDirectoryManager(IAzure azure, AzureUtilsCredentials credentials) : base(azure)
+ #region Constructors
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ActiveDirectoryManager"/> class.
+ /// </summary>
+ /// <param name="azure">The azure instance.</param>
+ public ActiveDirectoryManager(IAzure azure) : base(azure)
+ {
+
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private ActiveDirectoryClient GetActiveDirectoryClient()
{
- _credentials = credentials;
+ if (_adClient == null)
+ {
+ var credentials = AzureUtilsAuthenticationFactory.GetCredentials();
+ _adClient = new ActiveDirectoryClient(new Uri($"https://graph.windows.net/{credentials.TenantID}"), async () => await Task.FromResult(_authResult.AccessToken));
+ }
+ return _adClient;
}
- public async Task Authenticate()
+ #endregion
+
+ #region Public Methods
+
+ /// <summary>
+ /// Authenticates using application credentials.
+ /// </summary>
+ /// <param name="credentials">The credentials.</param>
+ /// <returns></returns>
+ public async Task Authenticate(AzureUtilsCredentials credentials)
{
if (_authResult == null)
{
- var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{_credentials.TenantID}");
- ClientCredential clientCredentials = new ClientCredential(_credentials.ClientID, _credentials.ClientSecret);
+ var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{credentials.TenantID}");
+ ClientCredential clientCredentials = new ClientCredential(credentials.ClientID, credentials.ClientSecret);
_authResult = await authContext.AcquireTokenAsync("https://graph.windows.net/", clientCredentials);
}
}
+ /// <summary>
+ /// Authenticates using an AD account.
+ /// </summary>
+ /// <param name="email">The email.</param>
+ /// <param name="password">The password.</param>
+ /// <returns></returns>
public async Task Authenticate(String email, String password)
{
+ OnProgress(AzureUtilsStage.ActiveDirectory, $"Authenticating with active directory graph...");
if (_authResult == null)
{
- var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{_credentials.TenantID}");
+ var credentials = AzureUtilsAuthenticationFactory.GetCredentials();
+ var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{credentials.TenantID}");
authContext.TokenCache.Clear();
UserCredential userCredential = new UserPasswordCredential(email, password);
_authResult = await authContext.AcquireTokenAsync("https://graph.windows.net/", "ec612854-7abc-457b-808a-5d0c5ba80c57", userCredential);
}
}
- private ActiveDirectoryClient GetActiveDirectoryClient()
- {
- if (_adClient == null)
- {
- _adClient = new ActiveDirectoryClient(new Uri($"https://graph.windows.net/{_credentials.TenantID}"), async () => await Task.FromResult(_authResult.AccessToken));
- }
- return _adClient;
- }
-
- public async Task<bool> IsGroupExists(String name)
+ /// <summary>
+ /// Determines whether the specified group name exists.
+ /// </summary>
+ /// <param name="groupName">Name of the group.</param>
+ /// <returns></returns>
+ public async Task<bool> IsGroupExists(String groupName)
{
try
{
var client = GetActiveDirectoryClient();
- var g = await client.Groups.Where(x => x.DisplayName == name).Take(1).ExecuteSingleAsync();
+ var g = await client.Groups.Where(x => x.DisplayName == groupName).Take(1).ExecuteSingleAsync();
return g != null;
}
catch
@@ -64,33 +96,49 @@ namespace Tango.AzureUtils.ActiveDirectory
}
}
- public async Task AddGroup(String name)
+ /// <summary>
+ /// Adds the specified group.
+ /// </summary>
+ /// <param name="groupName">Name of the group.</param>
+ /// <returns></returns>
+ public async Task AddGroup(String groupName)
{
+ OnProgress(AzureUtilsStage.ActiveDirectory, $"Creating environment group '{groupName}'...");
var client = GetActiveDirectoryClient();
await client.Groups.AddGroupAsync(new Group()
{
- DisplayName = name,
+ DisplayName = groupName,
MailEnabled = false,
MailNickname = Guid.NewGuid().ToString().ToLower(),
SecurityEnabled = true
});
}
- public async Task AddUserToGroup(String group, String userEmail)
+ /// <summary>
+ /// Adds the specified user to the specified group.
+ /// </summary>
+ /// <param name="groupName">Name of the group.</param>
+ /// <param name="userEmail">The user email.</param>
+ /// <returns></returns>
+ public async Task AddUserToGroup(String groupName, String userEmail)
{
+ OnProgress(AzureUtilsStage.ActiveDirectory, $"Adding environment group user '{userEmail}'...");
+
var client = GetActiveDirectoryClient();
List<Group> groups = new List<Group>();
var user = await client.Users.Where(x => x.UserPrincipalName == userEmail).ExecuteSingleAsync();
- var g = await client.Groups.Where(x => x.DisplayName == group).Take(1).ExecuteSingleAsync();
+ var g = await client.Groups.Where(x => x.DisplayName == groupName).Take(1).ExecuteSingleAsync();
var gg = g as Group;
gg.Members.Add(user as DirectoryObject);
await gg.UpdateAsync();
}
+
+ #endregion
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsComponentBase.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsComponentBase.cs
index 5ad584cd7..840f7bb58 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsComponentBase.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsComponentBase.cs
@@ -35,6 +35,11 @@ namespace Tango.AzureUtils
});
}
+ protected virtual void OnCompleted(String message)
+ {
+ OnProgress(AzureUtilsStage.Ready, message, 0, 100, false);
+ }
+
protected virtual void OnProgress(AzureUtilsProgressEventArgs e)
{
Progress?.Invoke(this, e);
@@ -69,5 +74,13 @@ namespace Tango.AzureUtils
{
ConfirmationRequired?.Invoke(this, e);
}
+
+ protected T CreateManager<T>() where T : AzureUtilsComponentBase
+ {
+ T manager = Activator.CreateInstance(typeof(T), new object[] { Azure }) as T;
+ manager.ConfirmationRequired += (x, e) => OnRequestConfirmation(e);
+ manager.Progress += (x, e) => OnProgress(e);
+ return manager;
+ }
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsStage.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsStage.cs
index 994ada3aa..c6a9c76e3 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsStage.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/AzureUtilsStage.cs
@@ -16,18 +16,16 @@ namespace Tango.AzureUtils
[Description("Confirmation Required")]
ConfirmationRequired,
- //Deployment
- Downloading,
- Uploading,
-
- //Environment
- Creating,
-
- [Description("Environment Group")]
- EnvironmentGroup,
- [Description("Deployment Slot")]
- DeploymentSlot,
+ [Description("FTP Download")]
+ FtpDownload,
+ [Description("FTP Upload")]
+ FtpUpload,
+ [Description("Active Directory")]
+ ActiveDirectory,
+ Deployment,
Database,
Storage,
+ Environment,
+ Validation,
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs
new file mode 100644
index 000000000..b54f243f8
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs
@@ -0,0 +1,339 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data.Entity;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+using Microsoft.Azure.Management.Sql.Fluent;
+using Microsoft.Azure.Management.Sql.Fluent.Models;
+using Tango.BL;
+using Tango.BL.Entities;
+using Tango.Core;
+using Tango.Core.DB;
+using Tango.Core.Helpers;
+
+namespace Tango.AzureUtils.Database
+{
+ public class DatabaseManager : AzureUtilsComponentBase
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DatabaseManager"/> class.
+ /// </summary>
+ /// <param name="azure">The azure.</param>
+ public DatabaseManager(IAzure azure) : base(azure)
+ {
+
+ }
+
+ #endregion
+
+ #region SQL Examiner
+
+ /// <summary>
+ /// Opens the SQL examiner schema using the specified source app and target app configuration.
+ /// </summary>
+ /// <param name="sourceApp">The source application.</param>
+ /// <param name="targetApp">The target application.</param>
+ /// <returns></returns>
+ public async Task OpenSQLExaminerSchema(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ String projectFile = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "Database", "GENERAL_ENV_UPGRADE.seproj");
+
+ using (Stream stream = GetProjectFileStream(projectFile))
+ {
+ XElement projectXml = XElement.Load(stream);
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+ ApplyDatabaseSettingsToProjectXml(projectXml, sourceSettings, targetSettings);
+
+ var tempFile = TemporaryManager.CreateImaginaryFile(".seproj");
+ tempFile.Persist = true;
+
+ File.WriteAllText(tempFile, projectXml.ToString());
+
+ Process.Start(tempFile);
+ }
+ }
+
+ /// <summary>
+ /// Opens the SQL examiner data using the specified source app and target app configuration.
+ /// </summary>
+ /// <param name="sourceApp">The source application.</param>
+ /// <param name="targetApp">The target application.</param>
+ /// <param name="forCreation">if set to <c>true</c> [for creation].</param>
+ /// <returns></returns>
+ public async Task OpenSQLExaminerData(IWebAppBase sourceApp, IWebAppBase targetApp, bool forCreation = false)
+ {
+ String projectFile = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "Database", "GENERAL_ENV_UPGRADE.sdeproj");
+
+ if (forCreation)
+ {
+ projectFile = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "Database", "GENERAL_ENV_CREATE.sdeproj");
+ }
+
+ using (Stream stream = GetProjectFileStream(projectFile))
+ {
+ XElement projectXml = XElement.Load(stream);
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+ ApplyDatabaseSettingsToProjectXml(projectXml, sourceSettings, targetSettings);
+
+ var tempFile = TemporaryManager.CreateImaginaryFile(".sdeproj");
+ tempFile.Persist = true;
+
+ File.WriteAllText(tempFile, projectXml.ToString());
+
+ Process.Start(tempFile);
+ }
+ }
+
+ private Stream GetProjectFileStream(String projectFile)
+ {
+ byte[] projectBytes = File.ReadAllBytes(projectFile);
+ MemoryStream stream = new MemoryStream(projectBytes);
+ return stream;
+ }
+
+ private void ApplyDatabaseSettingsToProjectXml(XElement projectXml, MachineServiceSettings sourceSettings, MachineServiceSettings targetSettings)
+ {
+ var sourceElement = projectXml.Elements().SelectMany(x => x.Descendants()).SingleOrDefault(x => x.Name == "Source" && x.Attributes().SingleOrDefault(y => y.Name == "id").Value == "1");
+ var targetElement = projectXml.Elements().SelectMany(x => x.Descendants()).SingleOrDefault(x => x.Name == "Source" && x.Attributes().SingleOrDefault(y => y.Name == "id").Value == "2");
+
+ ApplyDatabaseSettingsToSourceElement(sourceElement, sourceSettings);
+ ApplyDatabaseSettingsToSourceElement(targetElement, targetSettings);
+ }
+
+ private void ApplyDatabaseSettingsToSourceElement(XElement sourceElement, MachineServiceSettings settings)
+ {
+ sourceElement.Element("ServerName").SetValue(settings.DB_ADDRESS);
+ sourceElement.Element("Database").SetValue(settings.DB_CATALOG);
+ sourceElement.Element("Login").SetValue(settings.DB_USER_NAME);
+ sourceElement.Element("Password").SetValue(settings.DB_PASSWORD);
+ }
+
+ #endregion
+
+ #region Azure SQL Database
+
+ public async Task<bool> IsDatabaseExists(String serverName, String databaseName)
+ {
+ OnProgress(AzureUtilsStage.Database, $"Checking {serverName} database server...");
+ var sqlServer = (await Azure.SqlServers.ListAsync()).SingleOrDefault(x => x.Name == serverName);
+
+ var database = (await sqlServer.Databases.ListAsync()).SingleOrDefault(x => x.Name == databaseName);
+
+ return database != null;
+ }
+
+ public async Task<ISqlDatabase> AddDatabase(String serverName, String databaseName)
+ {
+ OnProgress(AzureUtilsStage.Database, $"Checking {serverName} database server...");
+ var sqlServer = (await Azure.SqlServers.ListAsync()).SingleOrDefault(x => x.Name == serverName);
+
+ OnProgress(AzureUtilsStage.Database, $"Creating new database '{databaseName}'...");
+ var database = await sqlServer.Databases.Define(databaseName).WithEdition(DatabaseEdition.Standard).CreateAsync();
+
+ return database;
+ }
+
+ public Task<ISqlDatabase> AddDatabase(String databaseName)
+ {
+ return AddDatabase("twine", databaseName);
+ }
+
+ #endregion
+
+ #region Users & Permissions
+
+ public async Task AddEnvironmentGroupPermissions(String address, String databaseName, String groupName, String email, String password)
+ {
+ OnProgress(AzureUtilsStage.Database, $"Adding environment group permissions on '{databaseName}'...");
+
+ using (DbManager db = DbManager.FromDataSource(new DataSource()
+ {
+ Type = DataSourceType.Azure,
+ Address = address,
+ Catalog = databaseName,
+ UserName = email,
+ Password = password,
+ IntegratedSecurity = false
+ }))
+ {
+ await db.ExecuteCommandAsync($"CREATE USER [{groupName}] FROM EXTERNAL PROVIDER");
+ await db.ExecuteCommandAsync($"ALTER ROLE db_datareader ADD MEMBER [{groupName}];");
+ await db.ExecuteCommandAsync($"ALTER ROLE db_datawriter ADD MEMBER [{groupName}];");
+ }
+ }
+
+ public async Task AddBackupUser(String address, String databaseName, String userName, String password)
+ {
+ OnProgress(AzureUtilsStage.Database, $"Adding BackupUser permissions on '{databaseName}'...");
+
+ using (DbManager db = DbManager.FromCredentials(address, databaseName, userName, password))
+ {
+ await db.ExecuteCommandAsync("CREATE USER [BackupUser] FOR LOGIN [BackupUser] WITH DEFAULT_SCHEMA=[dbo]");
+ await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_owner', N'BackupUser'");
+ await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_accessadmin', N'BackupUser'");
+ await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_securityadmin', N'BackupUser'");
+ await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_backupoperator', N'BackupUser'");
+ await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_datareader', N'BackupUser'");
+ await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_datawriter', N'BackupUser'");
+ }
+ }
+
+ #endregion
+
+ #region Versions
+
+ public async Task UpgradeMachineStudioVersion(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ var latestMachineStudioVersion = await GetLatestMachineStudioVersion(sourceApp);
+ var targetDataSource = (await targetApp.GetMachineServiceSettingsAsync()).ToDataSource();
+
+ OnProgress(AzureUtilsStage.Database, $"Adding machine studio database entry for version '{latestMachineStudioVersion.Version}'...");
+
+ using (var db = ObservablesContext.CreateDefault(targetDataSource))
+ {
+ db.MachineStudioVersions.Add(latestMachineStudioVersion);
+ await db.SaveChangesAsync();
+ }
+ }
+
+ public async Task UpgradePPCVersion(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ var latestPPCVersion = await GetLatestPPCVersion(sourceApp);
+
+ var targetDataSource = (await targetApp.GetMachineServiceSettingsAsync()).ToDataSource();
+
+ OnProgress(AzureUtilsStage.Database, $"Adding machine studio database entry for version '{latestPPCVersion.Version}'...");
+
+ using (var db = ObservablesContext.CreateDefault(targetDataSource))
+ {
+ db.TangoVersions.Add(latestPPCVersion);
+ await db.SaveChangesAsync();
+ }
+ }
+
+ public async Task<MachineStudioVersion> GetLatestMachineStudioVersion(IWebAppBase app)
+ {
+ OnProgress(AzureUtilsStage.Database, $"Getting latest machine studio version on '{app.Name}'...");
+
+ MachineServiceSettings settings = null;
+
+ try
+ {
+ settings = await app.GetMachineServiceSettingsAsync();
+ }
+ catch (Exception ex)
+ {
+ throw new ArgumentException("Could not fetch machine service settings. Please check that all settings are available.", ex);
+ }
+
+ try
+ {
+ DataSource dataSource = settings.ToDataSource();
+
+ using (var db = ObservablesContext.CreateDefault(dataSource))
+ {
+ var versions = await db.MachineStudioVersions.ToListAsync();
+ var latest_machine_version = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();
+ return latest_machine_version;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidDataException($"Could not retrieve '{app.Name}' latest Machine Studio version from database.", ex);
+ }
+ }
+
+ public async Task<TangoVersion> GetLatestPPCVersion(IWebAppBase app)
+ {
+ OnProgress(AzureUtilsStage.Database, $"Getting latest PPC version on '{app.Name}'...");
+
+ MachineServiceSettings settings = null;
+
+ try
+ {
+ settings = await app.GetMachineServiceSettingsAsync();
+ }
+ catch (Exception ex)
+ {
+ throw new ArgumentException("Could not fetch machine service settings. Please check that all settings are available.", ex);
+ }
+
+ try
+ {
+ DataSource dataSource = settings.ToDataSource();
+
+ using (var db = ObservablesContext.CreateDefault(dataSource))
+ {
+ var versions = await db.TangoVersions.ToListAsync();
+ var latest_machine_version = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();
+ return latest_machine_version;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidDataException($"Could not retrieve '{app.Name}' latest PPC version from database.", ex);
+ }
+ }
+
+ public async Task ValidateMachineStudioDatabaseUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ OnProgress(AzureUtilsStage.Validating, "Validating machine studio database upgrade...");
+
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+ var latestSourceMachineStudioVersion = await GetLatestMachineStudioVersion(sourceApp);
+
+ //Check if there is any source machine studio version.
+ if (latestSourceMachineStudioVersion == null)
+ {
+ throw new ValidationException("Could not locate a Machine Studio version entry on the source database.");
+ }
+
+ var latestTargetMachineStudioVersion = await GetLatestMachineStudioVersion(targetApp);
+
+ //Check target latest machine studio version is older if there is any.
+ if (latestTargetMachineStudioVersion != null && Version.Parse(latestSourceMachineStudioVersion.Version) <= Version.Parse(latestTargetMachineStudioVersion.Version))
+ {
+ throw new ValidationException($"Machine Studio source version is '{latestSourceMachineStudioVersion.Version}' while target version is '{latestTargetMachineStudioVersion.Version}'.");
+ }
+ }
+
+ public async Task ValidatePPCDatabaseUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ OnProgress(AzureUtilsStage.Validating, "Validating PPC database upgrade...");
+
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+ var latestSourcePPCVersion = await GetLatestPPCVersion(sourceApp);
+
+ //Check if there is any source PPC version.
+ if (latestSourcePPCVersion == null)
+ {
+ throw new ValidationException("Could not locate a PPC version entry on the source database.");
+ }
+
+ var latestTargetPPCVersion = await GetLatestPPCVersion(targetApp);
+
+ //Check target latest PPC version is older if there is any.
+ if (latestTargetPPCVersion != null && Version.Parse(latestSourcePPCVersion.Version) <= Version.Parse(latestTargetPPCVersion.Version))
+ {
+ throw new ValidationException($"PPC source version is '{latestSourcePPCVersion.Version}' while target version is '{latestTargetPPCVersion.Version}'.");
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs
index 2500b293c..5f1eb28fd 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs
@@ -22,461 +22,59 @@ using Tango.Core;
using Tango.Core.Helpers;
using Microsoft.Azure.Management.AppService.Fluent.DeploymentSlot.Definition;
using Microsoft.Azure.Management.AppService.Fluent.WebAppBase.Definition;
+using Tango.AzureUtils.Environment;
namespace Tango.AzureUtils.Deployment
{
public class DeploymentManager : AzureUtilsComponentBase
{
- private IProgress<FtpProgress> _ftpDownloadProgress;
- private IProgress<FtpProgress> _ftpUploadProgress;
-
- //TODO: Embedded TFP injection to current package!
-
- #region Properties
-
- private UpgradeConfiguration _upgradeConfiguration;
- public UpgradeConfiguration UpgradeConfiguration
- {
- get { return _upgradeConfiguration; }
- set { _upgradeConfiguration = value; RaisePropertyChangedAuto(); }
- }
-
- #endregion
-
#region Constructors
public DeploymentManager(IAzure azure) : base(azure)
{
- UpgradeConfiguration = new UpgradeConfiguration();
-
- _ftpDownloadProgress = new Progress<FtpProgress>((p) =>
- {
- OnProgress(AzureUtilsStage.Downloading, $"Downloading {p.RemotePath}...", p.Progress, 100, false);
- });
-
- _ftpUploadProgress = new Progress<FtpProgress>((p) =>
- {
- OnProgress(AzureUtilsStage.Uploading, $"Uploading {p.LocalPath}...", p.Progress, 100, false);
- });
- }
-
- #endregion
-
- #region Helpers
-
- public async Task<List<IWebApp>> GetAllWebAppsAsync()
- {
- return (await Azure.WebApps.ListAsync()).ToList();
- }
-
- #endregion
-
- #region Full Upgrade
-
- public async Task PerformFullUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- await ValidateUpgrade(sourceApp, targetApp);
-
- await OpenSQLExaminerSchema(sourceApp, targetApp);
- await OpenSQLExaminerData(sourceApp, targetApp);
- await UpgradeStorage(sourceApp, targetApp);
- await UpgradeVersions(sourceApp, targetApp);
-
- if (UpgradeConfiguration.UpgradeMachineService)
- {
- await UpgradeMachineService(sourceApp, targetApp);
- }
- }
-
- #endregion
-
- #region SQLExaminer
-
- public async Task OpenSQLExaminerSchema(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- String projectFile = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "Deployment", "GENERAL_ENV_UPGRADE.seproj");
-
- using (Stream stream = GetFileStream(projectFile))
- {
- XElement projectXml = XElement.Load(stream);
- var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
- var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
- ApplyDatabaseSettingsToProjectXml(projectXml, sourceSettings, targetSettings);
-
- var tempFile = TemporaryManager.CreateImaginaryFile(".seproj");
- tempFile.Persist = true;
-
- File.WriteAllText(tempFile, projectXml.ToString());
-
- Process.Start(tempFile);
-
- await RequestConfirmation($"Please synchronize the database schema between '{sourceSettings.DB_CATALOG}' and '{targetSettings.DB_CATALOG}'.\nPlease confirm in order to continue.");
- OnProgress(AzureUtilsStage.Database, $"Waiting for database schema synchronization...");
- }
- }
-
- public async Task OpenSQLExaminerData(IWebAppBase sourceApp, IWebAppBase targetApp, bool forCreation = false)
- {
- String projectFile = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "Deployment", "GENERAL_ENV_UPGRADE.sdeproj");
-
- if (forCreation)
- {
- projectFile = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "Deployment", "GENERAL_ENV_CREATE.sdeproj");
- }
-
- using (Stream stream = GetFileStream(projectFile))
- {
- XElement projectXml = XElement.Load(stream);
- var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
- var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
- ApplyDatabaseSettingsToProjectXml(projectXml, sourceSettings, targetSettings);
-
- var tempFile = TemporaryManager.CreateImaginaryFile(".sdeproj");
- tempFile.Persist = true;
-
- File.WriteAllText(tempFile, projectXml.ToString());
-
- Process.Start(tempFile);
-
- await RequestConfirmation($"Please synchronize the database static collections between '{sourceSettings.DB_CATALOG}' and '{targetSettings.DB_CATALOG}'.\nPlease confirm in order to continue.");
- OnProgress(AzureUtilsStage.Database, $"Waiting for database static collections synchronization...");
- }
- }
-
- private Stream GetFileStream(String projectFile)
- {
- byte[] projectBytes = File.ReadAllBytes(projectFile);
- MemoryStream stream = new MemoryStream(projectBytes);
- return stream;
- }
-
- private void ApplyDatabaseSettingsToProjectXml(XElement projectXml, MachineServiceSettings sourceSettings, MachineServiceSettings targetSettings)
- {
- var sourceElement = projectXml.Elements().SelectMany(x => x.Descendants()).SingleOrDefault(x => x.Name == "Source" && x.Attributes().SingleOrDefault(y => y.Name == "id").Value == "1");
- var targetElement = projectXml.Elements().SelectMany(x => x.Descendants()).SingleOrDefault(x => x.Name == "Source" && x.Attributes().SingleOrDefault(y => y.Name == "id").Value == "2");
-
- ApplyDatabaseSettingsToSourceElement(sourceElement, sourceSettings);
- ApplyDatabaseSettingsToSourceElement(targetElement, targetSettings);
- }
-
- private void ApplyDatabaseSettingsToSourceElement(XElement sourceElement, MachineServiceSettings settings)
- {
- sourceElement.Element("ServerName").SetValue(settings.DB_ADDRESS);
- sourceElement.Element("Database").SetValue(settings.DB_CATALOG);
- sourceElement.Element("Login").SetValue(settings.DB_USER_NAME);
- sourceElement.Element("Password").SetValue(settings.DB_PASSWORD);
- }
-
- #endregion
-
- #region FTP
-
- private async Task<List<FtpResult>> DownloadWebAppFiles(IWebAppBase app, String targetFolder)
- {
- var profile = await app.GetPublishingProfileAsync();
-
- using (var ftp = new FtpClient(profile.FtpUrl, profile.FtpUsername, profile.FtpPassword))
- {
- var downloadResults = await ftp.DownloadDirectoryAsync(targetFolder, "/site/wwwroot", progress: _ftpDownloadProgress);
-
- foreach (var downloadResult in downloadResults)
- {
- if (downloadResult.IsFailed)
- {
- throw downloadResult.Exception;
- }
- }
-
- return downloadResults;
- }
- }
-
- private async Task<List<FtpResult>> UploadWebAppFiles(IWebAppBase app, String sourceFolder)
- {
- var profile = await app.GetPublishingProfileAsync();
-
- using (var ftp = new FtpClient(profile.FtpUrl, profile.FtpUsername, profile.FtpPassword))
- {
- var uploadResults = await ftp.UploadDirectoryAsync(sourceFolder, "/site/wwwroot", existsMode: FtpRemoteExists.Overwrite, progress: _ftpUploadProgress);
-
- foreach (var uploadResult in uploadResults)
- {
- if (uploadResult.IsFailed)
- {
- throw uploadResult.Exception;
- }
- }
-
- return uploadResults;
- }
- }
-
- #endregion
-
- #region Machine Service
-
- public async Task UpgradeMachineService(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- var webAppFilesTempFolder = TemporaryManager.CreateFolder();
- var downloadResults = await DownloadWebAppFiles(sourceApp, webAppFilesTempFolder);
- var uploadResults = await UploadWebAppFiles(targetApp, webAppFilesTempFolder + "\\wwwroot");
- }
-
- #endregion
-
- #region Applications Versions & Storage Blobs
-
- public async Task<MachineStudioVersion> GetLatestMachineStudioVersion(IWebAppBase app)
- {
- MachineServiceSettings settings = null;
-
- try
- {
- settings = await app.GetMachineServiceSettingsAsync();
- }
- catch (Exception ex)
- {
- throw new ArgumentException("Could not fetch machine service settings. Please check that all settings are available.", ex);
- }
-
- try
- {
- DataSource dataSource = settings.ToDataSource();
-
- using (var db = ObservablesContext.CreateDefault(dataSource))
- {
- var versions = await db.MachineStudioVersions.ToListAsync();
- var latest_machine_version = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();
- return latest_machine_version;
- }
- }
- catch (Exception ex)
- {
- throw new InvalidDataException($"Could not retrieve '{app.Name}' latest Machine Studio version from database.", ex);
- }
- }
-
- public async Task<TangoVersion> GetLatestPPCVersion(IWebAppBase app)
- {
- MachineServiceSettings settings = null;
-
- try
- {
- settings = await app.GetMachineServiceSettingsAsync();
- }
- catch (Exception ex)
- {
- throw new ArgumentException("Could not fetch machine service settings. Please check that all settings are available.", ex);
- }
-
- try
- {
- DataSource dataSource = settings.ToDataSource();
-
- using (var db = ObservablesContext.CreateDefault(dataSource))
- {
- var versions = await db.TangoVersions.ToListAsync();
- var latest_machine_version = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();
- return latest_machine_version;
- }
- }
- catch (Exception ex)
- {
- throw new InvalidDataException($"Could not retrieve '{app.Name}' latest PPC version from database.", ex);
- }
- }
-
- public async Task UpgradeStorage(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- await ValidateUpgrade(sourceApp, targetApp);
-
- var latestMachineStudioVersion = await GetLatestMachineStudioVersion(sourceApp);
- var latestPPCVersion = await GetLatestPPCVersion(sourceApp);
-
- var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
- var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
-
- var sourceAccount = CloudStorageAccount.Parse(sourceSettings.STORAGE_ACCOUNT);
- var sourceClient = sourceAccount.CreateCloudBlobClient();
-
- var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
- var targetClient = targetAccount.CreateCloudBlobClient();
-
- var sourceMachineStudioContainer = sourceClient.GetContainerReference(sourceSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
- var targetMachineStudioContainer = targetClient.GetContainerReference(targetSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
-
- var sourcePPCContainer = sourceClient.GetContainerReference(sourceSettings.TANGO_VERSIONS_CONTAINER);
- var targetPPCContainer = targetClient.GetContainerReference(targetSettings.TANGO_VERSIONS_CONTAINER);
-
- var sourceMachineStudioBlob = sourceMachineStudioContainer.GetBlockBlobReference(latestMachineStudioVersion.BlobName);
- var sourceMachineStudioInstallerBlob = sourceMachineStudioContainer.GetBlockBlobReference(latestMachineStudioVersion.InstallerBlobName);
-
- var targetMachineStudioBlob = CreateEmptyBlob(targetMachineStudioContainer, sourceMachineStudioBlob.Name);
- var targetMachineStudioInstallerBlob = CreateEmptyBlob(targetMachineStudioContainer, sourceMachineStudioInstallerBlob.Name);
-
- await Task.Factory.StartNew(() =>
- {
- targetMachineStudioBlob.StartCopy(sourceMachineStudioBlob);
- targetMachineStudioInstallerBlob.StartCopy(sourceMachineStudioInstallerBlob);
- });
- }
-
- public async Task UpgradeVersions(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- await ValidateUpgrade(sourceApp, targetApp);
-
- if (UpgradeConfiguration.UpgradeMachineStudio)
- {
- await UpgradeMachineStudioVersion(sourceApp, targetApp);
- }
-
- if (UpgradeConfiguration.UpgradePPC)
- {
- await UpgradePPCVersion(sourceApp, targetApp);
- }
- }
-
- private async Task UpgradeMachineStudioVersion(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- var latestMachineStudioVersion = await GetLatestMachineStudioVersion(sourceApp);
-
- var targetDataSource = (await targetApp.GetMachineServiceSettingsAsync()).ToDataSource();
-
- using (var db = ObservablesContext.CreateDefault(targetDataSource))
- {
- db.MachineStudioVersions.Add(latestMachineStudioVersion);
- await db.SaveChangesAsync();
- }
- }
-
- private async Task UpgradePPCVersion(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- var latestPPCVersion = await GetLatestPPCVersion(sourceApp);
-
- var targetDataSource = (await targetApp.GetMachineServiceSettingsAsync()).ToDataSource();
-
- using (var db = ObservablesContext.CreateDefault(targetDataSource))
- {
- db.TangoVersions.Add(latestPPCVersion);
- await db.SaveChangesAsync();
- }
- }
-
- private CloudBlockBlob CreateEmptyBlob(CloudBlobContainer container, String name)
- {
- CloudBlockBlob targetBlob = container.GetBlockBlobReference(name);
- using (MemoryStream ms = new MemoryStream())
- {
- targetBlob.UploadFromStream(ms);//Empty memory stream. Will create an empty blob.
- }
-
- return targetBlob;
+
}
#endregion
- #region Validation
-
- public async Task ValidateUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
+ public async Task<IDeploymentSlot> CreateDeploymentSlot(IWebApp app, IDeploymentSlot sourceSlot, String slotName)
{
- if (sourceApp == targetApp)
- {
- throw new InvalidOperationException("Invalid upgrade configuration. source app and target app are identical.");
- }
+ OnProgress(AzureUtilsStage.Initializing, $"Retrieving '{sourceSlot.Name}' settings...");
- if (UpgradeConfiguration.UpgradeMachineStudio)
- {
- await ValidateMachineStudioUpgrade(sourceApp, targetApp);
- }
+ var sourceSettings = await sourceSlot.GetMachineServiceSettingsAsync();
+ var targetSettings = EnvironmentSettings.FromSlotName(app.Name, slotName);
- if (UpgradeConfiguration.UpgradePPC)
- {
- await ValidatePPCUpgrade(sourceApp, targetApp);
- }
- }
+ OnProgress(AzureUtilsStage.Deployment, $"Creating new deployment slot '{targetSettings.SLOT_NAME}'...");
- private async Task ValidateMachineStudioUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
- {
- var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
- var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
-
- var latestSourceMachineStudioVersion = await GetLatestMachineStudioVersion(sourceApp);
-
- //Check if there is any source machine studio version.
- if (latestSourceMachineStudioVersion == null)
- {
- throw new ValidationException("Could not locate a Machine Studio version entry on the source database.");
- }
-
- var latestTargetMachineStudioVersion = await GetLatestMachineStudioVersion(targetApp);
-
- //Check target latest machine studio version is older if there is any.
- if (latestTargetMachineStudioVersion != null && Version.Parse(latestSourceMachineStudioVersion.Version) <= Version.Parse(latestTargetMachineStudioVersion.Version))
- {
- throw new ValidationException($"Machine Studio source version is '{latestSourceMachineStudioVersion.Version}' while target version is '{latestTargetMachineStudioVersion.Version}'.");
- }
+ var dictionary = new Dictionary<string, string>();
+ dictionary.Add(nameof(MachineServiceSettings.DB_ADDRESS), sourceSettings.DB_ADDRESS);
+ dictionary.Add(nameof(MachineServiceSettings.DB_CATALOG), targetSettings.DB_CATALOG);
+ dictionary.Add(nameof(MachineServiceSettings.DB_PASSWORD), sourceSettings.DB_PASSWORD);
+ dictionary.Add(nameof(MachineServiceSettings.DB_USER_NAME), sourceSettings.DB_USER_NAME);
+ dictionary.Add(nameof(MachineServiceSettings.DEPLOYMENT_SLOT), slotName);
+ dictionary.Add(nameof(MachineServiceSettings.ENFORCE_MACHINE_STUDIO_VERSION), sourceSettings.ENFORCE_MACHINE_STUDIO_VERSION);
+ dictionary.Add(nameof(MachineServiceSettings.ENVIRONMENT_GROUP), targetSettings.ENVIRONMENT_GROUP);
+ dictionary.Add(nameof(MachineServiceSettings.STORAGE_ACCOUNT), sourceSettings.STORAGE_ACCOUNT);
+ dictionary.Add(nameof(MachineServiceSettings.MACHINE_STUDIO_VERSIONS_CONTAINER), targetSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
+ dictionary.Add(nameof(MachineServiceSettings.TANGO_VERSIONS_CONTAINER), targetSettings.TANGO_VERSIONS_CONTAINER);
- var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
- var targetClient = targetAccount.CreateCloudBlobClient();
+ var slot = await app.DeploymentSlots
+ .Define(targetSettings.SLOT_NAME)
+ .WithBrandNewConfiguration()
+ .WithWebAppAlwaysOn(true)
+ .WithWebSocketsEnabled(true)
+ .WithStickyAppSettings(dictionary)
+ .WithStickyConnectionString(targetSettings.DB_CATALOG, $"Server=tcp:twine.database.windows.net,1433;Initial Catalog={targetSettings.DB_CATALOG};Persist Security Info=False;User ID=BackupUser;Password=Aa123456;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;", Microsoft.Azure.Management.AppService.Fluent.Models.ConnectionStringType.SQLAzure)
+ .CreateAsync();
- var targetMachineStudioContainer = targetClient.GetContainerReference(targetSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
-
- //Check machine studio binaries blob not exists on the target.
- var targetMachineStudioBlob = targetMachineStudioContainer.GetBlockBlobReference(latestSourceMachineStudioVersion.BlobName);
- if (await targetMachineStudioBlob.ExistsAsync())
- {
- throw new ValidationException($"Machine Studio Block blob '{latestSourceMachineStudioVersion.BlobName}' already exists on the target storage.");
- }
-
- //Check machine studio installer blob not exists on the target.
- var targetMachineStudioInstallerBlob = targetMachineStudioContainer.GetBlockBlobReference(latestSourceMachineStudioVersion.InstallerBlobName);
- if (await targetMachineStudioInstallerBlob.ExistsAsync())
- {
- throw new ValidationException($"Machine Studio Block blob '{latestSourceMachineStudioVersion.InstallerBlobName}' already exists on the target storage.");
- }
+ return slot;
}
- private async Task ValidatePPCUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
+ public async Task<IDeploymentSlot> GetDeploymentSlot(IWebApp app, String slotName)
{
- var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
- var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
-
- var latestSourcePPCVersion = await GetLatestPPCVersion(sourceApp);
-
- //Check if there is any source PPC version.
- if (latestSourcePPCVersion == null)
- {
- throw new ValidationException("Could not locate a PPC version entry on the source database.");
- }
-
- var latestTargetPPCVersion = await GetLatestPPCVersion(targetApp);
-
- //Check target latest PPC version is older if there is any.
- if (latestTargetPPCVersion != null && Version.Parse(latestSourcePPCVersion.Version) <= Version.Parse(latestTargetPPCVersion.Version))
- {
- throw new ValidationException($"PPC source version is '{latestSourcePPCVersion.Version}' while target version is '{latestTargetPPCVersion.Version}'.");
- }
-
- var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
- var targetClient = targetAccount.CreateCloudBlobClient();
-
- var targetPPCContainer = targetClient.GetContainerReference(targetSettings.TANGO_VERSIONS_CONTAINER);
-
- //Check PPC binaries blob not exists on the target.
- var targetPPCBlob = targetPPCContainer.GetBlockBlobReference(latestSourcePPCVersion.BlobName);
- if (await targetPPCBlob.ExistsAsync())
- {
- throw new ValidationException($"PPC Block blob '{latestSourcePPCVersion.BlobName}' already exists on the target storage.");
- }
-
- //Check PPC installer blob not exists on the target.
- var targetPPCInstallerBlob = targetPPCContainer.GetBlockBlobReference(latestSourcePPCVersion.InstallerBlobName);
- if (await targetPPCInstallerBlob.ExistsAsync())
- {
- throw new ValidationException($"PPC Block blob '{latestSourcePPCVersion.InstallerBlobName}' already exists on the target storage.");
- }
+ OnProgress(AzureUtilsStage.Deployment, $"Checking '{app.Name}' deployment slots...");
+ IDeploymentSlot slot = (await app.DeploymentSlots.ListAsync()).ToList().SingleOrDefault(x => x.Name == slotName);
+ return slot;
}
-
- #endregion
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/UpgradeConfiguration.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/UpgradeConfiguration.cs
deleted file mode 100644
index ab1099617..000000000
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/UpgradeConfiguration.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Tango.Core;
-
-namespace Tango.AzureUtils.Deployment
-{
- public class UpgradeConfiguration : ExtendedObject
- {
- private bool _UpgradeMachineService;
- public bool UpgradeMachineService
- {
- get { return _UpgradeMachineService; }
- set { _UpgradeMachineService = value; RaisePropertyChangedAuto(); }
- }
-
- private bool _UpgradeMachineStudio;
- public bool UpgradeMachineStudio
- {
- get { return _UpgradeMachineStudio; }
- set { _UpgradeMachineStudio = value; RaisePropertyChangedAuto(); }
- }
-
- private bool _UpgradePPC;
- public bool UpgradePPC
- {
- get { return _UpgradePPC; }
- set { _UpgradePPC = value; RaisePropertyChangedAuto(); }
- }
- }
-}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/CreateEnvironmentConfiguration.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/CreateEnvironmentConfiguration.cs
new file mode 100644
index 000000000..bf1c2cb31
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/CreateEnvironmentConfiguration.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.AzureUtils.Environment
+{
+ public class CreateEnvironmentConfiguration
+ {
+ public String Email { get; set; }
+ public String Password { get; set; }
+
+ public bool CreateEnvironmentGroup { get; set; } = true;
+ public bool AddEnvironmentGroupAdminUser { get; set; } = true;
+ public bool CloneEnvironmentGroupUsers { get; set; } = true;
+ public bool CreateDeploymentSlot { get; set; } = true;
+ public bool CreateDatabase { get; set; } = true;
+ public bool AddDatabasePermissionsForEnvironmentGroup { get; set; } = true;
+ public bool CreateDatabaseBackupUser { get; set; } = true;
+ public bool SynchronizeDatabaseSchema { get; set; } = true;
+ public bool SynchronizeDatabaseData { get; set; } = true;
+ public bool CreateStorageContainers { get; set; } = true;
+ public bool CopyStorageBlobs { get; set; } = true;
+ public bool CopyMachineServiceFiles { get; set; } = true;
+ public bool IgnoreExistingSlot { get; set; } = false;
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs
index 822813742..f30a51671 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs
@@ -10,7 +10,10 @@ using Microsoft.Azure.Management.RecoveryServices.Backup;
using Microsoft.Azure.Management.Sql.Fluent.Models;
using Microsoft.WindowsAzure.Storage;
using Tango.AzureUtils.ActiveDirectory;
+using Tango.AzureUtils.Database;
using Tango.AzureUtils.Deployment;
+using Tango.AzureUtils.FTP;
+using Tango.AzureUtils.Storage;
using Tango.BL;
using Tango.Core;
using Tango.Core.DB;
@@ -21,197 +24,314 @@ namespace Tango.AzureUtils.Environment
{
private ActiveDirectoryManager _adManager;
private DeploymentManager _deploymentManager;
+ private DatabaseManager _databaseManager;
+ private StorageManager _storageManager;
+ private FtpManager _ftpManager;
public EnvironmentManager(IAzure azure) : base(azure)
{
- _adManager = new ActiveDirectoryManager(azure, AzureUtilsAuthenticationFactory.GetCredentials());
- _adManager.ConfirmationRequired += (x, e) => OnRequestConfirmation(e);
- _adManager.Progress += (x, e) => OnProgress(e);
-
- _deploymentManager = new DeploymentManager(azure);
- _deploymentManager.ConfirmationRequired += (x, e) => OnRequestConfirmation(e);
- _deploymentManager.Progress += (x, e) => OnProgress(e);
+ _adManager = CreateManager<ActiveDirectoryManager>();
+ _deploymentManager = CreateManager<DeploymentManager>();
+ _databaseManager = CreateManager<DatabaseManager>();
+ _storageManager = CreateManager<StorageManager>();
+ _ftpManager = CreateManager<FtpManager>();
}
- #region Deployment Slots
+ #region Creation
- public async Task<IDeploymentSlot> CreateDeploymentSlot(IWebApp app, IDeploymentSlot sourceSlot, String name, String adEmail, String adPassword)
+ public async Task<IDeploymentSlot> CreateEnvironment(IWebApp app, IDeploymentSlot sourceSlot, String name, CreateEnvironmentConfiguration config)
{
- String dbCatalog = $"Tango_{name}";
- String machineStudioContainerName = $"machine-studio-versions-{name.ToLower()}";
- String ppcContainerName = $"tango-versions-{name.ToLower()}";
- String machineServiceBackupsContainerName = $"machine-service-backups-{name.ToLower()}";
- String machineServiceLogsContainerName = $"machine-service-logs-{name.ToLower()}";
- String environmentGroupName = $"Tango {name}";
- String slotName = app.Name + "-" + name;
+ OnProgress(AzureUtilsStage.Environment, $"Retrieving '{sourceSlot.Name}' settings...");
+
+ var sourceSettings = await sourceSlot.GetMachineServiceSettingsAsync();
+ var targetSettings = EnvironmentSettings.FromSlotName(app.Name, name);
+
+ if (!config.IgnoreExistingSlot)
+ {
+ var deploymentSlots = await app.DeploymentSlots.ListAsync();
+ if (deploymentSlots.ToList().Exists(x => x.Name.ToLower() == targetSettings.SLOT_NAME.ToLower()))
+ {
+ throw new InvalidOperationException($"Deployment slot '{targetSettings.SLOT_NAME}' already exists.");
+ }
+ }
+
+ //Add Environment Group
+ await _adManager.Authenticate(config.Email, config.Password);
+
+ if (config.CreateEnvironmentGroup)
+ {
+ if (!await _adManager.IsGroupExists(targetSettings.ENVIRONMENT_GROUP))
+ {
+ await _adManager.AddGroup(targetSettings.ENVIRONMENT_GROUP);
+
+ if (config.AddEnvironmentGroupAdminUser)
+ {
+ await _adManager.AddUserToGroup(targetSettings.ENVIRONMENT_GROUP, config.Email);
+ }
+ }
+ else
+ {
+ await RequestConfirmation($"Environment group '{targetSettings.ENVIRONMENT_GROUP}' already exists. Do you wish to continue?");
+ }
+ }
- OnProgress(AzureUtilsStage.Initializing, $"Retrieving '{sourceSlot.Name}' settings...");
- var settings = await sourceSlot.GetMachineServiceSettingsAsync();
- OnProgress(AzureUtilsStage.EnvironmentGroup, $"Authenticating with active directory graph...");
- await _adManager.Authenticate(adEmail, adPassword);
+ //Add Deployment Slot
+ var slot = await _deploymentManager.GetDeploymentSlot(app, targetSettings.SLOT_NAME);
- if (!await _adManager.IsGroupExists(environmentGroupName))
+ if (config.CreateDeploymentSlot)
{
- OnProgress(AzureUtilsStage.EnvironmentGroup, $"Creating environment group '{environmentGroupName}'...");
- await _adManager.AddGroup(environmentGroupName);
+ if (slot == null)
+ {
+ slot = await _deploymentManager.CreateDeploymentSlot(app, sourceSlot, targetSettings.SLOT_NAME);
+ }
+ else
+ {
+ await RequestConfirmation($"Deployment slot '{targetSettings.SLOT_NAME}' already exists. Do you wish to continue.");
+ }
+ }
- OnProgress(AzureUtilsStage.EnvironmentGroup, $"Adding environment group user '{adEmail}'...");
- await _adManager.AddUserToGroup(environmentGroupName, adEmail);
+ //Add Database
+ if (config.CreateDatabase)
+ {
+ if (!await _databaseManager.IsDatabaseExists("twine", targetSettings.DB_CATALOG))
+ {
+ await _databaseManager.AddDatabase("twine", targetSettings.DB_CATALOG);
+ }
+ else
+ {
+ await RequestConfirmation($"Database '{targetSettings.DB_CATALOG}' already exists. Do you wish to continue?");
+ }
}
- else
+
+ //Add permissions for environment group on database
+ if (config.AddDatabasePermissionsForEnvironmentGroup)
{
- await RequestConfirmation($"Environment group '{environmentGroupName}' already exists. Do you wish to continue?");
+ try
+ {
+ await _databaseManager.AddEnvironmentGroupPermissions(sourceSettings.DB_ADDRESS, targetSettings.DB_CATALOG, targetSettings.ENVIRONMENT_GROUP, config.Email, config.Password);
+ }
+ catch (Exception ex)
+ {
+ await RequestConfirmation($"Error creating/adding permissions for environment group '{targetSettings.ENVIRONMENT_GROUP}' on database.\n{ex.FlattenMessage()}\n\nDo you wish to continue?");
+ }
}
- OnProgress(AzureUtilsStage.DeploymentSlot, $"Checking '{app.Name}' deployment slots...");
- IDeploymentSlot slot = (await app.DeploymentSlots.ListAsync()).ToList().SingleOrDefault(x => x.Name == slotName);
+ //Create backup user
+ if (config.CreateDatabaseBackupUser)
+ {
+ try
+ {
+ await _databaseManager.AddBackupUser(sourceSettings.DB_ADDRESS, targetSettings.DB_CATALOG, sourceSettings.DB_USER_NAME, sourceSettings.DB_PASSWORD);
+ }
+ catch (Exception ex)
+ {
+
+ await RequestConfirmation($"Error creating/adding permissions for BackupUser on database.\n{ex.FlattenMessage()}\n\nDo you wish to continue?");
+ }
+ }
- if (slot == null)
+ //Synchronize Schema
+ if (config.SynchronizeDatabaseSchema)
{
- //Add Slot
- OnProgress(AzureUtilsStage.DeploymentSlot, $"Creating new deployment slot '{slotName}'...");
+ await _databaseManager.OpenSQLExaminerSchema(sourceSlot, slot);
+ await RequestConfirmation($"Please synchronize the database schema between '{sourceSettings.DB_CATALOG}' and '{targetSettings.DB_CATALOG}'.\nPlease confirm in order to continue.");
+ OnProgress(AzureUtilsStage.Environment, $"Waiting for database schema synchronization...");
+ }
- var dictionary = new Dictionary<string, string>();
- dictionary.Add(nameof(MachineServiceSettings.DB_ADDRESS), settings.DB_ADDRESS);
- dictionary.Add(nameof(MachineServiceSettings.DB_CATALOG), dbCatalog);
- dictionary.Add(nameof(MachineServiceSettings.DB_PASSWORD), settings.DB_PASSWORD);
- dictionary.Add(nameof(MachineServiceSettings.DB_USER_NAME), settings.DB_USER_NAME);
- dictionary.Add(nameof(MachineServiceSettings.DEPLOYMENT_SLOT), name);
- dictionary.Add(nameof(MachineServiceSettings.ENFORCE_MACHINE_STUDIO_VERSION), settings.ENFORCE_MACHINE_STUDIO_VERSION);
- dictionary.Add(nameof(MachineServiceSettings.ENVIRONMENT_GROUP), environmentGroupName);
- dictionary.Add(nameof(MachineServiceSettings.STORAGE_ACCOUNT), settings.STORAGE_ACCOUNT);
- dictionary.Add(nameof(MachineServiceSettings.MACHINE_STUDIO_VERSIONS_CONTAINER), machineStudioContainerName);
- dictionary.Add(nameof(MachineServiceSettings.TANGO_VERSIONS_CONTAINER), ppcContainerName);
- slot = await app.DeploymentSlots
- .Define(slotName)
- .WithBrandNewConfiguration()
- .WithWebAppAlwaysOn(true)
- .WithWebSocketsEnabled(true)
- .WithStickyAppSettings(dictionary)
- .WithStickyConnectionString(dbCatalog, $"Server=tcp:twine.database.windows.net,1433;Initial Catalog={dbCatalog};Persist Security Info=False;User ID=BackupUser;Password=Aa123456;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;", Microsoft.Azure.Management.AppService.Fluent.Models.ConnectionStringType.SQLAzure)
- .CreateAsync();
+ //Synchronize Data
+ if (config.SynchronizeDatabaseData)
+ {
+ await _databaseManager.OpenSQLExaminerData(sourceSlot, slot, true);
+ await RequestConfirmation($"Please synchronize the database static collections between '{sourceSettings.DB_CATALOG}' and '{targetSettings.DB_CATALOG}'.\nPlease confirm in order to continue.");
+ OnProgress(AzureUtilsStage.Environment, $"Waiting for database static collections synchronization...");
}
- else
+
+
+ //Add Storage Containers
+ await _storageManager.Connect(sourceSettings.STORAGE_ACCOUNT);
+
+ if (config.CreateStorageContainers)
{
- await RequestConfirmation($"Deployment slot '{slotName}' already exists. Do you wish to continue.");
+ await _storageManager.CreateContainer(targetSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
+ await _storageManager.CreateContainer(targetSettings.TANGO_VERSIONS_CONTAINER);
+ await _storageManager.CreateContainer(targetSettings.MACHINE_SERVICE_BACKUPS_CONTAINER);
+ await _storageManager.CreateContainer(targetSettings.MACHINE_SERVICE_LOGS_CONTAINER);
}
- //Add Database
- OnProgress(AzureUtilsStage.Database, $"Checking twine database server...");
- var sqlServer = (await Azure.SqlServers.ListAsync()).SingleOrDefault(x => x.Name == "twine");
+ if (config.CopyStorageBlobs)
+ {
+ //Add Machine Studio storage versions.
+ try
+ {
+ await _storageManager.ValidateMachineStudioStorageUpgrade(sourceSlot, slot);
+ await _storageManager.UpgradeMachineStudioStorage(sourceSlot, slot);
+ }
+ catch (Exception ex)
+ {
+ await RequestConfirmation($"Issues encountered with upgrading machine studio storage versions.\n{ex.FlattenMessage()}\nDo you wish to continue?");
+ }
- var existingDatabase = (await sqlServer.Databases.ListAsync()).SingleOrDefault(x => x.Name == dbCatalog);
+ //Add PPC storage versions.
+ try
+ {
+ await _storageManager.ValidatePPCStorageUpgrade(sourceSlot, slot);
+ await _storageManager.UpgradePPCStorage(sourceSlot, slot);
+ }
+ catch (Exception ex)
+ {
+ await RequestConfirmation($"Issues encountered with upgrading PPC storage versions.\n{ex.FlattenMessage()}\nDo you wish to continue?");
+ }
+ }
- if (existingDatabase == null)
+ //Copy Website files.
+ if (config.CopyMachineServiceFiles)
{
- OnProgress(AzureUtilsStage.Database, $"Creating new database '{dbCatalog}'...");
- var database = await sqlServer.Databases.Define(dbCatalog).WithEdition(DatabaseEdition.Standard).CreateAsync();
+ await _ftpManager.CopyAppFiles(sourceSlot, slot);
}
- else
+
+ //Restart slot.
+ OnProgress(AzureUtilsStage.Environment, "Restarting deployment slot...");
+ await slot.RestartAsync();
+
+ OnCompleted("Environment created successfully.");
+
+ return slot;
+ }
+
+ public async Task UpgradeEnvironment(IWebAppBase sourceApp, IWebAppBase targetApp, UpgradeEnvironmentConfiguration config)
+ {
+ await ValidateEnvironmentUpgrade(sourceApp, targetApp, config);
+
+ OnProgress(AzureUtilsStage.Environment, $"Retrieving '{sourceApp.Name}' settings...");
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+
+ //Synchronize Schema
+ if (config.SynchronizeDatabaseSchema)
{
- await RequestConfirmation($"Database '{dbCatalog}' already exists. Do you wish to continue?");
+ await _databaseManager.OpenSQLExaminerSchema(sourceApp, targetApp);
+ await RequestConfirmation($"Please synchronize the database schema between '{sourceSettings.DB_CATALOG}' and '{targetSettings.DB_CATALOG}'.\nPlease confirm in order to continue.");
+ OnProgress(AzureUtilsStage.Environment, $"Waiting for database schema synchronization...");
}
- //Add permissions for environment group on database
- OnProgress(AzureUtilsStage.Database, $"Adding environment group permissions on '{dbCatalog}'...");
- using (DbManager db = DbManager.FromDataSource(new DataSource()
+ //Synchronize Data
+ if (config.SynchronizeDatabaseData)
{
- Type = DataSourceType.Azure,
- Address = settings.DB_ADDRESS,
- Catalog = dbCatalog,
- UserName = adEmail,
- Password = adPassword,
- IntegratedSecurity = false
- }))
+ await _databaseManager.OpenSQLExaminerData(sourceApp, targetApp);
+ await RequestConfirmation($"Please synchronize the database static collections between '{sourceSettings.DB_CATALOG}' and '{targetSettings.DB_CATALOG}'.\nPlease confirm in order to continue.");
+ OnProgress(AzureUtilsStage.Environment, $"Waiting for database static collections synchronization...");
+ }
+
+ //Add Machine Studio storage versions.
+ if (config.CopyMachineStudioStorageBlobs)
{
try
{
- await db.ExecuteCommandAsync($"CREATE USER [{environmentGroupName}] FROM EXTERNAL PROVIDER");
- await db.ExecuteCommandAsync($"ALTER ROLE db_datareader ADD MEMBER [{environmentGroupName}];");
- await db.ExecuteCommandAsync($"ALTER ROLE db_datawriter ADD MEMBER [{environmentGroupName}];");
+ await _storageManager.ValidateMachineStudioStorageUpgrade(sourceApp, targetApp);
+ await _storageManager.UpgradeMachineStudioStorage(sourceApp, targetApp);
}
catch (Exception ex)
{
- await RequestConfirmation($"Error creating/adding permissions for environment group '{environmentGroupName}' on database.\n{ex.FlattenMessage()}\n\nDo you wish to continue?");
+ await RequestConfirmation($"Issues encountered with upgrading machine studio storage versions.\n{ex.FlattenMessage()}\nDo you wish to continue?");
}
}
- OnProgress(AzureUtilsStage.Database, $"Adding BackupUser permissions on '{dbCatalog}'...");
- //Create backup user
- using (DbManager db = DbManager.FromCredentials(settings.DB_ADDRESS, dbCatalog, settings.DB_USER_NAME, settings.DB_PASSWORD))
+ //Add PPC storage versions.
+ if (config.CopyPPCStorageBlobs)
{
try
{
- await db.ExecuteCommandAsync("CREATE USER [BackupUser] FOR LOGIN [BackupUser] WITH DEFAULT_SCHEMA=[dbo]");
- await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_owner', N'BackupUser'");
- await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_accessadmin', N'BackupUser'");
- await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_securityadmin', N'BackupUser'");
- await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_backupoperator', N'BackupUser'");
- await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_datareader', N'BackupUser'");
- await db.ExecuteCommandAsync("EXEC sp_addrolemember N'db_datawriter', N'BackupUser'");
+ await _storageManager.ValidatePPCStorageUpgrade(sourceApp, targetApp);
+ await _storageManager.UpgradePPCStorage(sourceApp, targetApp);
}
catch (Exception ex)
{
- await RequestConfirmation($"Error creating/adding permissions for BackupUser on database.\n{ex.FlattenMessage()}\n\nDo you wish to continue?");
+ await RequestConfirmation($"Issues encountered with upgrading PPC storage versions.\n{ex.FlattenMessage()}\nDo you wish to continue?");
}
}
- //Synchronize Schema
- //await _deploymentManager.OpenSQLExaminerSchema(sourceSlot, slot);
- //await RequestConfirmation($"Please synchronize the database schema between '{settings.DB_CATALOG}' and '{dbCatalog}'.\nPlease confirm in order to continue.");
- //OnProgress(AzureUtilsStage.Database, $"Waiting for database schema synchronization...");
+ //Upgrade machine studio database version.
+ if (config.UpgradeMachineStudioDatabaseVersion)
+ {
+ try
+ {
+ await _databaseManager.ValidateMachineStudioDatabaseUpgrade(sourceApp, targetApp);
+ await _databaseManager.UpgradeMachineStudioVersion(sourceApp, targetApp);
+ }
+ catch (Exception ex)
+ {
+ await RequestConfirmation($"Issues encountered with upgrading Machine Studio database versions.\n{ex.FlattenMessage()}\nDo you wish to continue?");
+ }
+ }
- //await _deploymentManager.OpenSQLExaminerData(sourceSlot, slot, true);
- //await RequestConfirmation($"Please synchronize the database static collections between '{settings.DB_CATALOG}' and '{dbCatalog}'.\nPlease confirm in order to continue.");
- //OnProgress(AzureUtilsStage.Database, $"Waiting for database static collections synchronization...");
+ //Upgrade PPC database version.
+ if (config.UpgradePPCDatabaseVersion)
+ {
+ try
+ {
+ await _databaseManager.ValidatePPCDatabaseUpgrade(sourceApp, targetApp);
+ await _databaseManager.UpgradePPCVersion(sourceApp, targetApp);
+ }
+ catch (Exception ex)
+ {
+ await RequestConfirmation($"Issues encountered with upgrading PPC database versions.\n{ex.FlattenMessage()}\nDo you wish to continue?");
+ }
+ }
- //OnProgress(AzureUtilsStage.Database, $"Retrieving latest Machine Studio version...");
- //var latestMsVersion = await _deploymentManager.GetLatestMachineStudioVersion(sourceSlot);
- //OnProgress(AzureUtilsStage.Database, $"Retrieving latest PPC version...");
- //var latestPPCVersion = await _deploymentManager.GetLatestPPCVersion(sourceSlot);
+ //Copy Website files.
+ if (config.CopyMachineServiceFiles)
+ {
+ await _ftpManager.CopyAppFiles(sourceApp, targetApp);
+ }
- //var targetSettings = await slot.GetMachineServiceSettingsAsync();
+ //Restart slot.
+ OnProgress(AzureUtilsStage.Environment, "Restarting traget deployment slot...");
+ await targetApp.RestartAsync();
- //using (ObservablesContext db = ObservablesContext.CreateDefault(targetSettings.ToDataSource()))
- //{
- // db.MachineStudioVersions.Add(latestMsVersion);
- // db.TangoVersions.Add(latestPPCVersion);
- //}
+ OnCompleted("Environment upgraded successfully.");
+ }
- //Add Storage Containers
- OnProgress(AzureUtilsStage.Storage, $"Connecting to storage account...");
- var targetAccount = CloudStorageAccount.Parse(settings.STORAGE_ACCOUNT);
- var targetClient = targetAccount.CreateCloudBlobClient();
+ public async Task ValidateEnvironmentUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp, UpgradeEnvironmentConfiguration config)
+ {
+ if (sourceApp == targetApp || sourceApp.Name == targetApp.Name)
+ {
+ throw new InvalidOperationException("Source slot and target slot are identical.");
+ }
- OnProgress(AzureUtilsStage.Storage, $"Creating storage container '{machineStudioContainerName}'...");
- var machineStudioContainer = targetClient.GetContainerReference(machineStudioContainerName);
- await machineStudioContainer.CreateIfNotExistsAsync();
+ //Add Machine Studio storage versions.
+ if (config.CopyMachineStudioStorageBlobs)
+ {
+ await _storageManager.ValidateMachineStudioStorageUpgrade(sourceApp, targetApp);
+ }
- OnProgress(AzureUtilsStage.Storage, $"Creating storage container '{ppcContainerName}'...");
- var ppcContainer = targetClient.GetContainerReference(ppcContainerName);
- await ppcContainer.CreateIfNotExistsAsync();
+ //Add PPC storage versions.
+ if (config.CopyPPCStorageBlobs)
+ {
+ await _storageManager.ValidatePPCStorageUpgrade(sourceApp, targetApp);
+ }
- OnProgress(AzureUtilsStage.Storage, $"Creating storage container '{machineServiceBackupsContainerName}'...");
- var machineServiceBackupsContainer = targetClient.GetContainerReference(machineServiceBackupsContainerName);
- await machineServiceBackupsContainer.CreateIfNotExistsAsync();
+ //Upgrade machine studio database version.
+ if (config.UpgradeMachineStudioDatabaseVersion)
+ {
+ await _databaseManager.ValidateMachineStudioDatabaseUpgrade(sourceApp, targetApp);
+ }
- OnProgress(AzureUtilsStage.Storage, $"Creating storage container '{machineServiceLogsContainerName}'...");
- var machineServiceLogsContainer = targetClient.GetContainerReference(machineServiceLogsContainerName);
- await machineServiceLogsContainer.CreateIfNotExistsAsync();
+ //Upgrade PPC database version.
+ if (config.UpgradePPCDatabaseVersion)
+ {
+ await _databaseManager.ValidatePPCDatabaseUpgrade(sourceApp, targetApp);
+ }
+ }
- _deploymentManager.UpgradeConfiguration.UpgradeMachineService = true;
- _deploymentManager.UpgradeConfiguration.UpgradeMachineStudio = true;
- _deploymentManager.UpgradeConfiguration.UpgradePPC = true;
+ #endregion
- await _deploymentManager.PerformFullUpgrade(sourceSlot, slot);
+ #region Upgrade
- OnProgress(AzureUtilsStage.Ready, "Deployment slot created successfully.", 0, 100, false);
- return slot;
- }
#endregion
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentSettings.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentSettings.cs
new file mode 100644
index 000000000..8b8e3a757
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentSettings.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.AzureUtils.Environment
+{
+ public class EnvironmentSettings
+ {
+ public String SLOT_NAME { get; set; }
+ public String DB_CATALOG { get; set; }
+ public String MACHINE_STUDIO_VERSIONS_CONTAINER { get; set; }
+ public String TANGO_VERSIONS_CONTAINER { get; set; }
+ public String MACHINE_SERVICE_BACKUPS_CONTAINER { get; set; }
+ public String MACHINE_SERVICE_LOGS_CONTAINER { get; set; }
+ public String ENVIRONMENT_GROUP { get; set; }
+
+ public static EnvironmentSettings FromSlotName(String appName, String name)
+ {
+ EnvironmentSettings settings = new EnvironmentSettings();
+
+ settings.SLOT_NAME = appName + "-" + name;
+ settings.DB_CATALOG = $"Tango_{name}";
+ settings.MACHINE_STUDIO_VERSIONS_CONTAINER = $"machine-studio-versions-{name.ToLower()}";
+ settings.TANGO_VERSIONS_CONTAINER = $"tango-versions-{name.ToLower()}";
+ settings.MACHINE_SERVICE_BACKUPS_CONTAINER = $"machine-service-backups-{name.ToLower()}";
+ settings.MACHINE_SERVICE_LOGS_CONTAINER = $"machine-service-logs-{name.ToLower()}";
+ settings.ENVIRONMENT_GROUP = $"Tango {name}";
+
+ return settings;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/UpgradeEnvironmentConfiguration.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/UpgradeEnvironmentConfiguration.cs
new file mode 100644
index 000000000..537056701
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/UpgradeEnvironmentConfiguration.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.AzureUtils.Environment
+{
+ public class UpgradeEnvironmentConfiguration
+ {
+ public bool SynchronizeDatabaseSchema { get; set; } = true;
+ public bool SynchronizeDatabaseData { get; set; } = true;
+ public bool CopyMachineStudioStorageBlobs { get; set; } = true;
+ public bool UpgradeMachineStudioDatabaseVersion { get; set; } = true;
+ public bool CopyPPCStorageBlobs { get; set; } = true;
+ public bool UpgradePPCDatabaseVersion { get; set; } = true;
+ public bool CopyMachineServiceFiles { get; set; } = true;
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/FTP/FtpManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/FTP/FtpManager.cs
new file mode 100644
index 000000000..5a174dcb2
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/FTP/FtpManager.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Authentication;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using FluentFTP;
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+
+namespace Tango.AzureUtils.FTP
+{
+ public class FtpManager : AzureUtilsComponentBase
+ {
+ private IProgress<FtpProgress> _ftpDownloadProgress;
+ private IProgress<FtpProgress> _ftpUploadProgress;
+ private String _currentDownloadFile;
+
+ public FtpManager(IAzure azure) : base(azure)
+ {
+ _ftpDownloadProgress = new Progress<FtpProgress>((p) =>
+ {
+ OnProgress(AzureUtilsStage.FtpDownload, $"Downloading {_currentDownloadFile}...", p.Progress, 100, false);
+ });
+
+ _ftpUploadProgress = new Progress<FtpProgress>((p) =>
+ {
+ OnProgress(AzureUtilsStage.FtpUpload, $"Uploading {_currentDownloadFile}...", p.Progress, 100, false);
+ });
+ }
+
+ private FtpClient CreateFtpClient(String address, String userName, String password)
+ {
+ Uri uri = new Uri("ftp://" + address);
+ string host = uri.Host;
+
+ FtpClient client = new FtpClient(host, userName, password);
+ //client.EncryptionMode = FtpEncryptionMode.Explicit;
+ client.SslProtocols = SslProtocols.Tls;
+ client.ValidateAnyCertificate = true;
+ client.DataConnectionType = FtpDataConnectionType.PASV;
+ client.DownloadDataType = FtpDataType.Binary;
+ client.RetryAttempts = 5;
+ client.SocketPollInterval = 1000;
+ client.ConnectTimeout = 2000;
+ client.ReadTimeout = 2000;
+ client.DataConnectionConnectTimeout = 2000;
+ client.DataConnectionReadTimeout = 2000;
+ client.OnLogEvent = (ev, msg) =>
+ {
+ if (msg.Contains("DownloadFileAsync") || msg.Contains("UploadFileAsync"))
+ {
+ var matches = Regex.Matches(msg, "(?<=\").+?(?=\")");
+ var match = matches.OfType<Match>().LastOrDefault();
+
+ if (match != null)
+ {
+ _currentDownloadFile = match.ToString();
+ }
+ }
+ };
+
+ return client;
+ }
+
+ public async Task<List<FtpResult>> DownloadWebAppFiles(IWebAppBase app, String targetFolder)
+ {
+ OnProgress(AzureUtilsStage.FtpDownload, $"Downloading web app files for '{app.Name}'...");
+
+ var profile = await app.GetPublishingProfileAsync();
+
+ using (var ftp = CreateFtpClient(profile.FtpUrl, profile.FtpUsername, profile.FtpPassword))
+ {
+ await ftp.ConnectAsync();
+ var downloadResults = await ftp.DownloadDirectoryAsync(targetFolder, "/site/wwwroot", progress: _ftpDownloadProgress);
+
+ foreach (var downloadResult in downloadResults)
+ {
+ if (downloadResult.IsFailed)
+ {
+ throw downloadResult.Exception;
+ }
+ }
+
+ return downloadResults;
+ }
+ }
+
+ public async Task<List<FtpResult>> UploadWebAppFiles(IWebAppBase app, String sourceFolder)
+ {
+ OnProgress(AzureUtilsStage.FtpUpload, $"Uploading web app files for '{app.Name}'...");
+
+ var profile = await app.GetPublishingProfileAsync();
+
+ using (var ftp = CreateFtpClient(profile.FtpUrl, profile.FtpUsername, profile.FtpPassword))
+ {
+ var uploadResults = await ftp.UploadDirectoryAsync(sourceFolder, "/site/wwwroot", existsMode: FtpRemoteExists.Overwrite, progress: _ftpUploadProgress);
+
+ foreach (var uploadResult in uploadResults)
+ {
+ if (uploadResult.IsFailed)
+ {
+ throw uploadResult.Exception;
+ }
+ }
+
+ return uploadResults;
+ }
+ }
+
+ public async Task CopyAppFiles(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ var webAppFilesTempFolder = TemporaryManager.CreateFolder();
+ var downloadResults = await DownloadWebAppFiles(sourceApp, webAppFilesTempFolder);
+ var uploadResults = await UploadWebAppFiles(targetApp, webAppFilesTempFolder);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs
new file mode 100644
index 000000000..910f4b84f
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+using Microsoft.WindowsAzure.Storage;
+using Microsoft.WindowsAzure.Storage.Blob;
+using Tango.AzureUtils.Database;
+
+namespace Tango.AzureUtils.Storage
+{
+ public class StorageManager : AzureUtilsComponentBase
+ {
+ private String _account;
+ private CloudBlobClient _client;
+ private DatabaseManager _databaseManager;
+
+ public StorageManager(IAzure azure) : base(azure)
+ {
+ _databaseManager = CreateManager<DatabaseManager>();
+ }
+
+ public Task Connect(String account)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Connecting to storage account...");
+ _account = account;
+ var targetAccount = CloudStorageAccount.Parse(_account);
+ _client = targetAccount.CreateCloudBlobClient();
+
+ return Task.FromResult(true);
+ }
+
+ private async Task<CloudBlockBlob> CreateEmptyBlob(CloudBlobContainer container, String name)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Creating blob '{name}'...");
+
+ CloudBlockBlob targetBlob = container.GetBlockBlobReference(name);
+ using (MemoryStream ms = new MemoryStream())
+ {
+ await targetBlob.UploadFromStreamAsync(ms);//Empty memory stream. Will create an empty blob.
+ }
+
+ return targetBlob;
+ }
+
+ public async Task CreateContainer(String name)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Creating storage container '{name}'...");
+ var container = _client.GetContainerReference(name);
+ await container.CreateIfNotExistsAsync();
+ }
+
+ public async Task UpgradePPCStorage(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Retrieving source and target settings...");
+
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+ var latestPPCVersion = await _databaseManager.GetLatestPPCVersion(sourceApp);
+
+ OnProgress(AzureUtilsStage.Storage, $"Upgrading PPC version storage...");
+
+ var sourceAccount = CloudStorageAccount.Parse(sourceSettings.STORAGE_ACCOUNT);
+ var sourceClient = sourceAccount.CreateCloudBlobClient();
+
+ var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
+ var targetClient = targetAccount.CreateCloudBlobClient();
+
+ var sourcePPCContainer = sourceClient.GetContainerReference(sourceSettings.TANGO_VERSIONS_CONTAINER);
+ var targetPPCContainer = targetClient.GetContainerReference(targetSettings.TANGO_VERSIONS_CONTAINER);
+
+ var sourcePPCBlob = sourcePPCContainer.GetBlockBlobReference(latestPPCVersion.BlobName);
+ var sourcePPCInstallerBlob = sourcePPCContainer.GetBlockBlobReference(latestPPCVersion.InstallerBlobName);
+
+ var targetPPCBlob = await CreateEmptyBlob(targetPPCContainer, sourcePPCBlob.Name);
+ var targetPPCInstallerBlob = await CreateEmptyBlob(targetPPCContainer, sourcePPCInstallerBlob.Name);
+
+ await Task.Factory.StartNew(() =>
+ {
+ targetPPCBlob.StartCopy(sourcePPCBlob);
+ targetPPCInstallerBlob.StartCopy(sourcePPCInstallerBlob);
+ });
+ }
+
+ public async Task UpgradeMachineStudioStorage(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Retrieving source and target settings...");
+
+ var latestMachineStudioVersion = await _databaseManager.GetLatestMachineStudioVersion(sourceApp);
+
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+ OnProgress(AzureUtilsStage.Storage, $"Upgrading Machine Studio version storage...");
+
+ var sourceAccount = CloudStorageAccount.Parse(sourceSettings.STORAGE_ACCOUNT);
+ var sourceClient = sourceAccount.CreateCloudBlobClient();
+
+ var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
+ var targetClient = targetAccount.CreateCloudBlobClient();
+
+ var sourceMachineStudioContainer = sourceClient.GetContainerReference(sourceSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
+ var targetMachineStudioContainer = targetClient.GetContainerReference(targetSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
+
+ var sourceMachineStudioBlob = sourceMachineStudioContainer.GetBlockBlobReference(latestMachineStudioVersion.BlobName);
+ var sourceMachineStudioInstallerBlob = sourceMachineStudioContainer.GetBlockBlobReference(latestMachineStudioVersion.InstallerBlobName);
+
+ var targetMachineStudioBlob = await CreateEmptyBlob(targetMachineStudioContainer, sourceMachineStudioBlob.Name);
+ var targetMachineStudioInstallerBlob = await CreateEmptyBlob(targetMachineStudioContainer, sourceMachineStudioInstallerBlob.Name);
+
+ await Task.Factory.StartNew(() =>
+ {
+ targetMachineStudioBlob.StartCopy(sourceMachineStudioBlob);
+ targetMachineStudioInstallerBlob.StartCopy(sourceMachineStudioInstallerBlob);
+ });
+ }
+
+ public async Task ValidatePPCStorageUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ OnProgress(AzureUtilsStage.Validating, "Validating PPC database upgrade...");
+
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+ var latestSourcePPCVersion = await _databaseManager.GetLatestPPCVersion(sourceApp);
+ var latestTargetPPCVersion = await _databaseManager.GetLatestPPCVersion(targetApp);
+
+ var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
+ var targetClient = targetAccount.CreateCloudBlobClient();
+
+ var targetPPCContainer = targetClient.GetContainerReference(targetSettings.TANGO_VERSIONS_CONTAINER);
+
+ //Check PPC binaries blob not exists on the target.
+ var targetPPCBlob = targetPPCContainer.GetBlockBlobReference(latestSourcePPCVersion.BlobName);
+ if (await targetPPCBlob.ExistsAsync())
+ {
+ throw new ValidationException($"PPC Block blob '{latestSourcePPCVersion.BlobName}' already exists on the target storage.");
+ }
+
+ //Check PPC installer blob not exists on the target.
+ var targetPPCInstallerBlob = targetPPCContainer.GetBlockBlobReference(latestSourcePPCVersion.InstallerBlobName);
+ if (await targetPPCInstallerBlob.ExistsAsync())
+ {
+ throw new ValidationException($"PPC Block blob '{latestSourcePPCVersion.InstallerBlobName}' already exists on the target storage.");
+ }
+ }
+
+ public async Task ValidateMachineStudioStorageUpgrade(IWebAppBase sourceApp, IWebAppBase targetApp)
+ {
+ OnProgress(AzureUtilsStage.Validating, "Validating machine studio storage upgrade...");
+
+ var sourceSettings = await sourceApp.GetMachineServiceSettingsAsync();
+ var targetSettings = await targetApp.GetMachineServiceSettingsAsync();
+
+ var latestSourceMachineStudioVersion = await _databaseManager.GetLatestMachineStudioVersion(sourceApp);
+ var latestTargetMachineStudioVersion = await _databaseManager.GetLatestMachineStudioVersion(targetApp);
+
+ var targetAccount = CloudStorageAccount.Parse(targetSettings.STORAGE_ACCOUNT);
+ var targetClient = targetAccount.CreateCloudBlobClient();
+
+ var targetMachineStudioContainer = targetClient.GetContainerReference(targetSettings.MACHINE_STUDIO_VERSIONS_CONTAINER);
+
+ //Check machine studio binaries blob not exists on the target.
+ var targetMachineStudioBlob = targetMachineStudioContainer.GetBlockBlobReference(latestSourceMachineStudioVersion.BlobName);
+ if (await targetMachineStudioBlob.ExistsAsync())
+ {
+ throw new ValidationException($"Machine Studio Block blob '{latestSourceMachineStudioVersion.BlobName}' already exists on the target storage.");
+ }
+
+ //Check machine studio installer blob not exists on the target.
+ var targetMachineStudioInstallerBlob = targetMachineStudioContainer.GetBlockBlobReference(latestSourceMachineStudioVersion.InstallerBlobName);
+ if (await targetMachineStudioInstallerBlob.ExistsAsync())
+ {
+ throw new ValidationException($"Machine Studio Block blob '{latestSourceMachineStudioVersion.InstallerBlobName}' already exists on the target storage.");
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj b/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj
index f7a0e2436..b626a3b09 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj
@@ -227,26 +227,31 @@
<Compile Include="AzureUtilsComponentBase.cs" />
<Compile Include="AzureUtilsCredentials.cs" />
<Compile Include="AzureUtilsConfirmationEventArgs.cs" />
+ <Compile Include="Database\DatabaseManager.cs" />
<Compile Include="Deployment\DeploymentManager.cs" />
<Compile Include="AzureUtilsProgressEventArgs.cs" />
<Compile Include="AzureUtilsStage.cs" />
+ <Compile Include="Environment\CreateEnvironmentConfiguration.cs" />
+ <Compile Include="Environment\EnvironmentSettings.cs" />
+ <Compile Include="Environment\UpgradeEnvironmentConfiguration.cs" />
<Compile Include="ExtensionMethods.cs" />
+ <Compile Include="FTP\FtpManager.cs" />
<Compile Include="MachineServiceSettings.cs" />
- <Compile Include="Deployment\UpgradeConfiguration.cs" />
<Compile Include="Environment\EnvironmentManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Storage\StorageManager.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\..\DB\SQLExaminer Projects\GENERAL_ENV_UPGRADE.sdeproj">
- <Link>Deployment\GENERAL_ENV_UPGRADE.sdeproj</Link>
+ <Link>Database\GENERAL_ENV_UPGRADE.sdeproj</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\DB\SQLExaminer Projects\GENERAL_ENV_UPGRADE.seproj">
- <Link>Deployment\GENERAL_ENV_UPGRADE.seproj</Link>
+ <Link>Database\GENERAL_ENV_UPGRADE.seproj</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\DB\SQLExaminer Projects\GENERAL_ENV_CREATE.sdeproj">
- <Link>Deployment\GENERAL_ENV_CREATE.sdeproj</Link>
+ <Link>Database\GENERAL_ENV_CREATE.sdeproj</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="app.config" />
@@ -266,5 +271,6 @@
<Name>Tango.Logging</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file