public override async Task ExecuteAsync()
        {
            _repoNameFilterRegex = new Regex(ManifestFilter.GetFilterRegexPattern(Options.RepoName));

            _loggerService.WriteHeading("FINDING IMAGES TO CLEAN");

            _loggerService.WriteSubheading($"Connecting to ACR '{Options.RegistryName}'");
            using IAcrClient acrClient = await _acrClientFactory.CreateAsync(
                      Options.RegistryName,
                      Options.ServicePrincipal.Tenant,
                      Options.ServicePrincipal.ClientId,
                      Options.ServicePrincipal.Secret);

            _loggerService.WriteSubheading($"Querying catalog of ACR '{Options.RegistryName}'");
            Catalog catalog = await acrClient.GetCatalogAsync();

            _loggerService.WriteHeading("DELETING IMAGES");

            List <string> deletedRepos  = new List <string>();
            List <string> deletedImages = new List <string>();

            IEnumerable <Task> cleanupTasks = catalog.RepositoryNames
                                              .Where(repoName => _repoNameFilterRegex.IsMatch(repoName))
                                              .Select(repoName => acrClient.GetRepositoryAsync(repoName))
                                              .Select(getRepoTask => ProcessRepoAsync(acrClient, getRepoTask, deletedRepos, deletedImages))
                                              .ToArray();

            await Task.WhenAll(cleanupTasks);

            await LogSummaryAsync(acrClient, deletedRepos, deletedImages);
        }
        private static async Task <ManifestInfo?> GetSubscriptionManifestAsync(Subscription subscription,
                                                                               ManifestFilterOptions filterOptions, HttpClient httpClient, ILoggerService loggerService,
                                                                               Action <ManifestOptions>?configureOptions)
        {
            // If the command is filtered with an OS type that does not match the OsType filter of the subscription,
            // then there are no images that need to be inspected.
            string osTypeRegexPattern = ManifestFilter.GetFilterRegexPattern(filterOptions.OsType);

            if (!string.IsNullOrEmpty(subscription.OsType) &&
                !Regex.IsMatch(subscription.OsType, osTypeRegexPattern, RegexOptions.IgnoreCase))
            {
                return(null);
            }

            string repoPath = await GitHelper.DownloadAndExtractGitRepoArchiveAsync(httpClient, subscription.Manifest, loggerService);

            try
            {
                TempManifestOptions manifestOptions = new(filterOptions)
                {
                    Manifest  = Path.Combine(repoPath, subscription.Manifest.Path),
                    Variables = subscription.Manifest.Variables
                };

                configureOptions?.Invoke(manifestOptions);

                return(ManifestInfo.Load(manifestOptions));
            }
            finally
            {
                // The path to the repo is stored inside a zip extraction folder so be sure to delete that
                // zip extraction folder, not just the inner repo folder.
                Directory.Delete(new DirectoryInfo(repoPath).Parent !.FullName, true);
            }
        }
        public override ManifestFilter GetManifestFilter()
        {
            ManifestFilter filterInfo = base.GetManifestFilter();

            filterInfo.DockerArchitecture = Architecture;

            return(filterInfo);
        }
Exemple #4
0
        public override ManifestFilter GetManifestFilter()
        {
            ManifestFilter filterInfo = base.GetManifestFilter();

            filterInfo.DockerArchitecture = Architecture;
            filterInfo.IncludeOsVersion   = OsVersion;
            filterInfo.IncludePath        = Path;

            return(filterInfo);
        }
Exemple #5
0
        private async Task <IEnumerable <string> > GetPathsToRebuildAsync(Subscription subscription)
        {
            // If the command is filtered with an OS type that does not match the OsType filter of the subscription,
            // then there are no images that need to be inspected.
            string osTypeRegexPattern = ManifestFilter.GetFilterRegexPattern(Options.FilterOptions.OsType);

            if (!string.IsNullOrEmpty(subscription.OsType) &&
                !Regex.IsMatch(subscription.OsType, osTypeRegexPattern, RegexOptions.IgnoreCase))
            {
                return(Enumerable.Empty <string>());
            }

            _loggerService.WriteMessage($"Processing subscription:  {subscription.Id}");

            string repoPath = await GetGitRepoPath(subscription);

            TempManifestOptions manifestOptions = new TempManifestOptions(Options.FilterOptions)
            {
                Manifest = Path.Combine(repoPath, subscription.Manifest.Path)
            };

            ManifestInfo manifest = ManifestInfo.Load(manifestOptions);

            ImageArtifactDetails imageArtifactDetails = await GetImageInfoForSubscriptionAsync(subscription, manifest);

            List <string> pathsToRebuild = new List <string>();

            IEnumerable <PlatformInfo> allPlatforms = manifest.GetAllPlatforms().ToList();

            foreach (RepoInfo repo in manifest.FilteredRepos)
            {
                IEnumerable <PlatformInfo> platforms = repo.FilteredImages
                                                       .SelectMany(image => image.FilteredPlatforms)
                                                       .Where(platform => !platform.IsInternalFromImage(platform.FinalStageFromImage));

                RepoData repoData = imageArtifactDetails.Repos
                                    .FirstOrDefault(s => s.Repo == repo.Name);

                foreach (PlatformInfo platform in platforms)
                {
                    pathsToRebuild.AddRange(GetPathsToRebuild(allPlatforms, platform, repoData));
                }
            }

            return(pathsToRebuild.Distinct().ToList());
        }
Exemple #6
0
        public virtual ManifestFilter GetManifestFilter()
        {
            ManifestFilter filter = new ManifestFilter()
            {
                IncludeRepo = Repo,
            };

            if (this is IManifestFilterOptions)
            {
                IManifestFilterOptions filterOptions = (IManifestFilterOptions)this;
                filter.DockerArchitecture = filterOptions.Architecture;
                filter.IncludeOsVersion   = filterOptions.OsVersion;
                filter.IncludePaths       = filterOptions.Paths;
            }

            return(filter);
        }
        public virtual ManifestFilter GetManifestFilter()
        {
            ManifestFilter filter = new ManifestFilter()
            {
                IncludeRepos = Repos,
            };

            if (this is IFilterableOptions options)
            {
                ManifestFilterOptions filterOptions = options.FilterOptions;
                filter.IncludeArchitecture = filterOptions.Architecture;
                filter.IncludeOsType       = filterOptions.OsType;
                filter.IncludeOsVersions   = filterOptions.OsVersions;
                filter.IncludePaths        = filterOptions.Paths;
            }

            return(filter);
        }
Exemple #8
0
        private async Task <IEnumerable <string> > GetPathsToRebuildAsync(Subscription subscription)
        {
            // If the command is filtered with an OS type that does not match the OsType filter of the subscription,
            // then there are no images that need to be inspected.
            string osTypeRegexPattern = ManifestFilter.GetFilterRegexPattern(Options.FilterOptions.OsType);

            if (!String.IsNullOrEmpty(subscription.OsType) &&
                !Regex.IsMatch(subscription.OsType, osTypeRegexPattern, RegexOptions.IgnoreCase))
            {
                return(Enumerable.Empty <string>());
            }

            RepoData[] repos = await GetImageInfoForSubscriptionAsync(subscription);

            string repoPath = await GetGitRepoPath(subscription);

            TempManifestOptions manifestOptions = new TempManifestOptions(Options.FilterOptions)
            {
                Manifest = Path.Combine(repoPath, subscription.ManifestPath)
            };

            ManifestInfo manifest = ManifestInfo.Load(manifestOptions);

            List <string> pathsToRebuild = new List <string>();

            IEnumerable <PlatformInfo> allPlatforms = manifest.GetAllPlatforms().ToList();

            foreach (RepoInfo repo in manifest.FilteredRepos)
            {
                IEnumerable <PlatformInfo> platforms = repo.FilteredImages
                                                       .SelectMany(image => image.FilteredPlatforms);

                RepoData repoData = repos
                                    .FirstOrDefault(s => s.Repo == repo.Model.Name);

                foreach (var platform in platforms)
                {
                    if (repoData != null &&
                        repoData.Images != null &&
                        repoData.Images.TryGetValue(platform.DockerfilePathRelativeToManifest, out ImageData imageData))
                    {
                        bool hasDigestChanged = false;

                        foreach (string fromImage in platform.ExternalFromImages)
                        {
                            string currentDigest;

                            await this.imageDigestsSemaphore.WaitAsync();

                            try
                            {
                                if (!this.imageDigests.TryGetValue(fromImage, out currentDigest))
                                {
                                    this.dockerService.PullImage(fromImage, Options.IsDryRun);
                                    currentDigest = this.dockerService.GetImageDigest(fromImage, Options.IsDryRun);
                                    this.imageDigests.Add(fromImage, currentDigest);
                                }
                            }
                            finally
                            {
                                this.imageDigestsSemaphore.Release();
                            }

                            string lastDigest = null;
                            imageData.BaseImages?.TryGetValue(fromImage, out lastDigest);

                            if (lastDigest != currentDigest)
                            {
                                hasDigestChanged = true;
                                break;
                            }
                        }

                        if (hasDigestChanged)
                        {
                            IEnumerable <PlatformInfo> dependentPlatforms = platform.GetDependencyGraph(allPlatforms);
                            pathsToRebuild.AddRange(dependentPlatforms.Select(p => p.Model.Dockerfile));
                        }
                    }
                    else
                    {
                        this.loggerService.WriteMessage(
                            $"WARNING: Image info not found for '{platform.DockerfilePath}'. Adding path to build to be queued anyway.");
                        pathsToRebuild.Add(platform.Model.Dockerfile);
                    }
                }
            }

            return(pathsToRebuild.Distinct().ToList());
        }