public async Task <bool> EnqueueDeployment(Deployment deployment, TimeSpan?delay = null, bool force = false) { if (!force) { if (deployment.Status != DeploymentStatus.Pending) { return(false); } } // add entry in store var dao = await _deploymentQueueRepository.Add(new DeploymentQueue() { DeploymentId = deployment.Id, Id = Guid.NewGuid(), ApplicationId = deployment.ApplicationId, AttemptCount = 0, AvailableDateTime = DateTime.Now.Add(delay ?? TimeSpan.FromSeconds(0)), CreationDateTime = DateTime.Now }); await _deploymentQueueRepository.Save(); await _deploymentService.ChangeDeploymentUpdateStatus(deployment.Id, DeploymentStatus.Queued); return(true); }
private async Task <bool> InternalExecute <TManifest>(TManifest manifest, Application application) where TManifest : DeploymentManifest { // prefetch and structure some metadata required throughout var imageMap = application.Images.ToDictionary( x => $"{x.Repository}-{x.TagProperty.Path}" ); // store var manifestsChanged = false; // 1. check for any orphan preview releases var appImagesWithPreviewReleases = imageMap.Values .Where(x => x.SourceCode.IsAvailable && x.DeploymentSettings.PreviewReleases.Enabled) .ToArray(); if (appImagesWithPreviewReleases.Any()) { _log.LogInformation("Checking for orphan preview releases ..."); foreach (var item in appImagesWithPreviewReleases) { if (!item.SourceCode.IsAvailable) { continue; } var openPullRequests = (await _githubPullRequestService.GetOpenPRs(item)) .ToArray(); _log.LogTrace("Found {prCount} open pull requests", openPullRequests.Length); var appImageInstances = (await _applicationImageInstanceService.GetInstancesFor(application, item)) .ToArray(); _log.LogTrace("Found {instanceCount} active instances", appImageInstances.Length); foreach (var applicationImageInstance in appImageInstances) { if (applicationImageInstance.Source.Type != ApplicationImageInstanceSourceType.PullRequest) { continue; } if (openPullRequests.Any(x => x.PrNumber.Equals(applicationImageInstance.Source.PullRequestId))) { continue; } _log.LogTrace("No pull request found for instance {instanceName}, removing ...", applicationImageInstance.Name); await _deploymentManifestSourceManagementFacade.RemovePreviewRelease(manifest, item, applicationImageInstance.Name); await _applicationImageInstanceService.RemoveInstance(application, item, applicationImageInstance); manifestsChanged = true; } } } _log.LogTrace("Checking for pending deployments to apply."); // start updating files var updatedImageTags = new Dictionary <ApplicationImageInstanceKey, string>(); Deployment?nextPendingDeployment = null; while ((nextPendingDeployment = await _deploymentQueueService.GetNextPendingDeploymentUpdate(application)) != null) { await _deploymentService.ChangeDeploymentUpdateStatus( nextPendingDeployment.Id, DeploymentStatus.Starting ); _log.LogTrace("Executing pending deployment update ..."); await _deploymentService.ChangeDeploymentUpdateStatus( nextPendingDeployment.Id, DeploymentStatus.UpdatingManifests ); var deploymentManifestInfo = await _deploymentManifestSourceManagementFacade.GetDeploymentManifestInfo(manifest); var image = imageMap[$"{nextPendingDeployment.ImageRepository}-{nextPendingDeployment.UpdatePath}"]; var dmiKey = new DeploymentManifestInstanceKey(image, nextPendingDeployment.InstanceId); switch (nextPendingDeployment.Type) { case DeploymentType.ImageUpdate: await _deploymentManifestSourceManagementFacade.UpdateApplicationImageVersion( manifest, image, nextPendingDeployment.InstanceId, nextPendingDeployment.TargetTag ); break; case DeploymentType.PreviewRelease: if (!deploymentManifestInfo.Instances.ContainsKey(dmiKey)) { await _deploymentManifestSourceManagementFacade.CreatePreviewRelease( manifest, image, nextPendingDeployment.InstanceId, nextPendingDeployment.TargetTag ); } else { await _deploymentManifestSourceManagementFacade.UpdateApplicationImageVersion( manifest, image, nextPendingDeployment.InstanceId, nextPendingDeployment.TargetTag ); } break; default: throw new ArgumentOutOfRangeException(); } var key = new ApplicationImageInstanceKey(application, image, nextPendingDeployment.InstanceId); updatedImageTags[key] = nextPendingDeployment.TargetTag; manifestsChanged = true; // TODO: rework this so that failures to push get indicated await _deploymentService.FinishDeploymentUpdate( nextPendingDeployment.Id, manifestsChanged?DeploymentStatus.Complete : DeploymentStatus.Failed ); } await SyncApplicationMetadataFromManifest(manifest, application, updatedImageTags); _log.LogTrace("Deployment manifest repository syncing complete ..."); return(manifestsChanged); }
private async Task <bool> SynchronizeHelmApplicationSource(Repository gitRepository, ApplicationSourceTrackingContext context, HelmApplicationSource helmApplicationSource) { var relativePath = helmApplicationSource.Path; var applicationSourcePath = Path.Combine(context.GitRepositoryPath, relativePath); var application = context.Application; var yamlUtilities = new YamlUtilities(); // build map of images -> yaml file that defines them and image -> current tag _log.LogInformation("Beginning to parse value files defined in application source ..."); var imageToFilenameMap = new Dictionary <Image, string>(); var imageToTagInManifest = new Dictionary <Image, string>(); foreach (var file in helmApplicationSource.ValuesFiles) { var yaml = new YamlStream(); var filePath = Path.Combine(applicationSourcePath, file); yamlUtilities.ReadYamlStream(yaml, filePath); foreach (var doc in yaml.Documents) { foreach (var image in context.Application.Images) { var tagInManifest = yamlUtilities.ExtractValueFromDoc(image.TagProperty.Path, doc); if (tagInManifest == null) { continue; } if (imageToFilenameMap.ContainsKey(image)) { // TODO: handle situation where multiple files define the same image tag (ERROR and warn user) } imageToFilenameMap[image] = file; imageToTagInManifest[image] = tagInManifest; } } } _log.LogInformation("Completing parsing value files defined in application source ..."); // start updating files var manifestsChanged = false; DeploymentUpdate deploymentUpdate = null; while ((deploymentUpdate = await _deploymentService.GetNextPendingDeploymentUpdate(application)) != null) { _log.LogInformation("Executing pending deployment update ..."); await _deploymentService.ChangeDeploymentUpdateStatus( deploymentUpdate, DeploymentUpdateStatus.UpdatingManifests ); manifestsChanged = await UpdateDeploymentManifests(gitRepository, deploymentUpdate, imageToFilenameMap, imageToTagInManifest.TryGetAndReturn(deploymentUpdate.Image) ?? "n/a", applicationSourcePath, yamlUtilities, relativePath); if (manifestsChanged) { imageToTagInManifest[deploymentUpdate.Image] = deploymentUpdate.TargetTag; } await _deploymentService.FinishDeploymentUpdate( deploymentUpdate, manifestsChanged?DeploymentUpdateStatus.Complete : DeploymentUpdateStatus.Failed ); } if (!manifestsChanged) { // we don't have a deployment, ensure application manifest is up to date with latest image tags foreach (var keyValuePair in imageToTagInManifest) { _applicationService.SetCurrentImageTag(application, keyValuePair.Key, keyValuePair.Value); } } return(manifestsChanged); }