Merge pull request #1930 from mtrmac/sysregistriesv2
Update c/image for sysregistriesv2 changes and automatic docker:// insecure configuration
This commit is contained in:
commit
a387c723a9
3
API.md
3
API.md
|
@ -609,7 +609,8 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.PullImage '{"name": "regi
|
|||
|
||||
method PushImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string), tlsverify: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
|
||||
PushImage takes three input arguments: the name or ID of an image, the fully-qualified destination name of the image,
|
||||
and a boolean as to whether tls-verify should be used. It will return an [ImageNotFound](#ImageNotFound) error if
|
||||
and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior).
|
||||
It will return an [ImageNotFound](#ImageNotFound) error if
|
||||
the image cannot be found in local storage; otherwise the ID of the image will be returned on success.
|
||||
### <a name="RemoveContainer"></a>func RemoveContainer
|
||||
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
|
||||
|
|
|
@ -129,7 +129,7 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container
|
|||
var data *inspect.ImageData = nil
|
||||
|
||||
if rootfs == "" && !rootless.SkipStorageSetup() {
|
||||
newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false)
|
||||
newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/containers/image/docker"
|
||||
"github.com/containers/image/pkg/docker/config"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/libpod/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
|
@ -93,7 +94,9 @@ func loginCmd(c *cli.Context) error {
|
|||
return errors.Wrapf(err, "error getting username and password")
|
||||
}
|
||||
|
||||
sc.DockerInsecureSkipTLSVerify = !c.BoolT("tls-verify")
|
||||
if c.IsSet("tls-verify") {
|
||||
sc.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
|
||||
}
|
||||
if c.String("cert-dir") != "" {
|
||||
sc.DockerCertPath = c.String("cert-dir")
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ specified, the image with the 'latest' tag (if it exists) is pulled
|
|||
// pullCmd gets the data from the command line and calls pullImage
|
||||
// to copy an image from a registry to a local machine
|
||||
func pullCmd(c *cli.Context) error {
|
||||
forceSecure := false
|
||||
runtime, err := libpodruntime.GetRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
|
@ -104,12 +103,11 @@ func pullCmd(c *cli.Context) error {
|
|||
}
|
||||
|
||||
dockerRegistryOptions := image2.DockerRegistryOptions{
|
||||
DockerRegistryCreds: registryCreds,
|
||||
DockerCertPath: c.String("cert-dir"),
|
||||
DockerInsecureSkipTLSVerify: !c.BoolT("tls-verify"),
|
||||
DockerRegistryCreds: registryCreds,
|
||||
DockerCertPath: c.String("cert-dir"),
|
||||
}
|
||||
if c.IsSet("tls-verify") {
|
||||
forceSecure = c.Bool("tls-verify")
|
||||
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
|
||||
}
|
||||
|
||||
// Possible for docker-archive to have multiple tags, so use LoadFromArchiveReference instead
|
||||
|
@ -125,7 +123,7 @@ func pullCmd(c *cli.Context) error {
|
|||
imgID = newImage[0].ID()
|
||||
} else {
|
||||
authfile := getAuthFile(c.String("authfile"))
|
||||
newImage, err := runtime.ImageRuntime().New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true, forceSecure)
|
||||
newImage, err := runtime.ImageRuntime().New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error pulling image %q", image)
|
||||
}
|
||||
|
|
|
@ -81,7 +81,6 @@ func pushCmd(c *cli.Context) error {
|
|||
var (
|
||||
registryCreds *types.DockerAuthConfig
|
||||
destName string
|
||||
forceSecure bool
|
||||
)
|
||||
|
||||
args := c.Args()
|
||||
|
@ -108,7 +107,6 @@ func pushCmd(c *cli.Context) error {
|
|||
}
|
||||
|
||||
certPath := c.String("cert-dir")
|
||||
skipVerify := !c.BoolT("tls-verify")
|
||||
removeSignatures := c.Bool("remove-signatures")
|
||||
signBy := c.String("sign-by")
|
||||
|
||||
|
@ -145,14 +143,12 @@ func pushCmd(c *cli.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
if c.IsSet("tls-verify") {
|
||||
forceSecure = c.Bool("tls-verify")
|
||||
}
|
||||
|
||||
dockerRegistryOptions := image.DockerRegistryOptions{
|
||||
DockerRegistryCreds: registryCreds,
|
||||
DockerCertPath: certPath,
|
||||
DockerInsecureSkipTLSVerify: skipVerify,
|
||||
DockerRegistryCreds: registryCreds,
|
||||
DockerCertPath: certPath,
|
||||
}
|
||||
if c.IsSet("tls-verify") {
|
||||
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
|
||||
}
|
||||
|
||||
so := image.SigningOptions{
|
||||
|
@ -167,5 +163,5 @@ func pushCmd(c *cli.Context) error {
|
|||
|
||||
authfile := getAuthFile(c.String("authfile"))
|
||||
|
||||
return newImage.PushImageToHeuristicDestination(getContext(), destName, manifestType, authfile, c.String("signature-policy"), writer, c.Bool("compress"), so, &dockerRegistryOptions, forceSecure, nil)
|
||||
return newImage.PushImageToHeuristicDestination(getContext(), destName, manifestType, authfile, c.String("signature-policy"), writer, c.Bool("compress"), so, &dockerRegistryOptions, nil)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
|
@ -153,8 +154,10 @@ func runlabelCmd(c *cli.Context) error {
|
|||
}
|
||||
|
||||
dockerRegistryOptions := image.DockerRegistryOptions{
|
||||
DockerCertPath: c.String("cert-dir"),
|
||||
DockerInsecureSkipTLSVerify: !c.BoolT("tls-verify"),
|
||||
DockerCertPath: c.String("cert-dir"),
|
||||
}
|
||||
if c.IsSet("tls-verify") {
|
||||
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
|
||||
}
|
||||
|
||||
authfile := getAuthFile(c.String("authfile"))
|
||||
|
|
|
@ -146,7 +146,7 @@ func saveCmd(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := newImage.PushImageToReference(getContext(), destRef, manifestType, "", "", writer, c.Bool("compress"), libpodImage.SigningOptions{}, &libpodImage.DockerRegistryOptions{}, false, additionaltags); err != nil {
|
||||
if err := newImage.PushImageToReference(getContext(), destRef, manifestType, "", "", writer, c.Bool("compress"), libpodImage.SigningOptions{}, &libpodImage.DockerRegistryOptions{}, additionaltags); err != nil {
|
||||
if err2 := os.Remove(output); err2 != nil {
|
||||
logrus.Errorf("error deleting %q: %v", output, err)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/containers/image/docker"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/cmd/podman/formats"
|
||||
"github.com/containers/libpod/libpod/common"
|
||||
sysreg "github.com/containers/libpod/pkg/registries"
|
||||
|
@ -72,11 +73,12 @@ type searchParams struct {
|
|||
}
|
||||
|
||||
type searchOpts struct {
|
||||
filter []string
|
||||
limit int
|
||||
noTrunc bool
|
||||
format string
|
||||
authfile string
|
||||
filter []string
|
||||
limit int
|
||||
noTrunc bool
|
||||
format string
|
||||
authfile string
|
||||
insecureSkipTLSVerify types.OptionalBool
|
||||
}
|
||||
|
||||
type searchFilterParams struct {
|
||||
|
@ -116,7 +118,10 @@ func searchCmd(c *cli.Context) error {
|
|||
filter: c.StringSlice("filter"),
|
||||
authfile: getAuthFile(c.String("authfile")),
|
||||
}
|
||||
regAndSkipTLS, err := getRegistriesAndSkipTLS(c, registry)
|
||||
if c.IsSet("tls-verify") {
|
||||
opts.insecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
|
||||
}
|
||||
registries, err := getRegistries(registry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -126,7 +131,7 @@ func searchCmd(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return generateSearchOutput(term, regAndSkipTLS, opts, *filter)
|
||||
return generateSearchOutput(term, registries, opts, *filter)
|
||||
}
|
||||
|
||||
func genSearchFormat(format string) string {
|
||||
|
@ -157,16 +162,8 @@ func (s *searchParams) headerMap() map[string]string {
|
|||
return values
|
||||
}
|
||||
|
||||
// A function for finding which registries can skip TLS
|
||||
func getRegistriesAndSkipTLS(c *cli.Context, registry string) (map[string]bool, error) {
|
||||
// Variables for setting up Registry and TLSVerify
|
||||
tlsVerify := c.BoolT("tls-verify")
|
||||
forceSecure := false
|
||||
|
||||
if c.IsSet("tls-verify") {
|
||||
forceSecure = c.BoolT("tls-verify")
|
||||
}
|
||||
|
||||
// getRegistries returns the list of registries to search, depending on an optional registry specification
|
||||
func getRegistries(registry string) ([]string, error) {
|
||||
var registries []string
|
||||
if registry != "" {
|
||||
registries = append(registries, registry)
|
||||
|
@ -177,35 +174,10 @@ func getRegistriesAndSkipTLS(c *cli.Context, registry string) (map[string]bool,
|
|||
return nil, errors.Wrapf(err, "error getting registries to search")
|
||||
}
|
||||
}
|
||||
regAndSkipTLS := make(map[string]bool)
|
||||
// If tls-verify is set to false, allow insecure always.
|
||||
if !tlsVerify {
|
||||
for _, reg := range registries {
|
||||
regAndSkipTLS[reg] = true
|
||||
}
|
||||
} else {
|
||||
// initially set all registries to verify with TLS
|
||||
for _, reg := range registries {
|
||||
regAndSkipTLS[reg] = false
|
||||
}
|
||||
// if the user didn't allow nor disallow insecure registries, check to see if the registry is insecure
|
||||
if !forceSecure {
|
||||
insecureRegistries, err := sysreg.GetInsecureRegistries()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error getting insecure registries to search")
|
||||
}
|
||||
for _, reg := range insecureRegistries {
|
||||
// if there are any insecure registries in registries, allow for HTTP
|
||||
if _, ok := regAndSkipTLS[reg]; ok {
|
||||
regAndSkipTLS[reg] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return regAndSkipTLS, nil
|
||||
return registries, nil
|
||||
}
|
||||
|
||||
func getSearchOutput(term string, regAndSkipTLS map[string]bool, opts searchOpts, filter searchFilterParams) ([]searchParams, error) {
|
||||
func getSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) ([]searchParams, error) {
|
||||
// Max number of queries by default is 25
|
||||
limit := maxQueries
|
||||
if opts.limit != 0 {
|
||||
|
@ -213,10 +185,10 @@ func getSearchOutput(term string, regAndSkipTLS map[string]bool, opts searchOpts
|
|||
}
|
||||
|
||||
sc := common.GetSystemContext("", opts.authfile, false)
|
||||
sc.DockerInsecureSkipTLSVerify = opts.insecureSkipTLSVerify
|
||||
sc.SystemRegistriesConfPath = sysreg.SystemRegistriesConfPath() // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
|
||||
var paramsArr []searchParams
|
||||
for reg, skipTLS := range regAndSkipTLS {
|
||||
// set the SkipTLSVerify bool depending on the registry being searched through
|
||||
sc.DockerInsecureSkipTLSVerify = skipTLS
|
||||
for _, reg := range registries {
|
||||
results, err := docker.SearchRegistry(context.TODO(), sc, reg, term, limit)
|
||||
if err != nil {
|
||||
logrus.Errorf("error searching registry %q: %v", reg, err)
|
||||
|
@ -276,8 +248,8 @@ func getSearchOutput(term string, regAndSkipTLS map[string]bool, opts searchOpts
|
|||
return paramsArr, nil
|
||||
}
|
||||
|
||||
func generateSearchOutput(term string, regAndSkipTLS map[string]bool, opts searchOpts, filter searchFilterParams) error {
|
||||
searchOutput, err := getSearchOutput(term, regAndSkipTLS, opts, filter)
|
||||
func generateSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) error {
|
||||
searchOutput, err := getSearchOutput(term, registries, opts, filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,11 +4,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
"github.com/docker/go-units"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -18,9 +13,14 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
"github.com/containers/libpod/pkg/inspect"
|
||||
cc "github.com/containers/libpod/pkg/spec"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -620,7 +620,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim
|
|||
registryCreds = creds
|
||||
}
|
||||
dockerRegistryOptions.DockerRegistryCreds = registryCreds
|
||||
newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false, false)
|
||||
newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false)
|
||||
} else {
|
||||
newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage)
|
||||
}
|
||||
|
|
|
@ -610,7 +610,8 @@ method InspectImage(name: string) -> (image: string)
|
|||
method HistoryImage(name: string) -> (history: []ImageHistory)
|
||||
|
||||
# PushImage takes three input arguments: the name or ID of an image, the fully-qualified destination name of the image,
|
||||
# and a boolean as to whether tls-verify should be used. It will return an [ImageNotFound](#ImageNotFound) error if
|
||||
# and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior).
|
||||
# It will return an [ImageNotFound](#ImageNotFound) error if
|
||||
# the image cannot be found in local storage; otherwise the ID of the image will be returned on success.
|
||||
method PushImage(name: string, tag: string, tlsverify: bool) -> (image: string)
|
||||
|
||||
|
|
|
@ -95,8 +95,8 @@ option be used, as the default behavior of using the system-wide default policy
|
|||
**--tls-verify**
|
||||
|
||||
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
|
||||
then tls verification will be used, If set to false then tls verification will not be used. If not specified
|
||||
tls verification will be used unless the target registry is listed as an insecure registry in registries.conf
|
||||
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
|
||||
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf
|
||||
|
||||
## Examples ##
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ Default certificates directory is _/etc/containers/certs.d_.
|
|||
|
||||
**--tls-verify**
|
||||
|
||||
Require HTTPS and verify certificates when contacting registries (default: true)
|
||||
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
|
||||
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
|
||||
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
|
||||
|
||||
**--help**, **-h**
|
||||
|
||||
|
|
|
@ -77,8 +77,8 @@ option be used, as the default behavior of using the system-wide default policy
|
|||
**--tls-verify**
|
||||
|
||||
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
|
||||
then tls verification will be used, If set to false then tls verification will not be used. If not specified
|
||||
tls verification will be used unless the target registry is listed as an insecure registry in registries.conf.
|
||||
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
|
||||
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
|
||||
|
||||
**--help**, **-h**
|
||||
|
||||
|
|
|
@ -93,7 +93,9 @@ Add a signature at the destination using the specified key
|
|||
|
||||
**--tls-verify**
|
||||
|
||||
Require HTTPS and verify certificates when contacting registries (default: true)
|
||||
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
|
||||
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
|
||||
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ Do not truncate the output
|
|||
**--tls-verify**
|
||||
|
||||
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
|
||||
then tls verification will be used. If set to false then tls verification will not be used if needed. If not specified
|
||||
default registries will be searched through (in /etc/containers/registries.conf), and tls will be skipped if a default
|
||||
then TLS verification will be used. If set to false, then TLS verification will not be used if needed. If not specified,
|
||||
default registries will be searched through (in /etc/containers/registries.conf), and TLS will be skipped if a default
|
||||
registry is listed in the insecure registries.
|
||||
|
||||
**--help**, **-h**
|
||||
|
|
|
@ -1,32 +1,9 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
cp "github.com/containers/image/copy"
|
||||
"github.com/containers/image/types"
|
||||
)
|
||||
|
||||
// GetCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters
|
||||
func GetCopyOptions(reportWriter io.Writer, signaturePolicyPath string, srcDockerRegistry, destDockerRegistry *DockerRegistryOptions, signing SigningOptions, authFile, manifestType string, forceCompress bool) *cp.Options {
|
||||
if srcDockerRegistry == nil {
|
||||
srcDockerRegistry = &DockerRegistryOptions{}
|
||||
}
|
||||
if destDockerRegistry == nil {
|
||||
destDockerRegistry = &DockerRegistryOptions{}
|
||||
}
|
||||
srcContext := srcDockerRegistry.GetSystemContext(signaturePolicyPath, authFile, forceCompress)
|
||||
destContext := destDockerRegistry.GetSystemContext(signaturePolicyPath, authFile, forceCompress)
|
||||
return &cp.Options{
|
||||
RemoveSignatures: signing.RemoveSignatures,
|
||||
SignBy: signing.SignBy,
|
||||
ReportWriter: reportWriter,
|
||||
SourceCtx: srcContext,
|
||||
DestinationCtx: destContext,
|
||||
ForceManifestMIMEType: manifestType,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSystemContext Constructs a new containers/image/types.SystemContext{} struct from the given signaturePolicy path
|
||||
func GetSystemContext(signaturePolicyPath, authFilePath string, forceCompress bool) *types.SystemContext {
|
||||
sc := &types.SystemContext{}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
package common
|
||||
|
||||
import "github.com/containers/image/types"
|
||||
|
||||
// DockerRegistryOptions encapsulates settings that affect how we connect or
|
||||
// authenticate to a remote registry.
|
||||
type DockerRegistryOptions struct {
|
||||
// DockerRegistryCreds is the user name and password to supply in case
|
||||
// we need to pull an image from a registry, and it requires us to
|
||||
// authenticate.
|
||||
DockerRegistryCreds *types.DockerAuthConfig
|
||||
// DockerCertPath is the location of a directory containing CA
|
||||
// certificates which will be used to verify the registry's certificate
|
||||
// (all files with names ending in ".crt"), and possibly client
|
||||
// certificates and private keys (pairs of files with the same name,
|
||||
// except for ".cert" and ".key" suffixes).
|
||||
DockerCertPath string
|
||||
// DockerInsecureSkipTLSVerify turns off verification of TLS
|
||||
// certificates and allows connecting to registries without encryption.
|
||||
DockerInsecureSkipTLSVerify bool
|
||||
}
|
||||
|
||||
// GetSystemContext constructs a new system context from the given signaturePolicy path and the
|
||||
// values in the DockerRegistryOptions
|
||||
func (o DockerRegistryOptions) GetSystemContext(signaturePolicyPath, authFile string, forceCompress bool) *types.SystemContext {
|
||||
sc := &types.SystemContext{
|
||||
SignaturePolicyPath: signaturePolicyPath,
|
||||
DockerAuthConfig: o.DockerRegistryCreds,
|
||||
DockerCertPath: o.DockerCertPath,
|
||||
DockerInsecureSkipTLSVerify: o.DockerInsecureSkipTLSVerify,
|
||||
AuthFilePath: authFile,
|
||||
DirForceCompress: forceCompress,
|
||||
}
|
||||
return sc
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package common
|
|
@ -28,10 +28,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
|
|||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (c *Container) checkpoint(ctx context.Context, keep bool) error {
|
||||
func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (c *Container) restore(ctx context.Context, keep bool) error {
|
||||
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
|
|
@ -19,8 +19,9 @@ type DockerRegistryOptions struct {
|
|||
// except for ".cert" and ".key" suffixes).
|
||||
DockerCertPath string
|
||||
// DockerInsecureSkipTLSVerify turns off verification of TLS
|
||||
// certificates and allows connecting to registries without encryption.
|
||||
DockerInsecureSkipTLSVerify bool
|
||||
// certificates and allows connecting to registries without encryption
|
||||
// - or forces it on even if registries.conf has the registry configured as insecure.
|
||||
DockerInsecureSkipTLSVerify types.OptionalBool
|
||||
}
|
||||
|
||||
// GetSystemContext constructs a new system context from a parent context. the values in the DockerRegistryOptions, and other parameters.
|
||||
|
|
|
@ -125,7 +125,7 @@ func (ir *Runtime) NewFromLocal(name string) (*Image, error) {
|
|||
|
||||
// New creates a new image object where the image could be local
|
||||
// or remote
|
||||
func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull, forceSecure bool) (*Image, error) {
|
||||
func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull bool) (*Image, error) {
|
||||
// We don't know if the image is local or not ... check local first
|
||||
newImage := Image{
|
||||
InputName: name,
|
||||
|
@ -145,7 +145,7 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
|
|||
if signaturePolicyPath == "" {
|
||||
signaturePolicyPath = ir.SignaturePolicyPath
|
||||
}
|
||||
imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions, forceSecure)
|
||||
imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to pull %s", name)
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ func (ir *Runtime) LoadFromArchiveReference(ctx context.Context, srcRef types.Im
|
|||
if signaturePolicyPath == "" {
|
||||
signaturePolicyPath = ir.SignaturePolicyPath
|
||||
}
|
||||
imageNames, err := ir.pullImageFromReference(ctx, srcRef, writer, "", signaturePolicyPath, SigningOptions{}, &DockerRegistryOptions{}, false)
|
||||
imageNames, err := ir.pullImageFromReference(ctx, srcRef, writer, "", signaturePolicyPath, SigningOptions{}, &DockerRegistryOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to pull %s", transports.ImageName(srcRef))
|
||||
}
|
||||
|
@ -498,7 +498,7 @@ func (i *Image) UntagImage(tag string) error {
|
|||
|
||||
// PushImageToHeuristicDestination pushes the given image to "destination", which is heuristically parsed.
|
||||
// Use PushImageToReference if the destination is known precisely.
|
||||
func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, forceSecure bool, additionalDockerArchiveTags []reference.NamedTagged) error {
|
||||
func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
|
||||
if destination == "" {
|
||||
return errors.Wrapf(syscall.EINVAL, "destination image name must be specified")
|
||||
}
|
||||
|
@ -516,11 +516,11 @@ func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination
|
|||
return err
|
||||
}
|
||||
}
|
||||
return i.PushImageToReference(ctx, dest, manifestMIMEType, authFile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, forceSecure, additionalDockerArchiveTags)
|
||||
return i.PushImageToReference(ctx, dest, manifestMIMEType, authFile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, additionalDockerArchiveTags)
|
||||
}
|
||||
|
||||
// PushImageToReference pushes the given image to a location described by the given path
|
||||
func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageReference, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, forceSecure bool, additionalDockerArchiveTags []reference.NamedTagged) error {
|
||||
func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageReference, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
|
||||
sc := GetSystemContext(signaturePolicyPath, authFile, forceCompress)
|
||||
|
||||
policyContext, err := getPolicyContext(sc)
|
||||
|
@ -534,23 +534,8 @@ func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageRefere
|
|||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting source imageReference for %q", i.InputName)
|
||||
}
|
||||
insecureRegistries, err := registries.GetInsecureRegistries()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copyOptions := getCopyOptions(sc, writer, nil, dockerRegistryOptions, signingOptions, manifestMIMEType, additionalDockerArchiveTags)
|
||||
if dest.Transport().Name() == DockerTransport {
|
||||
imgRef := dest.DockerReference()
|
||||
if imgRef == nil { // This should never happen; such references can’t be created.
|
||||
return fmt.Errorf("internal error: DockerTransport reference %s does not have a DockerReference", transports.ImageName(dest))
|
||||
}
|
||||
registry := reference.Domain(imgRef)
|
||||
|
||||
if util.StringInSlice(registry, insecureRegistries) && !forceSecure {
|
||||
copyOptions.DestinationCtx.DockerInsecureSkipTLSVerify = true
|
||||
logrus.Info(fmt.Sprintf("%s is an insecure registry; pushing with tls-verify=false", registry))
|
||||
}
|
||||
}
|
||||
copyOptions.DestinationCtx.SystemRegistriesConfPath = registries.SystemRegistriesConfPath() // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
|
||||
// Copy the image to the remote destination
|
||||
_, err = cp.Image(ctx, policyContext, dest, src, copyOptions)
|
||||
if err != nil {
|
||||
|
|
|
@ -86,9 +86,9 @@ func TestImage_NewFromLocal(t *testing.T) {
|
|||
// Need images to be present for this test
|
||||
ir, err := NewImageRuntimeFromOptions(so)
|
||||
assert.NoError(t, err)
|
||||
bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false, false)
|
||||
bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false)
|
||||
assert.NoError(t, err)
|
||||
bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false, false)
|
||||
bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
tm, err := makeLocalMatrix(bb, bbglibc)
|
||||
|
@ -135,7 +135,7 @@ func TestImage_New(t *testing.T) {
|
|||
// Iterate over the names and delete the image
|
||||
// after the pull
|
||||
for _, img := range names {
|
||||
newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false, false)
|
||||
newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, newImage.ID(), "")
|
||||
err = newImage.Remove(false)
|
||||
|
@ -163,7 +163,7 @@ func TestImage_MatchRepoTag(t *testing.T) {
|
|||
}
|
||||
ir, err := NewImageRuntimeFromOptions(so)
|
||||
assert.NoError(t, err)
|
||||
newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false, false)
|
||||
newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false)
|
||||
assert.NoError(t, err)
|
||||
err = newImage.TagImage("foo:latest")
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/containers/image/directory"
|
||||
"github.com/containers/image/docker"
|
||||
dockerarchive "github.com/containers/image/docker/archive"
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/docker/tarfile"
|
||||
ociarchive "github.com/containers/image/oci/archive"
|
||||
"github.com/containers/image/pkg/sysregistries"
|
||||
|
@ -19,7 +18,6 @@ import (
|
|||
"github.com/containers/image/transports/alltransports"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/pkg/registries"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -193,7 +191,7 @@ func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types.
|
|||
|
||||
// pullImageFromHeuristicSource pulls an image based on inputName, which is heuristically parsed and may involve configured registries.
|
||||
// Use pullImageFromReference if the source is known precisely.
|
||||
func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
|
||||
func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) {
|
||||
var goal *pullGoal
|
||||
sc := GetSystemContext(signaturePolicyPath, authfile, false)
|
||||
srcRef, err := alltransports.ParseImageName(inputName)
|
||||
|
@ -209,48 +207,33 @@ func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName s
|
|||
return nil, errors.Wrapf(err, "error determining pull goal for image %q", inputName)
|
||||
}
|
||||
}
|
||||
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, forceSecure)
|
||||
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions)
|
||||
}
|
||||
|
||||
// pullImageFromReference pulls an image from a types.imageReference.
|
||||
func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.ImageReference, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
|
||||
func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.ImageReference, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) {
|
||||
sc := GetSystemContext(signaturePolicyPath, authfile, false)
|
||||
goal, err := ir.pullGoalFromImageReference(ctx, srcRef, transports.ImageName(srcRef), sc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error determining pull goal for image %q", transports.ImageName(srcRef))
|
||||
}
|
||||
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, forceSecure)
|
||||
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions)
|
||||
}
|
||||
|
||||
// doPullImage is an internal helper interpreting pullGoal. Almost everyone should call one of the callers of doPullImage instead.
|
||||
func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
|
||||
func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) {
|
||||
policyContext, err := getPolicyContext(sc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer policyContext.Destroy()
|
||||
|
||||
insecureRegistries, err := registries.GetInsecureRegistries()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
systemRegistriesConfPath := registries.SystemRegistriesConfPath()
|
||||
var images []string
|
||||
var pullErrors *multierror.Error
|
||||
for _, imageInfo := range goal.refPairs {
|
||||
copyOptions := getCopyOptions(sc, writer, dockerOptions, nil, signingOptions, "", nil)
|
||||
if imageInfo.srcRef.Transport().Name() == DockerTransport {
|
||||
imgRef := imageInfo.srcRef.DockerReference()
|
||||
if imgRef == nil { // This should never happen; such references can’t be created.
|
||||
return nil, fmt.Errorf("internal error: DockerTransport reference %s does not have a DockerReference",
|
||||
transports.ImageName(imageInfo.srcRef))
|
||||
}
|
||||
registry := reference.Domain(imgRef)
|
||||
|
||||
if util.StringInSlice(registry, insecureRegistries) && !forceSecure {
|
||||
copyOptions.SourceCtx.DockerInsecureSkipTLSVerify = true
|
||||
logrus.Info(fmt.Sprintf("%s is an insecure registry; pulling with tls-verify=false", registry))
|
||||
}
|
||||
}
|
||||
copyOptions.SourceCtx.SystemRegistriesConfPath = systemRegistriesConfPath // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
|
||||
// Print the following statement only when pulling from a docker or atomic registry
|
||||
if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) {
|
||||
io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image))
|
||||
|
@ -271,7 +254,7 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
|
|||
}
|
||||
// If no image was found, we should handle. Lets be nicer to the user and see if we can figure out why.
|
||||
if len(images) == 0 {
|
||||
registryPath := sysregistries.RegistriesConfPath(&types.SystemContext{})
|
||||
registryPath := sysregistries.RegistriesConfPath(&types.SystemContext{SystemRegistriesConfPath: systemRegistriesConfPath})
|
||||
if goal.usedSearchRegistries && len(goal.searchedRegistries) == 0 {
|
||||
return nil, errors.Errorf("image name provided is a short name and no search registries are defined in %s.", registryPath)
|
||||
}
|
||||
|
|
|
@ -3,50 +3,15 @@ package libpod
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/containers/buildah/imagebuildah"
|
||||
"github.com/containers/libpod/libpod/common"
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Runtime API
|
||||
|
||||
// CopyOptions contains the options given when pushing or pulling images
|
||||
type CopyOptions struct {
|
||||
// Compression specifies the type of compression which is applied to
|
||||
// layer blobs. The default is to not use compression, but
|
||||
// archive.Gzip is recommended.
|
||||
Compression archive.Compression
|
||||
// DockerRegistryOptions encapsulates settings that affect how we
|
||||
// connect or authenticate to a remote registry to which we want to
|
||||
// push the image.
|
||||
common.DockerRegistryOptions
|
||||
// SigningOptions encapsulates settings that control whether or not we
|
||||
// strip or add signatures to the image when pushing (uploading) the
|
||||
// image to a registry.
|
||||
common.SigningOptions
|
||||
|
||||
// SigningPolicyPath this points to a alternative signature policy file, used mainly for testing
|
||||
SignaturePolicyPath string
|
||||
// AuthFile is the path of the cached credentials file defined by the user
|
||||
AuthFile string
|
||||
// Writer is the reportWriter for the output
|
||||
Writer io.Writer
|
||||
// Reference is the name for the image created when a tar archive is imported
|
||||
Reference string
|
||||
// ImageConfig is the Image spec for the image created when a tar archive is imported
|
||||
ImageConfig ociv1.Image
|
||||
// ManifestMIMEType is the manifest type of the image when saving to a directory
|
||||
ManifestMIMEType string
|
||||
// ForceCompress compresses the image layers when saving to a directory using the dir transport if true
|
||||
ForceCompress bool
|
||||
}
|
||||
|
||||
// RemoveImage deletes an image from local storage
|
||||
// Images being used by running containers can only be removed if force=true
|
||||
func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool) (string, error) {
|
||||
|
|
|
@ -67,7 +67,7 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container,
|
|||
return nil, ErrRuntimeStopped
|
||||
}
|
||||
|
||||
newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false, false)
|
||||
newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,10 +9,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/cgroups"
|
||||
"github.com/containers/image/signature"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -189,26 +187,3 @@ func validPodNSOption(p *Pod, ctrPod string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetV1CGroups gets the V1 cgroup subsystems and then "filters"
|
||||
// out any subsystems that are provided by the caller. Passing nil
|
||||
// for excludes will return the subsystems unfiltered.
|
||||
//func GetV1CGroups(excludes []string) ([]cgroups.Subsystem, error) {
|
||||
func GetV1CGroups(excludes []string) cgroups.Hierarchy {
|
||||
return func() ([]cgroups.Subsystem, error) {
|
||||
var filtered []cgroups.Subsystem
|
||||
|
||||
subSystem, err := cgroups.V1()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range subSystem {
|
||||
// If the name of the subsystem is not in the list of excludes, then
|
||||
// add it as a keeper.
|
||||
if !util.StringInSlice(string(s.Name()), excludes) {
|
||||
filtered = append(filtered, s)
|
||||
}
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/containerd/cgroups"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -67,3 +68,26 @@ func assembleSystemdCgroupName(baseSlice, newSlice string) (string, error) {
|
|||
|
||||
return final, nil
|
||||
}
|
||||
|
||||
// GetV1CGroups gets the V1 cgroup subsystems and then "filters"
|
||||
// out any subsystems that are provided by the caller. Passing nil
|
||||
// for excludes will return the subsystems unfiltered.
|
||||
//func GetV1CGroups(excludes []string) ([]cgroups.Subsystem, error) {
|
||||
func GetV1CGroups(excludes []string) cgroups.Hierarchy {
|
||||
return func() ([]cgroups.Subsystem, error) {
|
||||
var filtered []cgroups.Subsystem
|
||||
|
||||
subSystem, err := cgroups.V1()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range subSystem {
|
||||
// If the name of the subsystem is not in the list of excludes, then
|
||||
// add it as a keeper.
|
||||
if !util.StringInSlice(string(s.Name()), excludes) {
|
||||
filtered = append(filtered, s)
|
||||
}
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,21 +13,28 @@ import (
|
|||
// userRegistriesFile is the path to the per user registry configuration file.
|
||||
var userRegistriesFile = filepath.Join(os.Getenv("HOME"), ".config/containers/registries.conf")
|
||||
|
||||
// GetRegistries obtains the list of registries defined in the global registries file.
|
||||
func GetRegistries() ([]string, error) {
|
||||
registryConfigPath := ""
|
||||
// SystemRegistriesConfPath returns an appropriate value for types.SystemContext.SystemRegistriesConfPath
|
||||
// (possibly "", which is not an error), taking into account rootless mode and environment variable overrides.
|
||||
//
|
||||
// FIXME: This should be centralized in a global SystemContext initializer inherited throughout the code,
|
||||
// not haphazardly called throughout the way it is being called now.
|
||||
func SystemRegistriesConfPath() string {
|
||||
if envOverride := os.Getenv("REGISTRIES_CONFIG_PATH"); len(envOverride) > 0 {
|
||||
return envOverride
|
||||
}
|
||||
|
||||
if rootless.IsRootless() {
|
||||
if _, err := os.Stat(userRegistriesFile); err == nil {
|
||||
registryConfigPath = userRegistriesFile
|
||||
return userRegistriesFile
|
||||
}
|
||||
}
|
||||
|
||||
envOverride := os.Getenv("REGISTRIES_CONFIG_PATH")
|
||||
if len(envOverride) > 0 {
|
||||
registryConfigPath = envOverride
|
||||
}
|
||||
searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath})
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetRegistries obtains the list of registries defined in the global registries file.
|
||||
func GetRegistries() ([]string, error) {
|
||||
searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: SystemRegistriesConfPath()})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to parse the registries.conf file")
|
||||
}
|
||||
|
@ -36,19 +43,7 @@ func GetRegistries() ([]string, error) {
|
|||
|
||||
// GetInsecureRegistries obtains the list of insecure registries from the global registration file.
|
||||
func GetInsecureRegistries() ([]string, error) {
|
||||
registryConfigPath := ""
|
||||
|
||||
if rootless.IsRootless() {
|
||||
if _, err := os.Stat(userRegistriesFile); err == nil {
|
||||
registryConfigPath = userRegistriesFile
|
||||
}
|
||||
}
|
||||
|
||||
envOverride := os.Getenv("REGISTRIES_CONFIG_PATH")
|
||||
if len(envOverride) > 0 {
|
||||
registryConfigPath = envOverride
|
||||
}
|
||||
registries, err := sysregistries.GetInsecureRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath})
|
||||
registries, err := sysregistries.GetInsecureRegistries(&types.SystemContext{SystemRegistriesConfPath: SystemRegistriesConfPath()})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to parse the registries.conf file")
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.C
|
|||
rtc := i.Runtime.GetConfig()
|
||||
ctx := getContext()
|
||||
|
||||
newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false)
|
||||
newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false)
|
||||
if err != nil {
|
||||
return call.ReplyErrorOccurred(err.Error())
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -16,6 +15,7 @@ import (
|
|||
"github.com/containers/image/docker"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"github.com/containers/libpod/cmd/podman/varlink"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
|
@ -322,13 +322,14 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
|
|||
destname = tag
|
||||
}
|
||||
|
||||
dockerRegistryOptions := image.DockerRegistryOptions{
|
||||
DockerInsecureSkipTLSVerify: !tlsVerify,
|
||||
dockerRegistryOptions := image.DockerRegistryOptions{}
|
||||
if !tlsVerify {
|
||||
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
|
||||
}
|
||||
|
||||
so := image.SigningOptions{}
|
||||
|
||||
if err := newImage.PushImageToHeuristicDestination(getContext(), destname, "", "", "", nil, false, so, &dockerRegistryOptions, false, nil); err != nil {
|
||||
if err := newImage.PushImageToHeuristicDestination(getContext(), destname, "", "", "", nil, false, so, &dockerRegistryOptions, nil); err != nil {
|
||||
return call.ReplyErrorOccurred(err.Error())
|
||||
}
|
||||
return call.ReplyPushImage(newImage.ID())
|
||||
|
@ -488,7 +489,7 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
|
|||
return err
|
||||
}
|
||||
|
||||
if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, false, additionalTags); err != nil {
|
||||
if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil {
|
||||
return call.ReplyErrorOccurred(err.Error())
|
||||
}
|
||||
return call.ReplyExportImage(newImage.ID())
|
||||
|
@ -497,7 +498,7 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
|
|||
// PullImage pulls an image from a registry to the image store.
|
||||
// TODO This implementation is incomplete
|
||||
func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
|
||||
newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", nil, &image.DockerRegistryOptions{}, image.SigningOptions{}, true, false)
|
||||
newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", nil, &image.DockerRegistryOptions{}, image.SigningOptions{}, true)
|
||||
if err != nil {
|
||||
return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error()))
|
||||
}
|
||||
|
@ -520,8 +521,10 @@ func (i *LibpodAPI) ImageExists(call iopodman.VarlinkCall, name string) error {
|
|||
func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.Runlabel) error {
|
||||
ctx := getContext()
|
||||
dockerRegistryOptions := image.DockerRegistryOptions{
|
||||
DockerCertPath: input.CertDir,
|
||||
DockerInsecureSkipTLSVerify: !input.TlsVerify,
|
||||
DockerCertPath: input.CertDir,
|
||||
}
|
||||
if !input.TlsVerify {
|
||||
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
|
||||
}
|
||||
|
||||
stdErr := os.Stderr
|
||||
|
|
|
@ -11,7 +11,7 @@ github.com/containerd/cgroups 58556f5ad8448d99a6f7bea69ea4bdb7747cfeb0
|
|||
github.com/containerd/continuity master
|
||||
github.com/containernetworking/cni v0.7.0-alpha1
|
||||
github.com/containernetworking/plugins 1562a1e60ed101aacc5e08ed9dbeba8e9f3d4ec1
|
||||
github.com/containers/image bd10b1b53b2976f215b3f2f848fb8e7cad779aeb
|
||||
github.com/containers/image 63a1cbdc5e6537056695cf0d627c0a33b334df53
|
||||
github.com/containers/storage db40f96d853dfced60c563e61fb66ba231ce7c8d
|
||||
github.com/containers/psgo 5dde6da0bc8831b35243a847625bcf18183bd1ee
|
||||
github.com/coreos/go-systemd v14
|
||||
|
@ -92,7 +92,7 @@ k8s.io/kube-openapi 275e2ce91dec4c05a4094a7b1daee5560b555ac9 https://github.com/
|
|||
k8s.io/utils 258e2a2fa64568210fbd6267cf1d8fd87c3cb86e https://github.com/kubernetes/utils
|
||||
github.com/mrunalp/fileutils master
|
||||
github.com/varlink/go master
|
||||
github.com/containers/buildah 2ac987a52ff8412fb8f2908a191009751a6a1c62
|
||||
github.com/containers/buildah 9c65e5699cfa486531b3f123d9ce74873f0e18aa
|
||||
github.com/Nvveen/Gotty master
|
||||
github.com/fsouza/go-dockerclient master
|
||||
github.com/openshift/imagebuilder master
|
||||
|
|
|
@ -105,6 +105,7 @@ $ sudo ./lighttpd.sh
|
|||
| [buildah-copy(1)](/docs/buildah-copy.md) | Copies the contents of a file, URL, or directory into a container's working directory. |
|
||||
| [buildah-from(1)](/docs/buildah-from.md) | Creates a new working container, either from scratch or using a specified image as a starting point. |
|
||||
| [buildah-images(1)](/docs/buildah-images.md) | List images in local storage. |
|
||||
| [buildah-info(1)](/docs/buildah-info.md) | Display Buildah system information. |
|
||||
| [buildah-inspect(1)](/docs/buildah-inspect.md) | Inspects the configuration of a container or image. |
|
||||
| [buildah-mount(1)](/docs/buildah-mount.md) | Mount the working container's root filesystem. |
|
||||
| [buildah-pull(1)](/docs/buildah-pull.md) | Pull an image from the specified location. |
|
||||
|
|
|
@ -25,7 +25,7 @@ const (
|
|||
Package = "buildah"
|
||||
// Version for the Package. Bump version in contrib/rpm/buildah.spec
|
||||
// too.
|
||||
Version = "1.5-dev"
|
||||
Version = "1.6-dev"
|
||||
// The value we use to identify what type of information, currently a
|
||||
// serialized Builder structure, we are using as per-container state.
|
||||
// This should only be changed when we make incompatible changes to
|
||||
|
|
|
@ -38,7 +38,6 @@ func getCopyOptions(reportWriter io.Writer, sourceReference types.ImageReference
|
|||
if err != nil {
|
||||
logrus.Debugf("error determining if registry for %q is insecure: %v", transports.ImageName(sourceReference), err)
|
||||
} else if sourceInsecure {
|
||||
sourceCtx.DockerInsecureSkipTLSVerify = true
|
||||
sourceCtx.OCIInsecureSkipTLSVerify = true
|
||||
}
|
||||
|
||||
|
@ -56,7 +55,6 @@ func getCopyOptions(reportWriter io.Writer, sourceReference types.ImageReference
|
|||
if err != nil {
|
||||
logrus.Debugf("error determining if registry for %q is insecure: %v", transports.ImageName(destinationReference), err)
|
||||
} else if destinationInsecure {
|
||||
destinationCtx.DockerInsecureSkipTLSVerify = true
|
||||
destinationCtx.OCIInsecureSkipTLSVerify = true
|
||||
}
|
||||
|
||||
|
|
|
@ -543,3 +543,37 @@ func (b *Builder) SetStopSignal(stopSignal string) {
|
|||
b.OCIv1.Config.StopSignal = stopSignal
|
||||
b.Docker.Config.StopSignal = stopSignal
|
||||
}
|
||||
|
||||
// Healthcheck returns information that recommends how a container engine
|
||||
// should check if a running container is "healthy".
|
||||
func (b *Builder) Healthcheck() *docker.HealthConfig {
|
||||
if b.Docker.Config.Healthcheck == nil {
|
||||
return nil
|
||||
}
|
||||
return &docker.HealthConfig{
|
||||
Test: copyStringSlice(b.Docker.Config.Healthcheck.Test),
|
||||
Interval: b.Docker.Config.Healthcheck.Interval,
|
||||
Timeout: b.Docker.Config.Healthcheck.Timeout,
|
||||
StartPeriod: b.Docker.Config.Healthcheck.StartPeriod,
|
||||
Retries: b.Docker.Config.Healthcheck.Retries,
|
||||
}
|
||||
}
|
||||
|
||||
// SetHealthcheck sets recommended commands to run in order to verify that a
|
||||
// running container based on this image is "healthy", along with information
|
||||
// specifying how often that test should be run, and how many times the test
|
||||
// should fail before the container should be considered unhealthy.
|
||||
// Note: this setting is not present in the OCIv1 image format, so it is
|
||||
// discarded when writing images using OCIv1 formats.
|
||||
func (b *Builder) SetHealthcheck(config *docker.HealthConfig) {
|
||||
b.Docker.Config.Healthcheck = nil
|
||||
if config != nil {
|
||||
b.Docker.Config.Healthcheck = &docker.HealthConfig{
|
||||
Test: copyStringSlice(config.Test),
|
||||
Interval: config.Interval,
|
||||
Timeout: config.Timeout,
|
||||
StartPeriod: config.StartPeriod,
|
||||
Retries: config.Retries,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,9 @@ type HealthConfig struct {
|
|||
Test []string `json:",omitempty"`
|
||||
|
||||
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
||||
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
StartPeriod time.Duration `json:",omitempty"` // Time to wait after the container starts before running the first check.
|
||||
|
||||
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
||||
// Zero means inherit.
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containers/buildah"
|
||||
buildahdocker "github.com/containers/buildah/docker"
|
||||
"github.com/containers/buildah/util"
|
||||
cp "github.com/containers/image/copy"
|
||||
"github.com/containers/image/docker/reference"
|
||||
|
@ -225,6 +226,18 @@ type Executor struct {
|
|||
copyFrom string // Used to keep track of the --from flag from COPY and ADD
|
||||
}
|
||||
|
||||
// builtinAllowedBuildArgs is list of built-in allowed build args
|
||||
var builtinAllowedBuildArgs = map[string]bool{
|
||||
"HTTP_PROXY": true,
|
||||
"http_proxy": true,
|
||||
"HTTPS_PROXY": true,
|
||||
"https_proxy": true,
|
||||
"FTP_PROXY": true,
|
||||
"ftp_proxy": true,
|
||||
"NO_PROXY": true,
|
||||
"no_proxy": true,
|
||||
}
|
||||
|
||||
// withName creates a new child executor that will be used whenever a COPY statement uses --from=NAME.
|
||||
func (b *Executor) withName(name string, index int) *Executor {
|
||||
if b.named == nil {
|
||||
|
@ -793,12 +806,28 @@ func (b *Executor) Execute(ctx context.Context, stage imagebuilder.Stage) error
|
|||
commitName := b.output
|
||||
b.containerIDs = nil
|
||||
|
||||
var leftoverArgs []string
|
||||
for arg := range b.builder.Args {
|
||||
if !builtinAllowedBuildArgs[arg] {
|
||||
leftoverArgs = append(leftoverArgs, arg)
|
||||
}
|
||||
}
|
||||
for i, node := range node.Children {
|
||||
step := ib.Step()
|
||||
if err := step.Resolve(node); err != nil {
|
||||
return errors.Wrapf(err, "error resolving step %+v", *node)
|
||||
}
|
||||
logrus.Debugf("Parsed Step: %+v", *step)
|
||||
if step.Command == "arg" {
|
||||
for index, arg := range leftoverArgs {
|
||||
for _, Arg := range step.Args {
|
||||
list := strings.SplitN(Arg, "=", 2)
|
||||
if arg == list[0] {
|
||||
leftoverArgs = append(leftoverArgs[:index], leftoverArgs[index+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !b.quiet {
|
||||
b.log("%s", step.Original)
|
||||
}
|
||||
|
@ -895,6 +924,9 @@ func (b *Executor) Execute(ctx context.Context, stage imagebuilder.Stage) error
|
|||
}
|
||||
}
|
||||
}
|
||||
if len(leftoverArgs) > 0 {
|
||||
fmt.Fprintf(b.out, "[Warning] One or more build-args %v were not consumed\n", leftoverArgs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1139,6 +1171,17 @@ func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder, created
|
|||
b.builder.SetEntrypoint(config.Entrypoint)
|
||||
b.builder.SetShell(config.Shell)
|
||||
b.builder.SetStopSignal(config.StopSignal)
|
||||
if config.Healthcheck != nil {
|
||||
b.builder.SetHealthcheck(&buildahdocker.HealthConfig{
|
||||
Test: append([]string{}, config.Healthcheck.Test...),
|
||||
Interval: config.Healthcheck.Interval,
|
||||
Timeout: config.Healthcheck.Timeout,
|
||||
StartPeriod: config.Healthcheck.StartPeriod,
|
||||
Retries: config.Healthcheck.Retries,
|
||||
})
|
||||
} else {
|
||||
b.builder.SetHealthcheck(nil)
|
||||
}
|
||||
b.builder.ClearLabels()
|
||||
for k, v := range config.Labels {
|
||||
b.builder.SetLabel(k, v)
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
package buildah
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// InfoData holds the info type, i.e store, host etc and the data for each type
|
||||
type InfoData struct {
|
||||
Type string
|
||||
Data map[string]interface{}
|
||||
}
|
||||
|
||||
// Info returns the store and host information
|
||||
func Info(store storage.Store) ([]InfoData, error) {
|
||||
info := []InfoData{}
|
||||
// get host information
|
||||
hostInfo, err := hostInfo()
|
||||
if err != nil {
|
||||
logrus.Error(err, "error getting host info")
|
||||
}
|
||||
info = append(info, InfoData{Type: "host", Data: hostInfo})
|
||||
|
||||
// get store information
|
||||
storeInfo, err := storeInfo(store)
|
||||
if err != nil {
|
||||
logrus.Error(err, "error getting store info")
|
||||
}
|
||||
info = append(info, InfoData{Type: "store", Data: storeInfo})
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func hostInfo() (map[string]interface{}, error) {
|
||||
info := map[string]interface{}{}
|
||||
info["os"] = runtime.GOOS
|
||||
info["arch"] = runtime.GOARCH
|
||||
info["cpus"] = runtime.NumCPU()
|
||||
info["rootless"] = rootless.IsRootless()
|
||||
mi, err := system.ReadMemInfo()
|
||||
if err != nil {
|
||||
logrus.Error(err, "err reading memory info")
|
||||
info["MemTotal"] = ""
|
||||
info["MenFree"] = ""
|
||||
info["SwapTotal"] = ""
|
||||
info["SwapFree"] = ""
|
||||
} else {
|
||||
info["MemTotal"] = mi.MemTotal
|
||||
info["MenFree"] = mi.MemFree
|
||||
info["SwapTotal"] = mi.SwapTotal
|
||||
info["SwapFree"] = mi.SwapFree
|
||||
}
|
||||
hostDistributionInfo := getHostDistributionInfo()
|
||||
info["Distribution"] = map[string]interface{}{
|
||||
"distribution": hostDistributionInfo["Distribution"],
|
||||
"version": hostDistributionInfo["Version"],
|
||||
}
|
||||
|
||||
kv, err := readKernelVersion()
|
||||
if err != nil {
|
||||
logrus.Error(err, "error reading kernel version")
|
||||
}
|
||||
info["kernel"] = kv
|
||||
|
||||
up, err := readUptime()
|
||||
if err != nil {
|
||||
logrus.Error(err, "error reading up time")
|
||||
}
|
||||
// Convert uptime in seconds to a human-readable format
|
||||
upSeconds := up + "s"
|
||||
upDuration, err := time.ParseDuration(upSeconds)
|
||||
if err != nil {
|
||||
logrus.Error(err, "error parsing system uptime")
|
||||
}
|
||||
|
||||
hoursFound := false
|
||||
var timeBuffer bytes.Buffer
|
||||
var hoursBuffer bytes.Buffer
|
||||
for _, elem := range upDuration.String() {
|
||||
timeBuffer.WriteRune(elem)
|
||||
if elem == 'h' || elem == 'm' {
|
||||
timeBuffer.WriteRune(' ')
|
||||
if elem == 'h' {
|
||||
hoursFound = true
|
||||
}
|
||||
}
|
||||
if !hoursFound {
|
||||
hoursBuffer.WriteRune(elem)
|
||||
}
|
||||
}
|
||||
|
||||
info["uptime"] = timeBuffer.String()
|
||||
if hoursFound {
|
||||
hours, err := strconv.ParseFloat(hoursBuffer.String(), 64)
|
||||
if err == nil {
|
||||
days := hours / 24
|
||||
info["uptime"] = fmt.Sprintf("%s (Approximately %.2f days)", info["uptime"], days)
|
||||
}
|
||||
}
|
||||
|
||||
host, err := os.Hostname()
|
||||
if err != nil {
|
||||
logrus.Error(err, "error getting hostname")
|
||||
}
|
||||
info["hostname"] = host
|
||||
|
||||
return info, nil
|
||||
|
||||
}
|
||||
|
||||
// top-level "store" info
|
||||
func storeInfo(store storage.Store) (map[string]interface{}, error) {
|
||||
// lets say storage driver in use, number of images, number of containers
|
||||
info := map[string]interface{}{}
|
||||
info["GraphRoot"] = store.GraphRoot()
|
||||
info["RunRoot"] = store.RunRoot()
|
||||
info["GraphDriverName"] = store.GraphDriverName()
|
||||
info["GraphOptions"] = store.GraphOptions()
|
||||
statusPairs, err := store.Status()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status := map[string]string{}
|
||||
for _, pair := range statusPairs {
|
||||
status[pair[0]] = pair[1]
|
||||
}
|
||||
info["GraphStatus"] = status
|
||||
images, err := store.Images()
|
||||
if err != nil {
|
||||
logrus.Error(err, "error getting number of images")
|
||||
}
|
||||
info["ImageStore"] = map[string]interface{}{
|
||||
"number": len(images),
|
||||
}
|
||||
|
||||
containers, err := store.Containers()
|
||||
if err != nil {
|
||||
logrus.Error(err, "error getting number of containers")
|
||||
}
|
||||
info["ContainerStore"] = map[string]interface{}{
|
||||
"number": len(containers),
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func readKernelVersion() (string, error) {
|
||||
buf, err := ioutil.ReadFile("/proc/version")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
f := bytes.Fields(buf)
|
||||
if len(f) < 2 {
|
||||
return string(bytes.TrimSpace(buf)), nil
|
||||
}
|
||||
return string(f[2]), nil
|
||||
}
|
||||
|
||||
func readUptime() (string, error) {
|
||||
buf, err := ioutil.ReadFile("/proc/uptime")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
f := bytes.Fields(buf)
|
||||
if len(f) < 1 {
|
||||
return "", fmt.Errorf("invalid uptime")
|
||||
}
|
||||
return string(f[0]), nil
|
||||
}
|
||||
|
||||
// getHostDistributionInfo returns a map containing the host's distribution and version
|
||||
func getHostDistributionInfo() map[string]string {
|
||||
dist := make(map[string]string)
|
||||
|
||||
// Populate values in case we cannot find the values
|
||||
// or the file
|
||||
dist["Distribution"] = "unknown"
|
||||
dist["Version"] = "unknown"
|
||||
|
||||
f, err := os.Open("/etc/os-release")
|
||||
if err != nil {
|
||||
return dist
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
l := bufio.NewScanner(f)
|
||||
for l.Scan() {
|
||||
if strings.HasPrefix(l.Text(), "ID=") {
|
||||
dist["Distribution"] = strings.TrimPrefix(l.Text(), "ID=")
|
||||
}
|
||||
if strings.HasPrefix(l.Text(), "VERSION_ID=") {
|
||||
dist["Version"] = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_ID="), "\"")
|
||||
}
|
||||
}
|
||||
return dist
|
||||
}
|
|
@ -282,7 +282,7 @@ func SystemContextFromOptions(c *cli.Context) (*types.SystemContext, error) {
|
|||
DockerCertPath: c.String("cert-dir"),
|
||||
}
|
||||
if c.IsSet("tls-verify") {
|
||||
ctx.DockerInsecureSkipTLSVerify = !c.BoolT("tls-verify")
|
||||
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
|
||||
ctx.OCIInsecureSkipTLSVerify = !c.BoolT("tls-verify")
|
||||
ctx.DockerDaemonInsecureSkipTLSVerify = !c.BoolT("tls-verify")
|
||||
}
|
||||
|
|
|
@ -175,11 +175,11 @@ func (b *Builder) tarPath() func(path string) (io.ReadCloser, error) {
|
|||
|
||||
// isRegistryInsecure checks if the named registry is marked as not secure
|
||||
func isRegistryInsecure(registry string, sc *types.SystemContext) (bool, error) {
|
||||
registries, err := sysregistriesv2.GetRegistries(sc)
|
||||
reginfo, err := sysregistriesv2.FindRegistry(sc, registry)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to parse the registries configuration (%s)", sysregistries.RegistriesConfPath(sc))
|
||||
}
|
||||
if reginfo := sysregistriesv2.FindRegistry(registry, registries); reginfo != nil {
|
||||
if reginfo != nil {
|
||||
if reginfo.Insecure {
|
||||
logrus.Debugf("registry %q is marked insecure in registries configuration %q", registry, sysregistries.RegistriesConfPath(sc))
|
||||
} else {
|
||||
|
@ -193,11 +193,11 @@ func isRegistryInsecure(registry string, sc *types.SystemContext) (bool, error)
|
|||
|
||||
// isRegistryBlocked checks if the named registry is marked as blocked
|
||||
func isRegistryBlocked(registry string, sc *types.SystemContext) (bool, error) {
|
||||
registries, err := sysregistriesv2.GetRegistries(sc)
|
||||
reginfo, err := sysregistriesv2.FindRegistry(sc, registry)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to parse the registries configuration (%s)", sysregistries.RegistriesConfPath(sc))
|
||||
}
|
||||
if reginfo := sysregistriesv2.FindRegistry(registry, registries); reginfo != nil {
|
||||
if reginfo != nil {
|
||||
if reginfo.Blocked {
|
||||
logrus.Debugf("registry %q is marked as blocked in registries configuration %q", registry, sysregistries.RegistriesConfPath(sc))
|
||||
} else {
|
||||
|
|
|
@ -122,12 +122,11 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto
|
|||
|
||||
// Figure out the list of registries.
|
||||
var registries []string
|
||||
allRegistries, err := sysregistriesv2.GetRegistries(sc)
|
||||
searchRegistries, err := sysregistriesv2.FindUnqualifiedSearchRegistries(sc)
|
||||
if err != nil {
|
||||
logrus.Debugf("unable to read configured registries to complete %q: %v", name, err)
|
||||
registries = []string{}
|
||||
}
|
||||
for _, registry := range sysregistriesv2.FindUnqualifiedSearchRegistries(allRegistries) {
|
||||
for _, registry := range searchRegistries {
|
||||
if !registry.Blocked {
|
||||
registries = append(registries, registry.URL)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ github.com/blang/semver master
|
|||
github.com/BurntSushi/toml master
|
||||
github.com/containerd/continuity master
|
||||
github.com/containernetworking/cni v0.7.0-alpha1
|
||||
github.com/containers/image de7be82ee3c7fb676bf6cfdc9090be7cc28f404c
|
||||
github.com/containers/image 63a1cbdc5e6537056695cf0d627c0a33b334df53
|
||||
github.com/containers/libpod fe4f09493f41f675d24c969d1b60d1a6a45ddb9e
|
||||
github.com/containers/storage 3161726d1db0d0d4e86a9667dd476f09b997f497
|
||||
github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/pkg/docker/config"
|
||||
"github.com/containers/image/pkg/sysregistriesv2"
|
||||
"github.com/containers/image/pkg/tlsclientconfig"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
|
@ -78,11 +79,13 @@ type bearerToken struct {
|
|||
// dockerClient is configuration for dealing with a single Docker registry.
|
||||
type dockerClient struct {
|
||||
// The following members are set by newDockerClient and do not change afterwards.
|
||||
sys *types.SystemContext
|
||||
registry string
|
||||
sys *types.SystemContext
|
||||
registry string
|
||||
client *http.Client
|
||||
insecureSkipTLSVerify bool
|
||||
// The following members are not set by newDockerClient and must be set by callers if needed.
|
||||
username string
|
||||
password string
|
||||
client *http.Client
|
||||
signatureBase signatureStorageBase
|
||||
scope authScope
|
||||
// The following members are detected registry properties:
|
||||
|
@ -194,13 +197,26 @@ func newDockerClientFromRef(sys *types.SystemContext, ref dockerReference, write
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteName := reference.Path(ref.ref)
|
||||
|
||||
return newDockerClientWithDetails(sys, registry, username, password, actions, sigBase, remoteName)
|
||||
client, err := newDockerClient(sys, registry, ref.ref.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.username = username
|
||||
client.password = password
|
||||
client.signatureBase = sigBase
|
||||
client.scope.actions = actions
|
||||
client.scope.remoteName = reference.Path(ref.ref)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// newDockerClientWithDetails returns a new dockerClient instance for the given parameters
|
||||
func newDockerClientWithDetails(sys *types.SystemContext, registry, username, password, actions string, sigBase signatureStorageBase, remoteName string) (*dockerClient, error) {
|
||||
// newDockerClient returns a new dockerClient instance for the given registry
|
||||
// and reference. The reference is used to query the registry configuration
|
||||
// and can either be a registry (e.g, "registry.com[:5000]"), a repository
|
||||
// (e.g., "registry.com[:5000][/some/namespace]/repo").
|
||||
// Please note that newDockerClient does not set all members of dockerClient
|
||||
// (e.g., username and password); those must be set by callers if necessary.
|
||||
func newDockerClient(sys *types.SystemContext, registry, reference string) (*dockerClient, error) {
|
||||
hostName := registry
|
||||
if registry == dockerHostname {
|
||||
registry = dockerRegistry
|
||||
|
@ -221,33 +237,43 @@ func newDockerClientWithDetails(sys *types.SystemContext, registry, username, pa
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if sys != nil && sys.DockerInsecureSkipTLSVerify {
|
||||
tr.TLSClientConfig.InsecureSkipVerify = true
|
||||
// Check if TLS verification shall be skipped (default=false) which can
|
||||
// either be specified in the sysregistriesv2 configuration or via the
|
||||
// SystemContext, whereas the SystemContext is prioritized.
|
||||
skipVerify := false
|
||||
if sys != nil && sys.DockerInsecureSkipTLSVerify != types.OptionalBoolUndefined {
|
||||
// Only use the SystemContext if the actual value is defined.
|
||||
skipVerify = sys.DockerInsecureSkipTLSVerify == types.OptionalBoolTrue
|
||||
} else {
|
||||
reg, err := sysregistriesv2.FindRegistry(sys, reference)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error loading registries")
|
||||
}
|
||||
if reg != nil {
|
||||
skipVerify = reg.Insecure
|
||||
}
|
||||
}
|
||||
tr.TLSClientConfig.InsecureSkipVerify = skipVerify
|
||||
|
||||
return &dockerClient{
|
||||
sys: sys,
|
||||
registry: registry,
|
||||
username: username,
|
||||
password: password,
|
||||
client: &http.Client{Transport: tr},
|
||||
signatureBase: sigBase,
|
||||
scope: authScope{
|
||||
actions: actions,
|
||||
remoteName: remoteName,
|
||||
},
|
||||
sys: sys,
|
||||
registry: registry,
|
||||
client: &http.Client{Transport: tr},
|
||||
insecureSkipTLSVerify: skipVerify,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CheckAuth validates the credentials by attempting to log into the registry
|
||||
// returns an error if an error occcured while making the http request or the status code received was 401
|
||||
func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password, registry string) error {
|
||||
newLoginClient, err := newDockerClientWithDetails(sys, registry, username, password, "", nil, "")
|
||||
client, err := newDockerClient(sys, registry, registry)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating new docker client")
|
||||
}
|
||||
client.username = username
|
||||
client.password = password
|
||||
|
||||
resp, err := newLoginClient.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth)
|
||||
resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -299,16 +325,21 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
|
|||
return nil, errors.Wrapf(err, "error getting username and password")
|
||||
}
|
||||
|
||||
// The /v2/_catalog endpoint has been disabled for docker.io therefore the call made to that endpoint will fail
|
||||
// So using the v1 hostname for docker.io for simplicity of implementation and the fact that it returns search results
|
||||
// The /v2/_catalog endpoint has been disabled for docker.io therefore
|
||||
// the call made to that endpoint will fail. So using the v1 hostname
|
||||
// for docker.io for simplicity of implementation and the fact that it
|
||||
// returns search results.
|
||||
hostname := registry
|
||||
if registry == dockerHostname {
|
||||
registry = dockerV1Hostname
|
||||
hostname = dockerV1Hostname
|
||||
}
|
||||
|
||||
client, err := newDockerClientWithDetails(sys, registry, username, password, "", nil, "")
|
||||
client, err := newDockerClient(sys, hostname, registry)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error creating new docker client")
|
||||
}
|
||||
client.username = username
|
||||
client.password = password
|
||||
|
||||
// Only try the v1 search endpoint if the search query is not empty. If it is
|
||||
// empty skip to the v2 endpoint.
|
||||
|
@ -530,7 +561,7 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
err := ping("https")
|
||||
if err != nil && c.sys != nil && c.sys.DockerInsecureSkipTLSVerify {
|
||||
if err != nil && c.insecureSkipTLSVerify {
|
||||
err = ping("http")
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -554,7 +585,7 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
|
|||
return true
|
||||
}
|
||||
isV1 := pingV1("https")
|
||||
if !isV1 && c.sys != nil && c.sys.DockerInsecureSkipTLSVerify {
|
||||
if !isV1 && c.insecureSkipTLSVerify {
|
||||
isV1 = pingV1("http")
|
||||
}
|
||||
if isV1 {
|
||||
|
|
86
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
86
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
|
@ -3,7 +3,7 @@ package sysregistriesv2
|
|||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -82,8 +82,8 @@ func (e *InvalidRegistries) Error() string {
|
|||
}
|
||||
|
||||
// parseURL parses the input string, performs some sanity checks and returns
|
||||
// the sanitized input string. An error is returned in case parsing fails or
|
||||
// or if URI scheme or user is set.
|
||||
// the sanitized input string. An error is returned if the input string is
|
||||
// empty or if contains an "http{s,}://" prefix.
|
||||
func parseURL(input string) (string, error) {
|
||||
trimmed := strings.TrimRight(input, "/")
|
||||
|
||||
|
@ -91,49 +91,11 @@ func parseURL(input string) (string, error) {
|
|||
return "", &InvalidRegistries{s: "invalid URL: cannot be empty"}
|
||||
}
|
||||
|
||||
// Ultimately, we expect input of the form example.com[/namespace/…], a prefix
|
||||
// of a fully-expended reference (containers/image/docker/Reference.String()).
|
||||
// c/image/docker/Reference does not currently provide such a parser.
|
||||
// So, we use url.Parse("http://"+trimmed) below to ~verify the format, possibly
|
||||
// letting some invalid input in, trading that off for a simpler parser.
|
||||
//
|
||||
// url.Parse("http://"+trimmed) is, sadly, too permissive, notably for
|
||||
// trimmed == "http://example.com/…", url.Parse("http://http://example.com/…")
|
||||
// is accepted and parsed as
|
||||
// {Scheme: "http", Host: "http:", Path: "//example.com/…"}.
|
||||
//
|
||||
// So, first we do an explicit check for an unwanted scheme prefix:
|
||||
|
||||
// This will parse trimmed=="http://example.com/…" with Scheme: "http". Perhaps surprisingly,
|
||||
// it also succeeds for the input we want to accept, in different ways:
|
||||
// "example.com" -> {Scheme:"", Opaque:"", Path:"example.com"}
|
||||
// "example.com/repo" -> {Scheme:"", Opaque:"", Path:"example.com/repo"}
|
||||
// "example.com:5000" -> {Scheme:"example.com", Opaque:"5000"}
|
||||
// "example.com:5000/repo" -> {Scheme:"example.com", Opaque:"5000/repo"}
|
||||
uri, err := url.Parse(trimmed)
|
||||
if err != nil {
|
||||
return "", &InvalidRegistries{s: fmt.Sprintf("invalid URL '%s': %v", input, err)}
|
||||
}
|
||||
|
||||
// Check if a URI Scheme is set.
|
||||
// Note that URLs that do not start with a slash after the scheme are
|
||||
// interpreted as `scheme:opaque[?query][#fragment]`; see above for examples.
|
||||
if uri.Scheme != "" && uri.Opaque == "" {
|
||||
if strings.HasPrefix(trimmed, "http://") || strings.HasPrefix(trimmed, "https://") {
|
||||
msg := fmt.Sprintf("invalid URL '%s': URI schemes are not supported", input)
|
||||
return "", &InvalidRegistries{s: msg}
|
||||
}
|
||||
|
||||
uri, err = url.Parse("http://" + trimmed)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("invalid URL '%s': sanitized URL did not parse: %v", input, err)
|
||||
return "", &InvalidRegistries{s: msg}
|
||||
}
|
||||
|
||||
if uri.User != nil {
|
||||
msg := fmt.Sprintf("invalid URL '%s': user/password are not supported", trimmed)
|
||||
return "", &InvalidRegistries{s: msg}
|
||||
}
|
||||
|
||||
return trimmed, nil
|
||||
}
|
||||
|
||||
|
@ -279,7 +241,18 @@ var configMutex = sync.Mutex{}
|
|||
// are synchronized via configMutex.
|
||||
var configCache = make(map[string][]Registry)
|
||||
|
||||
// InvalidateCache invalidates the registry cache. This function is meant to be
|
||||
// used for long-running processes that need to reload potential changes made to
|
||||
// the cached registry config files.
|
||||
func InvalidateCache() {
|
||||
configMutex.Lock()
|
||||
defer configMutex.Unlock()
|
||||
configCache = make(map[string][]Registry)
|
||||
}
|
||||
|
||||
// GetRegistries loads and returns the registries specified in the config.
|
||||
// Note the parsed content of registry config files is cached. For reloading,
|
||||
// use `InvalidateCache` and re-call `GetRegistries`.
|
||||
func GetRegistries(ctx *types.SystemContext) ([]Registry, error) {
|
||||
configPath := getConfigPath(ctx)
|
||||
|
||||
|
@ -293,6 +266,13 @@ func GetRegistries(ctx *types.SystemContext) ([]Registry, error) {
|
|||
// load the config
|
||||
config, err := loadRegistryConf(configPath)
|
||||
if err != nil {
|
||||
// Return an empty []Registry if we use the default config,
|
||||
// which implies that the config path of the SystemContext
|
||||
// isn't set. Note: if ctx.SystemRegistriesConfPath points to
|
||||
// the default config, we will still return an error.
|
||||
if os.IsNotExist(err) && (ctx == nil || ctx.SystemRegistriesConfPath == "") {
|
||||
return []Registry{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -323,23 +303,33 @@ func GetRegistries(ctx *types.SystemContext) ([]Registry, error) {
|
|||
|
||||
// FindUnqualifiedSearchRegistries returns all registries that are configured
|
||||
// for unqualified image search (i.e., with Registry.Search == true).
|
||||
func FindUnqualifiedSearchRegistries(registries []Registry) []Registry {
|
||||
func FindUnqualifiedSearchRegistries(ctx *types.SystemContext) ([]Registry, error) {
|
||||
registries, err := GetRegistries(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unqualified := []Registry{}
|
||||
for _, reg := range registries {
|
||||
if reg.Search {
|
||||
unqualified = append(unqualified, reg)
|
||||
}
|
||||
}
|
||||
return unqualified
|
||||
return unqualified, nil
|
||||
}
|
||||
|
||||
// FindRegistry returns the Registry with the longest prefix for ref. If no
|
||||
// Registry prefixes the image, nil is returned.
|
||||
func FindRegistry(ref string, registries []Registry) *Registry {
|
||||
func FindRegistry(ctx *types.SystemContext, ref string) (*Registry, error) {
|
||||
registries, err := GetRegistries(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reg := Registry{}
|
||||
prefixLen := 0
|
||||
for _, r := range registries {
|
||||
if strings.HasPrefix(ref, r.Prefix) {
|
||||
if strings.HasPrefix(ref, r.Prefix+"/") || ref == r.Prefix {
|
||||
length := len(r.Prefix)
|
||||
if length > prefixLen {
|
||||
reg = r
|
||||
|
@ -348,9 +338,9 @@ func FindRegistry(ref string, registries []Registry) *Registry {
|
|||
}
|
||||
}
|
||||
if prefixLen != 0 {
|
||||
return ®
|
||||
return ®, nil
|
||||
}
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Reads the global registry file from the filesystem. Returns a byte array.
|
||||
|
|
|
@ -324,6 +324,30 @@ type DockerAuthConfig struct {
|
|||
Password string
|
||||
}
|
||||
|
||||
// OptionalBool is a boolean with an additional undefined value, which is meant
|
||||
// to be used in the context of user input to distinguish between a
|
||||
// user-specified value and a default value.
|
||||
type OptionalBool byte
|
||||
|
||||
const (
|
||||
// OptionalBoolUndefined indicates that the OptionalBoolean hasn't been written.
|
||||
OptionalBoolUndefined OptionalBool = iota
|
||||
// OptionalBoolTrue represents the boolean true.
|
||||
OptionalBoolTrue
|
||||
// OptionalBoolFalse represents the boolean false.
|
||||
OptionalBoolFalse
|
||||
)
|
||||
|
||||
// NewOptionalBool converts the input bool into either OptionalBoolTrue or
|
||||
// OptionalBoolFalse. The function is meant to avoid boilerplate code of users.
|
||||
func NewOptionalBool(b bool) OptionalBool {
|
||||
o := OptionalBoolFalse
|
||||
if b == true {
|
||||
o = OptionalBoolTrue
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// SystemContext allows parameterizing access to implicitly-accessed resources,
|
||||
// like configuration files in /etc and users' login state in their home directory.
|
||||
// Various components can share the same field only if their semantics is exactly
|
||||
|
@ -376,7 +400,7 @@ type SystemContext struct {
|
|||
// Ignored if DockerCertPath is non-empty.
|
||||
DockerPerHostCertDirPath string
|
||||
// Allow contacting docker registries over HTTP, or HTTPS with failed TLS verification. Note that this does not affect other TLS connections.
|
||||
DockerInsecureSkipTLSVerify bool
|
||||
DockerInsecureSkipTLSVerify OptionalBool
|
||||
// if nil, the library tries to parse ~/.docker/config.json to retrieve credentials
|
||||
DockerAuthConfig *DockerAuthConfig
|
||||
// if not "", an User-Agent header is added to each request when contacting a registry.
|
||||
|
|
|
@ -34,7 +34,7 @@ github.com/xeipuuv/gojsonschema master
|
|||
github.com/xeipuuv/gojsonreference master
|
||||
github.com/xeipuuv/gojsonpointer master
|
||||
github.com/tchap/go-patricia v2.2.6
|
||||
github.com/opencontainers/selinux ba1aefe8057f1d0cfb8e88d0ec1dc85925ef987d
|
||||
github.com/opencontainers/selinux 077c8b6d1c18456fb7c792bc0de52295a0d1900e
|
||||
github.com/BurntSushi/toml b26d9c308763d68093482582cea63d69be07a0f0
|
||||
github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460
|
||||
github.com/gogo/protobuf fcdc5011193ff531a548e9b0301828d5a5b97fd8
|
||||
|
|
Loading…
Reference in New Issue