aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Azure
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-02-09 00:15:09 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-02-09 00:15:09 +0200
commitc9597d3b4a053b7a1246419cb31517dd9f530543 (patch)
tree0ff985015cc4c6a6bf0b5bdefa6ff9726d5de422 /Software/Visual_Studio/Azure
parentaf1c7bd1b6122c1387fe6e2749f9847f4be84b16 (diff)
downloadTango-c9597d3b4a053b7a1246419cb31517dd9f530543.tar.gz
Tango-c9597d3b4a053b7a1246419cb31517dd9f530543.zip
Working on azure utils...
Fixed issue with TangoWebApplication logging.
Diffstat (limited to 'Software/Visual_Studio/Azure')
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/AzureDashboardViewModel.cs18
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml9
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml.cs23
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Managers/DefaultStatusManager.cs22
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Tango.AzureUtils.UI.csproj28
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs27
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs16
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentFirmwareUpgradeViewVM.cs112
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentLogStreamViewVM.cs68
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentRemovalViewVM.cs116
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs10
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml53
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml.cs28
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml39
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml.cs28
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml62
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml.cs28
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/MainView.xaml13
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs46
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs9
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs9
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs70
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/RemoveEnvironmentConfiguration.cs18
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Firmware/FirmwareManager.cs120
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Logging/LogStreamManager.cs68
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs67
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj20
-rw-r--r--Software/Visual_Studio/Azure/Tango.AzureUtils/packages.config2
28 files changed, 1101 insertions, 28 deletions
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/AzureDashboardViewModel.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/AzureDashboardViewModel.cs
index 80431db3b..3c6a95ebf 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/AzureDashboardViewModel.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/AzureDashboardViewModel.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
using Tango.AzureUtils.UI.Managers;
using Tango.Core.DI;
using Tango.SharedUI;
@@ -25,5 +26,22 @@ namespace Tango.AzureUtils.UI
{
}
+
+ protected void ConfirmationHandler(object sender, AzureUtilsConfirmationEventArgs e)
+ {
+ if (MessageBox.Show(e.Message, "Confirmation Required", MessageBoxButton.OKCancel, MessageBoxImage.Question) == MessageBoxResult.OK)
+ {
+ e.Confirm();
+ }
+ else
+ {
+ e.Cancel();
+ }
+ }
+
+ public void ProgressHandler(object sender, AzureUtilsProgressEventArgs e)
+ {
+ StatusManager.UpdateStatus(e);
+ }
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml
index 54293c7d8..5adec916a 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml
@@ -52,6 +52,15 @@
<TextBlock FontWeight="SemiBold">TANGO_VERSIONS_CONTAINER:</TextBlock>
<TextBlock Text="{Binding ElementName=control,Path=Settings.TANGO_VERSIONS_CONTAINER}"></TextBlock>
+
+ <TextBlock FontWeight="SemiBold">Machine Studio Version:</TextBlock>
+ <TextBlock Text="{Binding ElementName=control,Path=MachineStudioVersion.Version}"></TextBlock>
+
+ <TextBlock FontWeight="SemiBold">Tango Application Version:</TextBlock>
+ <TextBlock Text="{Binding ElementName=control,Path=TangoVersion.Version}"></TextBlock>
+
+ <TextBlock FontWeight="SemiBold">Tango Firmware Version::</TextBlock>
+ <TextBlock Text="{Binding ElementName=control,Path=TangoVersion.FirmwareVersion}"></TextBlock>
</controls:TableGrid>
</StackPanel>
</Grid>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml.cs
index f046546f7..f71f236c7 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Controls/WebAppPropertiesControl.xaml.cs
@@ -13,6 +13,8 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
+using Tango.AzureUtils.Database;
+using Tango.BL.Entities;
namespace Tango.AzureUtils.UI.Controls
{
@@ -37,6 +39,22 @@ namespace Tango.AzureUtils.UI.Controls
public static readonly DependencyProperty HostNamesProperty =
DependencyProperty.Register("HostNames", typeof(List<String>), typeof(WebAppPropertiesControl), new PropertyMetadata(null));
+ public TangoVersion TangoVersion
+ {
+ get { return (TangoVersion)GetValue(TangoVersionProperty); }
+ set { SetValue(TangoVersionProperty, value); }
+ }
+ public static readonly DependencyProperty TangoVersionProperty =
+ DependencyProperty.Register("TangoVersion", typeof(TangoVersion), typeof(WebAppPropertiesControl), new PropertyMetadata(null));
+
+ public MachineStudioVersion MachineStudioVersion
+ {
+ get { return (MachineStudioVersion)GetValue(MachineStudioVersionProperty); }
+ set { SetValue(MachineStudioVersionProperty, value); }
+ }
+ public static readonly DependencyProperty MachineStudioVersionProperty =
+ DependencyProperty.Register("MachineStudioVersion", typeof(MachineStudioVersion), typeof(WebAppPropertiesControl), new PropertyMetadata(null));
+
public WebAppPropertiesControl()
{
@@ -56,6 +74,11 @@ namespace Tango.AzureUtils.UI.Controls
HostNames = app.HostNames.Select(x => x).ToList();
Settings = await app.GetMachineServiceSettingsAsync(false);
+
+ var azure = await AzureUtilsAuthenticationFactory.AuthenticateOrGetAsync();
+ var databaseManager = new DatabaseManager(azure);
+ TangoVersion = await databaseManager.GetLatestPPCVersion(app);
+ MachineStudioVersion = await databaseManager.GetLatestMachineStudioVersion(app);
}
catch { }
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Managers/DefaultStatusManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Managers/DefaultStatusManager.cs
index 59c2cdc40..712c6507b 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Managers/DefaultStatusManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Managers/DefaultStatusManager.cs
@@ -4,10 +4,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
+using Tango.Core;
namespace Tango.AzureUtils.UI.Managers
{
- public class DefaultStatusManager : IStatusManager
+ public class DefaultStatusManager : ExtendedObject, IStatusManager
{
public event EventHandler<AzureUtilsProgressEventArgs> StatusUpdated;
@@ -25,16 +26,19 @@ namespace Tango.AzureUtils.UI.Managers
public void UpdateStatus(AzureUtilsProgressEventArgs progress)
{
- if (progress.IsIndeterminate || (progress.Maximum == 0 && progress.Progress == 0))
+ InvokeUI(() =>
{
- Mouse.OverrideCursor = Cursors.Wait;
- }
- else
- {
- Mouse.OverrideCursor = null;
- }
+ if (progress.IsIndeterminate || (progress.Progress > 0 && progress.Progress != progress.Maximum))
+ {
+ Mouse.OverrideCursor = Cursors.Wait;
+ }
+ else
+ {
+ Mouse.OverrideCursor = null;
+ }
- StatusUpdated?.Invoke(this, progress);
+ StatusUpdated?.Invoke(this, progress);
+ });
}
public void UpdateStatus(Exception ex)
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Tango.AzureUtils.UI.csproj b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Tango.AzureUtils.UI.csproj
index 6812a5695..8f0546bfa 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Tango.AzureUtils.UI.csproj
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Tango.AzureUtils.UI.csproj
@@ -203,11 +203,23 @@
<Compile Include="Managers\IStatusManager.cs" />
<Compile Include="ViewModelLocator.cs" />
<Compile Include="ViewModels\EnvironmentCreationViewVM.cs" />
+ <Compile Include="ViewModels\EnvironmentLogStreamViewVM.cs" />
+ <Compile Include="ViewModels\EnvironmentRemovalViewVM.cs" />
<Compile Include="ViewModels\EnvironmentUpgradeViewVM.cs" />
+ <Compile Include="ViewModels\EnvironmentFirmwareUpgradeViewVM.cs" />
<Compile Include="ViewModels\MainViewVM.cs" />
<Compile Include="Views\EnvironmentCreationView.xaml.cs">
<DependentUpon>EnvironmentCreationView.xaml</DependentUpon>
</Compile>
+ <Compile Include="Views\EnvironmentLogStreamView.xaml.cs">
+ <DependentUpon>EnvironmentLogStreamView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\EnvironmentFirmwareUpgradeView.xaml.cs">
+ <DependentUpon>EnvironmentFirmwareUpgradeView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\EnvironmentRemovalView.xaml.cs">
+ <DependentUpon>EnvironmentRemovalView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Views\EnvironmentUpgradeView.xaml.cs">
<DependentUpon>EnvironmentUpgradeView.xaml</DependentUpon>
</Compile>
@@ -242,6 +254,18 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Views\EnvironmentLogStreamView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\EnvironmentFirmwareUpgradeView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\EnvironmentRemovalView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Views\EnvironmentUpgradeView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -279,6 +303,10 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{F441FEEE-322A-4943-B566-110E12FD3B72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs
index 196848e95..4fd7293c9 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModelLocator.cs
@@ -21,6 +21,9 @@ namespace Tango.AzureUtils.UI
TangoIOC.Default.Register<MainViewVM>();
TangoIOC.Default.Register<EnvironmentUpgradeViewVM>();
TangoIOC.Default.Register<EnvironmentCreationViewVM>();
+ TangoIOC.Default.Register<EnvironmentRemovalViewVM>();
+ TangoIOC.Default.Register<EnvironmentFirmwareUpgradeViewVM>();
+ TangoIOC.Default.Register<EnvironmentLogStreamViewVM>();
TangoIOC.Default.Register<IStatusManager, DefaultStatusManager>();
}
@@ -49,5 +52,29 @@ namespace Tango.AzureUtils.UI
return TangoIOC.Default.GetInstance<EnvironmentCreationViewVM>();
}
}
+
+ public static EnvironmentRemovalViewVM EnvironmentRemovalViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<EnvironmentRemovalViewVM>();
+ }
+ }
+
+ public static EnvironmentFirmwareUpgradeViewVM EnvironmentFirmwareUpgradeViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<EnvironmentFirmwareUpgradeViewVM>();
+ }
+ }
+
+ public static EnvironmentLogStreamViewVM EnvironmentLogStreamViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<EnvironmentLogStreamViewVM>();
+ }
+ }
}
}
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 d51cfb3bd..163565699 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentCreationViewVM.cs
@@ -87,20 +87,8 @@ namespace Tango.AzureUtils.UI.ViewModels
SelectedDeploymentSlot = DeploymentSlots.FirstOrDefault();
_environmentManager = new EnvironmentManager(azure);
- _environmentManager.ConfirmationRequired += _environmentManager_ConfirmationRequired;
- _environmentManager.Progress += (x, e) => StatusManager.UpdateStatus(e);
- }
-
- private void _environmentManager_ConfirmationRequired(object sender, AzureUtilsConfirmationEventArgs e)
- {
- if (MessageBox.Show(e.Message, "Confirmation Required", MessageBoxButton.OKCancel, MessageBoxImage.Question) == MessageBoxResult.OK)
- {
- e.Confirm();
- }
- else
- {
- e.Cancel();
- }
+ _environmentManager.ConfirmationRequired += ConfirmationHandler;
+ _environmentManager.Progress += ProgressHandler;
}
private async void CreateEnvironment()
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentFirmwareUpgradeViewVM.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentFirmwareUpgradeViewVM.cs
new file mode 100644
index 000000000..54576cda7
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentFirmwareUpgradeViewVM.cs
@@ -0,0 +1,112 @@
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using Tango.AzureUtils.Environment;
+using Tango.AzureUtils.Firmware;
+using Tango.Core.Commands;
+
+namespace Tango.AzureUtils.UI.ViewModels
+{
+ public class EnvironmentFirmwareUpgradeViewVM : AzureDashboardViewModel
+ {
+ private FirmwareManager _firmwareManager;
+
+ private List<IWebAppBase> _deploymentSlots;
+ public List<IWebAppBase> DeploymentSlots
+ {
+ get { return _deploymentSlots; }
+ set { _deploymentSlots = value; RaisePropertyChangedAuto(); }
+ }
+
+ private IWebAppBase _selectedDeploymentSlot;
+ public IWebAppBase SelectedDeploymentSlot
+ {
+ get { return _selectedDeploymentSlot; }
+ set { _selectedDeploymentSlot = value; RaisePropertyChangedAuto(); }
+ }
+
+ private String _filePath;
+ public String FilePath
+ {
+ get { return _filePath; }
+ set { _filePath = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
+ }
+
+ private String _firmwareVersion;
+ public String FirmwareVersion
+ {
+ get { return _firmwareVersion; }
+ set { _firmwareVersion = value; RaisePropertyChangedAuto(); }
+ }
+
+ public RelayCommand UpgradeFirmwareCommand { get; set; }
+ public RelayCommand BrowseFileCommand { get; set; }
+
+ public EnvironmentFirmwareUpgradeViewVM()
+ {
+ UpgradeFirmwareCommand = new RelayCommand(UpgradeFirmware,() => FilePath != null);
+ BrowseFileCommand = new RelayCommand(BrowseFile);
+ }
+
+ public override void OnAuthenticated(IAzure azure, List<IWebAppBase> apps)
+ {
+ DeploymentSlots = apps.Where(x => x.Name.Contains("MachineService")).ToList();
+ SelectedDeploymentSlot = DeploymentSlots.FirstOrDefault(x => x.Name.EndsWith("DEV"));
+
+ _firmwareManager = new FirmwareManager(azure);
+ _firmwareManager.ConfirmationRequired += ConfirmationHandler;
+ _firmwareManager.Progress += ProgressHandler;
+ }
+
+ private async void BrowseFile()
+ {
+ OpenFileDialog dlg = new OpenFileDialog();
+ dlg.Title = "Select Tango Firmware Package";
+ dlg.Filter = "Tango Firmware Package Files|*.tfp";
+ if (dlg.ShowDialog().Value)
+ {
+ FilePath = dlg.FileName;
+ try
+ {
+ FirmwareVersion = await _firmwareManager.GetFirmwareVersion(FilePath);
+ }
+ catch (Exception ex)
+ {
+ FilePath = null;
+ StatusManager.UpdateStatus(ex);
+ }
+ }
+ }
+
+ private async void UpgradeFirmware()
+ {
+ try
+ {
+ if (!Validate()) return;
+
+ IsFree = false;
+
+ await _firmwareManager.InjectFirmwarePackage(SelectedDeploymentSlot, FilePath);
+
+ var old = SelectedDeploymentSlot;
+ SelectedDeploymentSlot = null;
+ SelectedDeploymentSlot = old;
+ }
+ catch (Exception ex)
+ {
+ StatusManager.UpdateStatus(ex);
+ }
+ finally
+ {
+ IsFree = true;
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentLogStreamViewVM.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentLogStreamViewVM.cs
new file mode 100644
index 000000000..40548bd31
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentLogStreamViewVM.cs
@@ -0,0 +1,68 @@
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using Tango.AzureUtils.Environment;
+using Tango.AzureUtils.Logging;
+using Tango.SharedUI.Components;
+
+namespace Tango.AzureUtils.UI.ViewModels
+{
+ public class EnvironmentLogStreamViewVM : AzureDashboardViewModel
+ {
+ private LogStreamManager _logStreamManager;
+
+ private List<IWebAppBase> _deploymentSlots;
+ public List<IWebAppBase> DeploymentSlots
+ {
+ get { return _deploymentSlots; }
+ set { _deploymentSlots = value; RaisePropertyChangedAuto(); }
+ }
+
+ private IWebAppBase _selectedDeploymentSlot;
+ public IWebAppBase SelectedDeploymentSlot
+ {
+ get { return _selectedDeploymentSlot; }
+ set { _selectedDeploymentSlot = value; RaisePropertyChangedAuto(); OnSelectedDeploymentSlotChanged(); }
+ }
+
+ private TextController _log;
+ public TextController Log
+ {
+ get { return _log; }
+ set { _log = value; RaisePropertyChangedAuto(); }
+ }
+
+ public EnvironmentLogStreamViewVM()
+ {
+ Log = new TextController();
+ }
+
+ public override void OnAuthenticated(IAzure azure, List<IWebAppBase> apps)
+ {
+ DeploymentSlots = apps.ToList();
+
+ _logStreamManager = new LogStreamManager(azure);
+ _logStreamManager.ConfirmationRequired += ConfirmationHandler;
+ _logStreamManager.Progress += ProgressHandler;
+ _logStreamManager.LogAvailable += _logStreamManager_LogAvailable;
+ }
+
+ private void _logStreamManager_LogAvailable(object sender, string msg)
+ {
+ Log.WriteLine(msg);
+ }
+
+ private async void OnSelectedDeploymentSlotChanged()
+ {
+ if (SelectedDeploymentSlot != null && _logStreamManager != null)
+ {
+ await _logStreamManager.StartLogStreamingAsync(SelectedDeploymentSlot);
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentRemovalViewVM.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentRemovalViewVM.cs
new file mode 100644
index 000000000..e8d966158
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentRemovalViewVM.cs
@@ -0,0 +1,116 @@
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using Tango.AzureUtils.Environment;
+using Tango.Core.Commands;
+
+namespace Tango.AzureUtils.UI.ViewModels
+{
+ public class EnvironmentRemovalViewVM : AzureDashboardViewModel
+ {
+ private IWebAppBase _machineServiceApp;
+ private EnvironmentManager _environmentManager;
+
+ private List<IDeploymentSlot> _deploymentSlots;
+ public List<IDeploymentSlot> DeploymentSlots
+ {
+ get { return _deploymentSlots; }
+ set { _deploymentSlots = value; RaisePropertyChangedAuto(); }
+ }
+
+ private IDeploymentSlot _selectedDeploymentSlot;
+ public IDeploymentSlot SelectedDeploymentSlot
+ {
+ get { return _selectedDeploymentSlot; }
+ set { _selectedDeploymentSlot = value; RaisePropertyChangedAuto(); }
+ }
+
+ private String _slotName;
+ [Required(ErrorMessage = "Deployment slot name confirmation is required.")]
+ public String SlotName
+ {
+ get { return _slotName; }
+ set { _slotName = value; RaisePropertyChangedAuto(); }
+ }
+
+ private String _email;
+ [Required(ErrorMessage = "Active directory email is required.")]
+ [EmailAddress(ErrorMessage = "Please enter a valid email.")]
+ public String Email
+ {
+ get { return _email; }
+ set { _email = value; RaisePropertyChangedAuto(); }
+ }
+
+ private String _password;
+ [Required(ErrorMessage = "Password is required.")]
+ public String Password
+ {
+ get { return _password; }
+ set { _password = value; RaisePropertyChangedAuto(); }
+ }
+
+ private RemoveEnvironmentConfiguration _config;
+ public RemoveEnvironmentConfiguration Config
+ {
+ get { return _config; }
+ set { _config = value; RaisePropertyChangedAuto(); }
+ }
+
+ public RelayCommand RemoveEnvironmentCommand { get; set; }
+
+ public EnvironmentRemovalViewVM()
+ {
+ RemoveEnvironmentCommand = new RelayCommand(RemoveEnvironment);
+ Config = new RemoveEnvironmentConfiguration();
+ }
+
+ public override void OnApplicationReady()
+ {
+ Email = "roy@twine-s.com";
+ Password = "1Creativity";
+ }
+
+ public override void OnAuthenticated(IAzure azure, List<IWebAppBase> apps)
+ {
+ _machineServiceApp = apps.SingleOrDefault(x => x.Name == "MachineService");
+ DeploymentSlots = apps.OfType<IDeploymentSlot>().Where(x => x.Parent == _machineServiceApp).ToList();
+ SelectedDeploymentSlot = DeploymentSlots.FirstOrDefault();
+
+ _environmentManager = new EnvironmentManager(azure);
+ _environmentManager.ConfirmationRequired += ConfirmationHandler;
+ _environmentManager.Progress += ProgressHandler;
+ }
+
+ private async void RemoveEnvironment()
+ {
+ try
+ {
+ if (!Validate()) return;
+
+ IsFree = false;
+
+ Config.Email = Email;
+ Config.Password = Password;
+
+ await _environmentManager.RemoveEnvironment(SelectedDeploymentSlot, SlotName, Config);
+
+ SelectedDeploymentSlot = null;
+ }
+ catch (Exception ex)
+ {
+ StatusManager.UpdateStatus(ex);
+ }
+ finally
+ {
+ IsFree = true;
+ }
+ }
+ }
+}
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 695ef9d4f..14e4bf196 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/ViewModels/EnvironmentUpgradeViewVM.cs
@@ -76,7 +76,8 @@ namespace Tango.AzureUtils.UI.ViewModels
SelectedTargetApp = Apps.FirstOrDefault();
EnvironmentManager = new EnvironmentManager(azure);
- EnvironmentManager.Progress += (x, e) => StatusManager.UpdateStatus(e);
+ _environmentManager.ConfirmationRequired += ConfirmationHandler;
+ _environmentManager.Progress += ProgressHandler;
}
private async void ValidateUpgrade()
@@ -111,6 +112,13 @@ namespace Tango.AzureUtils.UI.ViewModels
{
IsFree = false;
await EnvironmentManager.UpgradeEnvironment(SelectedSourceApp, SelectedTargetApp, Config);
+
+ var oldSource = SelectedSourceApp;
+ var oldTarget = SelectedTargetApp;
+ SelectedSourceApp = null;
+ SelectedTargetApp = null;
+ SelectedSourceApp = oldSource;
+ SelectedTargetApp = oldTarget;
}
catch (Exception ex)
{
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml
new file mode 100644
index 000000000..9d122ab06
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml
@@ -0,0 +1,53 @@
+<UserControl x:Class="Tango.AzureUtils.UI.Views.EnvironmentFirmwareUpgradeView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:vm="clr-namespace:Tango.AzureUtils.UI.ViewModels"
+ xmlns:helpers="clr-namespace:Tango.SharedUI.Helpers;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.AzureUtils.UI"
+ xmlns:localControls="clr-namespace:Tango.AzureUtils.UI.Controls"
+ xmlns:local="clr-namespace:Tango.AzureUtils.UI.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700"
+ d:DesignWidth="1100"
+ d:DataContext="{d:DesignInstance Type=vm:EnvironmentFirmwareUpgradeViewVM, IsDesignTimeCreatable=False}"
+ DataContext="{x:Static global:ViewModelLocator.EnvironmentFirmwareUpgradeViewVM}"
+ Background="{StaticResource PrimaryBackgroundBrush}"
+ Foreground="{StaticResource PrimaryForegroundBrush}">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="50*"/>
+ <ColumnDefinition Width="60*"/>
+ </Grid.ColumnDefinitions>
+
+ <GroupBox Header="Source Deployment Slot" Padding="5" Margin="10">
+ <DockPanel>
+ <ComboBox DockPanel.Dock="Top" ItemsSource="{Binding DeploymentSlots}" SelectedItem="{Binding SelectedDeploymentSlot}" DisplayMemberPath="Name"></ComboBox>
+
+ <localControls:WebAppPropertiesControl VerticalAlignment="Top" Margin="0 20 0 0" DataContext="{Binding SelectedDeploymentSlot}" />
+ </DockPanel>
+ </GroupBox>
+
+ <Grid Grid.Column="1">
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="300">
+ <GroupBox Header="Firmware Package Selection" Padding="30" Width="500">
+ <StackPanel>
+ <TextBlock>Browse for .tfp file and press upgrade.</TextBlock>
+ <DockPanel Margin="0 10 0 0">
+ <Button Command="{Binding BrowseFileCommand}" Padding="10 0" Margin="5 0 0 0" DockPanel.Dock="Right">Browse</Button>
+ <TextBox Text="{Binding FilePath}" VerticalAlignment="Center" IsReadOnly="True" />
+ </DockPanel>
+ </StackPanel>
+ </GroupBox>
+
+ <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="14" FontWeight="SemiBold">
+ <Run>Selected Firmware Version:</Run>
+ <Run Text="{Binding FirmwareVersion,TargetNullValue='N/A',FallbackValue='N/A'}"></Run>
+ </TextBlock>
+
+ <Button Padding="20" Margin="0 80 0 0" MaxWidth="300" Command="{Binding UpgradeFirmwareCommand}">UPGRADE FIRMWARE</Button>
+ </StackPanel>
+ </Grid>
+ </Grid>
+</UserControl>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml.cs
new file mode 100644
index 000000000..ed2d4c56f
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentFirmwareUpgradeView.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Tango.AzureUtils.UI.Views
+{
+ /// <summary>
+ /// Interaction logic for EnvironmentRemovalView.xaml
+ /// </summary>
+ public partial class EnvironmentFirmwareUpgradeView : UserControl
+ {
+ public EnvironmentFirmwareUpgradeView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml
new file mode 100644
index 000000000..168e0b546
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml
@@ -0,0 +1,39 @@
+<UserControl x:Class="Tango.AzureUtils.UI.Views.EnvironmentLogStreamView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:vm="clr-namespace:Tango.AzureUtils.UI.ViewModels"
+ xmlns:components="clr-namespace:Tango.SharedUI.Components;assembly=Tango.SharedUI"
+ xmlns:helpers="clr-namespace:Tango.SharedUI.Helpers;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.AzureUtils.UI"
+ xmlns:localControls="clr-namespace:Tango.AzureUtils.UI.Controls"
+ xmlns:local="clr-namespace:Tango.AzureUtils.UI.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700"
+ d:DesignWidth="1100"
+ d:DataContext="{d:DesignInstance Type=vm:EnvironmentLogStreamViewVM, IsDesignTimeCreatable=False}"
+ DataContext="{x:Static global:ViewModelLocator.EnvironmentLogStreamViewVM}"
+ Background="{StaticResource PrimaryBackgroundBrush}"
+ Foreground="{StaticResource PrimaryForegroundBrush}">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="50*"/>
+ <ColumnDefinition Width="60*"/>
+ </Grid.ColumnDefinitions>
+
+ <GroupBox Header="Source Deployment Slot" Padding="5" Margin="10">
+ <DockPanel>
+ <ComboBox DockPanel.Dock="Top" ItemsSource="{Binding DeploymentSlots}" SelectedItem="{Binding SelectedDeploymentSlot}" DisplayMemberPath="Name"></ComboBox>
+
+ <localControls:WebAppPropertiesControl VerticalAlignment="Top" Margin="0 20 0 0" DataContext="{Binding SelectedDeploymentSlot}" />
+ </DockPanel>
+ </GroupBox>
+
+ <Grid Grid.Column="1">
+ <GroupBox Header="Logs" Margin="10" Padding="10">
+ <TextBox components:TextController.Controller="{Binding Log}" AcceptsReturn="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" IsReadOnlyCaretVisible="True" BorderThickness="0"></TextBox>
+ </GroupBox>
+ </Grid>
+ </Grid>
+</UserControl>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml.cs
new file mode 100644
index 000000000..77918c796
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentLogStreamView.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Tango.AzureUtils.UI.Views
+{
+ /// <summary>
+ /// Interaction logic for EnvironmentRemovalView.xaml
+ /// </summary>
+ public partial class EnvironmentLogStreamView : UserControl
+ {
+ public EnvironmentLogStreamView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml
new file mode 100644
index 000000000..2175aaaf3
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml
@@ -0,0 +1,62 @@
+<UserControl x:Class="Tango.AzureUtils.UI.Views.EnvironmentRemovalView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:vm="clr-namespace:Tango.AzureUtils.UI.ViewModels"
+ xmlns:helpers="clr-namespace:Tango.SharedUI.Helpers;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.AzureUtils.UI"
+ xmlns:localControls="clr-namespace:Tango.AzureUtils.UI.Controls"
+ xmlns:local="clr-namespace:Tango.AzureUtils.UI.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700"
+ d:DesignWidth="1100"
+ d:DataContext="{d:DesignInstance Type=vm:EnvironmentRemovalViewVM, IsDesignTimeCreatable=False}"
+ DataContext="{x:Static global:ViewModelLocator.EnvironmentRemovalViewVM}"
+ Background="{StaticResource PrimaryBackgroundBrush}"
+ Foreground="{StaticResource PrimaryForegroundBrush}">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="50*"/>
+ <ColumnDefinition Width="60*"/>
+ </Grid.ColumnDefinitions>
+
+ <GroupBox Header="Source Deployment Slot" Padding="5" Margin="10">
+ <DockPanel>
+ <ComboBox DockPanel.Dock="Top" ItemsSource="{Binding DeploymentSlots}" SelectedItem="{Binding SelectedDeploymentSlot}" DisplayMemberPath="Name"></ComboBox>
+
+ <localControls:WebAppPropertiesControl VerticalAlignment="Top" Margin="0 20 0 0" DataContext="{Binding SelectedDeploymentSlot}" />
+ </DockPanel>
+ </GroupBox>
+
+ <Grid Grid.Column="1">
+ <DockPanel>
+ <GroupBox DockPanel.Dock="Top" HorizontalAlignment="Left" Margin="50 10 10 10" Header="Removal Configuration" Padding="10 10 100 10">
+ <StackPanel>
+ <CheckBox IsChecked="{Binding Config.RemoveEnvironmentGroup}" >Remove Environment Group</CheckBox>
+ <CheckBox Margin="0 5 0 0" IsChecked="{Binding Config.RemoveDeploymentSlot}" >Remove Deployment Slot</CheckBox>
+ <CheckBox Margin="0 5 0 0" IsChecked="{Binding Config.RemoveStorageContainers}" >Remove Storage Containers</CheckBox>
+ <CheckBox Margin="0 5 0 0" IsChecked="{Binding Config.RemoveDatabase}" >Remove Database</CheckBox>
+ </StackPanel>
+ </GroupBox>
+
+ <StackPanel>
+ <GroupBox HorizontalAlignment="Left" Margin="50 10 10 10" Header="Environment Credentials" Padding="10 10 90 10">
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="300">
+ <TextBlock FontSize="10">Environment Name (e.g DEV)</TextBlock>
+ <TextBox Margin="0 2 0 0" Text="{Binding SlotName}"></TextBox>
+
+ <TextBlock FontSize="10" Margin="0 10 0 0">Active Directory Administrator Email</TextBlock>
+ <TextBox Margin="0 2 0 0" Text="{Binding Email}"></TextBox>
+
+ <TextBlock Margin="0 10 0 0" FontSize="10">Password</TextBlock>
+ <PasswordBox Margin="0 2 0 0" helpers:PasswordHelper.Attach="True" helpers:PasswordHelper.Password="{Binding Password,Mode=TwoWay}"></PasswordBox>
+ </StackPanel>
+ </GroupBox>
+
+ <Button HorizontalAlignment="Left" Width="410" Margin="50 20 0 0" Padding="20" Command="{Binding RemoveEnvironmentCommand}">REMOVE ENVIRONMENT</Button>
+ </StackPanel>
+ </DockPanel>
+ </Grid>
+ </Grid>
+</UserControl>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml.cs
new file mode 100644
index 000000000..f5abf0b66
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/EnvironmentRemovalView.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Tango.AzureUtils.UI.Views
+{
+ /// <summary>
+ /// Interaction logic for EnvironmentRemovalView.xaml
+ /// </summary>
+ public partial class EnvironmentRemovalView : UserControl
+ {
+ public EnvironmentRemovalView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/MainView.xaml b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/MainView.xaml
index 11749207e..40d431be1 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/MainView.xaml
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils.UI/Views/MainView.xaml
@@ -28,12 +28,21 @@
<Grid Grid.Row="1" IsEnabled="{Binding IsInitialized}">
<TabControl Margin="10">
- <TabItem Header="Environment Upgrade Dashboard" Padding="5">
+ <TabItem Header="Environment Upgrade" Padding="5">
<views:EnvironmentUpgradeView/>
</TabItem>
- <TabItem Header="Environment Creation Wizard" Padding="5">
+ <TabItem Header="Environment Creation" Padding="5">
<views:EnvironmentCreationView/>
</TabItem>
+ <TabItem Header="Environment Removal" Padding="5">
+ <views:EnvironmentRemovalView/>
+ </TabItem>
+ <TabItem Header="Environment Firmware Injection" Padding="5">
+ <views:EnvironmentFirmwareUpgradeView/>
+ </TabItem>
+ <TabItem Header="Environment Log Stream" Padding="5">
+ <views:EnvironmentLogStreamView/>
+ </TabItem>
</TabControl>
</Grid>
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs
index fe5934fa9..d6e1df042 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/ActiveDirectory/ActiveDirectoryManager.cs
@@ -103,7 +103,7 @@ namespace Tango.AzureUtils.ActiveDirectory
/// <returns></returns>
public async Task AddGroup(String groupName)
{
- OnProgress(AzureUtilsStage.ActiveDirectory, $"Creating environment group '{groupName}'...");
+ OnProgress(AzureUtilsStage.ActiveDirectory, $"Creating group '{groupName}'...");
var client = GetActiveDirectoryClient();
await client.Groups.AddGroupAsync(new Group()
@@ -116,6 +116,21 @@ namespace Tango.AzureUtils.ActiveDirectory
}
/// <summary>
+ /// Removes the specified group.
+ /// </summary>
+ /// <param name="groupName">Name of the group.</param>
+ /// <returns></returns>
+ public async Task RemoveGroup(String groupName)
+ {
+ OnProgress(AzureUtilsStage.ActiveDirectory, $"Removing group '{groupName}'...");
+ var client = GetActiveDirectoryClient();
+
+ var g = await client.Groups.OfType<Group>().Where(x => x.DisplayName == groupName).Take(1).ExecuteSingleAsync();
+
+ await g.DeleteAsync();
+ }
+
+ /// <summary>
/// Adds the specified user to the specified group.
/// </summary>
/// <param name="groupName">Name of the group.</param>
@@ -139,6 +154,35 @@ namespace Tango.AzureUtils.ActiveDirectory
await gg.UpdateAsync();
}
+ /// <summary>
+ /// Gets all users.
+ /// </summary>
+ /// <returns></returns>
+ public async Task<List<User>> GetAllUsers()
+ {
+ OnProgress(AzureUtilsStage.ActiveDirectory, $"Retrieving active directory users...");
+
+ var client = GetActiveDirectoryClient();
+
+ List<User> users = new List<User>();
+
+ var userPages = await client.Users.OfType<User>().ExecuteAsync();
+
+ do
+ {
+ List<User> directoryObjects = userPages.CurrentPage.ToList();
+ foreach (User u in directoryObjects)
+ {
+ users.Add(u);
+ }
+
+ userPages = await userPages.GetNextPageAsync();
+
+ } while (userPages != null);
+
+ return users;
+ }
+
#endregion
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs
index b54f243f8..0c2e56edf 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Database/DatabaseManager.cs
@@ -149,6 +149,15 @@ namespace Tango.AzureUtils.Database
return AddDatabase("twine", databaseName);
}
+ public async Task RemoveDatabase(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, $"Removing database '{databaseName}'...");
+ await sqlServer.Databases.DeleteAsync(databaseName);
+ }
+
#endregion
#region Users & Permissions
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs
index 2cdfce4b0..c45068c6c 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Deployment/DeploymentManager.cs
@@ -83,5 +83,14 @@ namespace Tango.AzureUtils.Deployment
IDeploymentSlot slot = (await app.DeploymentSlots.ListAsync()).ToList().SingleOrDefault(x => x.Name == slotName);
return slot;
}
+
+ public async Task RemoveDeploymentSlot(IDeploymentSlot slot)
+ {
+ OnProgress(AzureUtilsStage.Deployment, $"Removing '{slot.Name}' deployment slot...");
+
+ var app = slot.Parent;
+
+ await app.DeploymentSlots.DeleteByIdAsync(slot.Id);
+ }
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs
index 7f6c093d4..83b0c29ee 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/EnvironmentManager.cs
@@ -1,8 +1,12 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data.Entity;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Ionic.Zip;
using Microsoft.Azure;
using Microsoft.Azure.Management.AppService.Fluent;
using Microsoft.Azure.Management.AppService.Fluent.Models;
@@ -19,6 +23,7 @@ using Tango.AzureUtils.Storage;
using Tango.BL;
using Tango.Core;
using Tango.Core.DB;
+using Tango.PMR.FirmwareUpgrade;
namespace Tango.AzureUtils.Environment
{
@@ -251,6 +256,10 @@ namespace Tango.AzureUtils.Environment
return slot;
}
+ #endregion
+
+ #region Upgrade
+
public async Task UpgradeEnvironment(IWebAppBase sourceApp, IWebAppBase targetApp, UpgradeEnvironmentConfiguration config)
{
await ValidateEnvironmentUpgrade(sourceApp, targetApp, config);
@@ -380,9 +389,68 @@ namespace Tango.AzureUtils.Environment
#endregion
- #region Upgrade
+ #region Removal
+
+ public async Task RemoveEnvironment(IDeploymentSlot slot, String slotName, RemoveEnvironmentConfiguration config)
+ {
+ OnProgress(AzureUtilsStage.Environment, $"Retrieving '{slot.Name}' settings...");
+
+ var settings = await slot.GetMachineServiceSettingsAsync();
+
+ if (settings.DEPLOYMENT_SLOT != slotName)
+ {
+ throw new ValidationException("The specified slot name confirmation does not match the specified slot instance.");
+ }
+
+ var envSettings = EnvironmentSettings.FromSlotName(slot.Parent.Name, settings.DEPLOYMENT_SLOT);
+
+ //Remove Environment Group
+ if (config.RemoveEnvironmentGroup)
+ {
+ await _adManager.Authenticate(config.Email, config.Password);
+
+ if (await _adManager.IsGroupExists(settings.ENVIRONMENT_GROUP))
+ {
+ await _adManager.RemoveGroup(settings.ENVIRONMENT_GROUP);
+ }
+ else
+ {
+ await RequestConfirmation($"Environment group '{settings.ENVIRONMENT_GROUP}' does not exist. Do you wish to continue?");
+ }
+ }
+ //Remove Deployment Slot
+ if (config.RemoveDeploymentSlot)
+ {
+ try
+ {
+ await _deploymentManager.RemoveDeploymentSlot(slot);
+ }
+ catch (Exception ex)
+ {
+ await RequestConfirmation($"Encountered an error while trying to remove deployment slot.\n{ex.FlattenMessage()}\nDo you wish to continue.");
+ }
+ }
+
+ await _storageManager.Connect(settings.STORAGE_ACCOUNT);
+
+ //Remove Storage Containers
+ if (config.RemoveStorageContainers)
+ {
+ await _storageManager.RemoveContainer(settings.MACHINE_STUDIO_VERSIONS_CONTAINER);
+ await _storageManager.RemoveContainer(settings.TANGO_VERSIONS_CONTAINER);
+ await _storageManager.RemoveContainer(envSettings.MACHINE_SERVICE_LOGS_CONTAINER);
+ await _storageManager.RemoveContainer(envSettings.MACHINE_SERVICE_BACKUPS_CONTAINER);
+ }
+ //Remove Database
+ if (config.RemoveDatabase)
+ {
+ await _databaseManager.RemoveDatabase("twine", settings.DB_CATALOG);
+ }
+
+ OnCompleted("Environment removed successfully.");
+ }
#endregion
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/RemoveEnvironmentConfiguration.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/RemoveEnvironmentConfiguration.cs
new file mode 100644
index 000000000..af6f8983d
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Environment/RemoveEnvironmentConfiguration.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.AzureUtils.Environment
+{
+ public class RemoveEnvironmentConfiguration
+ {
+ public String Email { get; set; }
+ public String Password { get; set; }
+ public bool RemoveEnvironmentGroup { get; set; } = true;
+ public bool RemoveDeploymentSlot { get; set; } = true;
+ public bool RemoveStorageContainers { get; set; } = true;
+ public bool RemoveDatabase { get; set; } = true;
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Firmware/FirmwareManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Firmware/FirmwareManager.cs
new file mode 100644
index 000000000..07ffedf23
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Firmware/FirmwareManager.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data.Entity;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Ionic.Zip;
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+using Tango.AzureUtils.Database;
+using Tango.AzureUtils.Storage;
+using Tango.BL;
+using Tango.PMR.FirmwareUpgrade;
+using Tango.PPC.Common.Publish;
+
+namespace Tango.AzureUtils.Firmware
+{
+ public class FirmwareManager : AzureUtilsComponentBase
+ {
+ private DatabaseManager _databaseManager;
+ private StorageManager _storageManager;
+
+ public FirmwareManager(IAzure azure) : base(azure)
+ {
+ _databaseManager = CreateManager<DatabaseManager>();
+ _storageManager = CreateManager<StorageManager>();
+ }
+
+ #region Firmware Injection
+
+ public async Task InjectFirmwarePackage(IWebAppBase slot, String tfpFile)
+ {
+ OnProgress(AzureUtilsStage.Environment, $"Validating TFP package...");
+
+ VersionPackageDescriptor tfpPackage = null;
+
+ try
+ {
+ tfpPackage = await GetVersionPackageDescriptor(tfpFile);
+ tfpPackage.Validate();
+ }
+ catch (Exception ex)
+ {
+ throw new ValidationException($"The specified TFP package is invalid.\n{ex.FlattenMessage()}");
+ }
+
+ var ppcVersion = await _databaseManager.GetLatestPPCVersion(slot);
+
+ if (Version.Parse(ppcVersion.FirmwareVersion) >= tfpPackage.GetMcuVersion())
+ {
+ await RequestConfirmation($"The specified firmware version is '{tfpPackage.GetMcuVersion()}' while latest version is '{ppcVersion.FirmwareVersion}'. Do you wish to continue?");
+ }
+
+ OnProgress(AzureUtilsStage.Environment, $"Retrieving '{slot.Name}' settings...");
+ var settings = await slot.GetMachineServiceSettingsAsync();
+
+ await _storageManager.Connect(settings.STORAGE_ACCOUNT);
+
+ var zipFile = TemporaryManager.CreateImaginaryFile(".zip");
+
+ await _storageManager.DownloadLatestPPCVersion(slot, zipFile);
+
+ OnProgress(AzureUtilsStage.Environment, $"Replacing firmware_package.tfp...");
+ await Task.Factory.StartNew(() =>
+ {
+ using (ZipFile zip = new ZipFile(zipFile))
+ {
+ var versionReader = zip.Entries.SingleOrDefault(x => x.FileName == "version.json").OpenReader();
+ String versionJson = null;
+ using (StreamReader reader = new StreamReader(versionReader))
+ {
+ versionJson = reader.ReadToEnd();
+ }
+
+ PublishInfo publishInfo = PublishInfo.FromJson(versionJson);
+ publishInfo.Firmware = tfpPackage;
+
+ zip.UpdateEntry("version.json", Encoding.Default.GetBytes(publishInfo.ToJson()));
+
+ zip.UpdateEntry("firmware_package.tfp", tfpPackage.ToBytes());
+ zip.Save();
+ }
+ });
+
+ await _storageManager.ReplaceLatestPPCVersion(slot, zipFile);
+
+ OnProgress(AzureUtilsStage.Database, $"Updating firmware version on database...");
+ using (ObservablesContext db = ObservablesContext.CreateDefault(settings.ToDataSource()))
+ {
+ var v = await db.TangoVersions.SingleOrDefaultAsync(x => x.Guid == ppcVersion.Guid);
+ v.FirmwareVersion = tfpPackage.GetMcuVersion().ToString();
+ await db.SaveChangesAsync();
+ }
+
+ OnCompleted("Firmware version injected successfully.");
+ }
+
+ public Task<VersionPackageDescriptor> GetVersionPackageDescriptor(String tfpFile)
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ using (ZipFile zip = ZipFile.Read(tfpFile))
+ {
+ var reader = zip.Entries.SingleOrDefault(x => x.FileName == "package.cfg").OpenReader();
+ return VersionPackageDescriptor.Parser.ParseFrom(reader);
+ }
+ });
+ }
+
+ public async Task<String> GetFirmwareVersion(String tfpFile)
+ {
+ var desc = await GetVersionPackageDescriptor(tfpFile);
+ return desc.GetMcuVersion().ToString();
+ }
+
+ #endregion
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Logging/LogStreamManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Logging/LogStreamManager.cs
new file mode 100644
index 000000000..4c37adb61
--- /dev/null
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Logging/LogStreamManager.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Azure.Management.AppService.Fluent;
+using Microsoft.Azure.Management.Fluent;
+
+namespace Tango.AzureUtils.Logging
+{
+ public class LogStreamManager : AzureUtilsComponentBase
+ {
+ private Stream _currentStream;
+ private StreamReader _reader;
+ private Thread _pullThread;
+
+ public event EventHandler<String> LogAvailable;
+
+ public LogStreamManager(IAzure azure) : base(azure)
+ {
+
+ }
+
+ public void StopLogStreaming()
+ {
+ _reader.Dispose();
+ _currentStream.Dispose();
+
+ _reader = null;
+ _currentStream = null;
+ _pullThread = null;
+ }
+
+ public async Task StartLogStreamingAsync(IWebAppBase webApp)
+ {
+ _currentStream = await webApp.StreamApplicationLogsAsync();
+ _reader = new StreamReader(_currentStream);
+
+ if (_pullThread == null)
+ {
+ _pullThread = new Thread(PullThreadMethod);
+ _pullThread.IsBackground = true;
+ _pullThread.Start();
+ }
+ }
+
+ private void PullThreadMethod()
+ {
+ while (_currentStream != null)
+ {
+ String line = String.Empty;
+
+ do
+ {
+ line = _reader.ReadLine();
+ if (line != null)
+ {
+ LogAvailable?.Invoke(this, line);
+ }
+ } while (line != null);
+
+ Thread.Sleep(2000);
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs b/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs
index 8b3aeca2b..3551bf4f4 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Storage/StorageManager.cs
@@ -10,6 +10,7 @@ using Microsoft.Azure.Management.Fluent;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Tango.AzureUtils.Database;
+using Tango.Core.IO;
namespace Tango.AzureUtils.Storage
{
@@ -34,6 +35,11 @@ namespace Tango.AzureUtils.Storage
return Task.FromResult(true);
}
+ public CloudBlobClient GetClient()
+ {
+ return _client;
+ }
+
private async Task<CloudBlockBlob> CreateEmptyBlob(CloudBlobContainer container, String name)
{
OnProgress(AzureUtilsStage.Storage, $"Creating blob '{name}'...");
@@ -55,6 +61,13 @@ namespace Tango.AzureUtils.Storage
return container;
}
+ public async Task RemoveContainer(String name)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Removing storage container '{name}'...");
+ var container = _client.GetContainerReference(name);
+ await container.DeleteAsync();
+ }
+
public async Task UpgradePPCStorage(IWebAppBase sourceApp, IWebAppBase targetApp)
{
OnProgress(AzureUtilsStage.Storage, $"Retrieving source and target settings...");
@@ -180,5 +193,59 @@ namespace Tango.AzureUtils.Storage
throw new ValidationException($"Machine Studio Block blob '{latestSourceMachineStudioVersion.InstallerBlobName}' already exists on the target storage.");
}
}
+
+ public async Task DownloadLatestPPCVersion(IWebAppBase app, String filePath)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Retrieving source and target settings...");
+
+ var settings = await app.GetMachineServiceSettingsAsync();
+ var ppcVersion = await _databaseManager.GetLatestPPCVersion(app);
+
+ OnProgress(AzureUtilsStage.Storage, $"Downloading PPC version '{ppcVersion.Version}'...");
+
+ var account = CloudStorageAccount.Parse(settings.STORAGE_ACCOUNT);
+ var client = account.CreateCloudBlobClient();
+
+ var container = client.GetContainerReference(settings.TANGO_VERSIONS_CONTAINER);
+
+ var blob = container.GetBlockBlobReference(ppcVersion.BlobName);
+ await blob.FetchAttributesAsync();
+ var length = blob.Properties.Length;
+
+ using (FileStreamWrapper st = new FileStreamWrapper(filePath, FileMode.Create, (progress) =>
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Downloading PPC version '{ppcVersion.Version}'...", progress, length, false);
+ }))
+ {
+ await blob.DownloadToStreamAsync(st);
+ }
+ }
+
+ public async Task ReplaceLatestPPCVersion(IWebAppBase app, String filePath)
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Retrieving source and target settings...");
+
+ var settings = await app.GetMachineServiceSettingsAsync();
+ var ppcVersion = await _databaseManager.GetLatestPPCVersion(app);
+
+ OnProgress(AzureUtilsStage.Storage, $"Uploading PPC version '{ppcVersion.Version}'...");
+
+ var account = CloudStorageAccount.Parse(settings.STORAGE_ACCOUNT);
+ var client = account.CreateCloudBlobClient();
+
+ var container = client.GetContainerReference(settings.TANGO_VERSIONS_CONTAINER);
+
+ var blob = container.GetBlockBlobReference(ppcVersion.BlobName);
+
+ FileStreamWrapper st = null;
+
+ using (st = new FileStreamWrapper(filePath, FileMode.Open, (progress) =>
+ {
+ OnProgress(AzureUtilsStage.Storage, $"Uploading PPC version '{ppcVersion.Version}'...", progress, st.Length, false);
+ }))
+ {
+ await blob.UploadFromStreamAsync(st);
+ }
+ }
}
}
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj b/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj
index b626a3b09..021d081f1 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/Tango.AzureUtils.csproj
@@ -40,9 +40,15 @@
<Reference Include="FluentFTP, Version=30.0.0.0, Culture=neutral, PublicKeyToken=f4af092b1d8df44f, processorArchitecture=MSIL">
<HintPath>..\..\packages\FluentFTP.30.0.0\lib\net45\FluentFTP.dll</HintPath>
</Reference>
+ <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
+ </Reference>
<Reference Include="Hyak.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Hyak.Common.1.2.2\lib\net452\Hyak.Common.dll</HintPath>
</Reference>
+ <Reference Include="Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Ionic.Zip.1.9.1.8\lib\Ionic.Zip.dll</HintPath>
+ </Reference>
<Reference Include="Microsoft.Azure.ActiveDirectory.GraphClient, Version=2.1.10.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Azure.ActiveDirectory.GraphClient.2.1.1\lib\portable-net4+sl5+win+wpa+wp8\Microsoft.Azure.ActiveDirectory.GraphClient.dll</HintPath>
</Reference>
@@ -222,6 +228,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="..\..\PPC\Tango.PPC.Common\Publish\PublishInfo.cs">
+ <Link>Firmware\PublishInfo.cs</Link>
+ </Compile>
<Compile Include="ActiveDirectory\ActiveDirectoryManager.cs" />
<Compile Include="AzureUtilsAuthenticationFactory.cs" />
<Compile Include="AzureUtilsComponentBase.cs" />
@@ -232,10 +241,13 @@
<Compile Include="AzureUtilsProgressEventArgs.cs" />
<Compile Include="AzureUtilsStage.cs" />
<Compile Include="Environment\CreateEnvironmentConfiguration.cs" />
+ <Compile Include="Environment\RemoveEnvironmentConfiguration.cs" />
<Compile Include="Environment\EnvironmentSettings.cs" />
<Compile Include="Environment\UpgradeEnvironmentConfiguration.cs" />
<Compile Include="ExtensionMethods.cs" />
+ <Compile Include="Firmware\FirmwareManager.cs" />
<Compile Include="FTP\FtpManager.cs" />
+ <Compile Include="Logging\LogStreamManager.cs" />
<Compile Include="MachineServiceSettings.cs" />
<Compile Include="Environment\EnvironmentManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -270,6 +282,14 @@
<Project>{BC932DBD-7CDB-488C-99E4-F02CF441F55E}</Project>
<Name>Tango.Logging</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.PMR\Tango.PMR.csproj">
+ <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project>
+ <Name>Tango.PMR</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Web\Tango.Web.csproj">
+ <Project>{5001990f-977b-48ff-b217-0236a5022ad8}</Project>
+ <Name>Tango.Web</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
diff --git a/Software/Visual_Studio/Azure/Tango.AzureUtils/packages.config b/Software/Visual_Studio/Azure/Tango.AzureUtils/packages.config
index 16c9a9e88..57597d222 100644
--- a/Software/Visual_Studio/Azure/Tango.AzureUtils/packages.config
+++ b/Software/Visual_Studio/Azure/Tango.AzureUtils/packages.config
@@ -2,7 +2,9 @@
<packages>
<package id="EntityFramework" version="6.2.0" targetFramework="net461" />
<package id="FluentFTP" version="30.0.0" targetFramework="net461" />
+ <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" />
<package id="Hyak.Common" version="1.2.2" targetFramework="net461" />
+ <package id="Ionic.Zip" version="1.9.1.8" targetFramework="net461" />
<package id="Microsoft.Azure.ActiveDirectory.GraphClient" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.Azure.Common" version="2.2.1" targetFramework="net461" />
<package id="Microsoft.Azure.KeyVault" version="3.0.1" targetFramework="net461" />