public async Task <DescriptorDigest> HandleSuccessResponseAsync(HttpResponseMessage response) { // Checks if the image digest is as expected. DescriptorDigest expectedDigest = await Digests.ComputeJsonDigestAsync(manifestTemplate).ConfigureAwait(false); if (response.Headers.TryGetValues(RESPONSE_DIGEST_HEADER, out var receivedDigestEnum)) { var receivedDigests = receivedDigestEnum.ToList(); if (receivedDigests.Count == 1) { try { if (expectedDigest.Equals(DescriptorDigest.FromDigest(receivedDigests[0]))) { return(expectedDigest); } } catch (DigestException) { // Invalid digest. } } eventHandlers.Dispatch( LogEvent.Warn(MakeUnexpectedImageDigestWarning(expectedDigest, receivedDigests))); return(expectedDigest); } eventHandlers.Dispatch( LogEvent.Warn(MakeUnexpectedImageDigestWarning(expectedDigest, Array.Empty <string>()))); // The received digest is not as expected. Warns about this. return(expectedDigest); }
/** * Builds the container. * * @param containerizer the {@link Containerizer} that configures how to containerize * @return the built container * @throws IOException if an I/O exception occurs * @throws CacheDirectoryCreationException if a directory to be used for the cache could not be * created * @throws HttpHostConnectException if fib failed to connect to a registry * @throws RegistryUnauthorizedException if a registry request is unauthorized and needs * authentication * @throws RegistryAuthenticationFailedException if registry authentication failed * @throws UnknownHostException if the registry does not exist * @throws InsecureRegistryException if a server could not be verified due to an insecure * connection * @throws RegistryException if some other error occurred while interacting with a registry * @throws ExecutionException if some other exception occurred during execution * @throws InterruptedException if the execution was interrupted */ public async Task <FibContainer> ContainerizeAsync(IContainerizer containerizer) { containerizer = containerizer ?? throw new ArgumentNullException(nameof(containerizer)); BuildConfiguration buildConfiguration = ToBuildConfiguration(containerizer); IEventHandlers eventHandlers = buildConfiguration.GetEventHandlers(); LogSources(eventHandlers); using (new TimerEventDispatcher(eventHandlers, containerizer.GetDescription())) { try { IBuildResult result = await containerizer.CreateStepsRunner(buildConfiguration).RunAsync().ConfigureAwait(false); return(new FibContainer(result.GetImageDigest(), result.GetImageId())); } catch (Exception ex) { eventHandlers.Dispatch(LogEvent.Error(ex.Message)); // If an ExecutionException occurs, re-throw the cause to be more easily handled by the user if (ex.InnerException is RegistryException) { throw (RegistryException)ex.InnerException; } throw; } } }
private async Task <BaseImageWithAuthorization> GetOauthBaseImage(IEventHandlers eventHandlers, ProgressEventDispatcher progressEventDispatcher) { try { RetrieveRegistryCredentialsStep retrieveBaseRegistryCredentialsStep = RetrieveRegistryCredentialsStep.ForBaseImage( buildConfiguration, progressEventDispatcher.NewChildProducer(), this.Index); Credential registryCredential = await retrieveBaseRegistryCredentialsStep.GetFuture().ConfigureAwait(false); Authorization registryAuthorization = registryCredential?.IsOAuth2RefreshToken() != false ? null : Authorization.FromBasicCredentials( registryCredential.GetUsername(), registryCredential.GetPassword()); RegistryAuthenticator registryAuthenticator = await buildConfiguration .NewBaseImageRegistryClientFactory() .NewRegistryClient() .GetRegistryAuthenticatorAsync().ConfigureAwait(false); if (registryAuthenticator != null) { Authorization pullAuthorization = await registryAuthenticator.AuthenticatePullAsync(registryCredential, eventHandlers) .ConfigureAwait(false); return(new BaseImageWithAuthorization( await PullBaseImageAsync(pullAuthorization, progressEventDispatcher) .ConfigureAwait(false), pullAuthorization)); } } catch (Exception e) { // Cannot skip certificate validation or use HTTP; fall through. eventHandlers.Dispatch(LogEvent.Error(Resources.PullBaseImageStepAuthenticationErrorMessage + ",err:" + e.Message)); throw; } eventHandlers.Dispatch(LogEvent.Error(Resources.PullBaseImageStepAuthenticationErrorMessage + ",err:BaseImageCredential not config ")); throw new Exception("BaseImageCredential not config"); }
/** * Builds a new {@link BuildConfiguration} using the parameters passed into the builder. * * @return the corresponding build configuration * @throws IOException if an I/O exception occurs */ public BuildConfiguration Build() { // Validates the parameters. IList <string> missingFields = new List <string>(); if (baseImageConfiguration == null) { missingFields.Add("base image configuration"); } if (targetImageConfiguration == null) { missingFields.Add("target image configuration"); } if (baseImageLayersCacheDirectory == null) { missingFields.Add("base image layers cache directory"); } if (applicationLayersCacheDirectory == null) { missingFields.Add("application layers cache directory"); } switch (missingFields.Count) { case 0: // No errors if (Preconditions.CheckNotNull(baseImageConfiguration).GetImage().UsesDefaultTag()) { eventHandlers.Dispatch( LogEvent.Warn( "Base image '" + baseImageConfiguration.GetImage() + "' does not use a specific image digest - build may not be reproducible")); } return(new BuildConfiguration( baseImageConfiguration, Preconditions.CheckNotNull(targetImageConfiguration), additionalTargetImageTags, containerConfiguration, LayersCache.WithDirectory(Preconditions.CheckNotNull(baseImageLayersCacheDirectory)), LayersCache.WithDirectory(Preconditions.CheckNotNull(applicationLayersCacheDirectory)), targetFormat, allowInsecureRegistries, offline, layerConfigurations, toolName, toolVersion, eventHandlers)); case 1: throw new InvalidOperationException("Required field is not set: " + missingFields[0]); default: throw new InvalidOperationException("Required fields are not set: " + string.Join(", ", missingFields)); } }
/** * Sends the request. * * @param httpMethod the HTTP request method * @param request the request to send * @return the response to the sent request * @throws IOException if building the HTTP request fails. */ public async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request) { request = request ?? throw new ArgumentNullException(nameof(request)); try { return(await client.SendAsync(request).ConfigureAwait(false)); } catch (Exception e) { _eventHandlers?.Dispatch(LogEvent.Info("Exception retrieving " + request.RequestUri + "->ex:" + e.Message)); Debug.WriteLine("Exception retrieving " + request.RequestUri); throw; } }
private void LogSources(IEventHandlers eventHandlers) { // Logs the different source files used. var message = new StringBuilder(Resources.ContainerBuilderLogSourcesHeader); message.Append(":"); foreach (LayerConfiguration layerConfiguration in layerConfigurations) { if (layerConfiguration.LayerEntries.Length == 0) { continue; } message.Append(layerConfiguration.Name).Append(":file Counts:").Append(layerConfiguration.LayerEntries.Length); // // foreach (LayerEntry layerEntry in layerConfiguration.LayerEntries) // { // message.AppendLine("\t\t").Append(layerEntry.SourceFile); // } } eventHandlers.Dispatch(LogEvent.Info(message.ToString())); }
/** * Gets the BLOB referenced by {@code blobDigest}. Note that the BLOB is only pulled when it is * written out. * * @param blobDigest the digest of the BLOB to download * @param blobSizeListener callback to receive the total size of the BLOb to pull * @param writtenByteCountListener listens on byte count written to an output stream during the * pull * @return a {@link Blob} */ public IBlob PullBlob( DescriptorDigest blobDigest, Action <long> blobSizeListener, Action <long> writtenByteCountListener) { return(Blobs.From( async outputStream => { try { await CallRegistryEndpointAsync(new BlobPuller( registryEndpointRequestProperties, blobDigest, outputStream, blobSizeListener, writtenByteCountListener)).ConfigureAwait(false); } catch (RegistryException ex) { eventHandlers?.Dispatch(LogEvent.Error(ex.Message)); throw new IOException("", ex); } }, -1)); }
public async Task <BaseImageWithAuthorization> CallAsync() { IEventHandlers eventHandlers = buildConfiguration.GetEventHandlers(); // Skip this step if this is a scratch image ImageConfiguration baseImageConfiguration = buildConfiguration.GetBaseImageConfiguration(); string description = string.Format( CultureInfo.CurrentCulture, Resources.PullBaseImageStepDescriptionFormat, buildConfiguration.GetBaseImageConfiguration().GetImage()); eventHandlers.Dispatch(LogEvent.Progress(description)); if (baseImageConfiguration.GetImage().IsScratch()) { return(new BaseImageWithAuthorization( Image.CreateBuilder(buildConfiguration.GetTargetFormat()).Build(), null)); } if (buildConfiguration.IsOffline()) { return(new BaseImageWithAuthorization(PullBaseImageOffline(), null)); } using (ProgressEventDispatcher progressEventDispatcher = progressEventDispatcherFactory.Create(description, 2)) using (new TimerEventDispatcher(buildConfiguration.GetEventHandlers(), description)) { // First, try with no credentials. try { return(new BaseImageWithAuthorization(await PullBaseImageAsync(null, progressEventDispatcher).ConfigureAwait(false), null)); } catch (RegistryUnauthorizedException) { eventHandlers.Dispatch( LogEvent.Lifecycle( "The base image requires auth. Trying again for " + buildConfiguration.GetBaseImageConfiguration().GetImage() + "...")); // If failed, then, retrieve base registry credentials and try with retrieved credentials. // TODO: Refactor the logic in RetrieveRegistryCredentialsStep out to // registry.credentials.RegistryCredentialsRetriever to avoid this direct executor hack. RetrieveRegistryCredentialsStep retrieveBaseRegistryCredentialsStep = RetrieveRegistryCredentialsStep.ForBaseImage( buildConfiguration, progressEventDispatcher.NewChildProducer()); Credential registryCredential = await retrieveBaseRegistryCredentialsStep.GetFuture().ConfigureAwait(false); Authorization registryAuthorization = registryCredential?.IsOAuth2RefreshToken() != false ? null : Authorization.FromBasicCredentials( registryCredential.GetUsername(), registryCredential.GetPassword()); try { return(new BaseImageWithAuthorization( await PullBaseImageAsync(registryAuthorization, progressEventDispatcher).ConfigureAwait(false), registryAuthorization)); } catch (RegistryUnauthorizedException) { // The registry requires us to authenticate using the Docker Token Authentication. // See https://docs.docker.com/registry/spec/auth/token try { RegistryAuthenticator registryAuthenticator = await buildConfiguration .NewBaseImageRegistryClientFactory() .NewRegistryClient() .GetRegistryAuthenticatorAsync().ConfigureAwait(false); if (registryAuthenticator != null) { Authorization pullAuthorization = await registryAuthenticator.AuthenticatePullAsync(registryCredential).ConfigureAwait(false); return(new BaseImageWithAuthorization( await PullBaseImageAsync(pullAuthorization, progressEventDispatcher).ConfigureAwait(false), pullAuthorization)); } } catch (InsecureRegistryException) { // Cannot skip certificate validation or use HTTP; fall through. } eventHandlers.Dispatch(LogEvent.Error(Resources.PullBaseImageStepAuthenticationErrorMessage)); throw; } } } }
private void DispatchTimerEvent(State state, Duration duration, string eventDescription) { eventHandlers.Dispatch( new TimerEvent(state, duration, timer.GetElapsedTime(), eventDescription)); }
/** * Dispatches a {@link ProgressEvent} representing {@code progressUnits} of progress on the * managed {@link #allocation}. * * @param progressUnits units of progress */ public void DispatchProgress(long progressUnits) { // long unitsDecremented = DecrementRemainingAllocationUnits(progressUnits); eventHandlers.Dispatch(new ProgressEvent(allocation, progressUnits)); }
/** * Sends the authentication request and retrieves the Bearer authorization token. * * @param credential the credential used to authenticate * @param scope the scope of permissions to authenticate for * @return the {@link Authorization} response * @throws RegistryAuthenticationFailedException if authentication fails * @see <a * href="https://docs.docker.com/registry/spec/auth/token/#how-to-authenticate">https://docs.docker.com/registry/spec/auth/token/#how-to-authenticate</a> */ private async Task <Authorization> AuthenticateAsync(Credential credential, string scope, IEventHandlers eventHandlers) { try { using (Connection connection = Connection.GetConnectionFactory(eventHandlers)(GetAuthenticationUrl(credential, scope))) using (var request = new HttpRequestMessage()) { foreach (var value in userAgent) { request.Headers.UserAgent.Add(value); } if (IsOAuth2Auth(credential)) { string parameters = GetAuthRequestParameters(credential, scope); request.Content = new BlobHttpContent(Blobs.From(parameters), MediaType.FormData); } else if (credential != null) { Authorization authorization = Authorization.FromBasicCredentials(credential.GetUsername(), credential.GetPassword()); request.Headers.Authorization = new AuthenticationHeaderValue(authorization.GetScheme(), authorization.GetToken()); } if (IsOAuth2Auth(credential)) { request.Method = HttpMethod.Post; } else { request.Method = HttpMethod.Get; } string responseString; using (HttpResponseMessage response = await connection.SendAsync(request).ConfigureAwait(false)) using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8)) { responseString = await reader.ReadToEndAsync().ConfigureAwait(false); } AuthenticationResponseTemplate responseJson = JsonTemplateMapper.ReadJson <AuthenticationResponseTemplate>(responseString); if (responseJson.GetTokenOrAccessToken() == null) { var err = new RegistryAuthenticationFailedException( registryEndpointRequestProperties.GetRegistry(), registryEndpointRequestProperties.GetImageName(), "Did not get token in authentication response from " + GetAuthenticationUrl(credential, scope) + "; parameters: " + GetAuthRequestParameters(credential, scope)); eventHandlers?.Dispatch(LogEvent.Error(err.Message)); throw err; } return(Authorization.FromBearerToken(responseJson.GetTokenOrAccessToken())); } } catch (Exception ex) when(ex is IOException || ex is JsonException) { var eee = new RegistryAuthenticationFailedException( registryEndpointRequestProperties.GetRegistry(), registryEndpointRequestProperties.GetImageName(), ex); eventHandlers?.Dispatch(LogEvent.Error(eee.Message)); throw eee; } }