private void SetLocalInfo(SiteExtensionInfo info) { string localPath = GetInstallationDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(localPath)) { info.LocalPath = localPath; info.InstalledDateTime = FileSystemHelpers.GetLastWriteTimeUtc(info.LocalPath); } if (ExtensionRequiresApplicationHost(info)) { info.ExtensionUrl = GetFullUrl(GetUrlFromApplicationHost(localPath)); } else { info.ExtensionUrl = String.IsNullOrEmpty(info.LocalPath) ? null : GetFullUrl(info.ExtensionUrl); } foreach (var setting in GetSettingManager(info.Id).GetValues()) { if (String.Equals(setting.Key, _feedUrlSetting, StringComparison.OrdinalIgnoreCase)) { info.FeedUrl = setting.Value.Value <string>(); } else if (String.Equals(setting.Key, _installUtcTimestampSetting, StringComparison.OrdinalIgnoreCase)) { DateTime installedDateTime; if (DateTime.TryParse(setting.Value.Value <string>(), out installedDateTime)) { info.InstalledDateTime = installedDateTime.ToUniversalTime(); } } } }
public static void PurgeBuildArtifactsIfNecessary(string sitePackagesPath, BuildArtifactType fileExtension, ITracer tracer, int totalAllowedFiles) { string extension = fileExtension.ToString().ToLowerInvariant(); IEnumerable <string> fileNames = FileSystemHelpers.GetFiles(sitePackagesPath, $"*.{extension}"); if (fileNames.Count() > totalAllowedFiles) { // Order the files in descending order of the modified date and remove the last (N - allowed zip files). var fileNamesToDelete = fileNames.OrderByDescending(fileName => FileSystemHelpers.GetLastWriteTimeUtc(fileName)).Skip(totalAllowedFiles); foreach (var fileName in fileNamesToDelete) { using (tracer.Step("Deleting outdated zip file {0}", fileName)) { try { File.Delete(fileName); } catch (Exception ex) { tracer.TraceError(ex, "Unable to delete zip file {0}", fileName); } } } } }
private static void SetPreInstalledExtensionInfo(SiteExtensionInfo info) { string directory = GetPreInstalledDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(directory)) { if (info.Type == SiteExtensionInfo.SiteExtensionType.PreInstalledMonaco) { info.Version = GetPreInstalledLatestVersion(directory); } else if (info.Type == SiteExtensionInfo.SiteExtensionType.PreInstalledEnabled) { info.Version = typeof(SiteExtensionManager).Assembly.GetName().Version.ToString(); } info.PublishedDateTime = FileSystemHelpers.GetLastWriteTimeUtc(directory); } else { info.Version = null; info.PublishedDateTime = null; } info.LocalIsLatestVersion = true; }
private void SetLocalInfo(SiteExtensionInfo info) { string localPath = GetInstallationDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(localPath)) { info.LocalPath = localPath; info.InstalledDateTime = FileSystemHelpers.GetLastWriteTimeUtc(info.LocalPath); } if (ExtensionRequiresApplicationHost(info)) { info.ExtensionUrl = FileSystemHelpers.FileExists(Path.Combine(localPath, Constants.ApplicationHostXdtFileName)) ? GetFullUrl(GetUrlFromApplicationHost(info)) : null; } else if (String.Equals(info.Id, "Monaco", StringComparison.OrdinalIgnoreCase)) { // Monaco does not need ApplicationHost only when it is enabled through app setting info.ExtensionUrl = GetFullUrl(info.ExtensionUrl); } else { info.ExtensionUrl = String.IsNullOrEmpty(info.LocalPath) ? null : GetFullUrl(info.ExtensionUrl); } info.FeedUrl = GetSettingManager(info.Id).GetValue(_feedUrlSetting); }
private void SetLocalInfo(SiteExtensionInfo info) { string localPath = GetInstallationDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(localPath)) { info.LocalPath = localPath; info.InstalledDateTime = FileSystemHelpers.GetLastWriteTimeUtc(info.LocalPath); } if (ExtensionRequiresApplicationHost(info)) { if (FileSystemHelpers.FileExists(Path.Combine(localPath, _applicationHostFile))) { info.ExtensionUrl = GetUrlFromApplicationHost(info); } else { info.ExtensionUrl = null; } } else { if (!String.IsNullOrEmpty(info.LocalPath)) { info.ExtensionUrl = _baseUrl + info.ExtensionUrl + "/"; } else { info.ExtensionUrl = null; } } }
private async Task SetLocalInfo(SiteExtensionInfo info) { string localPath = GetInstallationDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(localPath)) { info.LocalPath = localPath; info.InstalledDateTime = FileSystemHelpers.GetLastWriteTimeUtc(info.LocalPath); } if (ExtensionRequiresApplicationHost(info)) { info.ExtensionUrl = GetFullUrl(GetUrlFromApplicationHost(localPath)); } else { info.ExtensionUrl = string.IsNullOrEmpty(info.LocalPath) ? null : GetFullUrl(info.ExtensionUrl); } foreach (var setting in GetSettingManager(info.Id).GetValues()) { if (string.Equals(setting.Key, _feedUrlSetting, StringComparison.OrdinalIgnoreCase)) { info.FeedUrl = setting.Value.Value <string>(); } else if (string.Equals(setting.Key, _packageUriSetting, StringComparison.OrdinalIgnoreCase)) { info.PackageUri = setting.Value.Value <string>(); } else if (string.Equals(setting.Key, _installUtcTimestampSetting, StringComparison.OrdinalIgnoreCase)) { DateTime installedDateTime; if (DateTime.TryParse(setting.Value.Value <string>(), out installedDateTime)) { info.InstalledDateTime = installedDateTime.ToUniversalTime(); } } else if (string.Equals(setting.Key, _installationArgs, StringComparison.OrdinalIgnoreCase)) { info.InstallationArgs = setting.Value.Value <string>(); } } if (IsInstalledToWebRoot(info.Id)) { // override WebRoot type from setting // WebRoot is a special type that install package to wwwroot, when perform update we need to update new content to wwwroot even if type is not specified info.Type = SiteExtensionInfo.SiteExtensionType.WebRoot; } if (FileSystemHelpers.DirectoryExists(localPath) && string.IsNullOrEmpty(info.PackageUri)) { await TryCheckLocalPackageLatestVersionFromRemote(info); } }
public void UpdateLocalInfo(SiteExtensionInfo info) { string localPath = GetInstallationDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(localPath)) { info.ExtensionUrl = "/" + info.Id + "/"; info.LocalPath = localPath; info.InstalledDateTime = FileSystemHelpers.GetLastWriteTimeUtc(info.LocalPath); } }
private void SetLocalInfo(SiteExtensionInfo info) { string localPath = GetInstallationDirectory(info.Id); if (FileSystemHelpers.DirectoryExists(localPath)) { info.LocalPath = localPath; info.InstalledDateTime = FileSystemHelpers.GetLastWriteTimeUtc(info.LocalPath); } if (ExtensionRequiresApplicationHost(info)) { info.ExtensionUrl = FileSystemHelpers.FileExists(Path.Combine(localPath, Constants.ApplicationHostXdtFileName)) ? GetFullUrl(GetUrlFromApplicationHost(info)) : null; } else { info.ExtensionUrl = String.IsNullOrEmpty(info.LocalPath) ? null : GetFullUrl(info.ExtensionUrl); } info.FeedUrl = GetSettingManager(info.Id).GetValue(_feedUrlSetting); }
public static void PurgeZipsIfNecessary(string sitePackagesPath, ITracer tracer, int totalAllowedZips) { IEnumerable <string> zipFiles = FileSystemHelpers.GetFiles(sitePackagesPath, "*.zip"); if (zipFiles.Count() > totalAllowedZips) { // Order the files in descending order of the modified date and remove the last (N - allowed zip files). var fileNamesToDelete = zipFiles.OrderByDescending(fileName => FileSystemHelpers.GetLastWriteTimeUtc(fileName)).Skip(totalAllowedZips); foreach (var fileName in fileNamesToDelete) { using (tracer.Step("Deleting outdated zip file {0}", fileName)) { try { File.Delete(fileName); } catch (Exception ex) { tracer.TraceError(ex, "Unable to delete zip file {0}", fileName); } } } } }
public async Task PerformDeployment(DeploymentInfoBase deploymentInfo, IDisposable tempDeployment = null, ChangeSet tempChangeSet = null) { DateTime currentMarkerFileUTC; DateTime nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); ChangeSet lastChange = null; do { // save the current marker currentMarkerFileUTC = nextMarkerFileUTC; string targetBranch = _settings.GetBranch(); using (_tracer.Step("Performing fetch based deployment")) { // create temporary deployment before the actual deployment item started // this allows portal ui to readily display on-going deployment (not having to wait for fetch to complete). // in addition, it captures any failure that may occur before the actual deployment item started tempDeployment = tempDeployment ?? _deploymentManager.CreateTemporaryDeployment( Resources.ReceivingChanges, out tempChangeSet, deploymentInfo.TargetChangeset, deploymentInfo.Deployer); ILogger innerLogger = null; DeployStatusApiResult updateStatusObj = null; try { ILogger logger = _deploymentManager.GetLogger(tempChangeSet.Id); // Fetch changes from the repository innerLogger = logger.Log(Resources.FetchingChanges); IRepository repository = deploymentInfo.GetRepository(); try { await deploymentInfo.Fetch(repository, deploymentInfo, targetBranch, innerLogger, _tracer); } catch (BranchNotFoundException) { // mark no deployment is needed deploymentInfo.TargetChangeset = null; } // set to null as Deploy() below takes over logging innerLogger = null; // The branch or commit id to deploy string deployBranch = !String.IsNullOrEmpty(deploymentInfo.CommitId) ? deploymentInfo.CommitId : targetBranch; try { _tracer.Trace($"Before sending {Constants.BuildRequestReceived} status to /api/updatedeploystatus"); if (PostDeploymentHelper.IsAzureEnvironment()) { if (deploymentInfo != null && !string.IsNullOrEmpty(deploymentInfo.DeploymentTrackingId)) { // Only send an updatedeploystatus request if DeploymentTrackingId is non null // This signifies the client has opted in for these deployment updates for this deploy request updateStatusObj = new DeployStatusApiResult(Constants.BuildRequestReceived, deploymentInfo.DeploymentTrackingId); await _deploymentManager.SendDeployStatusUpdate(updateStatusObj); } } } catch (Exception e) { _tracer.TraceError($"Exception while sending {Constants.BuildRequestReceived} status to /api/updatedeploystatus. " + $"Entry in the operations table for the deployment status may not have been created. {e}"); } // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null && ShouldDeploy(repository, deploymentInfo, deployBranch)) { // Perform the actual deployment var changeSet = repository.GetChangeSet(deployBranch); if (changeSet == null && !String.IsNullOrEmpty(deploymentInfo.CommitId)) { throw new InvalidOperationException(String.Format("Invalid revision '{0}'!", deploymentInfo.CommitId)); } lastChange = changeSet; // Here, we don't need to update the working files, since we know Fetch left them in the correct state // unless for GenericHandler where specific commitId is specified bool deploySpecificCommitId = !String.IsNullOrEmpty(deploymentInfo.CommitId); if (updateStatusObj != null) { updateStatusObj.DeploymentStatus = Constants.BuildInProgress; await _deploymentManager.SendDeployStatusUpdate(updateStatusObj); } await _deploymentManager.DeployAsync( repository, changeSet, deploymentInfo.Deployer, clean : false, deploymentInfo : deploymentInfo, needFileUpdate : deploySpecificCommitId, fullBuildByDefault : deploymentInfo.DoFullBuildByDefault); if (updateStatusObj != null && !deploymentInfo.RestartAllowed) { // If restart is disallowed, send BuildSuccessful here as PostBuildRestartRequired was not sent // during the DeployAsync flow. updateStatusObj.DeploymentStatus = Constants.BuildSuccessful; await _deploymentManager.SendDeployStatusUpdate(updateStatusObj); } } } catch (Exception ex) { if (innerLogger != null) { innerLogger.Log(ex); } // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null) { IDeploymentStatusFile statusFile = _status.Open(deploymentInfo.TargetChangeset.Id); if (statusFile != null) { statusFile.MarkFailed(); } } try { if (updateStatusObj != null) { // Set deployment status as failure if exception is thrown updateStatusObj.DeploymentStatus = Constants.BuildFailed; await _deploymentManager.SendDeployStatusUpdate(updateStatusObj); } } catch { // no-op } throw; } // only clean up temp deployment if successful tempDeployment.Dispose(); } // check marker file and, if changed (meaning new /deploy request), redeploy. nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); } while (deploymentInfo.IsReusable && currentMarkerFileUTC != nextMarkerFileUTC); if (lastChange != null && PostDeploymentHelper.IsAutoSwapEnabled()) { IDeploymentStatusFile statusFile = _status.Open(lastChange.Id); if (statusFile.Status == DeployStatus.Success) { // if last change is not null and finish successfully, mean there was at least one deployment happened // since deployment is now done, trigger swap if enabled await PostDeploymentHelper.PerformAutoSwap(_environment.RequestId, new PostDeploymentTraceListener(_tracer, _deploymentManager.GetLogger(lastChange.Id))); } } }
public async Task PerformDeployment(DeploymentInfo deploymentInfo, IDisposable tempDeployment = null, ChangeSet tempChangeSet = null) { DateTime currentMarkerFileUTC; DateTime nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); ChangeSet lastChange = null; do { // save the current marker currentMarkerFileUTC = nextMarkerFileUTC; string targetBranch = _settings.GetBranch(); using (_tracer.Step("Performing fetch based deployment")) { // create temporary deployment before the actual deployment item started // this allows portal ui to readily display on-going deployment (not having to wait for fetch to complete). // in addition, it captures any failure that may occur before the actual deployment item started tempDeployment = tempDeployment ?? _deploymentManager.CreateTemporaryDeployment( Resources.ReceivingChanges, out tempChangeSet, deploymentInfo.TargetChangeset, deploymentInfo.Deployer); ILogger innerLogger = null; try { ILogger logger = _deploymentManager.GetLogger(tempChangeSet.Id); // Fetch changes from the repository innerLogger = logger.Log(Resources.FetchingChanges); IRepository repository = _repositoryFactory.EnsureRepository(deploymentInfo.RepositoryType); try { await deploymentInfo.Handler.Fetch(repository, deploymentInfo, targetBranch, innerLogger, _tracer); } catch (BranchNotFoundException) { // mark no deployment is needed deploymentInfo.TargetChangeset = null; } // set to null as Deploy() below takes over logging innerLogger = null; // The branch or commit id to deploy string deployBranch = !String.IsNullOrEmpty(deploymentInfo.CommitId) ? deploymentInfo.CommitId : targetBranch; // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null && ShouldDeploy(repository, deploymentInfo, deployBranch)) { // Perform the actual deployment var changeSet = repository.GetChangeSet(deployBranch); if (changeSet == null && !String.IsNullOrEmpty(deploymentInfo.CommitId)) { throw new InvalidOperationException(String.Format("Invalid revision '{0}'!", deploymentInfo.CommitId)); } lastChange = changeSet; // Here, we don't need to update the working files, since we know Fetch left them in the correct state // unless for GenericHandler where specific commitId is specified bool deploySpecificCommitId = !String.IsNullOrEmpty(deploymentInfo.CommitId); await _deploymentManager.DeployAsync(repository, changeSet, deploymentInfo.Deployer, clean : false, needFileUpdate : deploySpecificCommitId); } } catch (Exception ex) { if (innerLogger != null) { innerLogger.Log(ex); } // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null) { IDeploymentStatusFile statusFile = _status.Open(deploymentInfo.TargetChangeset.Id); if (statusFile != null) { statusFile.MarkFailed(); } } throw; } // only clean up temp deployment if successful tempDeployment.Dispose(); } // check marker file and, if changed (meaning new /deploy request), redeploy. nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); } while (deploymentInfo.IsReusable && currentMarkerFileUTC != nextMarkerFileUTC); if (lastChange != null && PostDeploymentHelper.IsAutoSwapEnabled()) { IDeploymentStatusFile statusFile = _status.Open(lastChange.Id); if (statusFile.Status == DeployStatus.Success) { // if last change is not null and finish successfully, mean there was at least one deployoment happened // since deployment is now done, trigger swap if enabled await PostDeploymentHelper.PerformAutoSwap(_environment.RequestId, _environment.SiteRestrictedJwt, new PostDeploymentTraceListener(_tracer, _deploymentManager.GetLogger(lastChange.Id))); } } }
public async Task PerformDeployment(DeploymentInfo deploymentInfo) { DateTime currentMarkerFileUTC; DateTime nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); do { // save the current marker currentMarkerFileUTC = nextMarkerFileUTC; string targetBranch = _settings.GetBranch(); using (_tracer.Step("Performing fetch based deployment")) { // create temporary deployment before the actual deployment item started // this allows portal ui to readily display on-going deployment (not having to wait for fetch to complete). // in addition, it captures any failure that may occur before the actual deployment item started ChangeSet tempChangeSet; IDisposable tempDeployment = _deploymentManager.CreateTemporaryDeployment( Resources.ReceivingChanges, out tempChangeSet, deploymentInfo.TargetChangeset, deploymentInfo.Deployer); ILogger innerLogger = null; try { ILogger logger = _deploymentManager.GetLogger(tempChangeSet.Id); // Fetch changes from the repository innerLogger = logger.Log(Resources.FetchingChanges); IRepository repository = _repositoryFactory.EnsureRepository(deploymentInfo.RepositoryType); try { await deploymentInfo.Handler.Fetch(repository, deploymentInfo, targetBranch, innerLogger); } catch (BranchNotFoundException) { // mark no deployment is needed deploymentInfo.TargetChangeset = null; } // set to null as Deploy() below takes over logging innerLogger = null; // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null && ShouldDeploy(repository, deploymentInfo, targetBranch)) { // Perform the actual deployment var changeSet = repository.GetChangeSet(targetBranch); // Here, we don't need to update the working files, since we know Fetch left them in the correct state await _deploymentManager.DeployAsync(repository, changeSet, deploymentInfo.Deployer, clean : false, needFileUpdate : false); } } catch (Exception ex) { if (innerLogger != null) { innerLogger.Log(ex); } // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null) { IDeploymentStatusFile statusFile = _status.Open(deploymentInfo.TargetChangeset.Id); if (statusFile != null) { statusFile.MarkFailed(); } } throw; } // only clean up temp deployment if successful tempDeployment.Dispose(); } // check marker file and, if changed (meaning new /deploy request), redeploy. nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); } while (deploymentInfo.IsReusable && currentMarkerFileUTC != nextMarkerFileUTC); }
/// <summary> /// <para>Handle both file and folder create/update</para> /// <para>If local file timestamp the same as the file in server, assume file/folder unchanged, will skip action.</para> /// </summary> private async Task HandlingUpdateOrCreate(OneDriveModel.OneDriveChange change, string wwwroot, string accessToken) { if (change.IsDeleted) { return; } string fullPath = GetDestinationPath(wwwroot, change.Path); if (fullPath == null) { TraceMessage("Ignore folder {0}", change.Path); return; } if (change.IsFile) { // return "1/1/1601 12:00:00 AM" when file not existed DateTime lastWriteTime = FileSystemHelpers.GetLastWriteTimeUtc(fullPath); if (lastWriteTime != change.LastModifiedUtc) { string parentDir = Path.GetDirectoryName(fullPath); FileSystemHelpers.EnsureDirectory(parentDir); var now = DateTime.UtcNow; var success = false; try { using (var client = CreateHttpClient(accessToken)) using (HttpResponseMessage response = await client.GetAsync(change.ContentUri)) { var fileResponse = await ProcessResponse <Dictionary <string, object> >("HandlingUpdateOrCreate", response); string downloadUrl = (string)fileResponse["@content.downloadUrl"]; using (HttpResponseMessage downloadResponse = await client.GetAsync(downloadUrl)) using (Stream stream = await downloadResponse.EnsureSuccessStatusCode().Content.ReadAsStreamAsync()) { await WriteToFile(stream, fullPath); } } FileSystemHelpers.SetLastWriteTimeUtc(fullPath, change.LastModifiedUtc); success = true; } finally { var elapse = (DateTime.UtcNow - now).TotalMilliseconds; var result = success ? "successful" : "failed"; if (FileSystemHelpers.FileExists(fullPath)) { TraceMessage("Update file {0} {1} ({2:0}ms)", fullPath, result, elapse); } else { TraceMessage("Create file {0} {1} ({2:0}ms)", fullPath, result, elapse); } } } else { _tracer.Trace("Timestamp not changed. Skip updating file {0}", fullPath); } } else { if (FileSystemHelpers.DirectoryExists(fullPath)) { TraceMessage("Directory {0} exists, no action performed.", fullPath); } else { TraceMessage("Creating directory {0} ...", fullPath); FileSystemHelpers.CreateDirectory(fullPath); } } }
public static void PurgeOldDeploymentsIfNecessary(string deploymentsPath, ITracer tracer, int totalAllowedDeployments) { IEnumerable <string> deploymentNames = FileSystemHelpers.GetDirectories(deploymentsPath); if (deploymentNames.Count() > totalAllowedDeployments) { // Order the files in descending order of the modified date and remove the last (N - allowed zip files). var deploymentsToDelete = deploymentNames.OrderByDescending(fileName => FileSystemHelpers.GetLastWriteTimeUtc(fileName)).Skip(totalAllowedDeployments); foreach (var deploymentName in deploymentsToDelete) { using (tracer.Step("Purging old deployment {0}", deploymentName)) { try { FileSystemHelpers.DeleteDirectorySafe(deploymentName); } catch (Exception ex) { tracer.TraceError(ex, "Unable to delete deployment {0}", deploymentName); } } } } }