public override async Task DoRequestAsync(IndexRequest request) { try { RegistryCredentials credentials = null; // if the request was submitted by a user, it must have auth info included if (!string.IsNullOrEmpty(request.Authorization)) { var authResult = authDecoder.AuthenticateAsync(request.Authorization).Result; if (authResult.Succeeded) { credentials = authResult.Principal.ToRegistryCredentials(); } } // if the request came via an event sink, there is no auth provided, and we need to have a default user configured else { credentials = config.GetCatalogCredentials() ?? throw new ArgumentException("The indexing request had no included authorization, and no default catalog user is configured."); } if (credentials == null) { logger.LogWarning("Authorization failed for the work item. A token may have expired since it was first submitted."); } else { await authHandler.LoginAsync(credentials); var client = clientFactory.GetClient(authHandler); // if deep indexing is configured, ignore target paths if (config.DeepIndexing) { request.TargetPaths = new string[0]; } var imageSet = await client.GetImageSetAsync(request.TargetRepo, request.TargetDigest); if ((imageSet?.Images?.Count() ?? 0) != 1) { throw new Exception($"Couldn't find a valid image for {request.TargetRepo}:{request.TargetDigest}"); } var image = imageSet.Images.First(); using (var @lock = await cacheFactory.Get <object>().TakeLockAsync($"idx:{image.Digest}", TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5))) { if (!indexStore.IndexExists(image.Digest, request.TargetPaths.ToArray())) { logger.LogInformation($"Starting index for {request.TargetRepo}:{request.TargetDigest}"); var indexes = client.GetIndexes(request.TargetRepo, image, request.TargetPaths.ToArray()); indexStore.SetIndex(indexes, image.Digest, request.TargetPaths.ToArray()); logger.LogInformation($"Completed indexing {indexes.Max(i => i.Depth)} layer(s) from {request.TargetRepo}:{request.TargetDigest} {(request.TargetPaths.Count() == 0 ? "" : $"({string.Join(", ", request.TargetPaths)})")}"); } else { logger.LogInformation($"Index already exists for {request.TargetRepo}:{request.TargetDigest}"); } } } } catch (Exception ex) { logger.LogError(ex, $"Processing failed for work item\n {Newtonsoft.Json.JsonConvert.SerializeObject(request)}"); } }
public async Task <IActionResult> GetFilesAsync(string repository, string digest, string targets) { if (string.IsNullOrEmpty(digest)) { return(BadRequest("An image digest is required.")); } if (!digest.IsDigest()) { return(BadRequest("Digest appears invalid.")); } try { if (string.IsNullOrEmpty(RegistryCredentials.Registry)) { return(BadRequest("Session is missing registry information. Try creating a new session.")); } var targetList = string.IsNullOrEmpty(targets) ? Array.Empty <string>() : targets.Split(';'); var client = clientFactory.GetClient(AuthHandler); var imageSet = await client.GetImageSetAsync(repository, digest); if (imageSet.Images.Count() != 1) { return(NotFound("No image was found with the given digest.")); } // if we have a complete index, return it if (indexStore.IndexExists(digest)) { return(Ok(indexStore.GetIndex(digest))); } // otherwise, if they've requested a targeted index, look for that else if (indexStore.IndexExists(digest, targetList)) { return(Ok(indexStore.GetIndex(digest, targetList))); } // no dice, queue an indexing request else { var request = new IndexRequest { Authorization = Request.Headers["Authorization"], CreatedTime = DateTime.UtcNow, TargetRepo = repository, TargetDigest = digest, TargetPaths = targetList }; if (!indexQueue.Contains(request)) { indexQueue.Push(request); } return(StatusCode(202, new { Status = RequestStatus.Pending })); } } catch (RedisConnectionException) { return(StatusCode(503, "Cannot access cache")); } catch (Client.NotFoundException) { return(NotFound()); } catch (Client.AuthenticationException) { return(Unauthorized()); } }