diff --git a/CHANGELOG.md b/CHANGELOG.md index bd6dc6026e..14329ab96c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.11.1 (2014-05-07) + +#### Registry +- Fix push and pull to private registry + ## 0.11.0 (2014-05-07) #### Notable features since 0.10.0 diff --git a/VERSION b/VERSION index d9df1bbc0c..af88ba8248 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.0 +0.11.1 diff --git a/api/server/server.go b/api/server/server.go index 05d5e60690..3c93a3478d 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -872,6 +872,8 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.") } var ( + authEncoded = r.Header.Get("X-Registry-Auth") + authConfig = ®istry.AuthConfig{} configFileEncoded = r.Header.Get("X-Registry-Config") configFile = ®istry.ConfigFile{} job = eng.Job("build") @@ -881,18 +883,12 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite // Both headers will be parsed and sent along to the daemon, but if a non-empty // ConfigFile is present, any value provided as an AuthConfig directly will // be overridden. See BuildFile::CmdFrom for details. - var ( - authEncoded = r.Header.Get("X-Registry-Auth") - authConfig = ®istry.AuthConfig{} - ) if version.LessThan("1.9") && authEncoded != "" { authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) if err := json.NewDecoder(authJson).Decode(authConfig); err != nil { // for a pull it is not an error if no auth was given // to increase compatibility with the existing api it is defaulting to be empty authConfig = ®istry.AuthConfig{} - } else { - configFile.Configs[authConfig.ServerAddress] = *authConfig } } @@ -917,7 +913,8 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite job.Setenv("q", r.FormValue("q")) job.Setenv("nocache", r.FormValue("nocache")) job.Setenv("rm", r.FormValue("rm")) - job.SetenvJson("auth", configFile) + job.SetenvJson("authConfig", authConfig) + job.SetenvJson("configFile", configFile) if err := job.Run(); err != nil { if !job.Stdout.Used() { diff --git a/contrib/mkimage-debootstrap.sh b/contrib/mkimage-debootstrap.sh index 33ba7b07cb..613066e16b 100755 --- a/contrib/mkimage-debootstrap.sh +++ b/contrib/mkimage-debootstrap.sh @@ -43,7 +43,7 @@ usage() { debianStable=wheezy debianUnstable=sid # this should match the name found at http://releases.ubuntu.com/ -ubuntuLatestLTS=precise +ubuntuLatestLTS=trusty # this should match the name found at http://releases.tanglu.org/ tangluLatest=aequorea diff --git a/docker/docker.go b/docker/docker.go index 26ccd24bb4..60f34a1f14 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -43,11 +43,11 @@ func main() { flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode") flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode") flAutoRestart = flag.Bool([]string{"r", "-restart"}, true, "Restart previously running containers") - bridgeName = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge; use 'none' to disable container networking") + bridgeName = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking") bridgeIp = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b") pidfile = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file") flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the docker runtime") - flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode; use '' (the empty string) to disable setting of a group") + flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group") flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") flDns = opts.NewListOpts(opts.ValidateIp4Address) flDnsSearch = opts.NewListOpts(opts.ValidateDomain) @@ -58,7 +58,7 @@ func main() { flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the docker runtime to use a specific storage driver") flExecDriver = flag.String([]string{"e", "-exec-driver"}, "native", "Force the docker runtime to use a specific exec driver") flHosts = opts.NewListOpts(api.ValidateHost) - flMtu = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU; if no value is provided: default to the default route MTU or 1500 if no default route is available") + flMtu = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available") flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags") flTlsVerify = flag.Bool([]string{"-tlsverify"}, false, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)") flCa = flag.String([]string{"-tlscacert"}, dockerConfDir+defaultCaFile, "Trust only remotes providing a certificate signed by the CA given here") @@ -68,7 +68,7 @@ func main() { ) flag.Var(&flDns, []string{"#dns", "-dns"}, "Force docker to use specific DNS servers") flag.Var(&flDnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains") - flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.") + flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode\nspecified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.") flag.Parse() diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 8936bbe332..8e0507cbf8 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -809,33 +809,39 @@ Run a command in a new container Usage: docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...] - -a, --attach=[]: Attach to stdin, stdout or stderr. - -c, --cpu-shares=0: CPU shares (relative weight) - --cidfile="": Write the container ID to the file - -d, --detach=false: Detached mode: Run container in the background, print new container id - --dns=[]: Set custom dns servers - --dns-search=[]: Set custom dns search domains - -e, --env=[]: Set environment variables - --entrypoint="": Overwrite the default entrypoint of the image - --env-file=[]: Read in a line delimited file of ENV variables - --expose=[]: Expose a port from the container without publishing it to your host - -h, --hostname="": Container host name - -i, --interactive=false: Keep stdin open even if not attached - --link=[]: Add link to another container (name:alias) - --lxc-conf=[]: (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" - -m, --memory="": Memory limit (format: , where unit = b, k, m or g) - --name="": Assign a name to the container - --net="bridge": Set the Network mode for the container ('bridge': creates a new network stack for the container on the docker bridge, 'none': no networking for this container, 'container:': reuses another container network stack), 'host': use the host network stack inside the container - -P, --publish-all=false: Publish all exposed ports to the host interfaces - -p, --publish=[]: Publish a container's port to the host (format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort) (use 'docker port' to see the actual mapping) - --privileged=false: Give extended privileges to this container - --rm=false: Automatically remove the container when it exits (incompatible with -d) - --sig-proxy=true: Proxify all received signal to the process (even in non-tty mode) - -t, --tty=false: Allocate a pseudo-tty - -u, --user="": Username or UID - -v, --volume=[]: Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container) - --volumes-from=[]: Mount volumes from the specified container(s) - -w, --workdir="": Working directory inside the container + -a, --attach=[] Attach to stdin, stdout or stderr. + -c, --cpu-shares=0 CPU shares (relative weight) + --cidfile="" Write the container ID to the file + -d, --detach=false Detached mode: Run container in the background, print new container id + --dns=[] Set custom dns servers + --dns-search=[] Set custom dns search domains + -e, --env=[] Set environment variables + --entrypoint="" Overwrite the default entrypoint of the image + --env-file=[] Read in a line delimited file of ENV variables + --expose=[] Expose a port from the container without publishing it to your host + -h, --hostname="" Container host name + -i, --interactive=false Keep stdin open even if not attached + --link=[] Add link to another container (name:alias) + --lxc-conf=[] (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" + -m, --memory="" Memory limit (format: , where unit = b, k, m or g) + --name="" Assign a name to the container + --net="bridge" Set the Network mode for the container + 'bridge': creates a new network stack for the container on the docker bridge + 'none': no networking for this container + 'container:': reuses another container network stack + 'host': use the host network stack inside the contaner + -p, --publish=[] Publish a container's port to the host + format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort + (use 'docker port' to see the actual mapping) + -P, --publish-all=false Publish all exposed ports to the host interfaces + --privileged=false Give extended privileges to this container + --rm=false Automatically remove the container when it exits (incompatible with -d) + --sig-proxy=true Proxify all received signal to the process (even in non-tty mode) + -t, --tty=false Allocate a pseudo-tty + -u, --user="" Username or UID + -v, --volume=[] Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container) + --volumes-from=[] Mount volumes from the specified container(s) + -w, --workdir="" Working directory inside the container The `docker run` command first `creates` a writeable container layer over the specified image, and then `starts` it using the specified command. That is, diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index b3415330fe..09c2b642a1 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -138,6 +138,11 @@ PID files): --dns=[] : Set custom dns servers for the container --net="bridge": Set the Network mode for the container ('bridge': creates a new network stack for the container on the docker bridge, 'none': no networking for this container, 'container:': reuses another container network stack), 'host': use the host network stack inside the container + --net="bridge" Set the Network mode for the container + 'bridge': creates a new network stack for the container on the docker bridge + 'none': no networking for this container + 'container:': reuses another container network stack + 'host': use the host network stack inside the contaner By default, all containers have networking enabled and they can make any outgoing connections. The operator can completely disable networking diff --git a/integration/buildfile_test.go b/integration/buildfile_test.go index 81580ec98c..b87fa116eb 100644 --- a/integration/buildfile_test.go +++ b/integration/buildfile_test.go @@ -394,7 +394,7 @@ func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, u } dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := server.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil) + buildfile := server.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil) id, err := buildfile.Build(context.Archive(dockerfile, t)) if err != nil { return nil, err @@ -828,7 +828,7 @@ func TestForbiddenContextPath(t *testing.T) { } dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := server.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil) + buildfile := server.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil) _, err = buildfile.Build(context.Archive(dockerfile, t)) if err == nil { @@ -874,7 +874,7 @@ func TestBuildADDFileNotFound(t *testing.T) { } dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := server.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil) + buildfile := server.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil) _, err = buildfile.Build(context.Archive(dockerfile, t)) if err == nil { diff --git a/pkg/mflag/example/example.go b/pkg/mflag/example/example.go index ce9dd30e4c..2d78baa172 100644 --- a/pkg/mflag/example/example.go +++ b/pkg/mflag/example/example.go @@ -2,6 +2,7 @@ package main import ( "fmt" + flag "github.com/dotcloud/docker/pkg/mflag" ) @@ -19,15 +20,17 @@ func init() { flag.IntVar(&i, []string{"-integer", "-number"}, -1, "a simple integer") flag.StringVar(&str, []string{"s", "#hidden", "-string"}, "", "a simple string") //-s -hidden and --string will work, but -hidden won't be in the usage flag.BoolVar(&h, []string{"h", "#help", "-help"}, false, "display the help") + flag.StringVar(&str, []string{"mode"}, "mode1", "set the mode\nmode1: use the mode1\nmode2: use the mode2\nmode3: use the mode3") flag.Parse() } func main() { if h { flag.PrintDefaults() + } else { + fmt.Printf("s/#hidden/-string: %s\n", str) + fmt.Printf("b: %b\n", b) + fmt.Printf("-bool: %b\n", b2) + fmt.Printf("s/#hidden/-string(via lookup): %s\n", flag.Lookup("s").Value.String()) + fmt.Printf("ARGS: %v\n", flag.Args()) } - fmt.Printf("s/#hidden/-string: %s\n", str) - fmt.Printf("b: %b\n", b) - fmt.Printf("-bool: %b\n", b2) - fmt.Printf("s/#hidden/-string(via lookup): %s\n", flag.Lookup("s").Value.String()) - fmt.Printf("ARGS: %v\n", flag.Args()) } diff --git a/pkg/mflag/flag.go b/pkg/mflag/flag.go index ed6fad3b46..ed85a4a4c5 100644 --- a/pkg/mflag/flag.go +++ b/pkg/mflag/flag.go @@ -83,6 +83,7 @@ import ( "sort" "strconv" "strings" + "text/tabwriter" "time" ) @@ -419,11 +420,12 @@ func Set(name, value string) error { // PrintDefaults prints, to standard error unless configured // otherwise, the default values of all defined flags in the set. func (f *FlagSet) PrintDefaults() { + writer := tabwriter.NewWriter(f.out(), 20, 1, 3, ' ', 0) f.VisitAll(func(flag *Flag) { - format := " -%s=%s: %s\n" + format := " -%s=%s" if _, ok := flag.Value.(*stringValue); ok { // put quotes on the value - format = " -%s=%q: %s\n" + format = " -%s=%q" } names := []string{} for _, name := range flag.Names { @@ -432,9 +434,18 @@ func (f *FlagSet) PrintDefaults() { } } if len(names) > 0 { - fmt.Fprintf(f.out(), format, strings.Join(names, ", -"), flag.DefValue, flag.Usage) + fmt.Fprintf(writer, format, strings.Join(names, ", -"), flag.DefValue) + for i, line := range strings.Split(flag.Usage, "\n") { + if i != 0 { + line = " " + line + } + fmt.Fprintln(writer, "\t", line) + } + // start := fmt.Sprintf(format, strings.Join(names, ", -"), flag.DefValue) + // fmt.Fprintln(f.out(), start, strings.Replace(flag.Usage, "\n", "\n"+strings.Repeat(" ", len(start)+1), -1)) } }) + writer.Flush() } // PrintDefaults prints to standard error the default values of all defined command-line flags. diff --git a/runconfig/parse.go b/runconfig/parse.go index 74b7801532..f27adc2cae 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -14,7 +14,7 @@ import ( ) var ( - ErrInvalidWorikingDirectory = fmt.Errorf("The working directory is invalid. It needs to be an absolute path.") + ErrInvalidWorkingDirectory = fmt.Errorf("The working directory is invalid. It needs to be an absolute path.") ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d") ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d") ) @@ -62,7 +62,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID") flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container") flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)") - flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container ('bridge': creates a new network stack for the container on the docker bridge, 'none': no networking for this container, 'container:': reuses another container network stack), 'host': use the host network stack inside the container") + flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container\n'bridge': creates a new network stack for the container on the docker bridge\n'none': no networking for this container\n'container:': reuses another container network stack\n'host': use the host network stack inside the contaner") // For documentation purpose _ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)") _ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container") @@ -74,7 +74,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables") cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a line delimited file of ENV variables") - cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat)) + cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host\nformat: %s\n(use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat)) cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host") cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers") cmd.Var(&flDnsSearch, []string{"-dns-search"}, "Set custom dns search domains") @@ -95,7 +95,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf return nil, nil, cmd, ErrConflictAttachDetach } if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) { - return nil, nil, cmd, ErrInvalidWorikingDirectory + return nil, nil, cmd, ErrInvalidWorkingDirectory } if *flDetach && *flAutoRemove { return nil, nil, cmd, ErrConflictDetachAutoRemove diff --git a/server/buildfile.go b/server/buildfile.go index 24b0b58f25..5ab3b5ae8b 100644 --- a/server/buildfile.go +++ b/server/buildfile.go @@ -50,6 +50,7 @@ type buildFile struct { utilizeCache bool rm bool + authConfig *registry.AuthConfig configFile *registry.ConfigFile tmpContainers map[string]struct{} @@ -80,10 +81,20 @@ func (b *buildFile) CmdFrom(name string) error { if err != nil { if b.daemon.Graph().IsNotExist(err) { remote, tag := utils.ParseRepositoryTag(name) + pullRegistryAuth := b.authConfig + if len(b.configFile.Configs) > 0 { + // The request came with a full auth config file, we prefer to use that + endpoint, _, err := registry.ResolveRepositoryName(remote) + if err != nil { + return err + } + resolvedAuth := b.configFile.ResolveAuthConfig(endpoint) + pullRegistryAuth = &resolvedAuth + } job := b.srv.Eng.Job("pull", remote, tag) job.SetenvBool("json", b.sf.Json()) job.SetenvBool("parallel", true) - job.SetenvJson("auth", b.configFile) + job.SetenvJson("authConfig", pullRegistryAuth) job.Stdout.Add(b.outOld) if err := job.Run(); err != nil { return err @@ -821,7 +832,7 @@ func stripComments(raw []byte) string { return strings.Join(out, "\n") } -func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter, configFile *registry.ConfigFile) BuildFile { +func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter, auth *registry.AuthConfig, authConfigFile *registry.ConfigFile) BuildFile { return &buildFile{ daemon: srv.daemon, srv: srv, @@ -834,7 +845,8 @@ func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeC utilizeCache: utilizeCache, rm: rm, sf: sf, - configFile: configFile, + authConfig: auth, + configFile: authConfigFile, outOld: outOld, } } diff --git a/server/server.go b/server/server.go index 47565f0022..3763f87dd5 100644 --- a/server/server.go +++ b/server/server.go @@ -428,11 +428,13 @@ func (srv *Server) Build(job *engine.Job) engine.Status { suppressOutput = job.GetenvBool("q") noCache = job.GetenvBool("nocache") rm = job.GetenvBool("rm") + authConfig = ®istry.AuthConfig{} configFile = ®istry.ConfigFile{} tag string context io.ReadCloser ) - job.GetenvJson("auth", configFile) + job.GetenvJson("authConfig", authConfig) + job.GetenvJson("configFile", configFile) repoName, tag = utils.ParseRepositoryTag(repoName) if remoteURL == "" { @@ -484,7 +486,7 @@ func (srv *Server) Build(job *engine.Job) engine.Status { Writer: job.Stdout, StreamFormatter: sf, }, - !suppressOutput, !noCache, rm, job.Stdout, sf, configFile) + !suppressOutput, !noCache, rm, job.Stdout, sf, authConfig, configFile) id, err := b.Build(context) if err != nil { return job.Error(err) @@ -1341,23 +1343,16 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status { localName = job.Args[0] tag string sf = utils.NewStreamFormatter(job.GetenvBool("json")) - authConfig registry.AuthConfig - configFile = ®istry.ConfigFile{} + authConfig = ®istry.AuthConfig{} metaHeaders map[string][]string ) if len(job.Args) > 1 { tag = job.Args[1] } - job.GetenvJson("auth", configFile) + job.GetenvJson("authConfig", authConfig) job.GetenvJson("metaHeaders", metaHeaders) - endpoint, _, err := registry.ResolveRepositoryName(localName) - if err != nil { - return job.Error(err) - } - authConfig = configFile.ResolveAuthConfig(endpoint) - c, err := srv.poolAdd("pull", localName+":"+tag) if err != nil { if c != nil { @@ -1376,12 +1371,12 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status { return job.Error(err) } - endpoint, err = registry.ExpandAndVerifyRegistryUrl(hostname) + endpoint, err := registry.ExpandAndVerifyRegistryUrl(hostname) if err != nil { return job.Error(err) } - r, err := registry.NewRegistry(&authConfig, registry.HTTPRequestFactory(metaHeaders), endpoint) + r, err := registry.NewRegistry(authConfig, registry.HTTPRequestFactory(metaHeaders), endpoint) if err != nil { return job.Error(err) }