mirror of https://github.com/docker/cli.git
Fixes some unit tests to be able to run them on windows
Some of them are skipped for now (because the feature is not supported or needs more work), some of them are fixed. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
facb22573d
commit
0cf2e6353a
|
@ -3,6 +3,7 @@ package command
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
cliconfig "github.com/docker/cli/cli/config"
|
cliconfig "github.com/docker/cli/cli/config"
|
||||||
|
@ -20,6 +21,9 @@ import (
|
||||||
|
|
||||||
func TestNewAPIClientFromFlags(t *testing.T) {
|
func TestNewAPIClientFromFlags(t *testing.T) {
|
||||||
host := "unix://path"
|
host := "unix://path"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
host = "npipe://./"
|
||||||
|
}
|
||||||
opts := &flags.CommonOptions{Hosts: []string{host}}
|
opts := &flags.CommonOptions{Hosts: []string{host}}
|
||||||
configFile := &configfile.ConfigFile{
|
configFile := &configfile.ConfigFile{
|
||||||
HTTPHeaders: map[string]string{
|
HTTPHeaders: map[string]string{
|
||||||
|
|
|
@ -121,7 +121,12 @@ func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) {
|
||||||
}
|
}
|
||||||
cli := test.NewFakeCli(&fakeClient{})
|
cli := test.NewFakeCli(&fakeClient{})
|
||||||
err := runCopy(cli, options)
|
err := runCopy(cli, options)
|
||||||
assert.ErrorContains(t, err, "not a directory")
|
|
||||||
|
expectedError := "not a directory"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedError = "The filename, directory name, or volume label syntax is incorrect"
|
||||||
|
}
|
||||||
|
assert.ErrorContains(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) {
|
func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) {
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/gotestyourself/gotestyourself/assert"
|
"github.com/gotestyourself/gotestyourself/assert"
|
||||||
|
@ -51,6 +50,7 @@ func TestHistoryContext_ID(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHistoryContext_CreatedSince(t *testing.T) {
|
func TestHistoryContext_CreatedSince(t *testing.T) {
|
||||||
|
dateStr := "2009-11-10T23:00:00Z"
|
||||||
var ctx historyContext
|
var ctx historyContext
|
||||||
cases := []historyCase{
|
cases := []historyCase{
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ func TestHistoryContext_CreatedSince(t *testing.T) {
|
||||||
h: image.HistoryResponseItem{Created: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()},
|
h: image.HistoryResponseItem{Created: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()},
|
||||||
trunc: false,
|
trunc: false,
|
||||||
human: false,
|
human: false,
|
||||||
}, "2009-11-10T23:00:00Z", ctx.CreatedSince,
|
}, dateStr, ctx.CreatedSince,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
//+build linux
|
||||||
|
|
||||||
|
package image
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/cli/internal/test"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/pkg/archive"
|
||||||
|
"github.com/gotestyourself/gotestyourself/assert"
|
||||||
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
||||||
|
"github.com/gotestyourself/gotestyourself/fs"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
|
||||||
|
dest := fs.NewDir(t, "test-build-context-dest")
|
||||||
|
defer dest.Remove()
|
||||||
|
|
||||||
|
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
||||||
|
assert.NilError(t, archive.Untar(context, dest.Path(), nil))
|
||||||
|
|
||||||
|
body := new(bytes.Buffer)
|
||||||
|
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
|
||||||
|
}
|
||||||
|
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
|
||||||
|
|
||||||
|
dir := fs.NewDir(t, "test-build-context",
|
||||||
|
fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
|
||||||
|
fs.WithFile("Dockerfile", `
|
||||||
|
FROM alpine:3.6
|
||||||
|
COPY foo bar /
|
||||||
|
`),
|
||||||
|
)
|
||||||
|
defer dir.Remove()
|
||||||
|
|
||||||
|
options := newBuildOptions()
|
||||||
|
options.context = dir.Path()
|
||||||
|
|
||||||
|
err := runBuild(cli, options)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(dest.Path())
|
||||||
|
assert.NilError(t, err)
|
||||||
|
for _, fileInfo := range files {
|
||||||
|
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid))
|
||||||
|
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid))
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,9 +6,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"sort"
|
"sort"
|
||||||
"syscall"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
|
@ -18,45 +16,9 @@ import (
|
||||||
"github.com/gotestyourself/gotestyourself/assert"
|
"github.com/gotestyourself/gotestyourself/assert"
|
||||||
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
||||||
"github.com/gotestyourself/gotestyourself/fs"
|
"github.com/gotestyourself/gotestyourself/fs"
|
||||||
"github.com/gotestyourself/gotestyourself/skip"
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
|
|
||||||
skip.IfCondition(t, runtime.GOOS == "windows", "uid and gid not relevant on windows")
|
|
||||||
dest := fs.NewDir(t, "test-build-context-dest")
|
|
||||||
defer dest.Remove()
|
|
||||||
|
|
||||||
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
|
||||||
assert.NilError(t, archive.Untar(context, dest.Path(), nil))
|
|
||||||
|
|
||||||
body := new(bytes.Buffer)
|
|
||||||
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
|
|
||||||
}
|
|
||||||
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
|
|
||||||
|
|
||||||
dir := fs.NewDir(t, "test-build-context",
|
|
||||||
fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
|
|
||||||
fs.WithFile("Dockerfile", `
|
|
||||||
FROM alpine:3.6
|
|
||||||
COPY foo bar /
|
|
||||||
`),
|
|
||||||
)
|
|
||||||
defer dir.Remove()
|
|
||||||
|
|
||||||
options := newBuildOptions()
|
|
||||||
options.context = dir.Path()
|
|
||||||
|
|
||||||
err := runBuild(cli, options)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(dest.Path())
|
|
||||||
assert.NilError(t, err)
|
|
||||||
for _, fileInfo := range files {
|
|
||||||
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid))
|
|
||||||
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
|
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
|
||||||
dest, err := ioutil.TempDir("", "test-build-compress-dest")
|
dest, err := ioutil.TempDir("", "test-build-compress-dest")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
|
@ -14,7 +15,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateErrors(t *testing.T) {
|
func TestCreateErrors(t *testing.T) {
|
||||||
|
noSuchFile := "no such file or directory"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
noSuchFile = "The system cannot find the file specified."
|
||||||
|
}
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
args []string
|
args []string
|
||||||
expectedError string
|
expectedError string
|
||||||
|
@ -29,7 +33,7 @@ func TestCreateErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"plugin-foo", "nonexistent_context_dir"},
|
args: []string{"plugin-foo", "nonexistent_context_dir"},
|
||||||
expectedError: "no such file or directory",
|
expectedError: noSuchFile,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +65,12 @@ func TestCreateErrorOnContextDirWithoutConfig(t *testing.T) {
|
||||||
cmd := newCreateCommand(cli)
|
cmd := newCreateCommand(cli)
|
||||||
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
|
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
|
||||||
cmd.SetOutput(ioutil.Discard)
|
cmd.SetOutput(ioutil.Discard)
|
||||||
assert.ErrorContains(t, cmd.Execute(), "config.json: no such file or directory")
|
|
||||||
|
expectedErr := "config.json: no such file or directory"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedErr = "config.json: The system cannot find the file specified."
|
||||||
|
}
|
||||||
|
assert.ErrorContains(t, cmd.Execute(), expectedErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateErrorOnInvalidConfig(t *testing.T) {
|
func TestCreateErrorOnInvalidConfig(t *testing.T) {
|
||||||
|
|
|
@ -33,10 +33,13 @@ func TestValidateExternalNetworks(t *testing.T) {
|
||||||
inspectError: errors.New("Unexpected"),
|
inspectError: errors.New("Unexpected"),
|
||||||
expectedMsg: "Unexpected",
|
expectedMsg: "Unexpected",
|
||||||
},
|
},
|
||||||
|
// FIXME(vdemeester) that doesn't work under windows, the check needs to be smarter
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
inspectError: errors.New("host net does not exist on swarm classic"),
|
inspectError: errors.New("host net does not exist on swarm classic"),
|
||||||
network: "host",
|
network: "host",
|
||||||
},
|
},
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
network: "user",
|
network: "user",
|
||||||
expectedMsg: "is not in the right scope",
|
expectedMsg: "is not in the right scope",
|
||||||
|
|
|
@ -127,7 +127,7 @@ func TestValidateKeyArgs(t *testing.T) {
|
||||||
|
|
||||||
assert.NilError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms))
|
assert.NilError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms))
|
||||||
err = validateKeyArgs("a", pubKeyCWD)
|
err = validateKeyArgs("a", pubKeyCWD)
|
||||||
assert.Error(t, err, fmt.Sprintf("public key file already exists: \"%s/a.pub\"", pubKeyCWD))
|
assert.Error(t, err, fmt.Sprintf("public key file already exists: \"%s\"", filepath.Join(pubKeyCWD, "a.pub")))
|
||||||
|
|
||||||
err = validateKeyArgs("a", "/random/dir/")
|
err = validateKeyArgs("a", "/random/dir/")
|
||||||
assert.Error(t, err, "public key path does not exist: \"/random/dir/\"")
|
assert.Error(t, err, "public key path does not exist: \"/random/dir/\"")
|
||||||
|
|
|
@ -6,12 +6,14 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/gotestyourself/gotestyourself/assert"
|
"github.com/gotestyourself/gotestyourself/assert"
|
||||||
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
||||||
|
"github.com/gotestyourself/gotestyourself/skip"
|
||||||
"github.com/theupdateframework/notary"
|
"github.com/theupdateframework/notary"
|
||||||
"github.com/theupdateframework/notary/passphrase"
|
"github.com/theupdateframework/notary/passphrase"
|
||||||
"github.com/theupdateframework/notary/storage"
|
"github.com/theupdateframework/notary/storage"
|
||||||
|
@ -20,6 +22,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTrustKeyLoadErrors(t *testing.T) {
|
func TestTrustKeyLoadErrors(t *testing.T) {
|
||||||
|
noSuchFile := "stat iamnotakey: no such file or directory"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
noSuchFile = "CreateFile iamnotakey: The system cannot find the file specified."
|
||||||
|
}
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
|
@ -40,7 +46,7 @@ func TestTrustKeyLoadErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "not-a-key",
|
name: "not-a-key",
|
||||||
args: []string{"iamnotakey"},
|
args: []string{"iamnotakey"},
|
||||||
expectedError: "refusing to load key from iamnotakey: stat iamnotakey: no such file or directory",
|
expectedError: "refusing to load key from iamnotakey: " + noSuchFile,
|
||||||
expectedOutput: "Loading key from \"iamnotakey\"...\n",
|
expectedOutput: "Loading key from \"iamnotakey\"...\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -109,6 +115,7 @@ var testKeys = map[string][]byte{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadKeyFromPath(t *testing.T) {
|
func TestLoadKeyFromPath(t *testing.T) {
|
||||||
|
skip.If(t, runtime.GOOS == "windows")
|
||||||
for keyID, keyBytes := range testKeys {
|
for keyID, keyBytes := range testKeys {
|
||||||
t.Run(fmt.Sprintf("load-key-id-%s-from-path", keyID), func(t *testing.T) {
|
t.Run(fmt.Sprintf("load-key-id-%s-from-path", keyID), func(t *testing.T) {
|
||||||
testLoadKeyFromPath(t, keyID, keyBytes)
|
testLoadKeyFromPath(t, keyID, keyBytes)
|
||||||
|
@ -163,6 +170,7 @@ func testLoadKeyFromPath(t *testing.T, privKeyID string, privKeyFixture []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadKeyTooPermissive(t *testing.T) {
|
func TestLoadKeyTooPermissive(t *testing.T) {
|
||||||
|
skip.If(t, runtime.GOOS == "windows")
|
||||||
for keyID, keyBytes := range testKeys {
|
for keyID, keyBytes := range testKeys {
|
||||||
t.Run(fmt.Sprintf("load-key-id-%s-too-permissive", keyID), func(t *testing.T) {
|
t.Run(fmt.Sprintf("load-key-id-%s-too-permissive", keyID), func(t *testing.T) {
|
||||||
testLoadKeyTooPermissive(t, keyBytes)
|
testLoadKeyTooPermissive(t, keyBytes)
|
||||||
|
@ -219,6 +227,7 @@ H3nzy2O6Q/ct4BjOBKa+WCdRtPo78bA+C/7t81ADQO8Jqaj59W50rwoqDQ==
|
||||||
-----END PUBLIC KEY-----`)
|
-----END PUBLIC KEY-----`)
|
||||||
|
|
||||||
func TestLoadPubKeyFailure(t *testing.T) {
|
func TestLoadPubKeyFailure(t *testing.T) {
|
||||||
|
skip.If(t, runtime.GOOS == "windows")
|
||||||
pubKeyDir, err := ioutil.TempDir("", "key-load-test-pubkey-")
|
pubKeyDir, err := ioutil.TempDir("", "key-load-test-pubkey-")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
defer os.RemoveAll(pubKeyDir)
|
defer os.RemoveAll(pubKeyDir)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
|
@ -12,6 +13,7 @@ import (
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/gotestyourself/gotestyourself/assert"
|
"github.com/gotestyourself/gotestyourself/assert"
|
||||||
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
||||||
|
"github.com/gotestyourself/gotestyourself/skip"
|
||||||
"github.com/theupdateframework/notary"
|
"github.com/theupdateframework/notary"
|
||||||
"github.com/theupdateframework/notary/client"
|
"github.com/theupdateframework/notary/client"
|
||||||
"github.com/theupdateframework/notary/client/changelist"
|
"github.com/theupdateframework/notary/client/changelist"
|
||||||
|
@ -127,6 +129,7 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddStageSigners(t *testing.T) {
|
func TestAddStageSigners(t *testing.T) {
|
||||||
|
skip.If(t, runtime.GOOS == "windows", "FIXME: not supported currently")
|
||||||
tmpDir, err := ioutil.TempDir("", "notary-test-")
|
tmpDir, err := ioutil.TempDir("", "notary-test-")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
|
@ -96,7 +97,11 @@ func TestSignerAddCommandBadKeyPath(t *testing.T) {
|
||||||
cmd.SetArgs([]string{"--key", "/path/to/key.pem", "alice", "alpine"})
|
cmd.SetArgs([]string{"--key", "/path/to/key.pem", "alice", "alpine"})
|
||||||
|
|
||||||
cmd.SetOutput(ioutil.Discard)
|
cmd.SetOutput(ioutil.Discard)
|
||||||
assert.Error(t, cmd.Execute(), "unable to read public key from file: open /path/to/key.pem: no such file or directory")
|
expectedError := "unable to read public key from file: open /path/to/key.pem: no such file or directory"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedError = "unable to read public key from file: open /path/to/key.pem: The system cannot find the path specified."
|
||||||
|
}
|
||||||
|
assert.Error(t, cmd.Execute(), expectedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSignerAddCommandInvalidRepoName(t *testing.T) {
|
func TestSignerAddCommandInvalidRepoName(t *testing.T) {
|
||||||
|
@ -127,7 +132,11 @@ func TestSignerAddCommandInvalidRepoName(t *testing.T) {
|
||||||
func TestIngestPublicKeys(t *testing.T) {
|
func TestIngestPublicKeys(t *testing.T) {
|
||||||
// Call with a bad path
|
// Call with a bad path
|
||||||
_, err := ingestPublicKeys([]string{"foo", "bar"})
|
_, err := ingestPublicKeys([]string{"foo", "bar"})
|
||||||
assert.Error(t, err, "unable to read public key from file: open foo: no such file or directory")
|
expectedError := "unable to read public key from file: open foo: no such file or directory"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedError = "unable to read public key from file: open foo: The system cannot find the file specified."
|
||||||
|
}
|
||||||
|
assert.Error(t, err, expectedError)
|
||||||
// Call with real file path
|
// Call with real file path
|
||||||
tmpfile, err := ioutil.TempFile("", "pemfile")
|
tmpfile, err := ioutil.TempFile("", "pemfile")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/compose/types"
|
"github.com/docker/cli/cli/compose/types"
|
||||||
|
@ -313,10 +315,10 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
|
||||||
{Target: "/var/lib/mysql", Type: "volume"},
|
{Target: "/var/lib/mysql", Type: "volume"},
|
||||||
{Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"},
|
{Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"},
|
||||||
{Source: workingDir, Target: "/code", Type: "bind"},
|
{Source: workingDir, Target: "/code", Type: "bind"},
|
||||||
{Source: workingDir + "/static", Target: "/var/www/html", Type: "bind"},
|
{Source: filepath.Join(workingDir, "static"), Target: "/var/www/html", Type: "bind"},
|
||||||
{Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true},
|
{Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true},
|
||||||
{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"},
|
{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"},
|
||||||
{Source: workingDir + "/opt", Target: "/opt", Consistency: "cached", Type: "bind"},
|
{Source: filepath.Join(workingDir, "opt"), Target: "/opt", Consistency: "cached", Type: "bind"},
|
||||||
{Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{
|
{Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{
|
||||||
Size: int64(10000),
|
Size: int64(10000),
|
||||||
}},
|
}},
|
||||||
|
@ -389,3 +391,313 @@ func volumes() map[string]types.VolumeConfig {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fullExampleYAML(workingDir string) string {
|
||||||
|
return fmt.Sprintf(`version: "3.6"
|
||||||
|
services:
|
||||||
|
foo:
|
||||||
|
build:
|
||||||
|
context: ./dir
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
foo: bar
|
||||||
|
labels:
|
||||||
|
FOO: BAR
|
||||||
|
cache_from:
|
||||||
|
- foo
|
||||||
|
- bar
|
||||||
|
network: foo
|
||||||
|
target: foo
|
||||||
|
cap_add:
|
||||||
|
- ALL
|
||||||
|
cap_drop:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_ADMIN
|
||||||
|
cgroup_parent: m-executor-abcd
|
||||||
|
command:
|
||||||
|
- bundle
|
||||||
|
- exec
|
||||||
|
- thin
|
||||||
|
- -p
|
||||||
|
- "3000"
|
||||||
|
container_name: my-web-container
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- redis
|
||||||
|
deploy:
|
||||||
|
mode: replicated
|
||||||
|
replicas: 6
|
||||||
|
labels:
|
||||||
|
FOO: BAR
|
||||||
|
update_config:
|
||||||
|
parallelism: 3
|
||||||
|
delay: 10s
|
||||||
|
failure_action: continue
|
||||||
|
monitor: 1m0s
|
||||||
|
max_failure_ratio: 0.3
|
||||||
|
order: start-first
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: "0.001"
|
||||||
|
memory: "52428800"
|
||||||
|
reservations:
|
||||||
|
cpus: "0.0001"
|
||||||
|
memory: "20971520"
|
||||||
|
generic_resources:
|
||||||
|
- discrete_resource_spec:
|
||||||
|
kind: gpu
|
||||||
|
value: 2
|
||||||
|
- discrete_resource_spec:
|
||||||
|
kind: ssd
|
||||||
|
value: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
delay: 5s
|
||||||
|
max_attempts: 3
|
||||||
|
window: 2m0s
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- node=foo
|
||||||
|
preferences:
|
||||||
|
- spread: node.labels.az
|
||||||
|
endpoint_mode: dnsrr
|
||||||
|
devices:
|
||||||
|
- /dev/ttyUSB0:/dev/ttyUSB0
|
||||||
|
dns:
|
||||||
|
- 8.8.8.8
|
||||||
|
- 9.9.9.9
|
||||||
|
dns_search:
|
||||||
|
- dc1.example.com
|
||||||
|
- dc2.example.com
|
||||||
|
domainname: foo.com
|
||||||
|
entrypoint:
|
||||||
|
- /code/entrypoint.sh
|
||||||
|
- -p
|
||||||
|
- "3000"
|
||||||
|
environment:
|
||||||
|
BAR: bar_from_env_file_2
|
||||||
|
BAZ: baz_from_service_def
|
||||||
|
FOO: foo_from_env_file
|
||||||
|
QUX: qux_from_environment
|
||||||
|
env_file:
|
||||||
|
- ./example1.env
|
||||||
|
- ./example2.env
|
||||||
|
expose:
|
||||||
|
- "3000"
|
||||||
|
- "8000"
|
||||||
|
external_links:
|
||||||
|
- redis_1
|
||||||
|
- project_db_1:mysql
|
||||||
|
- project_db_1:postgresql
|
||||||
|
extra_hosts:
|
||||||
|
- somehost:162.242.195.82
|
||||||
|
- otherhost:50.31.209.229
|
||||||
|
hostname: foo
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
- CMD-SHELL
|
||||||
|
- echo "hello world"
|
||||||
|
timeout: 1s
|
||||||
|
interval: 10s
|
||||||
|
retries: 5
|
||||||
|
start_period: 15s
|
||||||
|
image: redis
|
||||||
|
ipc: host
|
||||||
|
labels:
|
||||||
|
com.example.description: Accounting webapp
|
||||||
|
com.example.empty-label: ""
|
||||||
|
com.example.number: "42"
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
- db:database
|
||||||
|
- redis
|
||||||
|
logging:
|
||||||
|
driver: syslog
|
||||||
|
options:
|
||||||
|
syslog-address: tcp://192.168.0.42:123
|
||||||
|
mac_address: 02:42:ac:11:65:43
|
||||||
|
network_mode: container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b
|
||||||
|
networks:
|
||||||
|
other-network:
|
||||||
|
ipv4_address: 172.16.238.10
|
||||||
|
ipv6_address: 2001:3984:3989::10
|
||||||
|
other-other-network: null
|
||||||
|
some-network:
|
||||||
|
aliases:
|
||||||
|
- alias1
|
||||||
|
- alias3
|
||||||
|
pid: host
|
||||||
|
ports:
|
||||||
|
- mode: ingress
|
||||||
|
target: 3000
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 3001
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 3002
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 3003
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 3004
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 3005
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 8000
|
||||||
|
published: 8000
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 8080
|
||||||
|
published: 9090
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 8081
|
||||||
|
published: 9091
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 22
|
||||||
|
published: 49100
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 8001
|
||||||
|
published: 8001
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5000
|
||||||
|
published: 5000
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5001
|
||||||
|
published: 5001
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5002
|
||||||
|
published: 5002
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5003
|
||||||
|
published: 5003
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5004
|
||||||
|
published: 5004
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5005
|
||||||
|
published: 5005
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5006
|
||||||
|
published: 5006
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5007
|
||||||
|
published: 5007
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5008
|
||||||
|
published: 5008
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5009
|
||||||
|
published: 5009
|
||||||
|
protocol: tcp
|
||||||
|
- mode: ingress
|
||||||
|
target: 5010
|
||||||
|
published: 5010
|
||||||
|
protocol: tcp
|
||||||
|
privileged: true
|
||||||
|
read_only: true
|
||||||
|
restart: always
|
||||||
|
security_opt:
|
||||||
|
- label=level:s0:c100,c200
|
||||||
|
- label=type:svirt_apache_t
|
||||||
|
stdin_open: true
|
||||||
|
stop_grace_period: 20s
|
||||||
|
stop_signal: SIGUSR1
|
||||||
|
tmpfs:
|
||||||
|
- /run
|
||||||
|
- /tmp
|
||||||
|
tty: true
|
||||||
|
ulimits:
|
||||||
|
nofile:
|
||||||
|
soft: 20000
|
||||||
|
hard: 40000
|
||||||
|
nproc: 65535
|
||||||
|
user: someone
|
||||||
|
volumes:
|
||||||
|
- type: volume
|
||||||
|
target: /var/lib/mysql
|
||||||
|
- type: bind
|
||||||
|
source: /opt/data
|
||||||
|
target: /var/lib/mysql
|
||||||
|
- type: bind
|
||||||
|
source: /foo
|
||||||
|
target: /code
|
||||||
|
- type: bind
|
||||||
|
source: %s
|
||||||
|
target: /var/www/html
|
||||||
|
- type: bind
|
||||||
|
source: /bar/configs
|
||||||
|
target: /etc/configs/
|
||||||
|
read_only: true
|
||||||
|
- type: volume
|
||||||
|
source: datavolume
|
||||||
|
target: /var/lib/mysql
|
||||||
|
- type: bind
|
||||||
|
source: %s
|
||||||
|
target: /opt
|
||||||
|
consistency: cached
|
||||||
|
- type: tmpfs
|
||||||
|
target: /opt
|
||||||
|
tmpfs:
|
||||||
|
size: 10000
|
||||||
|
working_dir: /code
|
||||||
|
networks:
|
||||||
|
external-network:
|
||||||
|
name: external-network
|
||||||
|
external: true
|
||||||
|
other-external-network:
|
||||||
|
name: my-cool-network
|
||||||
|
external: true
|
||||||
|
other-network:
|
||||||
|
driver: overlay
|
||||||
|
driver_opts:
|
||||||
|
baz: "1"
|
||||||
|
foo: bar
|
||||||
|
ipam:
|
||||||
|
driver: overlay
|
||||||
|
config:
|
||||||
|
- subnet: 172.16.238.0/24
|
||||||
|
- subnet: 2001:3984:3989::/64
|
||||||
|
some-network: {}
|
||||||
|
volumes:
|
||||||
|
another-volume:
|
||||||
|
name: user_specified_name
|
||||||
|
driver: vsphere
|
||||||
|
driver_opts:
|
||||||
|
baz: "1"
|
||||||
|
foo: bar
|
||||||
|
external-volume:
|
||||||
|
name: external-volume
|
||||||
|
external: true
|
||||||
|
external-volume3:
|
||||||
|
name: this-is-volume3
|
||||||
|
external: true
|
||||||
|
other-external-volume:
|
||||||
|
name: my-cool-volume
|
||||||
|
external: true
|
||||||
|
other-volume:
|
||||||
|
driver: flocker
|
||||||
|
driver_opts:
|
||||||
|
baz: "1"
|
||||||
|
foo: bar
|
||||||
|
some-volume: {}
|
||||||
|
secrets: {}
|
||||||
|
configs: {}
|
||||||
|
`, filepath.Join(workingDir, "static"), filepath.Join(workingDir, "opt"))
|
||||||
|
}
|
||||||
|
|
|
@ -9,314 +9,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMarshallConfig(t *testing.T) {
|
func TestMarshallConfig(t *testing.T) {
|
||||||
cfg := fullExampleConfig("/foo", "/bar")
|
workingDir := "/foo"
|
||||||
expected := `version: "3.6"
|
homeDir := "/bar"
|
||||||
services:
|
cfg := fullExampleConfig(workingDir, homeDir)
|
||||||
foo:
|
expected := fullExampleYAML(workingDir)
|
||||||
build:
|
|
||||||
context: ./dir
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
foo: bar
|
|
||||||
labels:
|
|
||||||
FOO: BAR
|
|
||||||
cache_from:
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
network: foo
|
|
||||||
target: foo
|
|
||||||
cap_add:
|
|
||||||
- ALL
|
|
||||||
cap_drop:
|
|
||||||
- NET_ADMIN
|
|
||||||
- SYS_ADMIN
|
|
||||||
cgroup_parent: m-executor-abcd
|
|
||||||
command:
|
|
||||||
- bundle
|
|
||||||
- exec
|
|
||||||
- thin
|
|
||||||
- -p
|
|
||||||
- "3000"
|
|
||||||
container_name: my-web-container
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
- redis
|
|
||||||
deploy:
|
|
||||||
mode: replicated
|
|
||||||
replicas: 6
|
|
||||||
labels:
|
|
||||||
FOO: BAR
|
|
||||||
update_config:
|
|
||||||
parallelism: 3
|
|
||||||
delay: 10s
|
|
||||||
failure_action: continue
|
|
||||||
monitor: 1m0s
|
|
||||||
max_failure_ratio: 0.3
|
|
||||||
order: start-first
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: "0.001"
|
|
||||||
memory: "52428800"
|
|
||||||
reservations:
|
|
||||||
cpus: "0.0001"
|
|
||||||
memory: "20971520"
|
|
||||||
generic_resources:
|
|
||||||
- discrete_resource_spec:
|
|
||||||
kind: gpu
|
|
||||||
value: 2
|
|
||||||
- discrete_resource_spec:
|
|
||||||
kind: ssd
|
|
||||||
value: 1
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
delay: 5s
|
|
||||||
max_attempts: 3
|
|
||||||
window: 2m0s
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node=foo
|
|
||||||
preferences:
|
|
||||||
- spread: node.labels.az
|
|
||||||
endpoint_mode: dnsrr
|
|
||||||
devices:
|
|
||||||
- /dev/ttyUSB0:/dev/ttyUSB0
|
|
||||||
dns:
|
|
||||||
- 8.8.8.8
|
|
||||||
- 9.9.9.9
|
|
||||||
dns_search:
|
|
||||||
- dc1.example.com
|
|
||||||
- dc2.example.com
|
|
||||||
domainname: foo.com
|
|
||||||
entrypoint:
|
|
||||||
- /code/entrypoint.sh
|
|
||||||
- -p
|
|
||||||
- "3000"
|
|
||||||
environment:
|
|
||||||
BAR: bar_from_env_file_2
|
|
||||||
BAZ: baz_from_service_def
|
|
||||||
FOO: foo_from_env_file
|
|
||||||
QUX: qux_from_environment
|
|
||||||
env_file:
|
|
||||||
- ./example1.env
|
|
||||||
- ./example2.env
|
|
||||||
expose:
|
|
||||||
- "3000"
|
|
||||||
- "8000"
|
|
||||||
external_links:
|
|
||||||
- redis_1
|
|
||||||
- project_db_1:mysql
|
|
||||||
- project_db_1:postgresql
|
|
||||||
extra_hosts:
|
|
||||||
- somehost:162.242.195.82
|
|
||||||
- otherhost:50.31.209.229
|
|
||||||
hostname: foo
|
|
||||||
healthcheck:
|
|
||||||
test:
|
|
||||||
- CMD-SHELL
|
|
||||||
- echo "hello world"
|
|
||||||
timeout: 1s
|
|
||||||
interval: 10s
|
|
||||||
retries: 5
|
|
||||||
start_period: 15s
|
|
||||||
image: redis
|
|
||||||
ipc: host
|
|
||||||
labels:
|
|
||||||
com.example.description: Accounting webapp
|
|
||||||
com.example.empty-label: ""
|
|
||||||
com.example.number: "42"
|
|
||||||
links:
|
|
||||||
- db
|
|
||||||
- db:database
|
|
||||||
- redis
|
|
||||||
logging:
|
|
||||||
driver: syslog
|
|
||||||
options:
|
|
||||||
syslog-address: tcp://192.168.0.42:123
|
|
||||||
mac_address: 02:42:ac:11:65:43
|
|
||||||
network_mode: container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b
|
|
||||||
networks:
|
|
||||||
other-network:
|
|
||||||
ipv4_address: 172.16.238.10
|
|
||||||
ipv6_address: 2001:3984:3989::10
|
|
||||||
other-other-network: null
|
|
||||||
some-network:
|
|
||||||
aliases:
|
|
||||||
- alias1
|
|
||||||
- alias3
|
|
||||||
pid: host
|
|
||||||
ports:
|
|
||||||
- mode: ingress
|
|
||||||
target: 3000
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 3001
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 3002
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 3003
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 3004
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 3005
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 8000
|
|
||||||
published: 8000
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 8080
|
|
||||||
published: 9090
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 8081
|
|
||||||
published: 9091
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 22
|
|
||||||
published: 49100
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 8001
|
|
||||||
published: 8001
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5000
|
|
||||||
published: 5000
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5001
|
|
||||||
published: 5001
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5002
|
|
||||||
published: 5002
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5003
|
|
||||||
published: 5003
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5004
|
|
||||||
published: 5004
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5005
|
|
||||||
published: 5005
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5006
|
|
||||||
published: 5006
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5007
|
|
||||||
published: 5007
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5008
|
|
||||||
published: 5008
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5009
|
|
||||||
published: 5009
|
|
||||||
protocol: tcp
|
|
||||||
- mode: ingress
|
|
||||||
target: 5010
|
|
||||||
published: 5010
|
|
||||||
protocol: tcp
|
|
||||||
privileged: true
|
|
||||||
read_only: true
|
|
||||||
restart: always
|
|
||||||
security_opt:
|
|
||||||
- label=level:s0:c100,c200
|
|
||||||
- label=type:svirt_apache_t
|
|
||||||
stdin_open: true
|
|
||||||
stop_grace_period: 20s
|
|
||||||
stop_signal: SIGUSR1
|
|
||||||
tmpfs:
|
|
||||||
- /run
|
|
||||||
- /tmp
|
|
||||||
tty: true
|
|
||||||
ulimits:
|
|
||||||
nofile:
|
|
||||||
soft: 20000
|
|
||||||
hard: 40000
|
|
||||||
nproc: 65535
|
|
||||||
user: someone
|
|
||||||
volumes:
|
|
||||||
- type: volume
|
|
||||||
target: /var/lib/mysql
|
|
||||||
- type: bind
|
|
||||||
source: /opt/data
|
|
||||||
target: /var/lib/mysql
|
|
||||||
- type: bind
|
|
||||||
source: /foo
|
|
||||||
target: /code
|
|
||||||
- type: bind
|
|
||||||
source: /foo/static
|
|
||||||
target: /var/www/html
|
|
||||||
- type: bind
|
|
||||||
source: /bar/configs
|
|
||||||
target: /etc/configs/
|
|
||||||
read_only: true
|
|
||||||
- type: volume
|
|
||||||
source: datavolume
|
|
||||||
target: /var/lib/mysql
|
|
||||||
- type: bind
|
|
||||||
source: /foo/opt
|
|
||||||
target: /opt
|
|
||||||
consistency: cached
|
|
||||||
- type: tmpfs
|
|
||||||
target: /opt
|
|
||||||
tmpfs:
|
|
||||||
size: 10000
|
|
||||||
working_dir: /code
|
|
||||||
networks:
|
|
||||||
external-network:
|
|
||||||
name: external-network
|
|
||||||
external: true
|
|
||||||
other-external-network:
|
|
||||||
name: my-cool-network
|
|
||||||
external: true
|
|
||||||
other-network:
|
|
||||||
driver: overlay
|
|
||||||
driver_opts:
|
|
||||||
baz: "1"
|
|
||||||
foo: bar
|
|
||||||
ipam:
|
|
||||||
driver: overlay
|
|
||||||
config:
|
|
||||||
- subnet: 172.16.238.0/24
|
|
||||||
- subnet: 2001:3984:3989::/64
|
|
||||||
some-network: {}
|
|
||||||
volumes:
|
|
||||||
another-volume:
|
|
||||||
name: user_specified_name
|
|
||||||
driver: vsphere
|
|
||||||
driver_opts:
|
|
||||||
baz: "1"
|
|
||||||
foo: bar
|
|
||||||
external-volume:
|
|
||||||
name: external-volume
|
|
||||||
external: true
|
|
||||||
external-volume3:
|
|
||||||
name: this-is-volume3
|
|
||||||
external: true
|
|
||||||
other-external-volume:
|
|
||||||
name: my-cool-volume
|
|
||||||
external: true
|
|
||||||
other-volume:
|
|
||||||
driver: flocker
|
|
||||||
driver_opts:
|
|
||||||
baz: "1"
|
|
||||||
foo: bar
|
|
||||||
some-volume: {}
|
|
||||||
secrets: {}
|
|
||||||
configs: {}
|
|
||||||
`
|
|
||||||
|
|
||||||
actual, err := yaml.Marshal(cfg)
|
actual, err := yaml.Marshal(cfg)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
|
@ -155,7 +155,7 @@ func pullManifestList(ctx context.Context, ref reference.Named, repo distributio
|
||||||
}
|
}
|
||||||
v, ok := manifest.(*schema2.DeserializedManifest)
|
v, ok := manifest.(*schema2.DeserializedManifest)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unsupported manifest format: %s", v)
|
return nil, fmt.Errorf("unsupported manifest format: %v", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestRef, err := reference.WithDigest(ref, manifestDescriptor.Digest)
|
manifestRef, err := reference.WithDigest(ref, manifestDescriptor.Digest)
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
shellcheck contrib/completion/bash/docker
|
shellcheck contrib/completion/bash/docker
|
||||||
find scripts/ -type f | grep -v scripts/winresources | grep -v '*.ps1' | xargs shellcheck
|
find scripts/ -type f | grep -v scripts/winresources | grep -v '.*.ps1' | xargs shellcheck
|
||||||
|
|
Loading…
Reference in New Issue