diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-11 05:02:18 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-11 05:02:18 +0300 |
| commit | bf5cbf5a6972cd8d725cc03fd6375b1eccbfe31c (patch) | |
| tree | 0902fda382956c1b749cf856d2a4d950f0196190 /Software | |
| parent | cb1b51c238c64f570d73b7dca6a2eee205b2da01 (diff) | |
| download | Tango-bf5cbf5a6972cd8d725cc03fd6375b1eccbfe31c.tar.gz Tango-bf5cbf5a6972cd8d725cc03fd6375b1eccbfe31c.zip | |
Started working on FSE TUP management.
Diffstat (limited to 'Software')
19 files changed, 656 insertions, 2 deletions
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/CacheEntities/CachedTangoVersion.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/CacheEntities/CachedTangoVersion.cs new file mode 100644 index 000000000..6d0d6cade --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/CacheEntities/CachedTangoVersion.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; + +namespace Tango.FSE.BL.CacheEntities +{ + public class CachedTangoVersion + { + public String EnvironmentID { get; set; } + public TangoVersionDTO TangoVersion { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs index 2fa6cae53..60d0fb372 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs @@ -38,6 +38,11 @@ namespace Tango.FSE.BL public BugReportingService BugReportingService { get; set; } /// <summary> + /// Gets or sets the tango versions service. + /// </summary> + public TangoVersionsService TangoVersionsService { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="FSEServicesContainer"/> class. /// </summary> /// <param name="authentication">The authentication.</param> @@ -48,6 +53,7 @@ namespace Tango.FSE.BL GatewayService = new GatewayService(); AuthenticationService = new AuthenticationService(); BugReportingService = new BugReportingService(); + TangoVersionsService = new TangoVersionsService(); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs new file mode 100644 index 000000000..ed0a2a356 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.DTO; +using Tango.BL.Entities; +using Tango.FSE.BL.CacheEntities; + +namespace Tango.FSE.BL.Services +{ + public class TangoVersionsService : FSEServiceBase + { + private const string TANGO_VERSIONS_COLLECTION = "TangoVersions"; + private ConcurrentDictionary<String, CachedTangoVersion> _tangoVersionsCache; + + public TangoVersionsService() + { + _tangoVersionsCache = new ConcurrentDictionary<string, CachedTangoVersion>(); + } + + /// <summary> + /// Gets all the available PPC/Firmware versions history. + /// </summary> + /// <returns></returns> + public Task<List<TangoVersion>> GetAllTangoVersions() + { + return DataResolver<List<TangoVersion>>.Builder.New() + .ConfigureCascade(DataResolverNode.InMemoryCache, DataResolverNode.Online, DataResolverNode.DiskCache) + .InMemoryCache((context) => + { + var tangoVersions = _tangoVersionsCache + .ToList() + .Select(x => x.Value) + .Where(x => x.EnvironmentID == Authentication.CurrentEnvironment.ID) + .Select(x => x.TangoVersion.ToObservable()) + .ToList(); + + if (tangoVersions.Count == 0) + { + throw new IndexOutOfRangeException("The memory cache did contain any Tango versions."); + } + + return tangoVersions; + }) + .Online((context) => + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var tangoVersions = db.TangoVersions.ToList().OrderByDescending(x => Version.Parse(x.Version)).ToList(); + + using (var cache = DiskCache.CreateContext()) + { + var collection = cache.GetCollection<CachedTangoVersion>(TANGO_VERSIONS_COLLECTION); + + foreach (var tangoVersion in tangoVersions) + { + try + { + var tangoVersionDTO = TangoVersionDTO.FromObservable(tangoVersion); + CachedTangoVersion cachedTangoVersion = new CachedTangoVersion(); + cachedTangoVersion.EnvironmentID = Authentication.CurrentEnvironment.ID; + cachedTangoVersion.TangoVersion = tangoVersionDTO; + + _tangoVersionsCache[tangoVersion.Version + " " + Authentication.CurrentEnvironment.ID] = cachedTangoVersion; + + collection.Upsert(cachedTangoVersion); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error caching Tango version '{tangoVersion.Version}' on disk."); + } + } + } + + return tangoVersions; + } + }) + .DiskCache((context) => + { + using (var cache = DiskCache.CreateContext()) + { + var collection = cache.GetCollection<CachedTangoVersion>(TANGO_VERSIONS_COLLECTION); + + return collection + .Find(x => x.EnvironmentID == Authentication.CurrentEnvironment.ID) + .ToList() + .Select(x => x.TangoVersion.ToObservable()) + .ToList() + .OrderByDescending(x => Version.Parse(x.Version)) + .ToList(); + } + }) + .BuildExecuteAsync(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj b/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj index 0eae2baa3..ad514c09c 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj @@ -75,6 +75,7 @@ <Compile Include="CacheEntities\CachedConfiguration.cs" /> <Compile Include="CacheEntities\CachedLoginResponse.cs" /> <Compile Include="CacheEntities\CachedMachine.cs" /> + <Compile Include="CacheEntities\CachedTangoVersion.cs" /> <Compile Include="CacheEntities\CachedUser.cs" /> <Compile Include="CacheManager.cs" /> <Compile Include="Connectivity\DefaultConnectivityProvider.cs" /> @@ -91,6 +92,7 @@ <Compile Include="Services\BugReportingService.cs" /> <Compile Include="Services\GatewayService.cs" /> <Compile Include="Services\MachinesService.cs" /> + <Compile Include="Services\TangoVersionsService.cs" /> <Compile Include="Services\UsersService.cs" /> <Compile Include="Web\FSEWebClient.cs" /> <Compile Include="Web\FSEWebClientBase.cs" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Web/FSEWebClientBase.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Web/FSEWebClientBase.cs index fbfd1e647..51e8777f7 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Web/FSEWebClientBase.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Web/FSEWebClientBase.cs @@ -48,5 +48,14 @@ namespace Tango.FSE.BL.Web return Post<Tango.FSE.Web.Messages.BugReportingInfoRequest, Tango.FSE.Web.Messages.BugReportingInfoResponse>("GetBugReportInfo", request); } + /// <summary> + /// Executes the DownloadTangoVersion action and returns Tango.FSE.Web.Messages.DownloadTangoVersionResponse. + /// </summary> + /// <returns></returns> + public Task<Tango.FSE.Web.Messages.DownloadTangoVersionResponse> DownloadTangoVersion(Tango.FSE.Web.Messages.DownloadTangoVersionRequest request) + { + return Post<Tango.FSE.Web.Messages.DownloadTangoVersionRequest, Tango.FSE.Web.Messages.DownloadTangoVersionResponse>("DownloadTangoVersion", request); + } + } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs index 01b27c8ea..d790a54a1 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs @@ -33,6 +33,7 @@ using Tango.SharedUI; using static Tango.SharedUI.Controls.NavigationControl; using Tango.FSE.BL.Connectivity; using Tango.FSE.Common.BugReporting; +using Tango.FSE.Common.RemoteUpgrade; namespace Tango.FSE.Common { @@ -147,6 +148,12 @@ namespace Tango.FSE.Common public IBugReporter BugReporter { get; set; } /// <summary> + /// Gets or sets the remote upgrade manager. + /// </summary> + [TangoInject] + public IRemoteUpgradeManager RemoteUpgradeManager { get; set; } + + /// <summary> /// Gets or sets the FSE service. /// </summary> [TangoInject] diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs new file mode 100644 index 000000000..9bbfb83f9 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.FSE.Common.MachineUpdates; + +namespace Tango.FSE.Common.RemoteUpgrade +{ + public interface IRemoteUpgradeManager + { + /// <summary> + /// Occurs when a TUP creation has made progress. + /// </summary> + event EventHandler<RemoteUpgradeProgressEventArgs> Progress; + + /// <summary> + /// Creates a Tango Update Package for the current connected machine. + /// </summary> + /// <param name="tangoVersion">The tango version.</param> + /// <param name="filePath">The file path.</param> + /// <returns></returns> + Task CreateTupFile(TangoVersion tangoVersion, String filePath); + + /// <summary> + /// Creates a Tango Update Package for specified machine. + /// </summary> + /// <param name="tangoVersion">The tango version.</param> + /// <param name="serialNumber">The machine serial number.</param> + /// <param name="filePath">The file path.</param> + /// <returns></returns> + Task CreateTupFile(TangoVersion tangoVersion, String serialNumber, String filePath); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeProgressEventArgs.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeProgressEventArgs.cs new file mode 100644 index 000000000..31f79d682 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeProgressEventArgs.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.RemoteUpgrade +{ + public class RemoteUpgradeProgressEventArgs + { + public double Progress { get; set; } + public double Total { get; set; } + public bool IsIntermediate { get; set; } + public String Message { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index d9b61f425..2628f2299 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -50,6 +50,9 @@ <Reference Include="GridExtra.Wpf, Version=0.4.0.0, Culture=neutral, processorArchitecture=MSIL"> <HintPath>..\..\packages\GridExtra.0.4.0\lib\net45\GridExtra.Wpf.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="MahApps.Metro, Version=1.6.5.1, Culture=neutral, processorArchitecture=MSIL"> <HintPath>..\..\packages\MahApps.Metro.1.6.5\lib\net46\MahApps.Metro.dll</HintPath> </Reference> @@ -157,6 +160,7 @@ <Compile Include="MachineUpdates\MachineUpdatesResult.cs" /> <Compile Include="RemoteDesktop\DesktopFrameReceivedEventArgs.cs" /> <Compile Include="RemoteDesktop\IRemoteDesktopProvider.cs" /> + <Compile Include="RemoteUpgrade\IRemoteUpgradeManager.cs" /> <Compile Include="Resolution\IResolutionService.cs" /> <Compile Include="Resolution\ResolutionHelper.cs" /> <Compile Include="Resolution\ResolutionMode.cs" /> @@ -167,6 +171,7 @@ <Compile Include="Storage\StorageMode.cs" /> <Compile Include="SystemInfo\ISystemInfoProvider.cs" /> <Compile Include="Threading\IDispatcherProvider.cs" /> + <Compile Include="RemoteUpgrade\RemoteUpgradeProgressEventArgs.cs" /> <Page Include="App.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/packages.config b/Software/Visual_Studio/FSE/Tango.FSE.Common/packages.config index 56b04f9e4..d020563f0 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/packages.config +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/packages.config @@ -4,6 +4,7 @@ <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> <package id="GridExtra" version="0.4.0" targetFramework="net461" /> + <package id="Ionic.Zip" version="1.9.1.8" targetFramework="net461" /> <package id="MahApps.Metro" version="1.6.5" targetFramework="net461" /> <package id="MaterialDesignColors" version="1.2.2" targetFramework="net461" /> <package id="MaterialDesignThemes" version="3.0.1" targetFramework="net461" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs new file mode 100644 index 000000000..bb808e685 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs @@ -0,0 +1,351 @@ +using Ionic.Zip; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core; +using Tango.Core.Components; +using Tango.Core.DB; +using Tango.Core.DI; +using Tango.Core.ExtensionMethods; +using Tango.FSE.BL.Web; +using Tango.FSE.Common; +using Tango.FSE.Common.Authentication; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.MachineUpdates; +using Tango.FSE.Common.RemoteUpgrade; +using Tango.FSE.Web.Messages; +using Tango.PPC.Common.Publish; +using Tango.PPC.Shared.Updates; +using Tango.SQLExaminer; +using Tango.Transport; +using Tango.Transport.Web; +using Tango.Web; + +namespace Tango.FSE.UI.RemoteUpgrade +{ + /// <summary> + /// Represents the <see cref="IMachineUpdatesProvider"/> default implementation. + /// </summary> + /// <seealso cref="Tango.FSE.Common.MachineUpdates.IMachineUpdatesProvider" /> + public class DefaultRemoteUpgradeManager : FSEExtendedObject, IRemoteUpgradeManager + { + private bool _isGeneratingTup; + private IMachineProvider MachineProvider { get; set; } + private FSEWebClient WebClient { get; set; } + private IAuthenticationProvider AuthenticationProvider { get; set; } + + /// <summary> + /// Occurs when a TUP creation has made progress. + /// </summary> + public event EventHandler<RemoteUpgradeProgressEventArgs> Progress; + + /// <summary> + /// Initializes a new instance of the <see cref="DefaultRemoteUpgradeManager"/> class. + /// </summary> + /// <param name="authenticationProvider">The authentication provider.</param> + /// <param name="machineProvider">The machine provider.</param> + /// <param name="webClient">The web client.</param> + public DefaultRemoteUpgradeManager(IAuthenticationProvider authenticationProvider, IMachineProvider machineProvider, FSEWebClient webClient) + { + AuthenticationProvider = authenticationProvider; + MachineProvider = machineProvider; + WebClient = webClient; + } + + /// <summary> + /// Creates a Tango Update Package for the current connected machine. + /// </summary> + /// <param name="tangoVersion">The tango version.</param> + /// <param name="filePath">The file path.</param> + /// <returns></returns> + public Task CreateTupFile(TangoVersion tangoVersion, string filePath) + { + if (MachineProvider.Machine == null) + { + throw new InvalidOperationException("Could not create a TUP file while machine is disconnected."); + } + + return CreateTupFile(tangoVersion, MachineProvider.Machine.SerialNumber); + } + + /// <summary> + /// Creates a Tango Update Package for specified machine. + /// </summary> + /// <param name="tangoVersion">The tango version.</param> + /// <param name="serialNumber">The machine serial number.</param> + /// <param name="targetFilePath">The file path.</param> + /// <returns></returns> + public Task CreateTupFile(TangoVersion tangoVersion, string serialNumber, string targetFilePath) + { + if (_isGeneratingTup) + { + throw new InvalidOperationException("Only one TUP file can be created at a time."); + } + + _isGeneratingTup = true; + + return Task.Factory.StartNew(() => + { + String tempDbName = "Tango_TUP"; + var tempPackageFolder = TemporaryManager.CreateFolder(); + String tempBackupFolder = "C:\\FSE_TUP"; + String tempBackupFile = Path.Combine(tempBackupFolder, tempDbName + ".bak"); + var tempZipFile = TemporaryManager.CreateImaginaryFile(); + DbManager dbManager = null; + + LogManager.Log("Generating tup file..."); + LogManager.Log($"Tup file: '{targetFilePath}.'"); + LogManager.Log($"Temporary db name: '{tempDbName}'."); + LogManager.Log($"Temporary package folder: '{tempPackageFolder}'."); + LogManager.Log($"Temporary db backup folder: '{tempBackupFolder}'."); + LogManager.Log($"Temporary db backup file: '{tempBackupFile}'."); + LogManager.Log($"Temporary zip file: '{tempZipFile}'."); + + try + { + LogManager.Log("Initializing..."); + + OnProgress("Initializing..."); + + Tango.Core.DataSource localDataSource = new Tango.Core.DataSource() + { + Address = "localhost\\SQLEXPRESS", + IntegratedSecurity = true, + Type = DataSourceType.SQLServer, + Catalog = null, + }; + + try + { + LogManager.Log($"Trying to connect via SQLEXPRESS:\n{localDataSource.ToJsonString()}"); + dbManager = DbManager.FromDataSource(localDataSource); + } + catch (Exception ex) + { + try + { + LogManager.Log(ex, "Could not connect using SQLEXPRESS. Trying local DB..."); + + CmdCommand command = new CmdCommand("sqllocaldb", "start \"MSSQLLocalDB\""); + var result = command.Run().Result; + + command = new CmdCommand("sqllocaldb", "info \"MSSQLLocalDB\""); + result = command.Run().Result; + + String pattern = "np:.+"; + Regex reg = new Regex(pattern); + var match = reg.Match(result.StandardOutput); + String address = match.ToString(); + if (address.Contains("np:")) + { + localDataSource.Address = address; + address = address.Trim().Replace("\r", ""); + } + else + { + throw new ArgumentException("Could not parse LocalDB address string."); + } + + LogManager.Log($"Trying to connect via LocalDB:\n{localDataSource.ToJsonString()}"); + dbManager = DbManager.FromDataSource(localDataSource); + } + catch (Exception x) + { + LogManager.Log(x, "Could not find any database service for this operation."); + throw x; + } + } + + + + OnProgress($"Downloading Tango version '{tangoVersion.Version}'..."); + + LogManager.Log("Connecting to machine service..."); + + LogManager.Log("Requesting version download from machine service..."); + var response = WebClient.DownloadTangoVersion(new DownloadTangoVersionRequest() { TangoVersionGuid = tangoVersion.Guid }).Result; + + LogManager.Log($"Machine service response:\n{response.ToJsonString()}"); + + var remoteDataSource = response.DataSource; + + using (AutoFileDownloader downloader = new AutoFileDownloader(response.BlobAddress, response.CdnAddress, tempZipFile)) + { + downloader.Progress += (x, e) => + { + OnProgress($"Downloading Tango version '{response.Version}'...", false, e.Current, e.Total); + }; + + downloader.ResolveMode().GetAwaiter().GetResult(); + + LogManager.Log($"Downloading Tango version from: '{downloader.Address}'"); + + downloader.Download().Wait(); + } + + LogManager.Log("Extracting version package..."); + + OnProgress("Extracting package..."); + + using (ZipFile zip = new ZipFile(tempZipFile)) + { + int currentEntry = 0; + + zip.ExtractProgress += (x, args) => + { + if (args.EventType == ZipProgressEventType.Extracting_AfterExtractEntry) + { + OnProgress("Extracting package...", false, currentEntry++, zip.Entries.Count); + } + }; + + zip.ExtractAll(tempPackageFolder); + } + + OnProgress("Extracting version information..."); + LogManager.Log("Extracting publish information..."); + PublishInfo publishInfo = PublishInfo.FromJson(File.ReadAllText(Path.Combine(tempPackageFolder, "version.json"))); + LogManager.Log($"Publish Information:\n{publishInfo}"); + + LogManager.Log("Modifying publish information to custom tup file..."); + publishInfo.IsMachineTupPackage = true; + publishInfo.MachineSerialNumber = serialNumber; + publishInfo.MachineDeploymentSlot = (DeploymentSlot)Enum.Parse(typeof(DeploymentSlot), AuthenticationProvider.CurrentEnvironment.Name); + + OnProgress("Creating temporary database..."); + + LogManager.Log($"Creating temporary db backup directory '{tempBackupFolder}'"); + + Directory.CreateDirectory(tempBackupFolder); + + LogManager.Log($"Creating new database: '{tempDbName}'"); + + //Create temp db + dbManager.Create(tempDbName, Path.Combine(tempBackupFolder, tempDbName + ".mdf")); + + OnProgress("Generating database snapshot..."); + + LogManager.Log("Starting database synchronization..."); + + Thread.Sleep(2000); + + localDataSource.Catalog = tempDbName; + + ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner( + Path.Combine(tempPackageFolder, "Provision Scripts", "config.xml"), + Path.Combine(tempPackageFolder, "Provision Scripts"), + remoteDataSource, + localDataSource, + serialNumber); + + runner.ScriptExecuting += (x, item) => + { + LogManager.Log($"Executing script '{item.FileName}'..."); + OnProgress($"{item.Name}..."); + }; + + runner.Log += (x, log) => + { + LogManager.Log(log); + }; + + runner.Run().GetAwaiter().GetResult(); + + OnProgress("Generating database snapshot..."); + + if (File.Exists(tempBackupFile)) + { + LogManager.Log($"Deleting file '{tempBackupFile}'"); + File.Delete(tempBackupFile); + } + + LogManager.Log($"Generating backup for '{tempDbName}' to '{tempBackupFile}'..."); + + dbManager.Backup(tempDbName, tempBackupFile); + + OnProgress("Injecting database snapshot to PPC package..."); + + using (ZipFile zip = new ZipFile(tempZipFile)) + { + LogManager.Log($"Injecting file '{tempBackupFile}' to original package at '{tempZipFile}'..."); + zip.AddFile(tempBackupFile, "/"); + + LogManager.Log($"Injecting modified publish information..."); + zip.UpdateEntry("version.json", publishInfo.ToJson()); + + zip.Save(); + } + + LogManager.Log($"Copying '{tempZipFile}' to '{targetFilePath}'..."); + + File.Copy(tempZipFile, targetFilePath, true); + + OnProgress("Completed", false, 100, 100); + + LogManager.Log("TUP file generation completed successfully."); + } + catch (Exception ex) + { + LogManager.Log(ex, "TUP file generation failed."); + OnProgress("Failed", false, 0, 100); + throw ex; + } + finally + { + _isGeneratingTup = false; + LogManager.Log($"Removing '{tempZipFile}'."); + tempZipFile.Delete(); + LogManager.Log($"Removing '{tempPackageFolder}'."); + tempPackageFolder.Delete(); + + try + { + LogManager.Log($"Removing database '{tempDbName}'."); + dbManager.SetOffline(tempDbName); + dbManager.SetOnline(tempDbName); + dbManager.Delete(tempDbName); + dbManager.Dispose(); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error removing temp database '{tempDbName}'."); + } + + try + { + LogManager.Log($"Removing '{tempBackupFolder}'."); + Directory.Delete(tempBackupFolder, true); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error removing folder '{tempBackupFolder}'."); + } + } + }); + } + + /// <summary> + /// Called when the TUP creation has made some progress. + /// </summary> + /// <param name="message">The message.</param> + /// <param name="isIntermediate">if set to <c>true</c> [is intermediate].</param> + /// <param name="progress">The progress.</param> + /// <param name="total">The total.</param> + protected virtual void OnProgress(String message, bool isIntermediate = true, double progress = 0, double total = 100) + { + Progress?.Invoke(this, new RemoteUpgradeProgressEventArgs() + { + Message = message, + IsIntermediate = isIntermediate, + Progress = progress, + Total = total, + }); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj index 24fbc3ae9..140c5b22c 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj @@ -121,6 +121,9 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </ApplicationDefinition> + <Compile Include="..\..\PPC\Tango.PPC.Common\Publish\PublishInfo.cs"> + <Link>RemoteUpgrade\PublishInfo.cs</Link> + </Compile> <Compile Include="Authentication\DefaultAuthenticationProvider.cs" /> <Compile Include="BugReporting\DefaultBugReporter.cs" /> <Compile Include="BugReporting\SystemInformationModel.cs" /> @@ -179,6 +182,7 @@ <Compile Include="Performance\DefaultPerformanceProvider.cs" /> <Compile Include="MachineUpdates\DefaultMachineUpdatesProvider.cs" /> <Compile Include="RemoteDesktop\DefaultRemoteDesktopProvider.cs" /> + <Compile Include="RemoteUpgrade\DefaultRemoteUpgradeManager.cs" /> <Compile Include="Resolution\DefaultResolutionService.cs" /> <Compile Include="Storage\DefaultStorageProvider.cs" /> <Compile Include="Storage\ExplorerControlDialog.xaml.cs"> @@ -405,6 +409,10 @@ <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project> <Name>Tango.SharedUI</Name> </ProjectReference> + <ProjectReference Include="..\..\Tango.SQLExaminer\Tango.SQLExaminer.csproj"> + <Project>{e1e66ed9-597d-45fa-8048-de90a6930484}</Project> + <Name>Tango.SQLExaminer</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.TFS\Tango.TFS.csproj"> <Project>{998f8471-dc1b-41b6-9d96-354e1b4e7a32}</Project> <Name>Tango.TFS</Name> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs index 4d9c49a74..bd012aea0 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs @@ -46,6 +46,8 @@ using Tango.FSE.UI.Threading; using Tango.FSE.UI.ViewModels; using Tango.FSE.Common.BugReporting; using Tango.FSE.UI.BugReporting; +using Tango.FSE.Common.RemoteUpgrade; +using Tango.FSE.UI.RemoteUpgrade; namespace Tango.FSE.UI { @@ -74,6 +76,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Unregister<FSEServicesContainer>(); TangoIOC.Default.Unregister<IMachineUpdatesProvider>(); TangoIOC.Default.Unregister<IBugReporter>(); + TangoIOC.Default.Unregister<IRemoteUpgradeManager>(); //TangoIOC.Default.Unregister<ExternalBridgeScanner>(); //TangoIOC.Default.Unregister<IDiagnosticsFrameProvider>(); //TangoIOC.Default.Unregister<IEventLogger>(); @@ -102,6 +105,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Register<ILoggingProvider, DefaultLoggingProvider>(); TangoIOC.Default.Register<IStorageProvider, DefaultStorageProvider>(); TangoIOC.Default.Register<IMachineUpdatesProvider, DefaultMachineUpdatesProvider>(); + TangoIOC.Default.Register<IRemoteUpgradeManager, DefaultRemoteUpgradeManager>(); TangoIOC.Default.Register<MainWindowVM>(); TangoIOC.Default.Register<MainViewVM>(); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Web/Messages/DownloadTangoVersionRequest.cs b/Software/Visual_Studio/FSE/Tango.FSE.Web/Messages/DownloadTangoVersionRequest.cs new file mode 100644 index 000000000..ffe0910cb --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Web/Messages/DownloadTangoVersionRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Transport.Web; + +namespace Tango.FSE.Web.Messages +{ + public class DownloadTangoVersionRequest : WebRequestMessage + { + public String TangoVersionGuid { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Web/Messages/DownloadTangoVersionResponse.cs b/Software/Visual_Studio/FSE/Tango.FSE.Web/Messages/DownloadTangoVersionResponse.cs new file mode 100644 index 000000000..d44859e8d --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Web/Messages/DownloadTangoVersionResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Transport.Web; + +namespace Tango.FSE.Web.Messages +{ + public class DownloadTangoVersionResponse : WebResponseMessage + { + public String Version { get; set; } + public String BlobAddress { get; set; } + public String CdnAddress { get; set; } + public DataSource DataSource { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Web/Tango.FSE.Web.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Web/Tango.FSE.Web.csproj index 299240d60..bd42e54f5 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Web/Tango.FSE.Web.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Web/Tango.FSE.Web.csproj @@ -43,6 +43,8 @@ <ItemGroup> <Compile Include="Messages\BugReportingInfoRequest.cs" /> <Compile Include="Messages\BugReportingInfoResponse.cs" /> + <Compile Include="Messages\DownloadTangoVersionRequest.cs" /> + <Compile Include="Messages\DownloadTangoVersionResponse.cs" /> <Compile Include="Messages\LoginRequest.cs" /> <Compile Include="Messages\LoginResponse.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> diff --git a/Software/Visual_Studio/Utilities/Tango.WebClientGenerator/Program.cs b/Software/Visual_Studio/Utilities/Tango.WebClientGenerator/Program.cs index 36c88bffb..501058016 100644 --- a/Software/Visual_Studio/Utilities/Tango.WebClientGenerator/Program.cs +++ b/Software/Visual_Studio/Utilities/Tango.WebClientGenerator/Program.cs @@ -24,6 +24,8 @@ namespace Tango.WebClientGenerator //Generate FSE client. GenerateWebClientV2<FSE.Web.Messages.LoginRequest, FSE.Web.Messages.LoginResponse, MachineService.Controllers.FSEController>("Tango.FSE.BL.Web", "FSEWebClientBase", PathHelper.GetSolutionFolder() + @"\FSE\Tango.FSE.BL\Web"); + + Console.WriteLine("Done"); } private static void GenerateWebClient<TLoginRequest, TLoginResponse, TController>(String nameSpace, String name, String path) where TLoginRequest : WebRequestMessage where TLoginResponse : WebTokenResponse where TController : TangoController diff --git a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/FSEController.cs b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/FSEController.cs index dccf2d24c..27d93f467 100644 --- a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/FSEController.cs +++ b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/FSEController.cs @@ -4,17 +4,22 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Security.Authentication; +using System.Threading.Tasks; using System.Web.Http; +using Tango.BL; using Tango.BL.Builders; using Tango.BL.Entities; using Tango.Core; using Tango.Core.Cryptography; +using Tango.Core.DB; using Tango.FSE.Web.Messages; using Tango.MachineService.Filters; using Tango.Web.Controllers; using Tango.Web.Helpers; using Tango.Web.Security; +using Tango.Web.SMO; using Tango.Web.SQLServer; +using Tango.Web.Storage; namespace Tango.MachineService.Controllers { @@ -117,5 +122,62 @@ namespace Tango.MachineService.Controllers UserEmail = MachineServiceConfig.FSE_TFS_USER_EMAIL }; } + + [HttpPost] + [JwtTokenFilter] + public DownloadTangoVersionResponse DownloadTangoVersion(DownloadTangoVersionRequest request) + { + DownloadTangoVersionResponse response = new DownloadTangoVersionResponse(); + + using (ObservablesContext db = ObservablesContextHelper.CreateContext()) + { + var tangoVersion = db.TangoVersions.SingleOrDefault(x => x.Guid == request.TangoVersionGuid); + + if (tangoVersion == null) + { + throw new ArgumentException("Could not locate the specified Tango version."); + } + + response.Version = tangoVersion.Version; + + var manager = new BlobStorageManager(); + var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER); + var blob = container.GetBlockBlobReference(tangoVersion.BlobName); + + response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60)); + + if (!String.IsNullOrWhiteSpace(MachineServiceConfig.CDN_ENDPOINT)) + { + response.CdnAddress = MachineServiceConfig.CDN_ENDPOINT + blob.Uri.AbsolutePath; + } + + DbCredentials credentials = new DbCredentials(); + + using (SmoManager smo = new SmoManager()) + { + credentials = smo.CreateRandomLoginAndUser(); + + Task.Delay(TimeSpan.FromMinutes(PPCController.SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) => + { + using (SmoManager m = new SmoManager()) + { + m.DeleteLoginAndUser(credentials.UserName); + } + }); + } + + response.DataSource = new DataSource() + { + Address = MachineServiceConfig.DB_ADDRESS, + Catalog = MachineServiceConfig.DB_CATALOG, + UserName = credentials.UserName, + Password = credentials.Password, + IntegratedSecurity = false, + Type = DataSourceType.SQLServer, + }; + } + + return response; + } } } diff --git a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/MachineStudioController.cs b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/MachineStudioController.cs index f508fea15..5f697f979 100644 --- a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/MachineStudioController.cs +++ b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/MachineStudioController.cs @@ -120,8 +120,6 @@ namespace Tango.MachineService.Controllers [JwtTokenFilter] public DownloadLatestVersionResponse DownloadLatestVersion(DownloadLatestVersionRequest request) { - LogManager.Log("Request received..."); - DownloadLatestVersionResponse response = new DownloadLatestVersionResponse(); using (ObservablesContext db = ObservablesContextHelper.CreateContext()) |
