mirror of https://github.com/docker/cli.git
Merge pull request #424 from simonferquel/update-vendoring
updated vendoring
This commit is contained in:
commit
5c5cdd0e36
|
@ -4,13 +4,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
|
@ -13,6 +12,7 @@ import (
|
||||||
apiclient "github.com/docker/docker/client"
|
apiclient "github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/pkg/promise"
|
"github.com/docker/docker/pkg/promise"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/stdcopy"
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/compose/loader"
|
"github.com/docker/cli/cli/compose/loader"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
@ -20,6 +19,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
|
@ -20,6 +19,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
|
@ -7,11 +7,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,11 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@ package container
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/events"
|
"github.com/docker/docker/api/types/events"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package command
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
eventtypes "github.com/docker/docker/api/types/events"
|
eventtypes "github.com/docker/docker/api/types/events"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EventHandler is abstract interface for user to customize
|
// EventHandler is abstract interface for user to customize
|
||||||
|
|
|
@ -504,7 +504,10 @@ func (c *serviceContext) Replicas() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serviceContext) Image() string {
|
func (c *serviceContext) Image() string {
|
||||||
image := c.service.Spec.TaskTemplate.ContainerSpec.Image
|
var image string
|
||||||
|
if c.service.Spec.TaskTemplate.ContainerSpec != nil {
|
||||||
|
image = c.service.Spec.TaskTemplate.ContainerSpec.Image
|
||||||
|
}
|
||||||
if ref, err := reference.ParseNormalizedNamed(image); err == nil {
|
if ref, err := reference.ParseNormalizedNamed(image); err == nil {
|
||||||
// update image string for display, (strips any digest)
|
// update image string for display, (strips any digest)
|
||||||
if nt, ok := ref.(reference.NamedTagged); ok {
|
if nt, ok := ref.(reference.NamedTagged); ok {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/image/build"
|
"github.com/docker/cli/cli/command/image/build"
|
||||||
|
@ -28,6 +27,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/urlutil"
|
"github.com/docker/docker/pkg/urlutil"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,9 +17,9 @@ import (
|
||||||
"github.com/docker/cli/cli/command/image/build"
|
"github.com/docker/cli/cli/command/image/build"
|
||||||
cliconfig "github.com/docker/cli/cli/config"
|
cliconfig "github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/client/session"
|
|
||||||
"github.com/docker/docker/client/session/filesync"
|
|
||||||
"github.com/docker/docker/pkg/progress"
|
"github.com/docker/docker/pkg/progress"
|
||||||
|
"github.com/moby/buildkit/session"
|
||||||
|
"github.com/moby/buildkit/session/filesync"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/trust"
|
"github.com/docker/cli/cli/trust"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
|
@ -19,6 +18,7 @@ import (
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/templates"
|
"github.com/docker/cli/templates"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Inspector defines an interface to implement to process elements
|
// Inspector defines an interface to implement to process elements
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OutStream is an output stream used by the DockerCli to write normal program
|
// OutStream is an output stream used by the DockerCli to write normal program
|
||||||
|
|
|
@ -7,13 +7,13 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,7 +41,7 @@ func formatServiceInspect(t *testing.T, format formatter.Format, now time.Time)
|
||||||
Labels: map[string]string{"com.label": "foo"},
|
Labels: map[string]string{"com.label": "foo"},
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: "foo/bar@sha256:this_is_a_test",
|
Image: "foo/bar@sha256:this_is_a_test",
|
||||||
},
|
},
|
||||||
Networks: []swarm.NetworkAttachmentConfig{
|
Networks: []swarm.NetworkAttachmentConfig{
|
||||||
|
|
|
@ -592,7 +592,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
|
||||||
Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()),
|
Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()),
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: options.image,
|
Image: options.image,
|
||||||
Args: options.args,
|
Args: options.args,
|
||||||
Command: options.entrypoint.Value(),
|
Command: options.entrypoint.Value(),
|
||||||
|
|
|
@ -3,7 +3,6 @@ package service
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/trust"
|
"github.com/docker/cli/cli/trust"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
|
@ -12,6 +11,7 @@ import (
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -270,7 +270,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cspec := &spec.TaskTemplate.ContainerSpec
|
cspec := spec.TaskTemplate.ContainerSpec
|
||||||
task := &spec.TaskTemplate
|
task := &spec.TaskTemplate
|
||||||
|
|
||||||
taskResources := func() *swarm.ResourceRequirements {
|
taskResources := func() *swarm.ResourceRequirements {
|
||||||
|
|
|
@ -19,8 +19,12 @@ func TestUpdateServiceArgs(t *testing.T) {
|
||||||
flags := newUpdateCommand(nil).Flags()
|
flags := newUpdateCommand(nil).Flags()
|
||||||
flags.Set("args", "the \"new args\"")
|
flags.Set("args", "the \"new args\"")
|
||||||
|
|
||||||
spec := &swarm.ServiceSpec{}
|
spec := &swarm.ServiceSpec{
|
||||||
cspec := &spec.TaskTemplate.ContainerSpec
|
TaskTemplate: swarm.TaskSpec{
|
||||||
|
ContainerSpec: &swarm.ContainerSpec{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cspec := spec.TaskTemplate.ContainerSpec
|
||||||
cspec.Args = []string{"old", "args"}
|
cspec.Args = []string{"old", "args"}
|
||||||
|
|
||||||
updateService(nil, nil, flags, spec)
|
updateService(nil, nil, flags, spec)
|
||||||
|
@ -452,8 +456,12 @@ func TestUpdateSecretUpdateInPlace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateReadOnly(t *testing.T) {
|
func TestUpdateReadOnly(t *testing.T) {
|
||||||
spec := &swarm.ServiceSpec{}
|
spec := &swarm.ServiceSpec{
|
||||||
cspec := &spec.TaskTemplate.ContainerSpec
|
TaskTemplate: swarm.TaskSpec{
|
||||||
|
ContainerSpec: &swarm.ContainerSpec{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cspec := spec.TaskTemplate.ContainerSpec
|
||||||
|
|
||||||
// Update with --read-only=true, changed to true
|
// Update with --read-only=true, changed to true
|
||||||
flags := newUpdateCommand(nil).Flags()
|
flags := newUpdateCommand(nil).Flags()
|
||||||
|
@ -474,8 +482,12 @@ func TestUpdateReadOnly(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateStopSignal(t *testing.T) {
|
func TestUpdateStopSignal(t *testing.T) {
|
||||||
spec := &swarm.ServiceSpec{}
|
spec := &swarm.ServiceSpec{
|
||||||
cspec := &spec.TaskTemplate.ContainerSpec
|
TaskTemplate: swarm.TaskSpec{
|
||||||
|
ContainerSpec: &swarm.ContainerSpec{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cspec := spec.TaskTemplate.ContainerSpec
|
||||||
|
|
||||||
// Update with --stop-signal=SIGUSR1
|
// Update with --stop-signal=SIGUSR1
|
||||||
flags := newUpdateCommand(nil).Flags()
|
flags := newUpdateCommand(nil).Flags()
|
||||||
|
|
|
@ -64,7 +64,7 @@ func deployBundle(ctx context.Context, dockerCli command.Cli, opts deployOptions
|
||||||
Labels: convert.AddStackLabel(namespace, service.Labels),
|
Labels: convert.AddStackLabel(namespace, service.Labels),
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: service.Image,
|
Image: service.Image,
|
||||||
Command: service.Command,
|
Command: service.Command,
|
||||||
Args: service.Args,
|
Args: service.Args,
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
|
||||||
Labels: map[string]string{"com.docker.stack.image": "foobar:1.2.3"},
|
Labels: map[string]string{"com.docker.stack.image": "foobar:1.2.3"},
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: "foobar:1.2.3@sha256:deadbeef",
|
Image: "foobar:1.2.3@sha256:deadbeef",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -86,7 +86,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
|
||||||
spec := map[string]swarm.ServiceSpec{
|
spec := map[string]swarm.ServiceSpec{
|
||||||
"myservice": {
|
"myservice": {
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: testcase.image,
|
Image: testcase.image,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -128,7 +128,7 @@ func Service(
|
||||||
Labels: AddStackLabel(namespace, service.Deploy.Labels),
|
Labels: AddStackLabel(namespace, service.Deploy.Labels),
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: service.Image,
|
Image: service.Image,
|
||||||
Command: service.Entrypoint,
|
Command: service.Entrypoint,
|
||||||
Args: service.Command,
|
Args: service.Command,
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/compose/interpolation"
|
"github.com/docker/cli/cli/compose/interpolation"
|
||||||
"github.com/docker/cli/cli/compose/schema"
|
"github.com/docker/cli/cli/compose/schema"
|
||||||
"github.com/docker/cli/cli/compose/template"
|
"github.com/docker/cli/cli/compose/template"
|
||||||
|
@ -19,6 +18,7 @@ import (
|
||||||
shellwords "github.com/mattn/go-shellwords"
|
shellwords "github.com/mattn/go-shellwords"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package debug
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enable sets the DEBUG env var to true
|
// Enable sets the DEBUG env var to true
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEnable(t *testing.T) {
|
func TestEnable(t *testing.T) {
|
||||||
|
|
|
@ -5,10 +5,10 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
cliconfig "github.com/docker/cli/cli/config"
|
cliconfig "github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
"github.com/docker/go-connections/tlsconfig"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
cliconfig "github.com/docker/cli/cli/config"
|
cliconfig "github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/distribution/registry/client/auth"
|
"github.com/docker/distribution/registry/client/auth"
|
||||||
|
@ -29,6 +28,7 @@ import (
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/commands"
|
"github.com/docker/cli/cli/command/commands"
|
||||||
|
@ -16,6 +15,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/debug"
|
"github.com/docker/cli/cli/debug"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ func ReplicatedService(replicas uint64) func(*swarm.Service) {
|
||||||
// ServiceImage sets the service's image
|
// ServiceImage sets the service's image
|
||||||
func ServiceImage(image string) func(*swarm.Service) {
|
func ServiceImage(image string) func(*swarm.Service) {
|
||||||
return func(service *swarm.Service) {
|
return func(service *swarm.Service) {
|
||||||
service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: swarm.ContainerSpec{Image: image}}
|
service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{Image: image}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ func WithTaskSpec(specBuilders ...func(*swarm.TaskSpec)) func(*swarm.Task) {
|
||||||
// Any number of taskSpec function builder can be pass to augment it.
|
// Any number of taskSpec function builder can be pass to augment it.
|
||||||
func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec {
|
func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec {
|
||||||
taskSpec := &swarm.TaskSpec{
|
taskSpec := &swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: &swarm.ContainerSpec{
|
||||||
Image: "myimage:mytag",
|
Image: "myimage:mytag",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
37
vendor.conf
37
vendor.conf
|
@ -1,56 +1,57 @@
|
||||||
github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
|
|
||||||
github.com/Microsoft/go-winio v0.4.2
|
|
||||||
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
|
|
||||||
github.com/Sirupsen/logrus v0.11.0
|
|
||||||
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
|
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
|
||||||
|
github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
|
||||||
github.com/coreos/etcd 824277cb3a577a0e8c829ca9ec557b973fe06d20
|
github.com/coreos/etcd 824277cb3a577a0e8c829ca9ec557b973fe06d20
|
||||||
github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
|
github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
|
||||||
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
||||||
github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621
|
github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
|
||||||
github.com/docker/docker d58ffa0364c04d03a8f25704d7f0489ee6cd9634
|
github.com/docker/docker 184cea5ff710abde25547749e5608b24a255ba09
|
||||||
github.com/docker/docker-credential-helpers v0.5.1
|
github.com/docker/docker-credential-helpers v0.5.1
|
||||||
|
|
||||||
# the docker/go package contains a customized version of canonical/json
|
# the docker/go package contains a customized version of canonical/json
|
||||||
# and is used by Notary. The package is periodically rebased on current Go versions.
|
# and is used by Notary. The package is periodically rebased on current Go versions.
|
||||||
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
||||||
github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
|
github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
|
||||||
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
|
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||||
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
||||||
github.com/docker/notary v0.4.2
|
github.com/docker/notary v0.4.2-sirupsen https://github.com/simonferquel/notary.git
|
||||||
github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb
|
github.com/docker/swarmkit 0554c9bc9a485025e89b8e5c2c1f0d75961906a2
|
||||||
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
|
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
|
||||||
github.com/gogo/protobuf 7efa791bd276fd4db00867cbd982b552627c24cb
|
github.com/gogo/protobuf v0.4
|
||||||
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
|
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
|
||||||
github.com/gotestyourself/gotestyourself v1.0.0
|
|
||||||
github.com/gorilla/context v1.1
|
github.com/gorilla/context v1.1
|
||||||
github.com/gorilla/mux v1.1
|
github.com/gorilla/mux v1.1
|
||||||
|
github.com/gotestyourself/gotestyourself v1.0.0
|
||||||
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||||
github.com/mattn/go-shellwords v1.0.3
|
github.com/mattn/go-shellwords v1.0.3
|
||||||
|
github.com/Microsoft/go-winio v0.4.4
|
||||||
github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f
|
github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f
|
||||||
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
|
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
|
||||||
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
github.com/moby/buildkit da2b9dc7dab99e824b2b1067ad7d0523e32dd2d9 https://github.com/dmcgowan/buildkit.git
|
||||||
github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe
|
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
|
||||||
github.com/opencontainers/runc 9c2d8d184e5da67c95d601382adf14862e4f2228 https://github.com/docker/runc.git
|
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
|
||||||
|
github.com/opencontainers/image-spec v1.0.0
|
||||||
|
github.com/opencontainers/runc d40db12e72a40109dfcf28539f5ee0930d2f0277
|
||||||
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
|
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib v1.0.0
|
||||||
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
|
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
|
||||||
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
||||||
|
github.com/sirupsen/logrus v1.0.1
|
||||||
github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git
|
github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git
|
||||||
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
|
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
|
||||||
|
github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
|
||||||
github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
|
github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
|
||||||
|
github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
|
||||||
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
|
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
|
||||||
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
|
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
|
||||||
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
|
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
|
||||||
golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2
|
golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2
|
||||||
golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
|
golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
|
||||||
golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
|
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
||||||
|
golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f
|
||||||
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
|
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
|
||||||
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
|
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
|
||||||
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||||
google.golang.org/grpc v1.3.0
|
google.golang.org/grpc v1.3.0
|
||||||
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
|
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
|
||||||
github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
|
|
||||||
github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
|
|
||||||
golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
|
|
||||||
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d
|
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d
|
||||||
|
|
|
@ -7,3 +7,6 @@ For example the parser might receive "ESC, [, A" as a stream of three characters
|
||||||
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
|
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
|
||||||
|
|
||||||
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
|
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
|
||||||
|
|
||||||
|
-----
|
||||||
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger *logrus.Logger
|
var logger *logrus.Logger
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Azure/go-ansiterm"
|
"github.com/Azure/go-ansiterm"
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger *logrus.Logger
|
var logger *logrus.Logger
|
||||||
|
|
|
@ -23,6 +23,13 @@ type atomicBool int32
|
||||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
||||||
|
func (b *atomicBool) swap(new bool) bool {
|
||||||
|
var newInt int32
|
||||||
|
if new {
|
||||||
|
newInt = 1
|
||||||
|
}
|
||||||
|
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
||||||
|
@ -71,7 +78,7 @@ func initIo() {
|
||||||
type win32File struct {
|
type win32File struct {
|
||||||
handle syscall.Handle
|
handle syscall.Handle
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
closing bool
|
closing atomicBool
|
||||||
readDeadline deadlineHandler
|
readDeadline deadlineHandler
|
||||||
writeDeadline deadlineHandler
|
writeDeadline deadlineHandler
|
||||||
}
|
}
|
||||||
|
@ -107,9 +114,9 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||||
|
|
||||||
// closeHandle closes the resources associated with a Win32 handle
|
// closeHandle closes the resources associated with a Win32 handle
|
||||||
func (f *win32File) closeHandle() {
|
func (f *win32File) closeHandle() {
|
||||||
if !f.closing {
|
// Atomically set that we are closing, releasing the resources only once.
|
||||||
|
if !f.closing.swap(true) {
|
||||||
// cancel all IO and wait for it to complete
|
// cancel all IO and wait for it to complete
|
||||||
f.closing = true
|
|
||||||
cancelIoEx(f.handle, nil)
|
cancelIoEx(f.handle, nil)
|
||||||
f.wg.Wait()
|
f.wg.Wait()
|
||||||
// at this point, no new IO can start
|
// at this point, no new IO can start
|
||||||
|
@ -127,10 +134,10 @@ func (f *win32File) Close() error {
|
||||||
// prepareIo prepares for a new IO operation.
|
// prepareIo prepares for a new IO operation.
|
||||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
||||||
func (f *win32File) prepareIo() (*ioOperation, error) {
|
func (f *win32File) prepareIo() (*ioOperation, error) {
|
||||||
f.wg.Add(1)
|
if f.closing.isSet() {
|
||||||
if f.closing {
|
|
||||||
return nil, ErrFileClosed
|
return nil, ErrFileClosed
|
||||||
}
|
}
|
||||||
|
f.wg.Add(1)
|
||||||
c := &ioOperation{}
|
c := &ioOperation{}
|
||||||
c.ch = make(chan ioResult)
|
c.ch = make(chan ioResult)
|
||||||
return c, nil
|
return c, nil
|
||||||
|
@ -159,7 +166,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
||||||
return int(bytes), err
|
return int(bytes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.closing {
|
if f.closing.isSet() {
|
||||||
cancelIoEx(f.handle, &c.o)
|
cancelIoEx(f.handle, &c.o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +182,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
||||||
case r = <-c.ch:
|
case r = <-c.ch:
|
||||||
err = r.err
|
err = r.err
|
||||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
if err == syscall.ERROR_OPERATION_ABORTED {
|
||||||
if f.closing {
|
if f.closing.isSet() {
|
||||||
err = ErrFileClosed
|
err = ErrFileClosed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONFormatter struct {
|
|
||||||
// TimestampFormat sets the format used for marshaling timestamps.
|
|
||||||
TimestampFormat string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
data := make(Fields, len(entry.Data)+3)
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case error:
|
|
||||||
// Otherwise errors are ignored by `encoding/json`
|
|
||||||
// https://github.com/Sirupsen/logrus/issues/137
|
|
||||||
data[k] = v.Error()
|
|
||||||
default:
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prefixFieldClashes(data)
|
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
|
||||||
if timestampFormat == "" {
|
|
||||||
timestampFormat = DefaultTimestampFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
data["time"] = entry.Time.Format(timestampFormat)
|
|
||||||
data["msg"] = entry.Message
|
|
||||||
data["level"] = entry.Level.String()
|
|
||||||
|
|
||||||
serialized, err := json.Marshal(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
|
||||||
}
|
|
||||||
return append(serialized, '\n'), nil
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// +build solaris,!appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build windows,!appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
||||||
|
|
||||||
var (
|
|
||||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
fd := syscall.Stderr
|
|
||||||
var st uint32
|
|
||||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
||||||
return r != 0 && e == 0
|
|
||||||
}
|
|
|
@ -76,8 +76,7 @@ may be the better choice.
|
||||||
For those who have previously deployed their own registry based on the Registry
|
For those who have previously deployed their own registry based on the Registry
|
||||||
1.0 implementation and wish to deploy a Registry 2.0 while retaining images,
|
1.0 implementation and wish to deploy a Registry 2.0 while retaining images,
|
||||||
data migration is required. A tool to assist with migration efforts has been
|
data migration is required. A tool to assist with migration efforts has been
|
||||||
created. For more information see [docker/migrator]
|
created. For more information see [docker/migrator](https://github.com/docker/migrator).
|
||||||
(https://github.com/docker/migrator).
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,7 @@ type BlobProvider interface {
|
||||||
|
|
||||||
// BlobServer can serve blobs via http.
|
// BlobServer can serve blobs via http.
|
||||||
type BlobServer interface {
|
type BlobServer interface {
|
||||||
// ServeBlob attempts to serve the blob, identifed by dgst, via http. The
|
// ServeBlob attempts to serve the blob, identified by dgst, via http. The
|
||||||
// service may decide to redirect the client elsewhere or serve the data
|
// service may decide to redirect the client elsewhere or serve the data
|
||||||
// directly.
|
// directly.
|
||||||
//
|
//
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
// Note that this only affects the new context, the previous context, with the
|
// Note that this only affects the new context, the previous context, with the
|
||||||
// version field, can be used independently. Put another way, the new logger,
|
// version field, can be used independently. Put another way, the new logger,
|
||||||
// added to the request context, is unique to that context and can have
|
// added to the request context, is unique to that context and can have
|
||||||
// request scoped varaibles.
|
// request scoped variables.
|
||||||
//
|
//
|
||||||
// HTTP Requests
|
// HTTP Requests
|
||||||
//
|
//
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/distribution/uuid"
|
"github.com/docker/distribution/uuid"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common errors used with this package.
|
// Common errors used with this package.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package context
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (err ErrManifestUnknownRevision) Error() string {
|
||||||
type ErrManifestUnverified struct{}
|
type ErrManifestUnverified struct{}
|
||||||
|
|
||||||
func (ErrManifestUnverified) Error() string {
|
func (ErrManifestUnverified) Error() string {
|
||||||
return fmt.Sprintf("unverified manifest")
|
return "unverified manifest"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrManifestVerification provides a type to collect errors encountered
|
// ErrManifestVerification provides a type to collect errors encountered
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// tag := /[\w][\w.-]{0,127}/
|
// tag := /[\w][\w.-]{0,127}/
|
||||||
//
|
//
|
||||||
// digest := digest-algorithm ":" digest-hex
|
// digest := digest-algorithm ":" digest-hex
|
||||||
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]
|
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
|
||||||
// digest-algorithm-separator := /[+.-_]/
|
// digest-algorithm-separator := /[+.-_]/
|
||||||
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
||||||
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
|
@ -48,66 +47,42 @@ func NewURLBuilderFromString(root string, relative bool) (*URLBuilder, error) {
|
||||||
// NewURLBuilderFromRequest uses information from an *http.Request to
|
// NewURLBuilderFromRequest uses information from an *http.Request to
|
||||||
// construct the root url.
|
// construct the root url.
|
||||||
func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
|
func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
|
||||||
var scheme string
|
var (
|
||||||
|
|
||||||
forwardedProto := r.Header.Get("X-Forwarded-Proto")
|
|
||||||
// TODO: log the error
|
|
||||||
forwardedHeader, _, _ := parseForwardedHeader(r.Header.Get("Forwarded"))
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case len(forwardedProto) > 0:
|
|
||||||
scheme = forwardedProto
|
|
||||||
case len(forwardedHeader["proto"]) > 0:
|
|
||||||
scheme = forwardedHeader["proto"]
|
|
||||||
case r.TLS != nil:
|
|
||||||
scheme = "https"
|
|
||||||
case len(r.URL.Scheme) > 0:
|
|
||||||
scheme = r.URL.Scheme
|
|
||||||
default:
|
|
||||||
scheme = "http"
|
scheme = "http"
|
||||||
|
host = r.Host
|
||||||
|
)
|
||||||
|
|
||||||
|
if r.TLS != nil {
|
||||||
|
scheme = "https"
|
||||||
|
} else if len(r.URL.Scheme) > 0 {
|
||||||
|
scheme = r.URL.Scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
host := r.Host
|
// Handle fowarded headers
|
||||||
|
// Prefer "Forwarded" header as defined by rfc7239 if given
|
||||||
if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 {
|
// see https://tools.ietf.org/html/rfc7239
|
||||||
// According to the Apache mod_proxy docs, X-Forwarded-Host can be a
|
if forwarded := r.Header.Get("Forwarded"); len(forwarded) > 0 {
|
||||||
// comma-separated list of hosts, to which each proxy appends the
|
forwardedHeader, _, err := parseForwardedHeader(forwarded)
|
||||||
// requested host. We want to grab the first from this comma-separated
|
if err == nil {
|
||||||
// list.
|
if fproto := forwardedHeader["proto"]; len(fproto) > 0 {
|
||||||
hosts := strings.SplitN(forwardedHost, ",", 2)
|
scheme = fproto
|
||||||
host = strings.TrimSpace(hosts[0])
|
}
|
||||||
} else if addr, exists := forwardedHeader["for"]; exists {
|
if fhost := forwardedHeader["host"]; len(fhost) > 0 {
|
||||||
host = addr
|
host = fhost
|
||||||
} else if h, exists := forwardedHeader["host"]; exists {
|
}
|
||||||
host = h
|
|
||||||
}
|
|
||||||
|
|
||||||
portLessHost, port := host, ""
|
|
||||||
if !isIPv6Address(portLessHost) {
|
|
||||||
// with go 1.6, this would treat the last part of IPv6 address as a port
|
|
||||||
portLessHost, port, _ = net.SplitHostPort(host)
|
|
||||||
}
|
|
||||||
if forwardedPort := r.Header.Get("X-Forwarded-Port"); len(port) == 0 && len(forwardedPort) > 0 {
|
|
||||||
ports := strings.SplitN(forwardedPort, ",", 2)
|
|
||||||
forwardedPort = strings.TrimSpace(ports[0])
|
|
||||||
if _, err := strconv.ParseInt(forwardedPort, 10, 32); err == nil {
|
|
||||||
port = forwardedPort
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
if forwardedProto := r.Header.Get("X-Forwarded-Proto"); len(forwardedProto) > 0 {
|
||||||
if len(portLessHost) > 0 {
|
scheme = forwardedProto
|
||||||
host = portLessHost
|
}
|
||||||
}
|
if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 {
|
||||||
if len(port) > 0 {
|
// According to the Apache mod_proxy docs, X-Forwarded-Host can be a
|
||||||
// remove enclosing brackets of ipv6 address otherwise they will be duplicated
|
// comma-separated list of hosts, to which each proxy appends the
|
||||||
if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' {
|
// requested host. We want to grab the first from this comma-separated
|
||||||
host = host[1 : len(host)-1]
|
// list.
|
||||||
|
hosts := strings.SplitN(forwardedHost, ",", 2)
|
||||||
|
host = strings.TrimSpace(hosts[0])
|
||||||
}
|
}
|
||||||
// JoinHostPort properly encloses ipv6 addresses in square brackets
|
|
||||||
host = net.JoinHostPort(host, port)
|
|
||||||
} else if isIPv6Address(host) && host[0] != '[' {
|
|
||||||
// ipv6 needs to be enclosed in square brackets in urls
|
|
||||||
host = "[" + host + "]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath := routeDescriptorsMap[RouteNameBase].Path
|
basePath := routeDescriptorsMap[RouteNameBase].Path
|
||||||
|
@ -175,6 +150,8 @@ func (ub *URLBuilder) BuildManifestURL(ref reference.Named) (string, error) {
|
||||||
tagOrDigest = v.Tag()
|
tagOrDigest = v.Tag()
|
||||||
case reference.Digested:
|
case reference.Digested:
|
||||||
tagOrDigest = v.Digest().String()
|
tagOrDigest = v.Digest().String()
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("reference must have a tag or digest")
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest)
|
manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest)
|
||||||
|
@ -287,28 +264,3 @@ func appendValues(u string, values ...url.Values) string {
|
||||||
|
|
||||||
return appendValuesURL(up, values...).String()
|
return appendValuesURL(up, values...).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// isIPv6Address returns true if given string is a valid IPv6 address. No port is allowed. The address may be
|
|
||||||
// enclosed in square brackets.
|
|
||||||
func isIPv6Address(host string) bool {
|
|
||||||
if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' {
|
|
||||||
host = host[1 : len(host)-1]
|
|
||||||
}
|
|
||||||
// The IPv6 scoped addressing zone identifier starts after the last percent sign.
|
|
||||||
if i := strings.LastIndexByte(host, '%'); i > 0 {
|
|
||||||
host = host[:i]
|
|
||||||
}
|
|
||||||
ip := net.ParseIP(host)
|
|
||||||
if ip == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if ip.To16() == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if ip.To4() == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// dot can be present in ipv4-mapped address, it needs to come after a colon though
|
|
||||||
i := strings.IndexAny(host, ":.")
|
|
||||||
return i >= 0 && host[i] == ':'
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/distribution/registry/client"
|
"github.com/docker/distribution/registry/client"
|
||||||
"github.com/docker/distribution/registry/client/auth/challenge"
|
"github.com/docker/distribution/registry/client/auth/challenge"
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
github.com/Azure/azure-sdk-for-go c6f0533defaaaa26ea4dff3c9774e36033088112
|
github.com/Azure/azure-sdk-for-go 088007b3b08cc02b27f2eadfdcd870958460ce7e
|
||||||
github.com/Sirupsen/logrus d26492970760ca5d33129d2d799e34be5c4782eb
|
github.com/Azure/go-autorest ec5f4903f77ed9927ac95b19ab8e44ada64c1356
|
||||||
|
github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4
|
||||||
github.com/aws/aws-sdk-go c6fc52983ea2375810aa38ddb5370e9cdf611716
|
github.com/aws/aws-sdk-go c6fc52983ea2375810aa38ddb5370e9cdf611716
|
||||||
github.com/bshuster-repo/logrus-logstash-hook 5f729f2fb50a301153cae84ff5c58981d51c095a
|
github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a
|
||||||
github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274
|
github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274
|
||||||
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
|
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
|
||||||
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
|
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
|
||||||
github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2
|
github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2
|
||||||
|
github.com/dgrijalva/jwt-go a601269ab70c205d26370c16f7c81e9017c14e04
|
||||||
github.com/docker/goamz f0a21f5b2e12f83a505ecf79b633bb2035cf6f85
|
github.com/docker/goamz f0a21f5b2e12f83a505ecf79b633bb2035cf6f85
|
||||||
github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21
|
github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21
|
||||||
github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257
|
github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257
|
||||||
github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c
|
github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c
|
||||||
github.com/golang/protobuf/proto 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
|
github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
|
||||||
github.com/gorilla/context 14f550f51af52180c2eefed15e5fd18d63c0a64a
|
github.com/gorilla/context 14f550f51af52180c2eefed15e5fd18d63c0a64a
|
||||||
github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b
|
github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b
|
||||||
github.com/gorilla/mux e444e69cbd2e2e3e0749a2f3c717cec491552bbf
|
github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604
|
||||||
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||||
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||||
github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39
|
github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39
|
||||||
|
@ -21,15 +23,15 @@ github.com/mitchellh/mapstructure 482a9fd5fa83e8c4e7817413b80f3eb8feec03ef
|
||||||
github.com/ncw/swift b964f2ca856aac39885e258ad25aec08d5f64ee6
|
github.com/ncw/swift b964f2ca856aac39885e258ad25aec08d5f64ee6
|
||||||
github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064
|
github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064
|
||||||
github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842
|
github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842
|
||||||
github.com/stevvooe/resumable 51ad44105773cafcbe91927f70ac68e1bf78f8b4
|
github.com/stevvooe/resumable 2aaf90b2ceea5072cb503ef2a620b08ff3119870
|
||||||
github.com/xenolf/lego/acme a9d8cec0e6563575e5868a005359ac97911b5985
|
github.com/xenolf/lego a9d8cec0e6563575e5868a005359ac97911b5985
|
||||||
github.com/yvasiyarov/go-metrics 57bccd1ccd43f94bb17fdd8bf3007059b802f85e
|
github.com/yvasiyarov/go-metrics 57bccd1ccd43f94bb17fdd8bf3007059b802f85e
|
||||||
github.com/yvasiyarov/gorelic a9bba5b9ab508a086f9a12b8c51fab68478e2128
|
github.com/yvasiyarov/gorelic a9bba5b9ab508a086f9a12b8c51fab68478e2128
|
||||||
github.com/yvasiyarov/newrelic_platform_go b21fdbd4370f3717f3bbd2bf41c223bc273068e6
|
github.com/yvasiyarov/newrelic_platform_go b21fdbd4370f3717f3bbd2bf41c223bc273068e6
|
||||||
golang.org/x/crypto c10c31b5e94b6f7a0283272dc2bb27163dcea24b
|
golang.org/x/crypto c10c31b5e94b6f7a0283272dc2bb27163dcea24b
|
||||||
golang.org/x/net 4876518f9e71663000c348837735820161a42df7
|
golang.org/x/net 4876518f9e71663000c348837735820161a42df7
|
||||||
golang.org/x/oauth2 045497edb6234273d67dbc25da3f2ddbc4c4cacf
|
golang.org/x/oauth2 045497edb6234273d67dbc25da3f2ddbc4c4cacf
|
||||||
golang.org/x/time/rate a4bde12657593d5e90d0533a3e4fd95e635124cb
|
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
|
||||||
google.golang.org/api 9bf6e6e569ff057f75d9604a46c52928f17d2b54
|
google.golang.org/api 9bf6e6e569ff057f75d9604a46c52928f17d2b54
|
||||||
google.golang.org/appengine 12d5545dc1cfa6047a286d5e853841b6471f4c19
|
google.golang.org/appengine 12d5545dc1cfa6047a286d5e853841b6471f4c19
|
||||||
google.golang.org/cloud 975617b05ea8a58727e6c1a06b6161ff4185a9f2
|
google.golang.org/cloud 975617b05ea8a58727e6c1a06b6161ff4185a9f2
|
||||||
|
|
|
@ -51,7 +51,7 @@ Moby is NOT recommended for:
|
||||||
|
|
||||||
- Application developers looking for an easy way to run their applications in containers. We recommend Docker CE instead.
|
- Application developers looking for an easy way to run their applications in containers. We recommend Docker CE instead.
|
||||||
- Enterprise IT and development teams looking for a ready-to-use, commercially supported container platform. We recommend Docker EE instead.
|
- Enterprise IT and development teams looking for a ready-to-use, commercially supported container platform. We recommend Docker EE instead.
|
||||||
- Anyone curious about containers and looking for an easy way to learn. We recommend the docker.com website instead.
|
- Anyone curious about containers and looking for an easy way to learn. We recommend the [docker.com](https://www.docker.com/) website instead.
|
||||||
|
|
||||||
# Transitioning to Moby
|
# Transitioning to Moby
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
// Common constants for daemon and client.
|
// Common constants for daemon and client.
|
||||||
const (
|
const (
|
||||||
// DefaultVersion of Current REST API
|
// DefaultVersion of Current REST API
|
||||||
DefaultVersion string = "1.31"
|
DefaultVersion string = "1.32"
|
||||||
|
|
||||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||||
// command to specify that no base image is to be used.
|
// command to specify that no base image is to be used.
|
||||||
|
|
|
@ -23,41 +23,46 @@ func (i Isolation) IsDefault() bool {
|
||||||
// IpcMode represents the container ipc stack.
|
// IpcMode represents the container ipc stack.
|
||||||
type IpcMode string
|
type IpcMode string
|
||||||
|
|
||||||
// IsPrivate indicates whether the container uses its private ipc stack.
|
// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared.
|
||||||
func (n IpcMode) IsPrivate() bool {
|
func (n IpcMode) IsPrivate() bool {
|
||||||
return !(n.IsHost() || n.IsContainer())
|
return n == "private"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsHost indicates whether the container uses the host's ipc stack.
|
// IsHost indicates whether the container shares the host's ipc namespace.
|
||||||
func (n IpcMode) IsHost() bool {
|
func (n IpcMode) IsHost() bool {
|
||||||
return n == "host"
|
return n == "host"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsContainer indicates whether the container uses a container's ipc stack.
|
// IsShareable indicates whether the container's ipc namespace can be shared with another container.
|
||||||
|
func (n IpcMode) IsShareable() bool {
|
||||||
|
return n == "shareable"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsContainer indicates whether the container uses another container's ipc namespace.
|
||||||
func (n IpcMode) IsContainer() bool {
|
func (n IpcMode) IsContainer() bool {
|
||||||
parts := strings.SplitN(string(n), ":", 2)
|
parts := strings.SplitN(string(n), ":", 2)
|
||||||
return len(parts) > 1 && parts[0] == "container"
|
return len(parts) > 1 && parts[0] == "container"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid indicates whether the ipc stack is valid.
|
// IsNone indicates whether container IpcMode is set to "none".
|
||||||
|
func (n IpcMode) IsNone() bool {
|
||||||
|
return n == "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty indicates whether container IpcMode is empty
|
||||||
|
func (n IpcMode) IsEmpty() bool {
|
||||||
|
return n == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid indicates whether the ipc mode is valid.
|
||||||
func (n IpcMode) Valid() bool {
|
func (n IpcMode) Valid() bool {
|
||||||
parts := strings.Split(string(n), ":")
|
return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer()
|
||||||
switch mode := parts[0]; mode {
|
|
||||||
case "", "host":
|
|
||||||
case "container":
|
|
||||||
if len(parts) != 2 || parts[1] == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container returns the name of the container ipc stack is going to be used.
|
// Container returns the name of the container ipc stack is going to be used.
|
||||||
func (n IpcMode) Container() string {
|
func (n IpcMode) Container() string {
|
||||||
parts := strings.SplitN(string(n), ":", 2)
|
parts := strings.SplitN(string(n), ":", 2)
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 && parts[0] == "container" {
|
||||||
return parts[1]
|
return parts[1]
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -19,6 +19,8 @@ const (
|
||||||
NodeEventType = "node"
|
NodeEventType = "node"
|
||||||
// SecretEventType is the event type that secrets generate
|
// SecretEventType is the event type that secrets generate
|
||||||
SecretEventType = "secret"
|
SecretEventType = "secret"
|
||||||
|
// ConfigEventType is the event type that configs generate
|
||||||
|
ConfigEventType = "config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Actor describes something that generates events,
|
// Actor describes something that generates events,
|
||||||
|
|
|
@ -5,7 +5,6 @@ package filters
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -258,12 +257,20 @@ func (filters Args) Include(field string) bool {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type invalidFilter string
|
||||||
|
|
||||||
|
func (e invalidFilter) Error() string {
|
||||||
|
return "Invalid filter '" + string(e) + "'"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (invalidFilter) InvalidParameter() {}
|
||||||
|
|
||||||
// Validate ensures that all the fields in the filter are valid.
|
// Validate ensures that all the fields in the filter are valid.
|
||||||
// It returns an error as soon as it finds an invalid field.
|
// It returns an error as soon as it finds an invalid field.
|
||||||
func (filters Args) Validate(accepted map[string]bool) error {
|
func (filters Args) Validate(accepted map[string]bool) error {
|
||||||
for name := range filters.fields {
|
for name := range filters.fields {
|
||||||
if !accepted[name] {
|
if !accepted[name] {
|
||||||
return fmt.Errorf("Invalid filter '%s'", name)
|
return invalidFilter(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -15,6 +15,8 @@ const (
|
||||||
TypeVolume Type = "volume"
|
TypeVolume Type = "volume"
|
||||||
// TypeTmpfs is the type for mounting tmpfs
|
// TypeTmpfs is the type for mounting tmpfs
|
||||||
TypeTmpfs Type = "tmpfs"
|
TypeTmpfs Type = "tmpfs"
|
||||||
|
// TypeNamedPipe is the type for mounting Windows named pipes
|
||||||
|
TypeNamedPipe Type = "npipe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mount represents a mount (volume).
|
// Mount represents a mount (volume).
|
||||||
|
@ -65,7 +67,7 @@ var Propagations = []Propagation{
|
||||||
type Consistency string
|
type Consistency string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ConsistencyFull guarantees bind-mount-like consistency
|
// ConsistencyFull guarantees bind mount-like consistency
|
||||||
ConsistencyFull Consistency = "consistent"
|
ConsistencyFull Consistency = "consistent"
|
||||||
// ConsistencyCached mounts can cache read data and FS structure
|
// ConsistencyCached mounts can cache read data and FS structure
|
||||||
ConsistencyCached Consistency = "cached"
|
ConsistencyCached Consistency = "cached"
|
||||||
|
|
|
@ -11,7 +11,7 @@ type Plugin struct {
|
||||||
// Required: true
|
// Required: true
|
||||||
Config PluginConfig `json:"Config"`
|
Config PluginConfig `json:"Config"`
|
||||||
|
|
||||||
// True when the plugin is running. False when the plugin is not running, only installed.
|
// True if the plugin is running. False if the plugin is not running, only installed.
|
||||||
// Required: true
|
// Required: true
|
||||||
Enabled bool `json:"Enabled"`
|
Enabled bool `json:"Enabled"`
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,6 @@ import (
|
||||||
// PluginsListResponse contains the response for the Engine API
|
// PluginsListResponse contains the response for the Engine API
|
||||||
type PluginsListResponse []*Plugin
|
type PluginsListResponse []*Plugin
|
||||||
|
|
||||||
const (
|
|
||||||
authzDriver = "AuthzDriver"
|
|
||||||
graphDriver = "GraphDriver"
|
|
||||||
ipamDriver = "IpamDriver"
|
|
||||||
networkDriver = "NetworkDriver"
|
|
||||||
volumeDriver = "VolumeDriver"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
|
// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
|
||||||
func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
|
func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
|
||||||
versionIndex := len(p)
|
versionIndex := len(p)
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Annotations struct {
|
||||||
Labels map[string]string `json:"Labels"`
|
Labels map[string]string `json:"Labels"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Driver represents a driver (network, logging).
|
// Driver represents a driver (network, logging, secrets backend).
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
Name string `json:",omitempty"`
|
Name string `json:",omitempty"`
|
||||||
Options map[string]string `json:",omitempty"`
|
Options map[string]string `json:",omitempty"`
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
//go:generate protoc -I . --gogofast_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto
|
||||||
|
|
||||||
|
package runtime
|
712
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go
generated
vendored
Normal file
712
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,712 @@
|
||||||
|
// Code generated by protoc-gen-gogo.
|
||||||
|
// source: plugin.proto
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package runtime is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
plugin.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
PluginSpec
|
||||||
|
PluginPrivilege
|
||||||
|
*/
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import proto "github.com/gogo/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import io "io"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// PluginSpec defines the base payload which clients can specify for creating
|
||||||
|
// a service with the plugin runtime.
|
||||||
|
type PluginSpec struct {
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"`
|
||||||
|
Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges" json:"privileges,omitempty"`
|
||||||
|
Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginSpec) Reset() { *m = PluginSpec{} }
|
||||||
|
func (m *PluginSpec) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*PluginSpec) ProtoMessage() {}
|
||||||
|
func (*PluginSpec) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} }
|
||||||
|
|
||||||
|
func (m *PluginSpec) GetName() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginSpec) GetRemote() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Remote
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginSpec) GetPrivileges() []*PluginPrivilege {
|
||||||
|
if m != nil {
|
||||||
|
return m.Privileges
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginSpec) GetDisabled() bool {
|
||||||
|
if m != nil {
|
||||||
|
return m.Disabled
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginPrivilege describes a permission the user has to accept
|
||||||
|
// upon installing a plugin.
|
||||||
|
type PluginPrivilege struct {
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
|
||||||
|
Value []string `protobuf:"bytes,3,rep,name=value" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) Reset() { *m = PluginPrivilege{} }
|
||||||
|
func (m *PluginPrivilege) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*PluginPrivilege) ProtoMessage() {}
|
||||||
|
func (*PluginPrivilege) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} }
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) GetName() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) GetDescription() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Description
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) GetValue() []string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*PluginSpec)(nil), "PluginSpec")
|
||||||
|
proto.RegisterType((*PluginPrivilege)(nil), "PluginPrivilege")
|
||||||
|
}
|
||||||
|
func (m *PluginSpec) Marshal() (dAtA []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
dAtA = make([]byte, size)
|
||||||
|
n, err := m.MarshalTo(dAtA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dAtA[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
var i int
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Name) > 0 {
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
i++
|
||||||
|
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
|
||||||
|
i += copy(dAtA[i:], m.Name)
|
||||||
|
}
|
||||||
|
if len(m.Remote) > 0 {
|
||||||
|
dAtA[i] = 0x12
|
||||||
|
i++
|
||||||
|
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Remote)))
|
||||||
|
i += copy(dAtA[i:], m.Remote)
|
||||||
|
}
|
||||||
|
if len(m.Privileges) > 0 {
|
||||||
|
for _, msg := range m.Privileges {
|
||||||
|
dAtA[i] = 0x1a
|
||||||
|
i++
|
||||||
|
i = encodeVarintPlugin(dAtA, i, uint64(msg.Size()))
|
||||||
|
n, err := msg.MarshalTo(dAtA[i:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i += n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if m.Disabled {
|
||||||
|
dAtA[i] = 0x20
|
||||||
|
i++
|
||||||
|
if m.Disabled {
|
||||||
|
dAtA[i] = 1
|
||||||
|
} else {
|
||||||
|
dAtA[i] = 0
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) Marshal() (dAtA []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
dAtA = make([]byte, size)
|
||||||
|
n, err := m.MarshalTo(dAtA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dAtA[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
var i int
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Name) > 0 {
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
i++
|
||||||
|
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
|
||||||
|
i += copy(dAtA[i:], m.Name)
|
||||||
|
}
|
||||||
|
if len(m.Description) > 0 {
|
||||||
|
dAtA[i] = 0x12
|
||||||
|
i++
|
||||||
|
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Description)))
|
||||||
|
i += copy(dAtA[i:], m.Description)
|
||||||
|
}
|
||||||
|
if len(m.Value) > 0 {
|
||||||
|
for _, s := range m.Value {
|
||||||
|
dAtA[i] = 0x1a
|
||||||
|
i++
|
||||||
|
l = len(s)
|
||||||
|
for l >= 1<<7 {
|
||||||
|
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
|
||||||
|
l >>= 7
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
dAtA[i] = uint8(l)
|
||||||
|
i++
|
||||||
|
i += copy(dAtA[i:], s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeFixed64Plugin(dAtA []byte, offset int, v uint64) int {
|
||||||
|
dAtA[offset] = uint8(v)
|
||||||
|
dAtA[offset+1] = uint8(v >> 8)
|
||||||
|
dAtA[offset+2] = uint8(v >> 16)
|
||||||
|
dAtA[offset+3] = uint8(v >> 24)
|
||||||
|
dAtA[offset+4] = uint8(v >> 32)
|
||||||
|
dAtA[offset+5] = uint8(v >> 40)
|
||||||
|
dAtA[offset+6] = uint8(v >> 48)
|
||||||
|
dAtA[offset+7] = uint8(v >> 56)
|
||||||
|
return offset + 8
|
||||||
|
}
|
||||||
|
func encodeFixed32Plugin(dAtA []byte, offset int, v uint32) int {
|
||||||
|
dAtA[offset] = uint8(v)
|
||||||
|
dAtA[offset+1] = uint8(v >> 8)
|
||||||
|
dAtA[offset+2] = uint8(v >> 16)
|
||||||
|
dAtA[offset+3] = uint8(v >> 24)
|
||||||
|
return offset + 4
|
||||||
|
}
|
||||||
|
func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int {
|
||||||
|
for v >= 1<<7 {
|
||||||
|
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||||
|
v >>= 7
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
dAtA[offset] = uint8(v)
|
||||||
|
return offset + 1
|
||||||
|
}
|
||||||
|
func (m *PluginSpec) Size() (n int) {
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
l = len(m.Name)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovPlugin(uint64(l))
|
||||||
|
}
|
||||||
|
l = len(m.Remote)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovPlugin(uint64(l))
|
||||||
|
}
|
||||||
|
if len(m.Privileges) > 0 {
|
||||||
|
for _, e := range m.Privileges {
|
||||||
|
l = e.Size()
|
||||||
|
n += 1 + l + sovPlugin(uint64(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if m.Disabled {
|
||||||
|
n += 2
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginPrivilege) Size() (n int) {
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
l = len(m.Name)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovPlugin(uint64(l))
|
||||||
|
}
|
||||||
|
l = len(m.Description)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovPlugin(uint64(l))
|
||||||
|
}
|
||||||
|
if len(m.Value) > 0 {
|
||||||
|
for _, s := range m.Value {
|
||||||
|
l = len(s)
|
||||||
|
n += 1 + l + sovPlugin(uint64(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func sovPlugin(x uint64) (n int) {
|
||||||
|
for {
|
||||||
|
n++
|
||||||
|
x >>= 7
|
||||||
|
if x == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
func sozPlugin(x uint64) (n int) {
|
||||||
|
return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||||
|
}
|
||||||
|
func (m *PluginSpec) Unmarshal(dAtA []byte) error {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: PluginSpec: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: PluginSpec: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Name = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 2:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Remote = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 3:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType)
|
||||||
|
}
|
||||||
|
var msglen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
msglen |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if msglen < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + msglen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Privileges = append(m.Privileges, &PluginPrivilege{})
|
||||||
|
if err := m.Privileges[len(m.Privileges)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 4:
|
||||||
|
if wireType != 0 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType)
|
||||||
|
}
|
||||||
|
var v int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
v |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Disabled = bool(v != 0)
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipPlugin(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *PluginPrivilege) Unmarshal(dAtA []byte) error {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: PluginPrivilege: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: PluginPrivilege: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Name = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 2:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Description = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 3:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Value = append(m.Value, string(dAtA[iNdEx:postIndex]))
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipPlugin(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func skipPlugin(dAtA []byte) (n int, err error) {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
switch wireType {
|
||||||
|
case 0:
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx++
|
||||||
|
if dAtA[iNdEx-1] < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 1:
|
||||||
|
iNdEx += 8
|
||||||
|
return iNdEx, nil
|
||||||
|
case 2:
|
||||||
|
var length int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
length |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iNdEx += length
|
||||||
|
if length < 0 {
|
||||||
|
return 0, ErrInvalidLengthPlugin
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 3:
|
||||||
|
for {
|
||||||
|
var innerWire uint64
|
||||||
|
var start int = iNdEx
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowPlugin
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
innerWire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
innerWireType := int(innerWire & 0x7)
|
||||||
|
if innerWireType == 4 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
next, err := skipPlugin(dAtA[start:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
iNdEx = start + next
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 4:
|
||||||
|
return iNdEx, nil
|
||||||
|
case 5:
|
||||||
|
iNdEx += 4
|
||||||
|
return iNdEx, nil
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||||
|
ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) }
|
||||||
|
|
||||||
|
var fileDescriptorPlugin = []byte{
|
||||||
|
// 196 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d,
|
||||||
|
0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x6a, 0x63, 0xe4, 0xe2, 0x0a, 0x00, 0x0b,
|
||||||
|
0x04, 0x17, 0xa4, 0x26, 0x0b, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30,
|
||||||
|
0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x62, 0x5c, 0x6c, 0x45, 0xa9, 0xb9, 0xf9, 0x25, 0xa9, 0x12,
|
||||||
|
0x4c, 0x60, 0x51, 0x28, 0x4f, 0xc8, 0x80, 0x8b, 0xab, 0xa0, 0x28, 0xb3, 0x2c, 0x33, 0x27, 0x35,
|
||||||
|
0x3d, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x40, 0x0f, 0x62, 0x58, 0x00, 0x4c,
|
||||||
|
0x22, 0x08, 0x49, 0x8d, 0x90, 0x14, 0x17, 0x47, 0x4a, 0x66, 0x71, 0x62, 0x52, 0x4e, 0x6a, 0x8a,
|
||||||
|
0x04, 0x8b, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x9c, 0xaf, 0x14, 0xcb, 0xc5, 0x8f, 0xa6, 0x15, 0xab,
|
||||||
|
0x63, 0x14, 0xb8, 0xb8, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x32, 0xf3, 0xf3, 0xa0,
|
||||||
|
0x2e, 0x42, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0xbb, 0x88, 0x33,
|
||||||
|
0x08, 0xc2, 0x71, 0xe2, 0x39, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
|
||||||
|
0x18, 0x93, 0xd8, 0xc0, 0x9e, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb8, 0x84, 0xad, 0x79,
|
||||||
|
0x0c, 0x01, 0x00, 0x00,
|
||||||
|
}
|
18
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto
generated
vendored
Normal file
18
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
// PluginSpec defines the base payload which clients can specify for creating
|
||||||
|
// a service with the plugin runtime.
|
||||||
|
message PluginSpec {
|
||||||
|
string name = 1;
|
||||||
|
string remote = 2;
|
||||||
|
repeated PluginPrivilege privileges = 3;
|
||||||
|
bool disabled = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginPrivilege describes a permission the user has to accept
|
||||||
|
// upon installing a plugin.
|
||||||
|
message PluginPrivilege {
|
||||||
|
string name = 1;
|
||||||
|
string description = 2;
|
||||||
|
repeated string value = 3;
|
||||||
|
}
|
|
@ -12,7 +12,8 @@ type Secret struct {
|
||||||
// SecretSpec represents a secret specification from a secret in swarm
|
// SecretSpec represents a secret specification from a secret in swarm
|
||||||
type SecretSpec struct {
|
type SecretSpec struct {
|
||||||
Annotations
|
Annotations
|
||||||
Data []byte `json:",omitempty"`
|
Data []byte `json:",omitempty"`
|
||||||
|
Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretReferenceFileTarget is a file target in a secret reference
|
// SecretReferenceFileTarget is a file target in a secret reference
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package swarm
|
package swarm
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/swarm/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
// TaskState represents the state of a task.
|
// TaskState represents the state of a task.
|
||||||
type TaskState string
|
type TaskState string
|
||||||
|
@ -47,11 +51,16 @@ type Task struct {
|
||||||
Status TaskStatus `json:",omitempty"`
|
Status TaskStatus `json:",omitempty"`
|
||||||
DesiredState TaskState `json:",omitempty"`
|
DesiredState TaskState `json:",omitempty"`
|
||||||
NetworksAttachments []NetworkAttachment `json:",omitempty"`
|
NetworksAttachments []NetworkAttachment `json:",omitempty"`
|
||||||
|
GenericResources []GenericResource `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TaskSpec represents the spec of a task.
|
// TaskSpec represents the spec of a task.
|
||||||
type TaskSpec struct {
|
type TaskSpec struct {
|
||||||
ContainerSpec ContainerSpec `json:",omitempty"`
|
// ContainerSpec and PluginSpec are mutually exclusive.
|
||||||
|
// PluginSpec will only be used when the `Runtime` field is set to `plugin`
|
||||||
|
ContainerSpec *ContainerSpec `json:",omitempty"`
|
||||||
|
PluginSpec *runtime.PluginSpec `json:",omitempty"`
|
||||||
|
|
||||||
Resources *ResourceRequirements `json:",omitempty"`
|
Resources *ResourceRequirements `json:",omitempty"`
|
||||||
RestartPolicy *RestartPolicy `json:",omitempty"`
|
RestartPolicy *RestartPolicy `json:",omitempty"`
|
||||||
Placement *Placement `json:",omitempty"`
|
Placement *Placement `json:",omitempty"`
|
||||||
|
@ -71,8 +80,34 @@ type TaskSpec struct {
|
||||||
|
|
||||||
// Resources represents resources (CPU/Memory).
|
// Resources represents resources (CPU/Memory).
|
||||||
type Resources struct {
|
type Resources struct {
|
||||||
NanoCPUs int64 `json:",omitempty"`
|
NanoCPUs int64 `json:",omitempty"`
|
||||||
MemoryBytes int64 `json:",omitempty"`
|
MemoryBytes int64 `json:",omitempty"`
|
||||||
|
GenericResources []GenericResource `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericResource represents a "user defined" resource which can
|
||||||
|
// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
|
||||||
|
type GenericResource struct {
|
||||||
|
NamedResourceSpec *NamedGenericResource `json:",omitempty"`
|
||||||
|
DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamedGenericResource represents a "user defined" resource which is defined
|
||||||
|
// as a string.
|
||||||
|
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
|
||||||
|
// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
|
||||||
|
type NamedGenericResource struct {
|
||||||
|
Kind string `json:",omitempty"`
|
||||||
|
Value string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscreteGenericResource represents a "user defined" resource which is defined
|
||||||
|
// as an integer
|
||||||
|
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
|
||||||
|
// Value is used to count the resource (SSD=5, HDD=3, ...)
|
||||||
|
type DiscreteGenericResource struct {
|
||||||
|
Kind string `json:",omitempty"`
|
||||||
|
Value int64 `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceRequirements represents resources requirements.
|
// ResourceRequirements represents resources requirements.
|
||||||
|
|
|
@ -168,6 +168,7 @@ type Info struct {
|
||||||
RegistryConfig *registry.ServiceConfig
|
RegistryConfig *registry.ServiceConfig
|
||||||
NCPU int
|
NCPU int
|
||||||
MemTotal int64
|
MemTotal int64
|
||||||
|
GenericResources []swarm.GenericResource
|
||||||
DockerRootDir string
|
DockerRootDir string
|
||||||
HTTPProxy string `json:"HttpProxy"`
|
HTTPProxy string `json:"HttpProxy"`
|
||||||
HTTPSProxy string `json:"HttpsProxy"`
|
HTTPSProxy string `json:"HttpsProxy"`
|
||||||
|
|
|
@ -7,7 +7,7 @@ package types
|
||||||
// swagger:model Volume
|
// swagger:model Volume
|
||||||
type Volume struct {
|
type Volume struct {
|
||||||
|
|
||||||
// Time volume was created.
|
// Date/Time the volume was created.
|
||||||
CreatedAt string `json:"CreatedAt,omitempty"`
|
CreatedAt string `json:"CreatedAt,omitempty"`
|
||||||
|
|
||||||
// Name of the volume driver used by the volume.
|
// Name of the volume driver used by the volume.
|
||||||
|
@ -47,15 +47,23 @@ type Volume struct {
|
||||||
UsageData *VolumeUsageData `json:"UsageData,omitempty"`
|
UsageData *VolumeUsageData `json:"UsageData,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeUsageData volume usage data
|
// VolumeUsageData Usage details about the volume. This information is used by the
|
||||||
|
// `GET /system/df` endpoint, and omitted in other endpoints.
|
||||||
|
//
|
||||||
// swagger:model VolumeUsageData
|
// swagger:model VolumeUsageData
|
||||||
type VolumeUsageData struct {
|
type VolumeUsageData struct {
|
||||||
|
|
||||||
// The number of containers referencing this volume.
|
// The number of containers referencing this volume. This field
|
||||||
|
// is set to `-1` if the reference-count is not available.
|
||||||
|
//
|
||||||
// Required: true
|
// Required: true
|
||||||
RefCount int64 `json:"RefCount"`
|
RefCount int64 `json:"RefCount"`
|
||||||
|
|
||||||
// The disk space used by the volume (local driver only)
|
// Amount of disk space used by the volume (in bytes). This information
|
||||||
|
// is only available for volumes created with the `"local"` volume
|
||||||
|
// driver. For volumes created with other volume drivers, this field
|
||||||
|
// is set to `-1` ("not available")
|
||||||
|
//
|
||||||
// Required: true
|
// Required: true
|
||||||
Size int64 `json:"Size"`
|
Size int64 `json:"Size"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -98,22 +97,46 @@ func getRefAndSubdir(fragment string) (ref string, subdir string) {
|
||||||
|
|
||||||
func fetchArgs(remoteURL string, ref string) []string {
|
func fetchArgs(remoteURL string, ref string) []string {
|
||||||
args := []string{"fetch", "--recurse-submodules=yes"}
|
args := []string{"fetch", "--recurse-submodules=yes"}
|
||||||
shallow := true
|
|
||||||
|
|
||||||
if urlutil.IsURL(remoteURL) {
|
if supportsShallowClone(remoteURL) {
|
||||||
res, err := http.Head(fmt.Sprintf("%s/info/refs?service=git-upload-pack", remoteURL))
|
|
||||||
if err != nil || res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
|
|
||||||
shallow = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if shallow {
|
|
||||||
args = append(args, "--depth", "1")
|
args = append(args, "--depth", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(args, "origin", ref)
|
return append(args, "origin", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a given git URL supports a shallow git clone,
|
||||||
|
// i.e. it is a non-HTTP server or a smart HTTP server.
|
||||||
|
func supportsShallowClone(remoteURL string) bool {
|
||||||
|
if urlutil.IsURL(remoteURL) {
|
||||||
|
// Check if the HTTP server is smart
|
||||||
|
|
||||||
|
// Smart servers must correctly respond to a query for the git-upload-pack service
|
||||||
|
serviceURL := remoteURL + "/info/refs?service=git-upload-pack"
|
||||||
|
|
||||||
|
// Try a HEAD request and fallback to a Get request on error
|
||||||
|
res, err := http.Head(serviceURL)
|
||||||
|
if err != nil || res.StatusCode != http.StatusOK {
|
||||||
|
res, err = http.Get(serviceURL)
|
||||||
|
if err == nil {
|
||||||
|
res.Body.Close()
|
||||||
|
}
|
||||||
|
if err != nil || res.StatusCode != http.StatusOK {
|
||||||
|
// request failed
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
|
||||||
|
// Fallback, not a smart server
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Non-HTTP protocols always support shallow clones
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func checkoutGit(root, ref, subdir string) (string, error) {
|
func checkoutGit(root, ref, subdir string) (string, error) {
|
||||||
// Try checking out by ref name first. This will work on branches and sets
|
// Try checking out by ref name first. This will work on branches and sets
|
||||||
// .git/HEAD to the current branch name
|
// .git/HEAD to the current branch name
|
||||||
|
|
|
@ -51,6 +51,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map
|
||||||
}
|
}
|
||||||
|
|
||||||
if client != nil {
|
if client != nil {
|
||||||
if _, ok := client.Transport.(*http.Transport); !ok {
|
if _, ok := client.Transport.(http.RoundTripper); !ok {
|
||||||
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport)
|
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -219,9 +220,9 @@ func (cli *Client) getAPIPath(p string, query url.Values) string {
|
||||||
var apiPath string
|
var apiPath string
|
||||||
if cli.version != "" {
|
if cli.version != "" {
|
||||||
v := strings.TrimPrefix(cli.version, "v")
|
v := strings.TrimPrefix(cli.version, "v")
|
||||||
apiPath = cli.basePath + "/v" + v + p
|
apiPath = path.Join(cli.basePath, "/v"+v+p)
|
||||||
} else {
|
} else {
|
||||||
apiPath = cli.basePath + p
|
apiPath = path.Join(cli.basePath, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
|
|
|
@ -228,7 +228,7 @@ func IsErrPluginPermissionDenied(err error) bool {
|
||||||
// NewVersionError returns an error if the APIVersion required
|
// NewVersionError returns an error if the APIVersion required
|
||||||
// if less than the current supported version
|
// if less than the current supported version
|
||||||
func (cli *Client) NewVersionError(APIrequired, feature string) error {
|
func (cli *Client) NewVersionError(APIrequired, feature string) error {
|
||||||
if versions.LessThan(cli.version, APIrequired) {
|
if cli.version != "" && versions.LessThan(cli.version, APIrequired) {
|
||||||
return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version)
|
return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -177,12 +177,14 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, e
|
||||||
|
|
||||||
// Server hijacks the connection, error 'connection closed' expected
|
// Server hijacks the connection, error 'connection closed' expected
|
||||||
resp, err := clientconn.Do(req)
|
resp, err := clientconn.Do(req)
|
||||||
if err != nil {
|
if err != httputil.ErrPersistEOF {
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
if resp.StatusCode != http.StatusSwitchingProtocols {
|
}
|
||||||
resp.Body.Close()
|
if resp.StatusCode != http.StatusSwitchingProtocols {
|
||||||
return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
|
resp.Body.Close()
|
||||||
|
return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c, br := clientconn.Hijack()
|
c, br := clientconn.Hijack()
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
@ -21,6 +22,9 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type
|
||||||
|
|
||||||
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
|
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if resp.statusCode == http.StatusNotFound {
|
||||||
|
return nil, imageNotFoundError{imageID}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
@ -8,7 +10,7 @@ import (
|
||||||
// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers
|
// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers
|
||||||
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
||||||
var ping types.Ping
|
var ping types.Ping
|
||||||
req, err := cli.buildRequest("GET", cli.basePath+"/_ping", nil, nil)
|
req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ping, err
|
return ping, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,24 +24,51 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
|
||||||
headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
|
headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure that the image is tagged
|
// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container
|
||||||
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
|
if service.TaskTemplate.ContainerSpec == nil && (service.TaskTemplate.Runtime == "" || service.TaskTemplate.Runtime == swarm.RuntimeContainer) {
|
||||||
service.TaskTemplate.ContainerSpec.Image = taggedImg
|
service.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contact the registry to retrieve digest and platform information
|
if err := validateServiceSpec(service); err != nil {
|
||||||
if options.QueryRegistry {
|
return types.ServiceCreateResponse{}, err
|
||||||
distributionInspect, err := cli.DistributionInspect(ctx, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
|
}
|
||||||
distErr = err
|
|
||||||
if err == nil {
|
// ensure that the image is tagged
|
||||||
// now pin by digest if the image doesn't already contain a digest
|
var imgPlatforms []swarm.Platform
|
||||||
if img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest); img != "" {
|
if service.TaskTemplate.ContainerSpec != nil {
|
||||||
|
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
|
||||||
|
service.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||||
|
}
|
||||||
|
if options.QueryRegistry {
|
||||||
|
var img string
|
||||||
|
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
|
||||||
|
if img != "" {
|
||||||
service.TaskTemplate.ContainerSpec.Image = img
|
service.TaskTemplate.ContainerSpec.Image = img
|
||||||
}
|
}
|
||||||
// add platforms that are compatible with the service
|
|
||||||
service.TaskTemplate.Placement = setServicePlatforms(service.TaskTemplate.Placement, distributionInspect)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that the image is tagged
|
||||||
|
if service.TaskTemplate.PluginSpec != nil {
|
||||||
|
if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
|
||||||
|
service.TaskTemplate.PluginSpec.Remote = taggedImg
|
||||||
|
}
|
||||||
|
if options.QueryRegistry {
|
||||||
|
var img string
|
||||||
|
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.PluginSpec.Remote, options.EncodedRegistryAuth)
|
||||||
|
if img != "" {
|
||||||
|
service.TaskTemplate.PluginSpec.Remote = img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if service.TaskTemplate.Placement == nil && len(imgPlatforms) > 0 {
|
||||||
|
service.TaskTemplate.Placement = &swarm.Placement{}
|
||||||
|
}
|
||||||
|
if len(imgPlatforms) > 0 {
|
||||||
|
service.TaskTemplate.Placement.Platforms = imgPlatforms
|
||||||
|
}
|
||||||
|
|
||||||
var response types.ServiceCreateResponse
|
var response types.ServiceCreateResponse
|
||||||
resp, err := cli.post(ctx, "/services/create", nil, service, headers)
|
resp, err := cli.post(ctx, "/services/create", nil, service, headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,6 +85,28 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func imageDigestAndPlatforms(ctx context.Context, cli *Client, image, encodedAuth string) (string, []swarm.Platform, error) {
|
||||||
|
distributionInspect, err := cli.DistributionInspect(ctx, image, encodedAuth)
|
||||||
|
imageWithDigest := image
|
||||||
|
var platforms []swarm.Platform
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
imageWithDigest = imageWithDigestString(image, distributionInspect.Descriptor.Digest)
|
||||||
|
|
||||||
|
if len(distributionInspect.Platforms) > 0 {
|
||||||
|
platforms = make([]swarm.Platform, 0, len(distributionInspect.Platforms))
|
||||||
|
for _, p := range distributionInspect.Platforms {
|
||||||
|
platforms = append(platforms, swarm.Platform{
|
||||||
|
Architecture: p.Architecture,
|
||||||
|
OS: p.OS,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imageWithDigest, platforms, err
|
||||||
|
}
|
||||||
|
|
||||||
// imageWithDigestString takes an image string and a digest, and updates
|
// imageWithDigestString takes an image string and a digest, and updates
|
||||||
// the image string if it didn't originally contain a digest. It returns
|
// the image string if it didn't originally contain a digest. It returns
|
||||||
// an empty string if there are no updates.
|
// an empty string if there are no updates.
|
||||||
|
@ -86,27 +135,22 @@ func imageWithTagString(image string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// setServicePlatforms sets Platforms in swarm.Placement to list all
|
|
||||||
// compatible platforms for the service, as found in distributionInspect
|
|
||||||
// and returns a pointer to the new or updated swarm.Placement struct.
|
|
||||||
func setServicePlatforms(placement *swarm.Placement, distributionInspect registrytypes.DistributionInspect) *swarm.Placement {
|
|
||||||
if placement == nil {
|
|
||||||
placement = &swarm.Placement{}
|
|
||||||
}
|
|
||||||
// reset any existing listed platforms
|
|
||||||
placement.Platforms = []swarm.Platform{}
|
|
||||||
for _, p := range distributionInspect.Platforms {
|
|
||||||
placement.Platforms = append(placement.Platforms, swarm.Platform{
|
|
||||||
Architecture: p.Architecture,
|
|
||||||
OS: p.OS,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return placement
|
|
||||||
}
|
|
||||||
|
|
||||||
// digestWarning constructs a formatted warning string using the
|
// digestWarning constructs a formatted warning string using the
|
||||||
// image name that could not be pinned by digest. The formatting
|
// image name that could not be pinned by digest. The formatting
|
||||||
// is hardcoded, but could me made smarter in the future
|
// is hardcoded, but could me made smarter in the future
|
||||||
func digestWarning(image string) string {
|
func digestWarning(image string) string {
|
||||||
return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image)
|
return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateServiceSpec(s swarm.ServiceSpec) error {
|
||||||
|
if s.TaskTemplate.ContainerSpec != nil && s.TaskTemplate.PluginSpec != nil {
|
||||||
|
return errors.New("must not specify both a container spec and a plugin spec in the task template")
|
||||||
|
}
|
||||||
|
if s.TaskTemplate.PluginSpec != nil && s.TaskTemplate.Runtime != swarm.RuntimePlugin {
|
||||||
|
return errors.New("mismatched runtime with plugin spec")
|
||||||
|
}
|
||||||
|
if s.TaskTemplate.ContainerSpec != nil && (s.TaskTemplate.Runtime != "" && s.TaskTemplate.Runtime != swarm.RuntimeContainer) {
|
||||||
|
return errors.New("mismatched runtime with container spec")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -35,26 +35,46 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
|
||||||
|
|
||||||
query.Set("version", strconv.FormatUint(version.Index, 10))
|
query.Set("version", strconv.FormatUint(version.Index, 10))
|
||||||
|
|
||||||
// ensure that the image is tagged
|
if err := validateServiceSpec(service); err != nil {
|
||||||
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
|
return types.ServiceUpdateResponse{}, err
|
||||||
service.TaskTemplate.ContainerSpec.Image = taggedImg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contact the registry to retrieve digest and platform information
|
var imgPlatforms []swarm.Platform
|
||||||
// This happens only when the image has changed
|
// ensure that the image is tagged
|
||||||
if options.QueryRegistry {
|
if service.TaskTemplate.ContainerSpec != nil {
|
||||||
distributionInspect, err := cli.DistributionInspect(ctx, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
|
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
|
||||||
distErr = err
|
service.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||||
if err == nil {
|
}
|
||||||
// now pin by digest if the image doesn't already contain a digest
|
if options.QueryRegistry {
|
||||||
if img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest); img != "" {
|
var img string
|
||||||
|
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
|
||||||
|
if img != "" {
|
||||||
service.TaskTemplate.ContainerSpec.Image = img
|
service.TaskTemplate.ContainerSpec.Image = img
|
||||||
}
|
}
|
||||||
// add platforms that are compatible with the service
|
|
||||||
service.TaskTemplate.Placement = setServicePlatforms(service.TaskTemplate.Placement, distributionInspect)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that the image is tagged
|
||||||
|
if service.TaskTemplate.PluginSpec != nil {
|
||||||
|
if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
|
||||||
|
service.TaskTemplate.PluginSpec.Remote = taggedImg
|
||||||
|
}
|
||||||
|
if options.QueryRegistry {
|
||||||
|
var img string
|
||||||
|
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.PluginSpec.Remote, options.EncodedRegistryAuth)
|
||||||
|
if img != "" {
|
||||||
|
service.TaskTemplate.PluginSpec.Remote = img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if service.TaskTemplate.Placement == nil && len(imgPlatforms) > 0 {
|
||||||
|
service.TaskTemplate.Placement = &swarm.Placement{}
|
||||||
|
}
|
||||||
|
if len(imgPlatforms) > 0 {
|
||||||
|
service.TaskTemplate.Placement.Platforms = imgPlatforms
|
||||||
|
}
|
||||||
|
|
||||||
var response types.ServiceUpdateResponse
|
var response types.ServiceUpdateResponse
|
||||||
resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
|
resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,14 +5,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// transportFunc allows us to inject a mock transport for testing. We define it
|
|
||||||
// here so we can detect the tlsconfig and return nil for only this type.
|
|
||||||
type transportFunc func(*http.Request) (*http.Response, error)
|
|
||||||
|
|
||||||
func (tf transportFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
return tf(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveTLSConfig attempts to resolve the TLS configuration from the
|
// resolveTLSConfig attempts to resolve the TLS configuration from the
|
||||||
// RoundTripper.
|
// RoundTripper.
|
||||||
func resolveTLSConfig(transport http.RoundTripper) *tls.Config {
|
func resolveTLSConfig(transport http.RoundTripper) *tls.Config {
|
||||||
|
|
|
@ -18,14 +18,6 @@ Generates AUTHORS; a file with all the names and corresponding emails of
|
||||||
individual contributors. AUTHORS can be found in the home directory of
|
individual contributors. AUTHORS can be found in the home directory of
|
||||||
this repository.
|
this repository.
|
||||||
|
|
||||||
## Install (install.sh)
|
|
||||||
|
|
||||||
Executable install script for installing Docker. If updates to this are
|
|
||||||
desired, please use hack/release.sh during a normal release. The following
|
|
||||||
one-liner may be used for script hotfixes:
|
|
||||||
|
|
||||||
- `aws s3 cp --acl public-read hack/install.sh s3://get.docker.com/index`
|
|
||||||
|
|
||||||
## Make
|
## Make
|
||||||
|
|
||||||
There are two make files, each with different extensions. Neither are supposed
|
There are two make files, each with different extensions. Neither are supposed
|
||||||
|
@ -45,14 +37,14 @@ More information is found within `make.ps1` by the author, @jhowardmsft
|
||||||
- Referenced via `make test` when running tests on a local machine,
|
- Referenced via `make test` when running tests on a local machine,
|
||||||
or directly referenced when running tests inside a Docker development container.
|
or directly referenced when running tests inside a Docker development container.
|
||||||
- When running on a local machine, `make test` to run all tests found in
|
- When running on a local machine, `make test` to run all tests found in
|
||||||
`test`, `test-unit`, `test-integration-cli`, and `test-docker-py` on
|
`test`, `test-unit`, `test-integration`, and `test-docker-py` on
|
||||||
your local machine. The default timeout is set in `make.sh` to 60 minutes
|
your local machine. The default timeout is set in `make.sh` to 60 minutes
|
||||||
(`${TIMEOUT:=60m}`), since it currently takes up to an hour to run
|
(`${TIMEOUT:=60m}`), since it currently takes up to an hour to run
|
||||||
all of the tests.
|
all of the tests.
|
||||||
- When running inside a Docker development container, `hack/make.sh` does
|
- When running inside a Docker development container, `hack/make.sh` does
|
||||||
not have a single target that runs all the tests. You need to provide a
|
not have a single target that runs all the tests. You need to provide a
|
||||||
single command line with multiple targets that performs the same thing.
|
single command line with multiple targets that performs the same thing.
|
||||||
An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration-cli test-docker-py`
|
An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration test-docker-py`
|
||||||
- For more information related to testing outside the scope of this README,
|
- For more information related to testing outside the scope of this README,
|
||||||
refer to
|
refer to
|
||||||
[Run tests and test documentation](https://docs.docker.com/opensource/project/test-and-docs/)
|
[Run tests and test documentation](https://docs.docker.com/opensource/project/test-and-docs/)
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ValidateEnv validates an environment variable and returns it.
|
|
||||||
// If no value is specified, it returns the current value using os.Getenv.
|
|
||||||
//
|
|
||||||
// As on ParseEnvFile and related to #16585, environment variable names
|
|
||||||
// are not validate what so ever, it's up to application inside docker
|
|
||||||
// to validate them or not.
|
|
||||||
//
|
|
||||||
// The only validation here is to check if name is empty, per #25099
|
|
||||||
func ValidateEnv(val string) (string, error) {
|
|
||||||
arr := strings.Split(val, "=")
|
|
||||||
if arr[0] == "" {
|
|
||||||
return "", fmt.Errorf("invalid environment variable: %s", val)
|
|
||||||
}
|
|
||||||
if len(arr) > 1 {
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
if !doesEnvExist(val) {
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func doesEnvExist(name string) bool {
|
|
||||||
for _, entry := range os.Environ() {
|
|
||||||
parts := strings.SplitN(entry, "=", 2)
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
// Environment variable are case-insensitive on Windows. PaTh, path and PATH are equivalent.
|
|
||||||
if strings.EqualFold(parts[0], name) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if parts[0] == name {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -1,165 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. dockerd -H tcp://
|
|
||||||
// These are the IANA registered port numbers for use with Docker
|
|
||||||
// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
|
|
||||||
DefaultHTTPPort = 2375 // Default HTTP Port
|
|
||||||
// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
|
|
||||||
DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
|
|
||||||
// DefaultUnixSocket Path for the unix socket.
|
|
||||||
// Docker daemon by default always listens on the default unix socket
|
|
||||||
DefaultUnixSocket = "/var/run/docker.sock"
|
|
||||||
// DefaultTCPHost constant defines the default host string used by docker on Windows
|
|
||||||
DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
|
|
||||||
// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
|
|
||||||
DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
|
|
||||||
// DefaultNamedPipe defines the default named pipe used by docker on Windows
|
|
||||||
DefaultNamedPipe = `//./pipe/docker_engine`
|
|
||||||
)
|
|
||||||
|
|
||||||
// ValidateHost validates that the specified string is a valid host and returns it.
|
|
||||||
func ValidateHost(val string) (string, error) {
|
|
||||||
host := strings.TrimSpace(val)
|
|
||||||
// The empty string means default and is not handled by parseDockerDaemonHost
|
|
||||||
if host != "" {
|
|
||||||
_, err := parseDockerDaemonHost(host)
|
|
||||||
if err != nil {
|
|
||||||
return val, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Note: unlike most flag validators, we don't return the mutated value here
|
|
||||||
// we need to know what the user entered later (using ParseHost) to adjust for TLS
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseHost and set defaults for a Daemon host string
|
|
||||||
func ParseHost(defaultToTLS bool, val string) (string, error) {
|
|
||||||
host := strings.TrimSpace(val)
|
|
||||||
if host == "" {
|
|
||||||
if defaultToTLS {
|
|
||||||
host = DefaultTLSHost
|
|
||||||
} else {
|
|
||||||
host = DefaultHost
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
host, err = parseDockerDaemonHost(host)
|
|
||||||
if err != nil {
|
|
||||||
return val, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return host, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseDockerDaemonHost parses the specified address and returns an address that will be used as the host.
|
|
||||||
// Depending of the address specified, this may return one of the global Default* strings defined in hosts.go.
|
|
||||||
func parseDockerDaemonHost(addr string) (string, error) {
|
|
||||||
addrParts := strings.SplitN(addr, "://", 2)
|
|
||||||
if len(addrParts) == 1 && addrParts[0] != "" {
|
|
||||||
addrParts = []string{"tcp", addrParts[0]}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch addrParts[0] {
|
|
||||||
case "tcp":
|
|
||||||
return ParseTCPAddr(addrParts[1], DefaultTCPHost)
|
|
||||||
case "unix":
|
|
||||||
return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
|
|
||||||
case "npipe":
|
|
||||||
return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
|
|
||||||
case "fd":
|
|
||||||
return addr, nil
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("Invalid bind address format: %s", addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseSimpleProtoAddr parses and validates that the specified address is a valid
|
|
||||||
// socket address for simple protocols like unix and npipe. It returns a formatted
|
|
||||||
// socket address, either using the address parsed from addr, or the contents of
|
|
||||||
// defaultAddr if addr is a blank string.
|
|
||||||
func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
|
|
||||||
addr = strings.TrimPrefix(addr, proto+"://")
|
|
||||||
if strings.Contains(addr, "://") {
|
|
||||||
return "", fmt.Errorf("Invalid proto, expected %s: %s", proto, addr)
|
|
||||||
}
|
|
||||||
if addr == "" {
|
|
||||||
addr = defaultAddr
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s://%s", proto, addr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseTCPAddr parses and validates that the specified address is a valid TCP
|
|
||||||
// address. It returns a formatted TCP address, either using the address parsed
|
|
||||||
// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
|
|
||||||
// tryAddr is expected to have already been Trim()'d
|
|
||||||
// defaultAddr must be in the full `tcp://host:port` form
|
|
||||||
func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
|
|
||||||
if tryAddr == "" || tryAddr == "tcp://" {
|
|
||||||
return defaultAddr, nil
|
|
||||||
}
|
|
||||||
addr := strings.TrimPrefix(tryAddr, "tcp://")
|
|
||||||
if strings.Contains(addr, "://") || addr == "" {
|
|
||||||
return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://")
|
|
||||||
defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but
|
|
||||||
// not 1.4. See https://github.com/golang/go/issues/12200 and
|
|
||||||
// https://github.com/golang/go/issues/6530.
|
|
||||||
if strings.HasSuffix(addr, "]:") {
|
|
||||||
addr += defaultPort
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse("tcp://" + addr)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
// try port addition once
|
|
||||||
host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if host == "" {
|
|
||||||
host = defaultHost
|
|
||||||
}
|
|
||||||
if port == "" {
|
|
||||||
port = defaultPort
|
|
||||||
}
|
|
||||||
p, err := strconv.Atoi(port)
|
|
||||||
if err != nil && p == 0 {
|
|
||||||
return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateExtraHost validates that the specified string is a valid extrahost and returns it.
|
|
||||||
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (IPv4 or IPv6).
|
|
||||||
func ValidateExtraHost(val string) (string, error) {
|
|
||||||
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
|
|
||||||
arr := strings.SplitN(val, ":", 2)
|
|
||||||
if len(arr) != 2 || len(arr[0]) == 0 {
|
|
||||||
return "", fmt.Errorf("bad format for add-host: %q", val)
|
|
||||||
}
|
|
||||||
if _, err := ValidateIPAddress(arr[1]); err != nil {
|
|
||||||
return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
|
|
||||||
}
|
|
||||||
return val, nil
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package opts
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// DefaultHost constant defines the default host string used by docker on other hosts than Windows
|
|
||||||
var DefaultHost = fmt.Sprintf("unix://%s", DefaultUnixSocket)
|
|
|
@ -1,6 +0,0 @@
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package opts
|
|
||||||
|
|
||||||
// DefaultHost constant defines the default host string used by docker on Windows
|
|
||||||
var DefaultHost = "npipe://" + DefaultNamedPipe
|
|
|
@ -1,47 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IPOpt holds an IP. It is used to store values from CLI flags.
|
|
||||||
type IPOpt struct {
|
|
||||||
*net.IP
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewIPOpt creates a new IPOpt from a reference net.IP and a
|
|
||||||
// string representation of an IP. If the string is not a valid
|
|
||||||
// IP it will fallback to the specified reference.
|
|
||||||
func NewIPOpt(ref *net.IP, defaultVal string) *IPOpt {
|
|
||||||
o := &IPOpt{
|
|
||||||
IP: ref,
|
|
||||||
}
|
|
||||||
o.Set(defaultVal)
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sets an IPv4 or IPv6 address from a given string. If the given
|
|
||||||
// string is not parsable as an IP address it returns an error.
|
|
||||||
func (o *IPOpt) Set(val string) error {
|
|
||||||
ip := net.ParseIP(val)
|
|
||||||
if ip == nil {
|
|
||||||
return fmt.Errorf("%s is not an ip address", val)
|
|
||||||
}
|
|
||||||
*o.IP = ip
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the IP address stored in the IPOpt. If stored IP is a
|
|
||||||
// nil pointer, it returns an empty string.
|
|
||||||
func (o *IPOpt) String() string {
|
|
||||||
if *o.IP == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return o.IP.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the type of the option
|
|
||||||
func (o *IPOpt) Type() string {
|
|
||||||
return "ip"
|
|
||||||
}
|
|
|
@ -1,327 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"path"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
units "github.com/docker/go-units"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
|
|
||||||
domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// ListOpts holds a list of values and a validation function.
|
|
||||||
type ListOpts struct {
|
|
||||||
values *[]string
|
|
||||||
validator ValidatorFctType
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewListOpts creates a new ListOpts with the specified validator.
|
|
||||||
func NewListOpts(validator ValidatorFctType) ListOpts {
|
|
||||||
var values []string
|
|
||||||
return *NewListOptsRef(&values, validator)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewListOptsRef creates a new ListOpts with the specified values and validator.
|
|
||||||
func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
|
|
||||||
return &ListOpts{
|
|
||||||
values: values,
|
|
||||||
validator: validator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts *ListOpts) String() string {
|
|
||||||
if len(*opts.values) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%v", *opts.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set validates if needed the input value and adds it to the
|
|
||||||
// internal slice.
|
|
||||||
func (opts *ListOpts) Set(value string) error {
|
|
||||||
if opts.validator != nil {
|
|
||||||
v, err := opts.validator(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
value = v
|
|
||||||
}
|
|
||||||
(*opts.values) = append((*opts.values), value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes the specified element from the slice.
|
|
||||||
func (opts *ListOpts) Delete(key string) {
|
|
||||||
for i, k := range *opts.values {
|
|
||||||
if k == key {
|
|
||||||
(*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMap returns the content of values in a map in order to avoid
|
|
||||||
// duplicates.
|
|
||||||
func (opts *ListOpts) GetMap() map[string]struct{} {
|
|
||||||
ret := make(map[string]struct{})
|
|
||||||
for _, k := range *opts.values {
|
|
||||||
ret[k] = struct{}{}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAll returns the values of slice.
|
|
||||||
func (opts *ListOpts) GetAll() []string {
|
|
||||||
return (*opts.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllOrEmpty returns the values of the slice
|
|
||||||
// or an empty slice when there are no values.
|
|
||||||
func (opts *ListOpts) GetAllOrEmpty() []string {
|
|
||||||
v := *opts.values
|
|
||||||
if v == nil {
|
|
||||||
return make([]string, 0)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get checks the existence of the specified key.
|
|
||||||
func (opts *ListOpts) Get(key string) bool {
|
|
||||||
for _, k := range *opts.values {
|
|
||||||
if k == key {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the amount of element in the slice.
|
|
||||||
func (opts *ListOpts) Len() int {
|
|
||||||
return len((*opts.values))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns a string name for this Option type
|
|
||||||
func (opts *ListOpts) Type() string {
|
|
||||||
return "list"
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithValidator returns the ListOpts with validator set.
|
|
||||||
func (opts *ListOpts) WithValidator(validator ValidatorFctType) *ListOpts {
|
|
||||||
opts.validator = validator
|
|
||||||
return opts
|
|
||||||
}
|
|
||||||
|
|
||||||
// NamedOption is an interface that list and map options
|
|
||||||
// with names implement.
|
|
||||||
type NamedOption interface {
|
|
||||||
Name() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NamedListOpts is a ListOpts with a configuration name.
|
|
||||||
// This struct is useful to keep reference to the assigned
|
|
||||||
// field name in the internal configuration struct.
|
|
||||||
type NamedListOpts struct {
|
|
||||||
name string
|
|
||||||
ListOpts
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ NamedOption = &NamedListOpts{}
|
|
||||||
|
|
||||||
// NewNamedListOptsRef creates a reference to a new NamedListOpts struct.
|
|
||||||
func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts {
|
|
||||||
return &NamedListOpts{
|
|
||||||
name: name,
|
|
||||||
ListOpts: *NewListOptsRef(values, validator),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the NamedListOpts in the configuration.
|
|
||||||
func (o *NamedListOpts) Name() string {
|
|
||||||
return o.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapOpts holds a map of values and a validation function.
|
|
||||||
type MapOpts struct {
|
|
||||||
values map[string]string
|
|
||||||
validator ValidatorFctType
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set validates if needed the input value and add it to the
|
|
||||||
// internal map, by splitting on '='.
|
|
||||||
func (opts *MapOpts) Set(value string) error {
|
|
||||||
if opts.validator != nil {
|
|
||||||
v, err := opts.validator(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
value = v
|
|
||||||
}
|
|
||||||
vals := strings.SplitN(value, "=", 2)
|
|
||||||
if len(vals) == 1 {
|
|
||||||
(opts.values)[vals[0]] = ""
|
|
||||||
} else {
|
|
||||||
(opts.values)[vals[0]] = vals[1]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAll returns the values of MapOpts as a map.
|
|
||||||
func (opts *MapOpts) GetAll() map[string]string {
|
|
||||||
return opts.values
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts *MapOpts) String() string {
|
|
||||||
return fmt.Sprintf("%v", map[string]string((opts.values)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns a string name for this Option type
|
|
||||||
func (opts *MapOpts) Type() string {
|
|
||||||
return "map"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMapOpts creates a new MapOpts with the specified map of values and a validator.
|
|
||||||
func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
|
|
||||||
if values == nil {
|
|
||||||
values = make(map[string]string)
|
|
||||||
}
|
|
||||||
return &MapOpts{
|
|
||||||
values: values,
|
|
||||||
validator: validator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NamedMapOpts is a MapOpts struct with a configuration name.
|
|
||||||
// This struct is useful to keep reference to the assigned
|
|
||||||
// field name in the internal configuration struct.
|
|
||||||
type NamedMapOpts struct {
|
|
||||||
name string
|
|
||||||
MapOpts
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ NamedOption = &NamedMapOpts{}
|
|
||||||
|
|
||||||
// NewNamedMapOpts creates a reference to a new NamedMapOpts struct.
|
|
||||||
func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts {
|
|
||||||
return &NamedMapOpts{
|
|
||||||
name: name,
|
|
||||||
MapOpts: *NewMapOpts(values, validator),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the NamedMapOpts in the configuration.
|
|
||||||
func (o *NamedMapOpts) Name() string {
|
|
||||||
return o.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidatorFctType defines a validator function that returns a validated string and/or an error.
|
|
||||||
type ValidatorFctType func(val string) (string, error)
|
|
||||||
|
|
||||||
// ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
|
|
||||||
type ValidatorFctListType func(val string) ([]string, error)
|
|
||||||
|
|
||||||
// ValidateIPAddress validates an Ip address.
|
|
||||||
func ValidateIPAddress(val string) (string, error) {
|
|
||||||
var ip = net.ParseIP(strings.TrimSpace(val))
|
|
||||||
if ip != nil {
|
|
||||||
return ip.String(), nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("%s is not an ip address", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateDNSSearch validates domain for resolvconf search configuration.
|
|
||||||
// A zero length domain is represented by a dot (.).
|
|
||||||
func ValidateDNSSearch(val string) (string, error) {
|
|
||||||
if val = strings.Trim(val, " "); val == "." {
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
return validateDomain(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateDomain(val string) (string, error) {
|
|
||||||
if alphaRegexp.FindString(val) == "" {
|
|
||||||
return "", fmt.Errorf("%s is not a valid domain", val)
|
|
||||||
}
|
|
||||||
ns := domainRegexp.FindSubmatch([]byte(val))
|
|
||||||
if len(ns) > 0 && len(ns[1]) < 255 {
|
|
||||||
return string(ns[1]), nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("%s is not a valid domain", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateLabel validates that the specified string is a valid label, and returns it.
|
|
||||||
// Labels are in the form on key=value.
|
|
||||||
func ValidateLabel(val string) (string, error) {
|
|
||||||
if strings.Count(val, "=") < 1 {
|
|
||||||
return "", fmt.Errorf("bad attribute format: %s", val)
|
|
||||||
}
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseLink parses and validates the specified string as a link format (name:alias)
|
|
||||||
func ParseLink(val string) (string, string, error) {
|
|
||||||
if val == "" {
|
|
||||||
return "", "", fmt.Errorf("empty string specified for links")
|
|
||||||
}
|
|
||||||
arr := strings.Split(val, ":")
|
|
||||||
if len(arr) > 2 {
|
|
||||||
return "", "", fmt.Errorf("bad format for links: %s", val)
|
|
||||||
}
|
|
||||||
if len(arr) == 1 {
|
|
||||||
return val, val, nil
|
|
||||||
}
|
|
||||||
// This is kept because we can actually get a HostConfig with links
|
|
||||||
// from an already created container and the format is not `foo:bar`
|
|
||||||
// but `/foo:/c1/bar`
|
|
||||||
if strings.HasPrefix(arr[0], "/") {
|
|
||||||
_, alias := path.Split(arr[1])
|
|
||||||
return arr[0][1:], alias, nil
|
|
||||||
}
|
|
||||||
return arr[0], arr[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MemBytes is a type for human readable memory bytes (like 128M, 2g, etc)
|
|
||||||
type MemBytes int64
|
|
||||||
|
|
||||||
// String returns the string format of the human readable memory bytes
|
|
||||||
func (m *MemBytes) String() string {
|
|
||||||
// NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not.
|
|
||||||
// We return "0" in case value is 0 here so that the default value is hidden.
|
|
||||||
// (Sometimes "default 0 B" is actually misleading)
|
|
||||||
if m.Value() != 0 {
|
|
||||||
return units.BytesSize(float64(m.Value()))
|
|
||||||
}
|
|
||||||
return "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sets the value of the MemBytes by passing a string
|
|
||||||
func (m *MemBytes) Set(value string) error {
|
|
||||||
val, err := units.RAMInBytes(value)
|
|
||||||
*m = MemBytes(val)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the type
|
|
||||||
func (m *MemBytes) Type() string {
|
|
||||||
return "bytes"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the value in int64
|
|
||||||
func (m *MemBytes) Value() int64 {
|
|
||||||
return int64(*m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON is the customized unmarshaler for MemBytes
|
|
||||||
func (m *MemBytes) UnmarshalJSON(s []byte) error {
|
|
||||||
if len(s) <= 2 || s[0] != '"' || s[len(s)-1] != '"' {
|
|
||||||
return fmt.Errorf("invalid size: %q", s)
|
|
||||||
}
|
|
||||||
val, err := units.RAMInBytes(string(s[1 : len(s)-1]))
|
|
||||||
*m = MemBytes(val)
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package opts
|
|
||||||
|
|
||||||
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
|
|
||||||
const DefaultHTTPHost = "localhost"
|
|
|
@ -1,56 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
// TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5.
|
|
||||||
// @jhowardmsft, @swernli.
|
|
||||||
//
|
|
||||||
// On Windows, this mitigates a problem with the default options of running
|
|
||||||
// a docker client against a local docker daemon on TP5.
|
|
||||||
//
|
|
||||||
// What was found that if the default host is "localhost", even if the client
|
|
||||||
// (and daemon as this is local) is not physically on a network, and the DNS
|
|
||||||
// cache is flushed (ipconfig /flushdns), then the client will pause for
|
|
||||||
// exactly one second when connecting to the daemon for calls. For example
|
|
||||||
// using docker run windowsservercore cmd, the CLI will send a create followed
|
|
||||||
// by an attach. You see the delay between the attach finishing and the attach
|
|
||||||
// being seen by the daemon.
|
|
||||||
//
|
|
||||||
// Here's some daemon debug logs with additional debug spew put in. The
|
|
||||||
// AfterWriteJSON log is the very last thing the daemon does as part of the
|
|
||||||
// create call. The POST /attach is the second CLI call. Notice the second
|
|
||||||
// time gap.
|
|
||||||
//
|
|
||||||
// time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs"
|
|
||||||
// time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig"
|
|
||||||
// time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...."
|
|
||||||
// time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking....
|
|
||||||
// time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...."
|
|
||||||
// time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...."
|
|
||||||
// time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func"
|
|
||||||
// time="2015-11-06T13:38:37.282628100-08:00" level=debug msg="After daemon.create"
|
|
||||||
// time="2015-11-06T13:38:37.286651700-08:00" level=debug msg="return 2"
|
|
||||||
// time="2015-11-06T13:38:37.289629500-08:00" level=debug msg="Returned from daemon.ContainerCreate"
|
|
||||||
// time="2015-11-06T13:38:37.311629100-08:00" level=debug msg="After WriteJSON"
|
|
||||||
// ... 1 second gap here....
|
|
||||||
// time="2015-11-06T13:38:38.317866200-08:00" level=debug msg="Calling POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach"
|
|
||||||
// time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1"
|
|
||||||
//
|
|
||||||
// We suspect this is either a bug introduced in GOLang 1.5.1, or that a change
|
|
||||||
// in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory,
|
|
||||||
// the Windows networking stack is supposed to resolve "localhost" internally,
|
|
||||||
// without hitting DNS, or even reading the hosts file (which is why localhost
|
|
||||||
// is commented out in the hosts file on Windows).
|
|
||||||
//
|
|
||||||
// We have validated that working around this using the actual IPv4 localhost
|
|
||||||
// address does not cause the delay.
|
|
||||||
//
|
|
||||||
// This does not occur with the docker client built with 1.4.3 on the same
|
|
||||||
// Windows build, regardless of whether the daemon is built using 1.5.1
|
|
||||||
// or 1.4.3. It does not occur on Linux. We also verified we see the same thing
|
|
||||||
// on a cross-compiled Windows binary (from Linux).
|
|
||||||
//
|
|
||||||
// Final note: This is a mitigation, not a 'real' fix. It is still susceptible
|
|
||||||
// to the delay if a user were to do 'docker run -H=tcp://localhost:2375...'
|
|
||||||
// explicitly.
|
|
||||||
|
|
||||||
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
|
|
||||||
const DefaultHTTPHost = "127.0.0.1"
|
|
|
@ -1,37 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
// QuotedString is a string that may have extra quotes around the value. The
|
|
||||||
// quotes are stripped from the value.
|
|
||||||
type QuotedString struct {
|
|
||||||
value *string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sets a new value
|
|
||||||
func (s *QuotedString) Set(val string) error {
|
|
||||||
*s.value = trimQuotes(val)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the type of the value
|
|
||||||
func (s *QuotedString) Type() string {
|
|
||||||
return "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QuotedString) String() string {
|
|
||||||
return string(*s.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func trimQuotes(value string) string {
|
|
||||||
lastIndex := len(value) - 1
|
|
||||||
for _, char := range []byte{'\'', '"'} {
|
|
||||||
if value[0] == char && value[lastIndex] == char {
|
|
||||||
return value[1:lastIndex]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewQuotedString returns a new quoted string option
|
|
||||||
func NewQuotedString(value *string) *QuotedString {
|
|
||||||
return &QuotedString{value: value}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RuntimeOpt defines a map of Runtimes
|
|
||||||
type RuntimeOpt struct {
|
|
||||||
name string
|
|
||||||
stockRuntimeName string
|
|
||||||
values *map[string]types.Runtime
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNamedRuntimeOpt creates a new RuntimeOpt
|
|
||||||
func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime, stockRuntime string) *RuntimeOpt {
|
|
||||||
if ref == nil {
|
|
||||||
ref = &map[string]types.Runtime{}
|
|
||||||
}
|
|
||||||
return &RuntimeOpt{name: name, values: ref, stockRuntimeName: stockRuntime}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the NamedListOpts in the configuration.
|
|
||||||
func (o *RuntimeOpt) Name() string {
|
|
||||||
return o.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set validates and updates the list of Runtimes
|
|
||||||
func (o *RuntimeOpt) Set(val string) error {
|
|
||||||
parts := strings.SplitN(val, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("invalid runtime argument: %s", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
parts[0] = strings.TrimSpace(parts[0])
|
|
||||||
parts[1] = strings.TrimSpace(parts[1])
|
|
||||||
if parts[0] == "" || parts[1] == "" {
|
|
||||||
return fmt.Errorf("invalid runtime argument: %s", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
parts[0] = strings.ToLower(parts[0])
|
|
||||||
if parts[0] == o.stockRuntimeName {
|
|
||||||
return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := (*o.values)[parts[0]]; ok {
|
|
||||||
return fmt.Errorf("runtime '%s' was already defined", parts[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
(*o.values)[parts[0]] = types.Runtime{Path: parts[1]}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns Runtime values as a string.
|
|
||||||
func (o *RuntimeOpt) String() string {
|
|
||||||
var out []string
|
|
||||||
for k := range *o.values {
|
|
||||||
out = append(out, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%v", out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMap returns a map of Runtimes (name: path)
|
|
||||||
func (o *RuntimeOpt) GetMap() map[string]types.Runtime {
|
|
||||||
if o.values != nil {
|
|
||||||
return *o.values
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]types.Runtime{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the type of the option
|
|
||||||
func (o *RuntimeOpt) Type() string {
|
|
||||||
return "runtime"
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
package opts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UlimitOpt defines a map of Ulimits
|
|
||||||
type UlimitOpt struct {
|
|
||||||
values *map[string]*units.Ulimit
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUlimitOpt creates a new UlimitOpt
|
|
||||||
func NewUlimitOpt(ref *map[string]*units.Ulimit) *UlimitOpt {
|
|
||||||
if ref == nil {
|
|
||||||
ref = &map[string]*units.Ulimit{}
|
|
||||||
}
|
|
||||||
return &UlimitOpt{ref}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set validates a Ulimit and sets its name as a key in UlimitOpt
|
|
||||||
func (o *UlimitOpt) Set(val string) error {
|
|
||||||
l, err := units.ParseUlimit(val)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
(*o.values)[l.Name] = l
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns Ulimit values as a string.
|
|
||||||
func (o *UlimitOpt) String() string {
|
|
||||||
var out []string
|
|
||||||
for _, v := range *o.values {
|
|
||||||
out = append(out, v.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%v", out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetList returns a slice of pointers to Ulimits.
|
|
||||||
func (o *UlimitOpt) GetList() []*units.Ulimit {
|
|
||||||
var ulimits []*units.Ulimit
|
|
||||||
for _, v := range *o.values {
|
|
||||||
ulimits = append(ulimits, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulimits
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the option type
|
|
||||||
func (o *UlimitOpt) Type() string {
|
|
||||||
return "ulimit"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NamedUlimitOpt defines a named map of Ulimits
|
|
||||||
type NamedUlimitOpt struct {
|
|
||||||
name string
|
|
||||||
UlimitOpt
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ NamedOption = &NamedUlimitOpt{}
|
|
||||||
|
|
||||||
// NewNamedUlimitOpt creates a new NamedUlimitOpt
|
|
||||||
func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt {
|
|
||||||
if ref == nil {
|
|
||||||
ref = &map[string]*units.Ulimit{}
|
|
||||||
}
|
|
||||||
return &NamedUlimitOpt{
|
|
||||||
name: name,
|
|
||||||
UlimitOpt: *NewUlimitOpt(ref),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the option name
|
|
||||||
func (o *NamedUlimitOpt) Name() string {
|
|
||||||
return o.name
|
|
||||||
}
|
|
|
@ -16,13 +16,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/fileutils"
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/pools"
|
"github.com/docker/docker/pkg/pools"
|
||||||
"github.com/docker/docker/pkg/promise"
|
"github.com/docker/docker/pkg/promise"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -93,6 +93,16 @@ const (
|
||||||
OverlayWhiteoutFormat
|
OverlayWhiteoutFormat
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
modeISDIR = 040000 // Directory
|
||||||
|
modeISFIFO = 010000 // FIFO
|
||||||
|
modeISREG = 0100000 // Regular file
|
||||||
|
modeISLNK = 0120000 // Symbolic link
|
||||||
|
modeISBLK = 060000 // Block special file
|
||||||
|
modeISCHR = 020000 // Character special file
|
||||||
|
modeISSOCK = 0140000 // Socket
|
||||||
|
)
|
||||||
|
|
||||||
// IsArchivePath checks if the (possibly compressed) file at the given path
|
// IsArchivePath checks if the (possibly compressed) file at the given path
|
||||||
// starts with a tar file header.
|
// starts with a tar file header.
|
||||||
func IsArchivePath(path string) bool {
|
func IsArchivePath(path string) bool {
|
||||||
|
@ -305,12 +315,14 @@ func (compression *Compression) Extension() string {
|
||||||
|
|
||||||
// FileInfoHeader creates a populated Header from fi.
|
// FileInfoHeader creates a populated Header from fi.
|
||||||
// Compared to archive pkg this function fills in more information.
|
// Compared to archive pkg this function fills in more information.
|
||||||
|
// Also, regardless of Go version, this function fills file type bits (e.g. hdr.Mode |= modeISDIR),
|
||||||
|
// which have been deleted since Go 1.9 archive/tar.
|
||||||
func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) {
|
func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) {
|
||||||
hdr, err := tar.FileInfoHeader(fi, link)
|
hdr, err := tar.FileInfoHeader(fi, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi)
|
||||||
name, err = canonicalTarName(name, fi.IsDir())
|
name, err = canonicalTarName(name, fi.IsDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err)
|
return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err)
|
||||||
|
@ -322,6 +334,31 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
|
||||||
return hdr, nil
|
return hdr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fillGo18FileTypeBits fills type bits which have been removed on Go 1.9 archive/tar
|
||||||
|
// https://github.com/golang/go/commit/66b5a2f
|
||||||
|
func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
|
||||||
|
fm := fi.Mode()
|
||||||
|
switch {
|
||||||
|
case fm.IsRegular():
|
||||||
|
mode |= modeISREG
|
||||||
|
case fi.IsDir():
|
||||||
|
mode |= modeISDIR
|
||||||
|
case fm&os.ModeSymlink != 0:
|
||||||
|
mode |= modeISLNK
|
||||||
|
case fm&os.ModeDevice != 0:
|
||||||
|
if fm&os.ModeCharDevice != 0 {
|
||||||
|
mode |= modeISCHR
|
||||||
|
} else {
|
||||||
|
mode |= modeISBLK
|
||||||
|
}
|
||||||
|
case fm&os.ModeNamedPipe != 0:
|
||||||
|
mode |= modeISFIFO
|
||||||
|
case fm&os.ModeSocket != 0:
|
||||||
|
mode |= modeISSOCK
|
||||||
|
}
|
||||||
|
return mode
|
||||||
|
}
|
||||||
|
|
||||||
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
|
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
|
||||||
// to a tar header
|
// to a tar header
|
||||||
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||||
|
@ -345,6 +382,7 @@ type tarAppender struct {
|
||||||
// for hardlink mapping
|
// for hardlink mapping
|
||||||
SeenFiles map[uint64]string
|
SeenFiles map[uint64]string
|
||||||
IDMappings *idtools.IDMappings
|
IDMappings *idtools.IDMappings
|
||||||
|
ChownOpts *idtools.IDPair
|
||||||
|
|
||||||
// For packing and unpacking whiteout files in the
|
// For packing and unpacking whiteout files in the
|
||||||
// non standard format. The whiteout files defined
|
// non standard format. The whiteout files defined
|
||||||
|
@ -353,12 +391,13 @@ type tarAppender struct {
|
||||||
WhiteoutConverter tarWhiteoutConverter
|
WhiteoutConverter tarWhiteoutConverter
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer) *tarAppender {
|
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
|
||||||
return &tarAppender{
|
return &tarAppender{
|
||||||
SeenFiles: make(map[uint64]string),
|
SeenFiles: make(map[uint64]string),
|
||||||
TarWriter: tar.NewWriter(writer),
|
TarWriter: tar.NewWriter(writer),
|
||||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
Buffer: pools.BufioWriter32KPool.Get(nil),
|
||||||
IDMappings: idMapping,
|
IDMappings: idMapping,
|
||||||
|
ChownOpts: chownOpts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,6 +472,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// explicitly override with ChownOpts
|
||||||
|
if ta.ChownOpts != nil {
|
||||||
|
hdr.Uid = ta.ChownOpts.UID
|
||||||
|
hdr.Gid = ta.ChownOpts.GID
|
||||||
|
}
|
||||||
|
|
||||||
if ta.WhiteoutConverter != nil {
|
if ta.WhiteoutConverter != nil {
|
||||||
wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi)
|
wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -558,7 +603,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unhandled tar header type %d\n", hdr.Typeflag)
|
return fmt.Errorf("unhandled tar header type %d", hdr.Typeflag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lchown is not supported on Windows.
|
// Lchown is not supported on Windows.
|
||||||
|
@ -655,6 +700,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
||||||
ta := newTarAppender(
|
ta := newTarAppender(
|
||||||
idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
|
idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
|
||||||
compressWriter,
|
compressWriter,
|
||||||
|
options.ChownOpts,
|
||||||
)
|
)
|
||||||
ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)
|
ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
|
func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
|
||||||
|
@ -67,7 +67,7 @@ func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool,
|
||||||
|
|
||||||
// if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay
|
// if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay
|
||||||
if base == WhiteoutOpaqueDir {
|
if base == WhiteoutOpaqueDir {
|
||||||
err := syscall.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0)
|
err := unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0)
|
||||||
// don't write the file itself
|
// don't write the file itself
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool,
|
||||||
originalBase := base[len(WhiteoutPrefix):]
|
originalBase := base[len(WhiteoutPrefix):]
|
||||||
originalPath := filepath.Join(dir, originalBase)
|
originalPath := filepath.Join(dir, originalBase)
|
||||||
|
|
||||||
if err := syscall.Mknod(originalPath, syscall.S_IFCHR, 0); err != nil {
|
if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil {
|
if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fixVolumePathPrefix does platform specific processing to ensure that if
|
// fixVolumePathPrefix does platform specific processing to ensure that if
|
||||||
|
@ -47,8 +48,8 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
// Currently go does not fill in the major/minors
|
// Currently go does not fill in the major/minors
|
||||||
if s.Mode&syscall.S_IFBLK != 0 ||
|
if s.Mode&unix.S_IFBLK != 0 ||
|
||||||
s.Mode&syscall.S_IFCHR != 0 {
|
s.Mode&unix.S_IFCHR != 0 {
|
||||||
hdr.Devmajor = int64(major(uint64(s.Rdev)))
|
hdr.Devmajor = int64(major(uint64(s.Rdev)))
|
||||||
hdr.Devminor = int64(minor(uint64(s.Rdev)))
|
hdr.Devminor = int64(minor(uint64(s.Rdev)))
|
||||||
}
|
}
|
||||||
|
@ -95,11 +96,11 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
|
||||||
mode := uint32(hdr.Mode & 07777)
|
mode := uint32(hdr.Mode & 07777)
|
||||||
switch hdr.Typeflag {
|
switch hdr.Typeflag {
|
||||||
case tar.TypeBlock:
|
case tar.TypeBlock:
|
||||||
mode |= syscall.S_IFBLK
|
mode |= unix.S_IFBLK
|
||||||
case tar.TypeChar:
|
case tar.TypeChar:
|
||||||
mode |= syscall.S_IFCHR
|
mode |= unix.S_IFCHR
|
||||||
case tar.TypeFifo:
|
case tar.TypeFifo:
|
||||||
mode |= syscall.S_IFIFO
|
mode |= unix.S_IFIFO
|
||||||
}
|
}
|
||||||
|
|
||||||
return system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor)))
|
return system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor)))
|
||||||
|
|
|
@ -13,10 +13,10 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/pools"
|
"github.com/docker/docker/pkg/pools"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChangeType represents the change type.
|
// ChangeType represents the change type.
|
||||||
|
@ -394,7 +394,7 @@ func ChangesSize(newDir string, changes []Change) int64 {
|
||||||
func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
|
func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
go func() {
|
go func() {
|
||||||
ta := newTarAppender(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer)
|
ta := newTarAppender(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer, nil)
|
||||||
|
|
||||||
// this buffer is needed for the duration of this piped stream
|
// this buffer is needed for the duration of this piped stream
|
||||||
defer pools.BufioWriter32KPool.Put(ta.Buffer)
|
defer pools.BufioWriter32KPool.Put(ta.Buffer)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// walker is used to implement collectFileInfoForChanges on linux. Where this
|
// walker is used to implement collectFileInfoForChanges on linux. Where this
|
||||||
|
@ -233,7 +234,7 @@ func readdirnames(dirname string) (names []nameIno, err error) {
|
||||||
// Refill the buffer if necessary
|
// Refill the buffer if necessary
|
||||||
if bufp >= nbuf {
|
if bufp >= nbuf {
|
||||||
bufp = 0
|
bufp = 0
|
||||||
nbuf, err = syscall.ReadDirent(int(f.Fd()), buf) // getdents on linux
|
nbuf, err = unix.ReadDirent(int(f.Fd()), buf) // getdents on linux
|
||||||
if nbuf < 0 {
|
if nbuf < 0 {
|
||||||
nbuf = 0
|
nbuf = 0
|
||||||
}
|
}
|
||||||
|
@ -255,12 +256,12 @@ func readdirnames(dirname string) (names []nameIno, err error) {
|
||||||
return sl, nil
|
return sl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseDirent is a minor modification of syscall.ParseDirent (linux version)
|
// parseDirent is a minor modification of unix.ParseDirent (linux version)
|
||||||
// which returns {name,inode} pairs instead of just names.
|
// which returns {name,inode} pairs instead of just names.
|
||||||
func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
|
func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
|
||||||
origlen := len(buf)
|
origlen := len(buf)
|
||||||
for len(buf) > 0 {
|
for len(buf) > 0 {
|
||||||
dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0]))
|
dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0]))
|
||||||
buf = buf[dirent.Reclen:]
|
buf = buf[dirent.Reclen:]
|
||||||
if dirent.Ino == 0 { // File absent in directory.
|
if dirent.Ino == 0 { // File absent in directory.
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
|
func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
|
||||||
|
@ -16,7 +17,7 @@ func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
|
||||||
oldStat.GID() != newStat.GID() ||
|
oldStat.GID() != newStat.GID() ||
|
||||||
oldStat.Rdev() != newStat.Rdev() ||
|
oldStat.Rdev() != newStat.Rdev() ||
|
||||||
// Don't look at size for dirs, its not a good measure of change
|
// Don't look at size for dirs, its not a good measure of change
|
||||||
(oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR &&
|
(oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR &&
|
||||||
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) {
|
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -24,7 +25,7 @@ func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *FileInfo) isDir() bool {
|
func (info *FileInfo) isDir() bool {
|
||||||
return info.parent == nil || info.stat.Mode()&syscall.S_IFDIR != 0
|
return info.parent == nil || info.stat.Mode()&unix.S_IFDIR != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIno(fi os.FileInfo) uint64 {
|
func getIno(fi os.FileInfo) uint64 {
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors used or returned by this file.
|
// Errors used or returned by this file.
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/pools"
|
"github.com/docker/docker/pkg/pools"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnpackLayer unpack `layer` to a `dest`. The stream `layer` can be
|
// UnpackLayer unpack `layer` to a `dest`. The stream `layer` can be
|
||||||
|
|
|
@ -5,10 +5,10 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// chroot on linux uses pivot_root instead of chroot
|
// chroot on linux uses pivot_root instead of chroot
|
||||||
|
@ -22,7 +22,7 @@ func chroot(path string) (err error) {
|
||||||
if rsystem.RunningInUserNS() {
|
if rsystem.RunningInUserNS() {
|
||||||
return realChroot(path)
|
return realChroot(path)
|
||||||
}
|
}
|
||||||
if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
|
if err := unix.Unshare(unix.CLONE_NEWNS); err != nil {
|
||||||
return fmt.Errorf("Error creating mount namespace before pivot: %v", err)
|
return fmt.Errorf("Error creating mount namespace before pivot: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ func chroot(path string) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if mounted {
|
if mounted {
|
||||||
// make sure pivotDir is not mounted before we try to remove it
|
// make sure pivotDir is not mounted before we try to remove it
|
||||||
if errCleanup := syscall.Unmount(pivotDir, syscall.MNT_DETACH); errCleanup != nil {
|
if errCleanup := unix.Unmount(pivotDir, unix.MNT_DETACH); errCleanup != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = errCleanup
|
err = errCleanup
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ func chroot(path string) (err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := syscall.PivotRoot(path, pivotDir); err != nil {
|
if err := unix.PivotRoot(path, pivotDir); err != nil {
|
||||||
// If pivot fails, fall back to the normal chroot after cleaning up temp dir
|
// If pivot fails, fall back to the normal chroot after cleaning up temp dir
|
||||||
if err := os.Remove(pivotDir); err != nil {
|
if err := os.Remove(pivotDir); err != nil {
|
||||||
return fmt.Errorf("Error cleaning up after failed pivot: %v", err)
|
return fmt.Errorf("Error cleaning up after failed pivot: %v", err)
|
||||||
|
@ -79,17 +79,17 @@ func chroot(path string) (err error) {
|
||||||
// This dir contains the rootfs of the caller, which we need to remove so it is not visible during extraction
|
// This dir contains the rootfs of the caller, which we need to remove so it is not visible during extraction
|
||||||
pivotDir = filepath.Join("/", filepath.Base(pivotDir))
|
pivotDir = filepath.Join("/", filepath.Base(pivotDir))
|
||||||
|
|
||||||
if err := syscall.Chdir("/"); err != nil {
|
if err := unix.Chdir("/"); err != nil {
|
||||||
return fmt.Errorf("Error changing to new root: %v", err)
|
return fmt.Errorf("Error changing to new root: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the pivotDir (where the old root lives) private so it can be unmounted without propagating to the host
|
// Make the pivotDir (where the old root lives) private so it can be unmounted without propagating to the host
|
||||||
if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
|
if err := unix.Mount("", pivotDir, "", unix.MS_PRIVATE|unix.MS_REC, ""); err != nil {
|
||||||
return fmt.Errorf("Error making old root private after pivot: %v", err)
|
return fmt.Errorf("Error making old root private after pivot: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now unmount the old root so it's no longer visible from the new root
|
// Now unmount the old root so it's no longer visible from the new root
|
||||||
if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
|
if err := unix.Unmount(pivotDir, unix.MNT_DETACH); err != nil {
|
||||||
return fmt.Errorf("Error while unmounting old root after pivot: %v", err)
|
return fmt.Errorf("Error while unmounting old root after pivot: %v", err)
|
||||||
}
|
}
|
||||||
mounted = false
|
mounted = false
|
||||||
|
@ -98,10 +98,10 @@ func chroot(path string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func realChroot(path string) error {
|
func realChroot(path string) error {
|
||||||
if err := syscall.Chroot(path); err != nil {
|
if err := unix.Chroot(path); err != nil {
|
||||||
return fmt.Errorf("Error after fallback to chroot: %v", err)
|
return fmt.Errorf("Error after fallback to chroot: %v", err)
|
||||||
}
|
}
|
||||||
if err := syscall.Chdir("/"); err != nil {
|
if err := unix.Chdir("/"); err != nil {
|
||||||
return fmt.Errorf("Error changing to new root after chroot: %v", err)
|
return fmt.Errorf("Error changing to new root after chroot: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
package chrootarchive
|
package chrootarchive
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
func chroot(path string) error {
|
func chroot(path string) error {
|
||||||
if err := syscall.Chroot(path); err != nil {
|
if err := unix.Chroot(path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return syscall.Chdir("/")
|
return unix.Chdir("/")
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/scanner"
|
"text/scanner"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PatternMatcher allows checking paths agaist a list of patterns
|
// PatternMatcher allows checking paths agaist a list of patterns
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetTotalUsedFds Returns the number of used File Descriptors by
|
// GetTotalUsedFds Returns the number of used File Descriptors by
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue