示例#1
0
        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);
        }
示例#2
0
        /**
         * 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;
                }
            }
        }
示例#3
0
        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");
        }
示例#4
0
            /**
             * 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));
                }
            }
示例#5
0
 /**
  * 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;
     }
 }
示例#6
0
        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()));
        }
示例#7
0
 /**
  * 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));
 }
示例#8
0
        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;
                        }
                    }
                }
        }
示例#9
0
 private void DispatchTimerEvent(State state, Duration duration, string eventDescription)
 {
     eventHandlers.Dispatch(
         new TimerEvent(state, duration, timer.GetElapsedTime(), eventDescription));
 }
示例#10
0
 /**
  * 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));
 }
示例#11
0
        /**
         * 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;
            }
        }