diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-02-09 00:15:09 +0200 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-02-09 00:15:09 +0200 |
| commit | c9597d3b4a053b7a1246419cb31517dd9f530543 (patch) | |
| tree | 0ff985015cc4c6a6bf0b5bdefa6ff9726d5de422 /Software/Visual_Studio/Azure | |
| parent | af1c7bd1b6122c1387fe6e2749f9847f4be84b16 (diff) | |
| download | Tango-c9597d3b4a053b7a1246419cb31517dd9f530543.tar.gz Tango-c9597d3b4a053b7a1246419cb31517dd9f530543.zip | |
Working on azure utils...
Fixed issue with TangoWebApplication logging.
Diffstat (limited to 'Software/Visual_Studio/Azure')
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" /> |
