Merge component 'engine' from git@github.com:moby/moby master
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
.PHONY: all binary dynbinary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration test-unit tgz validate win
|
||||
.PHONY: all binary dynbinary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration test-unit validate win
|
||||
|
||||
# set the graph driver as the current graphdriver if not set
|
||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
|
||||
@@ -164,9 +164,6 @@ test-integration: build ## run the integration tests
|
||||
test-unit: build ## run the unit tests
|
||||
$(DOCKER_RUN_DOCKER) hack/test/unit
|
||||
|
||||
tgz: build ## build the archives (.zip on windows and .tgz\notherwise) containing the binaries
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross tgz
|
||||
|
||||
validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func (s *containerRouter) getContainersJSON(ctx context.Context, w http.Response
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -588,7 +588,7 @@ func (s *containerRouter) postContainersPrune(ctx context.Context, w http.Respon
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return validationError{err}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
||||
return err
|
||||
}
|
||||
|
||||
imageFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
imageFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -385,7 +385,7 @@ func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -45,27 +45,27 @@ func filterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.N
|
||||
|
||||
displayNet := []types.NetworkResource{}
|
||||
for _, nw := range nws {
|
||||
if filter.Include("driver") {
|
||||
if filter.Contains("driver") {
|
||||
if !filter.ExactMatch("driver", nw.Driver) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("name") {
|
||||
if filter.Contains("name") {
|
||||
if !filter.Match("name", nw.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("id") {
|
||||
if filter.Contains("id") {
|
||||
if !filter.Match("id", nw.ID) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("label") {
|
||||
if filter.Contains("label") {
|
||||
if !filter.MatchKVList("label", nw.Labels) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("scope") {
|
||||
if filter.Contains("scope") {
|
||||
if !filter.ExactMatch("scope", nw.Scope) {
|
||||
continue
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func filterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.N
|
||||
displayNet = append(displayNet, nw)
|
||||
}
|
||||
|
||||
if filter.Include("type") {
|
||||
if filter.Contains("type") {
|
||||
typeNet := []types.NetworkResource{}
|
||||
errFilter := filter.WalkValues("type", func(fval string) error {
|
||||
passList, err := filterNetworkByType(displayNet, fval)
|
||||
|
||||
@@ -37,7 +37,7 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
||||
}
|
||||
|
||||
filter := r.Form.Get("filters")
|
||||
netFilters, err := filters.FromParam(filter)
|
||||
netFilters, err := filters.FromJSON(filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -489,7 +489,7 @@ func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWr
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ func (pr *pluginRouter) listPlugins(ctx context.Context, w http.ResponseWriter,
|
||||
return err
|
||||
}
|
||||
|
||||
pluginFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
pluginFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return invalidRequestError{err}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -339,7 +339,7 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -367,7 +367,7 @@ func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
filters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -434,7 +434,7 @@ func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
filters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
}
|
||||
}
|
||||
|
||||
ef, err := filters.FromParam(r.Form.Get("filters"))
|
||||
ef, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (v *volumeRouter) postVolumesPrune(ctx context.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6941,16 +6941,20 @@ paths:
|
||||
description: |
|
||||
A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters:
|
||||
|
||||
- `config=<string>` config name or ID
|
||||
- `container=<string>` container name or ID
|
||||
- `daemon=<string>` daemon name or ID
|
||||
- `event=<string>` event type
|
||||
- `image=<string>` image name or ID
|
||||
- `label=<string>` image or container label
|
||||
- `network=<string>` network name or ID
|
||||
- `node=<string>` node ID
|
||||
- `plugin`=<string> plugin name or ID
|
||||
- `scope`=<string> local or swarm
|
||||
- `type=<string>` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service` or `secret`
|
||||
- `volume=<string>` volume name or ID
|
||||
- `secret=<string>` secret name or ID
|
||||
- `service=<string>` service name or ID
|
||||
- `type=<string>` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config`
|
||||
- `volume=<string>` volume name
|
||||
type: "string"
|
||||
tags: ["System"]
|
||||
/system/df:
|
||||
|
||||
@@ -42,14 +42,14 @@ func TestParseArgsEdgeCase(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestToParam(t *testing.T) {
|
||||
func TestToJSON(t *testing.T) {
|
||||
fields := map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"image.name": {"ubuntu*": true, "*untu": true},
|
||||
}
|
||||
a := Args{fields: fields}
|
||||
|
||||
_, err := ToParam(a)
|
||||
_, err := ToJSON(a)
|
||||
if err != nil {
|
||||
t.Errorf("failed to marshal the filters: %s", err)
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func TestToParamWithVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromParam(t *testing.T) {
|
||||
func TestFromJSON(t *testing.T) {
|
||||
invalids := []string{
|
||||
"anything",
|
||||
"['a','list']",
|
||||
@@ -103,14 +103,14 @@ func TestFromParam(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, invalid := range invalids {
|
||||
if _, err := FromParam(invalid); err == nil {
|
||||
if _, err := FromJSON(invalid); err == nil {
|
||||
t.Fatalf("Expected an error with %v, got nothing", invalid)
|
||||
}
|
||||
}
|
||||
|
||||
for expectedArgs, matchers := range valid {
|
||||
for _, json := range matchers {
|
||||
args, err := FromParam(json)
|
||||
args, err := FromJSON(json)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -136,11 +136,11 @@ func TestFromParam(t *testing.T) {
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
a := Args{}
|
||||
v, err := ToParam(a)
|
||||
v, err := ToJSON(a)
|
||||
if err != nil {
|
||||
t.Errorf("failed to marshal the filters: %s", err)
|
||||
}
|
||||
v1, err := FromParam(v)
|
||||
v1, err := FromJSON(v)
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
@@ -337,6 +337,17 @@ func TestOnlyOneExactMatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
f := NewArgs()
|
||||
if f.Contains("status") {
|
||||
t.Fatal("Expected to not contain a status key, got true")
|
||||
}
|
||||
f.Add("status", "running")
|
||||
if !f.Contains("status") {
|
||||
t.Fatal("Expected to contain a status key, got false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclude(t *testing.T) {
|
||||
f := NewArgs()
|
||||
if f.Include("status") {
|
||||
|
||||
@@ -18,7 +18,7 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(options.Filters)
|
||||
filterJSON, err := filters.ToJSON(options.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
|
||||
query.Set("limit", fmt.Sprintf("%d", options.Limit))
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(options.Filters)
|
||||
filterJSON, err := filters.ToJSON(options.Filters)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions)
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(options.Filters)
|
||||
filterJSON, err := filters.ToJSON(options.Filters)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -18,7 +18,7 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(options.Filters)
|
||||
filterJSON, err := filters.ToJSON(options.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(options.Filters)
|
||||
filterJSON, err := filters.ToJSON(options.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions)
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(options.Filters)
|
||||
filterJSON, err := filters.ToJSON(options.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func getDockerOS(serverHeader string) string {
|
||||
func getFiltersQuery(f filters.Args) (url.Values, error) {
|
||||
query := url.Values{}
|
||||
if f.Len() > 0 {
|
||||
filterJSON, err := filters.ToParam(f)
|
||||
filterJSON, err := filters.ToJSON(f)
|
||||
if err != nil {
|
||||
return query, err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ const (
|
||||
|
||||
// errSwarmCertificatesExpired is returned if docker was not started for the whole validity period and they had no chance to renew automatically.
|
||||
errSwarmCertificatesExpired notAvailableError = "Swarm certificates have expired. To replace them, leave the swarm and join again."
|
||||
|
||||
// errSwarmNotManager is returned if the node is not a swarm manager.
|
||||
errSwarmNotManager notAvailableError = "This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager."
|
||||
)
|
||||
|
||||
type notFoundError struct {
|
||||
|
||||
@@ -74,7 +74,7 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
|
||||
services := make([]types.Service, 0, len(r.Services))
|
||||
|
||||
for _, service := range r.Services {
|
||||
if options.Filters.Include("mode") {
|
||||
if options.Filters.Contains("mode") {
|
||||
var mode string
|
||||
switch service.Spec.GetMode().(type) {
|
||||
case *swarmapi.ServiceSpec_Global:
|
||||
|
||||
@@ -26,9 +26,13 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) {
|
||||
defer c.controlMutex.Unlock()
|
||||
if c.nr != nil {
|
||||
if req.ForceNewCluster {
|
||||
|
||||
// Take c.mu temporarily to wait for presently running
|
||||
// API handlers to finish before shutting down the node.
|
||||
c.mu.Lock()
|
||||
if !c.nr.nodeState.IsManager() {
|
||||
return "", errSwarmNotManager
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
if err := c.nr.Stop(); err != nil {
|
||||
|
||||
@@ -15,7 +15,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro
|
||||
|
||||
if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
|
||||
filterTransform := func(filter filters.Args) error {
|
||||
if filter.Include("service") {
|
||||
if filter.Contains("service") {
|
||||
serviceFilters := filter.Get("service")
|
||||
for _, serviceFilter := range serviceFilters {
|
||||
service, err := getService(ctx, state.controlClient, serviceFilter, false)
|
||||
@@ -26,7 +26,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro
|
||||
filter.Add("service", service.ID)
|
||||
}
|
||||
}
|
||||
if filter.Include("node") {
|
||||
if filter.Contains("node") {
|
||||
nodeFilters := filter.Get("node")
|
||||
for _, nodeFilter := range nodeFilters {
|
||||
node, err := getNode(ctx, state.controlClient, nodeFilter)
|
||||
@@ -37,7 +37,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro
|
||||
filter.Add("node", node.ID)
|
||||
}
|
||||
}
|
||||
if !filter.Include("runtime") {
|
||||
if !filter.Contains("runtime") {
|
||||
// default to only showing container tasks
|
||||
filter.Add("runtime", "container")
|
||||
filter.Add("runtime", "")
|
||||
|
||||
@@ -140,10 +140,7 @@ func (daemon *Daemon) StoreHosts(hosts []string) {
|
||||
|
||||
// HasExperimental returns whether the experimental features of the daemon are enabled or not
|
||||
func (daemon *Daemon) HasExperimental() bool {
|
||||
if daemon.configStore != nil && daemon.configStore.Experimental {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return daemon.configStore != nil && daemon.configStore.Experimental
|
||||
}
|
||||
|
||||
func (daemon *Daemon) restore() error {
|
||||
|
||||
@@ -27,8 +27,10 @@ import (
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
blkiodev "github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -238,6 +240,29 @@ func checkSystem() error {
|
||||
return fmt.Errorf("failed to load vmcompute.dll, ensure that the Containers feature is installed")
|
||||
}
|
||||
|
||||
// Ensure that the required Host Network Service and vmcompute services
|
||||
// are running. Docker will fail in unexpected ways if this is not present.
|
||||
var requiredServices = []string{"hns", "vmcompute"}
|
||||
if err := ensureServicesInstalled(requiredServices); err != nil {
|
||||
return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureServicesInstalled(services []string) error {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
for _, service := range services {
|
||||
s, err := m.OpenService(service)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open service %s", service)
|
||||
}
|
||||
s.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// +build windows
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
const existingService = "Power"
|
||||
|
||||
func TestEnsureServicesExist(t *testing.T) {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
t.Fatal("failed to connect to service manager, this test needs admin")
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(existingService)
|
||||
if err != nil {
|
||||
t.Fatalf("expected to find known inbox service %q, this test needs a known inbox service to run correctly", existingService)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
input := []string{existingService}
|
||||
err = ensureServicesInstalled(input)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error for input %q: %q", input, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureServicesExistErrors(t *testing.T) {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
t.Fatal("failed to connect to service manager, this test needs admin")
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(existingService)
|
||||
if err != nil {
|
||||
t.Fatalf("expected to find known inbox service %q, this test needs a known inbox service to run correctly", existingService)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
for _, testcase := range []struct {
|
||||
input []string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
input: []string{"daemon_windows_test_fakeservice"},
|
||||
expectedError: "failed to open service daemon_windows_test_fakeservice",
|
||||
},
|
||||
{
|
||||
input: []string{"daemon_windows_test_fakeservice1", "daemon_windows_test_fakeservice2"},
|
||||
expectedError: "failed to open service daemon_windows_test_fakeservice1",
|
||||
},
|
||||
{
|
||||
input: []string{existingService, "daemon_windows_test_fakeservice"},
|
||||
expectedError: "failed to open service daemon_windows_test_fakeservice",
|
||||
},
|
||||
} {
|
||||
t.Run(strings.Join(testcase.input, ";"), func(t *testing.T) {
|
||||
err := ensureServicesInstalled(testcase.input)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for input %v", testcase.input)
|
||||
}
|
||||
if !strings.Contains(err.Error(), testcase.expectedError) {
|
||||
t.Fatalf("expected error %q to contain %q", err.Error(), testcase.expectedError)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,10 @@ func (ef *Filter) Include(ev events.Message) bool {
|
||||
ef.matchVolume(ev) &&
|
||||
ef.matchNetwork(ev) &&
|
||||
ef.matchImage(ev) &&
|
||||
ef.matchNode(ev) &&
|
||||
ef.matchService(ev) &&
|
||||
ef.matchSecret(ev) &&
|
||||
ef.matchConfig(ev) &&
|
||||
ef.matchLabels(ev.Actor.Attributes)
|
||||
}
|
||||
|
||||
@@ -49,14 +53,14 @@ func (ef *Filter) filterContains(field string, values map[string]struct{}) bool
|
||||
}
|
||||
|
||||
func (ef *Filter) matchScope(scope string) bool {
|
||||
if !ef.filter.Include("scope") {
|
||||
if !ef.filter.Contains("scope") {
|
||||
return true
|
||||
}
|
||||
return ef.filter.ExactMatch("scope", scope)
|
||||
}
|
||||
|
||||
func (ef *Filter) matchLabels(attributes map[string]string) bool {
|
||||
if !ef.filter.Include("label") {
|
||||
if !ef.filter.Contains("label") {
|
||||
return true
|
||||
}
|
||||
return ef.filter.MatchKVList("label", attributes)
|
||||
|
||||
@@ -67,7 +67,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if imageFilters.Include("dangling") {
|
||||
if imageFilters.Contains("dangling") {
|
||||
if imageFilters.ExactMatch("dangling", "true") {
|
||||
danglingOnly = true
|
||||
} else if !imageFilters.ExactMatch("dangling", "false") {
|
||||
@@ -116,7 +116,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
}
|
||||
}
|
||||
|
||||
if imageFilters.Include("label") {
|
||||
if imageFilters.Contains("label") {
|
||||
// Very old image that do not have image.Config (or even labels)
|
||||
if img.Config == nil {
|
||||
continue
|
||||
@@ -150,7 +150,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
newImage := newImage(img, size)
|
||||
|
||||
for _, ref := range daemon.referenceStore.References(id.Digest()) {
|
||||
if imageFilters.Include("reference") {
|
||||
if imageFilters.Contains("reference") {
|
||||
var found bool
|
||||
var matchErr error
|
||||
for _, pattern := range imageFilters.Get("reference") {
|
||||
@@ -173,11 +173,11 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
if newImage.RepoDigests == nil && newImage.RepoTags == nil {
|
||||
if all || len(daemon.stores[platform].imageStore.Children(id)) == 0 {
|
||||
|
||||
if imageFilters.Include("dangling") && !danglingOnly {
|
||||
if imageFilters.Contains("dangling") && !danglingOnly {
|
||||
//dangling=false case, so dangling image is not needed
|
||||
continue
|
||||
}
|
||||
if imageFilters.Include("reference") { // skip images with no references if filtering by reference
|
||||
if imageFilters.Contains("reference") { // skip images with no references if filtering by reference
|
||||
continue
|
||||
}
|
||||
newImage.RepoDigests = []string{"<none>@<none>"}
|
||||
|
||||
@@ -276,7 +276,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
|
||||
}
|
||||
|
||||
var taskFilter, isTask bool
|
||||
if psFilters.Include("is-task") {
|
||||
if psFilters.Contains("is-task") {
|
||||
if psFilters.ExactMatch("is-task", "true") {
|
||||
taskFilter = true
|
||||
isTask = true
|
||||
@@ -319,7 +319,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
|
||||
|
||||
imagesFilter := map[image.ID]bool{}
|
||||
var ancestorFilter bool
|
||||
if psFilters.Include("ancestor") {
|
||||
if psFilters.Contains("ancestor") {
|
||||
ancestorFilter = true
|
||||
psFilters.WalkValues("ancestor", func(ancestor string) error {
|
||||
id, platform, err := daemon.GetImageIDAndPlatform(ancestor)
|
||||
@@ -465,7 +465,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite
|
||||
return excludeContainer
|
||||
}
|
||||
|
||||
if ctx.filters.Include("volume") {
|
||||
if ctx.filters.Contains("volume") {
|
||||
volumesByName := make(map[string]types.MountPoint)
|
||||
for _, m := range container.Mounts {
|
||||
if m.Name != "" {
|
||||
@@ -509,7 +509,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite
|
||||
networkExist = errors.New("container part of network")
|
||||
noNetworks = errors.New("container is not part of any networks")
|
||||
)
|
||||
if ctx.filters.Include("network") {
|
||||
if ctx.filters.Contains("network") {
|
||||
err := ctx.filters.WalkValues("network", func(value string) error {
|
||||
if container.NetworkSettings == nil {
|
||||
return noNetworks
|
||||
@@ -585,7 +585,7 @@ func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error)
|
||||
var (
|
||||
volumesOut []*types.Volume
|
||||
)
|
||||
volFilters, err := filters.FromParam(filter)
|
||||
volFilters, err := filters.FromJSON(filter)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -627,17 +627,17 @@ func (daemon *Daemon) filterVolumes(vols []volume.Volume, filter filters.Args) (
|
||||
|
||||
var retVols []volume.Volume
|
||||
for _, vol := range vols {
|
||||
if filter.Include("name") {
|
||||
if filter.Contains("name") {
|
||||
if !filter.Match("name", vol.Name()) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("driver") {
|
||||
if filter.Contains("driver") {
|
||||
if !filter.ExactMatch("driver", vol.DriverName()) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("label") {
|
||||
if filter.Contains("label") {
|
||||
v, ok := vol.(volume.DetailedVolume)
|
||||
if !ok {
|
||||
continue
|
||||
@@ -649,7 +649,7 @@ func (daemon *Daemon) filterVolumes(vols []volume.Volume, filter filters.Args) (
|
||||
retVols = append(retVols, vol)
|
||||
}
|
||||
danglingOnly := false
|
||||
if filter.Include("dangling") {
|
||||
if filter.Contains("dangling") {
|
||||
if filter.ExactMatch("dangling", "true") || filter.ExactMatch("dangling", "1") {
|
||||
danglingOnly = true
|
||||
} else if !filter.ExactMatch("dangling", "false") && !filter.ExactMatch("dangling", "0") {
|
||||
|
||||
@@ -182,7 +182,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
||||
rep := &types.ImagesPruneReport{}
|
||||
|
||||
danglingOnly := true
|
||||
if pruneFilters.Include("dangling") {
|
||||
if pruneFilters.Contains("dangling") {
|
||||
if pruneFilters.ExactMatch("dangling", "false") || pruneFilters.ExactMatch("dangling", "0") {
|
||||
danglingOnly = false
|
||||
} else if !pruneFilters.ExactMatch("dangling", "true") && !pruneFilters.ExactMatch("dangling", "1") {
|
||||
@@ -440,7 +440,7 @@ func (daemon *Daemon) NetworksPrune(ctx context.Context, pruneFilters filters.Ar
|
||||
|
||||
func getUntilFromPruneFilters(pruneFilters filters.Args) (time.Time, error) {
|
||||
until := time.Time{}
|
||||
if !pruneFilters.Include("until") {
|
||||
if !pruneFilters.Contains("until") {
|
||||
return until, nil
|
||||
}
|
||||
untilFilters := pruneFilters.Get("until")
|
||||
@@ -464,8 +464,8 @@ func matchLabels(pruneFilters filters.Args, labels map[string]string) bool {
|
||||
return false
|
||||
}
|
||||
// By default MatchKVList will return true if field (like 'label!') does not exist
|
||||
// So we have to add additional Include("label!") check
|
||||
if pruneFilters.Include("label!") {
|
||||
// So we have to add additional Contains("label!") check
|
||||
if pruneFilters.Contains("label!") {
|
||||
if pruneFilters.MatchKVList("label!", labels) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs s
|
||||
authConfig *types.AuthConfig,
|
||||
headers map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
|
||||
searchFilters, err := filters.FromParam(filtersArgs)
|
||||
searchFilters, err := filters.FromJSON(filtersArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -33,21 +33,21 @@ func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs s
|
||||
|
||||
var isAutomated, isOfficial bool
|
||||
var hasStarFilter = 0
|
||||
if searchFilters.Include("is-automated") {
|
||||
if searchFilters.Contains("is-automated") {
|
||||
if searchFilters.UniqueExactMatch("is-automated", "true") {
|
||||
isAutomated = true
|
||||
} else if !searchFilters.UniqueExactMatch("is-automated", "false") {
|
||||
return nil, invalidFilter{"is-automated", searchFilters.Get("is-automated")}
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("is-official") {
|
||||
if searchFilters.Contains("is-official") {
|
||||
if searchFilters.UniqueExactMatch("is-official", "true") {
|
||||
isOfficial = true
|
||||
} else if !searchFilters.UniqueExactMatch("is-official", "false") {
|
||||
return nil, invalidFilter{"is-official", searchFilters.Get("is-official")}
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("stars") {
|
||||
if searchFilters.Contains("stars") {
|
||||
hasStars := searchFilters.Get("stars")
|
||||
for _, hasStar := range hasStars {
|
||||
iHasStar, err := strconv.Atoi(hasStar)
|
||||
@@ -67,17 +67,17 @@ func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs s
|
||||
|
||||
filteredResults := []registrytypes.SearchResult{}
|
||||
for _, result := range unfilteredResult.Results {
|
||||
if searchFilters.Include("is-automated") {
|
||||
if searchFilters.Contains("is-automated") {
|
||||
if isAutomated != result.IsAutomated {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("is-official") {
|
||||
if searchFilters.Contains("is-official") {
|
||||
if isOfficial != result.IsOfficial {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if searchFilters.Include("stars") {
|
||||
if searchFilters.Contains("stars") {
|
||||
if result.StarCount < hasStarFilter {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ keywords: "API, Docker, rcli, REST, documentation"
|
||||
|
||||
[Docker Engine API v1.33](https://docs.docker.com/engine/api/v1.33/) documentation
|
||||
|
||||
|
||||
* `GET /events` now supports filtering 4 more kinds of events: `config`, `node`,
|
||||
`secret` and `service`.
|
||||
|
||||
## v1.32 API changes
|
||||
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# Entrypoint for jenkins arm CI build
|
||||
set -eu -o pipefail
|
||||
|
||||
hack/test/unit
|
||||
|
||||
hack/make.sh \
|
||||
binary-daemon \
|
||||
dynbinary \
|
||||
test-integration
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Entrypoint for jenkins experimental CI
|
||||
set -eu -o pipefail
|
||||
|
||||
export DOCKER_EXPERIMENTAL=y
|
||||
|
||||
hack/make.sh \
|
||||
binary-daemon \
|
||||
test-integration
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Entrypoint for jenkins janky CI build
|
||||
set -eu -o pipefail
|
||||
|
||||
hack/validate/default
|
||||
hack/test/unit
|
||||
|
||||
hack/make.sh \
|
||||
binary-daemon \
|
||||
dynbinary \
|
||||
test-integration \
|
||||
test-docker-py \
|
||||
cross
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Entrypoint for jenkins powerpc CI build
|
||||
set -eu -o pipefail
|
||||
|
||||
hack/test/unit
|
||||
hack/make.sh dynbinary test-integration
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Entrypoint for jenkins s390x (z) CI build
|
||||
set -eu -o pipefail
|
||||
|
||||
hack/test/unit
|
||||
hack/make.sh dynbinary test-integration
|
||||
@@ -3,7 +3,7 @@
|
||||
TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
|
||||
|
||||
# When updating RUNC_COMMIT, also update runc in vendor.conf accordingly
|
||||
RUNC_COMMIT=1c81e2a794c6e26a4c650142ae8893c47f619764
|
||||
RUNC_COMMIT=0351df1c5a66838d0c392b4ac4cf9450de844e2d
|
||||
CONTAINERD_COMMIT=06b9cb35161009dcb7123345749fef02f7cea8e0
|
||||
TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574
|
||||
LIBNETWORK_COMMIT=7b2b1feb1de4817d522cc372af149ff48d25028e
|
||||
|
||||
@@ -59,12 +59,10 @@ DEFAULT_BUNDLES=(
|
||||
binary-daemon
|
||||
dynbinary
|
||||
|
||||
test-unit
|
||||
test-integration
|
||||
test-docker-py
|
||||
|
||||
cross
|
||||
tgz
|
||||
)
|
||||
|
||||
VERSION=${VERSION:-$(< ./VERSION)}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo "DEPRECATED: use hack/test/unit instead of hack/make.sh test-unit" >&2
|
||||
|
||||
$SCRIPTDIR/test/unit 2>&1 | tee -a "$DEST/test.log"
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "tgz is deprecated"
|
||||
@@ -282,7 +282,7 @@ func getNetworkIDByName(c *check.C, name string) string {
|
||||
filterArgs = filters.NewArgs()
|
||||
)
|
||||
filterArgs.Add("name", name)
|
||||
filterJSON, err := filters.ToParam(filterArgs)
|
||||
filterJSON, err := filters.ToJSON(filterArgs)
|
||||
c.Assert(err, checker.IsNil)
|
||||
v.Set("filters", filterJSON)
|
||||
|
||||
|
||||
@@ -56,10 +56,6 @@ func ExperimentalDaemon() bool {
|
||||
return testEnv.DaemonInfo.ExperimentalBuild
|
||||
}
|
||||
|
||||
func NotExperimentalDaemon() bool {
|
||||
return !testEnv.DaemonInfo.ExperimentalBuild
|
||||
}
|
||||
|
||||
func IsAmd64() bool {
|
||||
return os.Getenv("DOCKER_ENGINE_GOARCH") == "amd64"
|
||||
}
|
||||
|
||||
@@ -365,7 +365,7 @@ func (pm *Manager) List(pluginFilters filters.Args) ([]types.Plugin, error) {
|
||||
|
||||
enabledOnly := false
|
||||
disabledOnly := false
|
||||
if pluginFilters.Include("enabled") {
|
||||
if pluginFilters.Contains("enabled") {
|
||||
if pluginFilters.ExactMatch("enabled", "true") {
|
||||
enabledOnly = true
|
||||
} else if pluginFilters.ExactMatch("enabled", "false") {
|
||||
@@ -386,7 +386,7 @@ next:
|
||||
if disabledOnly && p.PluginObj.Enabled {
|
||||
continue
|
||||
}
|
||||
if pluginFilters.Include("capability") {
|
||||
if pluginFilters.Contains("capability") {
|
||||
for _, f := range p.GetTypes() {
|
||||
if !pluginFilters.Match("capability", f.Capability) {
|
||||
continue next
|
||||
|
||||
@@ -66,7 +66,7 @@ github.com/pborman/uuid v1.0
|
||||
google.golang.org/grpc v1.3.0
|
||||
|
||||
# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly
|
||||
github.com/opencontainers/runc 1c81e2a794c6e26a4c650142ae8893c47f619764
|
||||
github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
|
||||
github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
|
||||
github.com/opencontainers/runtime-spec v1.0.0
|
||||
|
||||
|
||||
Generated
Vendored
+4
@@ -187,6 +187,10 @@ type Config struct {
|
||||
|
||||
// Rootless specifies whether the container is a rootless container.
|
||||
Rootless bool `json:"rootless"`
|
||||
|
||||
// IntelRdt specifies settings for Intel RDT/CAT group that the container is placed into
|
||||
// to limit the resources (e.g., L3 cache) the container has available
|
||||
IntelRdt *IntelRdt `json:"intel_rdt,omitempty"`
|
||||
}
|
||||
|
||||
type Hooks struct {
|
||||
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package configs
|
||||
|
||||
type IntelRdt struct {
|
||||
// The schema for L3 cache id and capacity bitmask (CBM)
|
||||
// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
|
||||
L3CacheSchema string `json:"l3_cache_schema,omitempty"`
|
||||
}
|
||||
Generated
Vendored
+109
-12
@@ -1,3 +1,4 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
@@ -19,6 +20,8 @@
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <linux/netlink.h>
|
||||
@@ -64,7 +67,13 @@ struct clone_t {
|
||||
|
||||
struct nlconfig_t {
|
||||
char *data;
|
||||
|
||||
/* Process settings. */
|
||||
uint32_t cloneflags;
|
||||
char *oom_score_adj;
|
||||
size_t oom_score_adj_len;
|
||||
|
||||
/* User namespace settings.*/
|
||||
char *uidmap;
|
||||
size_t uidmap_len;
|
||||
char *gidmap;
|
||||
@@ -72,9 +81,13 @@ struct nlconfig_t {
|
||||
char *namespaces;
|
||||
size_t namespaces_len;
|
||||
uint8_t is_setgroup;
|
||||
|
||||
/* Rootless container settings.*/
|
||||
uint8_t is_rootless;
|
||||
char *oom_score_adj;
|
||||
size_t oom_score_adj_len;
|
||||
char *uidmappath;
|
||||
size_t uidmappath_len;
|
||||
char *gidmappath;
|
||||
size_t gidmappath_len;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -89,6 +102,8 @@ struct nlconfig_t {
|
||||
#define SETGROUP_ATTR 27285
|
||||
#define OOM_SCORE_ADJ_ATTR 27286
|
||||
#define ROOTLESS_ATTR 27287
|
||||
#define UIDMAPPATH_ATTR 27288
|
||||
#define GIDMAPPATH_ATTR 27289
|
||||
|
||||
/*
|
||||
* Use the raw syscall for versions of glibc which don't include a function for
|
||||
@@ -191,22 +206,96 @@ static void update_setgroups(int pid, enum policy_t setgroup)
|
||||
}
|
||||
}
|
||||
|
||||
static void update_uidmap(int pid, char *map, size_t map_len)
|
||||
static int try_mapping_tool(const char *app, int pid, char *map, size_t map_len)
|
||||
{
|
||||
if (map == NULL || map_len <= 0)
|
||||
return;
|
||||
int child;
|
||||
|
||||
if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0)
|
||||
bail("failed to update /proc/%d/uid_map", pid);
|
||||
/*
|
||||
* If @app is NULL, execve will segfault. Just check it here and bail (if
|
||||
* we're in this path, the caller is already getting desparate and there
|
||||
* isn't a backup to this failing). This usually would be a configuration
|
||||
* or programming issue.
|
||||
*/
|
||||
if (!app)
|
||||
bail("mapping tool not present");
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
bail("failed to fork");
|
||||
|
||||
if (!child) {
|
||||
#define MAX_ARGV 20
|
||||
char *argv[MAX_ARGV];
|
||||
char *envp[] = {NULL};
|
||||
char pid_fmt[16];
|
||||
int argc = 0;
|
||||
char *next;
|
||||
|
||||
snprintf(pid_fmt, 16, "%d", pid);
|
||||
|
||||
argv[argc++] = (char *) app;
|
||||
argv[argc++] = pid_fmt;
|
||||
/*
|
||||
* Convert the map string into a list of argument that
|
||||
* newuidmap/newgidmap can understand.
|
||||
*/
|
||||
|
||||
while (argc < MAX_ARGV) {
|
||||
if (*map == '\0') {
|
||||
argv[argc++] = NULL;
|
||||
break;
|
||||
}
|
||||
argv[argc++] = map;
|
||||
next = strpbrk(map, "\n ");
|
||||
if (next == NULL)
|
||||
break;
|
||||
*next++ = '\0';
|
||||
map = next + strspn(next, "\n ");
|
||||
}
|
||||
|
||||
execve(app, argv, envp);
|
||||
bail("failed to execv");
|
||||
} else {
|
||||
int status;
|
||||
|
||||
while (true) {
|
||||
if (waitpid(child, &status, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
bail("failed to waitpid");
|
||||
}
|
||||
if (WIFEXITED(status) || WIFSIGNALED(status))
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void update_gidmap(int pid, char *map, size_t map_len)
|
||||
static void update_uidmap(const char *path, int pid, char *map, size_t map_len)
|
||||
{
|
||||
if (map == NULL || map_len <= 0)
|
||||
return;
|
||||
|
||||
if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0)
|
||||
bail("failed to update /proc/%d/gid_map", pid);
|
||||
if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0) {
|
||||
if (errno != EPERM)
|
||||
bail("failed to update /proc/%d/uid_map", pid);
|
||||
if (try_mapping_tool(path, pid, map, map_len))
|
||||
bail("failed to use newuid map on %d", pid);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_gidmap(const char *path, int pid, char *map, size_t map_len)
|
||||
{
|
||||
if (map == NULL || map_len <= 0)
|
||||
return;
|
||||
|
||||
if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0) {
|
||||
if (errno != EPERM)
|
||||
bail("failed to update /proc/%d/gid_map", pid);
|
||||
if (try_mapping_tool(path, pid, map, map_len))
|
||||
bail("failed to use newgid map on %d", pid);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_oom_score_adj(char *data, size_t len)
|
||||
@@ -350,6 +439,14 @@ static void nl_parse(int fd, struct nlconfig_t *config)
|
||||
config->gidmap = current;
|
||||
config->gidmap_len = payload_len;
|
||||
break;
|
||||
case UIDMAPPATH_ATTR:
|
||||
config->uidmappath = current;
|
||||
config->uidmappath_len = payload_len;
|
||||
break;
|
||||
case GIDMAPPATH_ATTR:
|
||||
config->gidmappath = current;
|
||||
config->gidmappath_len = payload_len;
|
||||
break;
|
||||
case SETGROUP_ATTR:
|
||||
config->is_setgroup = readint8(current);
|
||||
break;
|
||||
@@ -596,8 +693,8 @@ void nsexec(void)
|
||||
update_setgroups(child, SETGROUPS_DENY);
|
||||
|
||||
/* Set up mappings. */
|
||||
update_uidmap(child, config.uidmap, config.uidmap_len);
|
||||
update_gidmap(child, config.gidmap, config.gidmap_len);
|
||||
update_uidmap(config.uidmappath, child, config.uidmap, config.uidmap_len);
|
||||
update_gidmap(config.gidmappath, child, config.gidmap, config.gidmap_len);
|
||||
|
||||
s = SYNC_USERMAP_ACK;
|
||||
if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
|
||||
|
||||
+5
-1
@@ -18,4 +18,8 @@ github.com/golang/protobuf 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8
|
||||
github.com/docker/docker 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d
|
||||
github.com/docker/go-units v0.2.0
|
||||
github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e
|
||||
golang.org/x/sys 0e0164865330d5cf1c00247be08330bf96e2f87c https://github.com/golang/sys
|
||||
golang.org/x/sys 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce https://github.com/golang/sys
|
||||
|
||||
# console dependencies
|
||||
github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e
|
||||
github.com/pkg/errors v0.8.0
|
||||
|
||||
@@ -3,6 +3,7 @@ package volume
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -155,13 +156,20 @@ func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun f
|
||||
return
|
||||
}
|
||||
|
||||
err = label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode))
|
||||
var sourcePath string
|
||||
sourcePath, err = filepath.EvalSymlinks(m.Source)
|
||||
if err != nil {
|
||||
path = ""
|
||||
err = errors.Wrapf(err, "error evaluating symlinks from mount source %q", m.Source)
|
||||
return
|
||||
}
|
||||
err = label.Relabel(sourcePath, mountLabel, label.IsShared(m.Mode))
|
||||
if err == syscall.ENOTSUP {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
path = ""
|
||||
err = errors.Wrapf(err, "error setting label on mount source '%s'", m.Source)
|
||||
err = errors.Wrapf(err, "error setting label on mount source '%s'", sourcePath)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user