mirror of https://github.com/docker/cli.git
Merge pull request #3790 from thaJeztah/context_cleanup
context: various cleanups and improvements
This commit is contained in:
commit
a5c8d39a15
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
"github.com/docker/go-connections/tlsconfig"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -462,8 +463,8 @@ func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigF
|
||||||
}
|
}
|
||||||
if config != nil && config.CurrentContext != "" {
|
if config != nil && config.CurrentContext != "" {
|
||||||
_, err := contextstore.GetMetadata(config.CurrentContext)
|
_, err := contextstore.GetMetadata(config.CurrentContext)
|
||||||
if store.IsErrContextDoesNotExist(err) {
|
if errdefs.IsNotFound(err) {
|
||||||
return "", errors.Errorf("Current context %q is not found on the file system, please check your config file at %s", config.CurrentContext, config.Filename)
|
return "", errors.Errorf("current context %q is not found on the file system, please check your config file at %s", config.CurrentContext, config.Filename)
|
||||||
}
|
}
|
||||||
return config.CurrentContext, err
|
return config.CurrentContext, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/docker/cli/cli/command/formatter/tabwriter"
|
"github.com/docker/cli/cli/command/formatter/tabwriter"
|
||||||
"github.com/docker/cli/cli/context/docker"
|
"github.com/docker/cli/cli/context/docker"
|
||||||
"github.com/docker/cli/cli/context/store"
|
"github.com/docker/cli/cli/context/store"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -127,7 +128,7 @@ func checkContextNameForCreation(s store.Reader, name string) error {
|
||||||
if err := store.ValidateContextName(name); err != nil {
|
if err := store.ValidateContextName(name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := s.GetMetadata(name); !store.IsErrContextDoesNotExist(err) {
|
if _, err := s.GetMetadata(name); !errdefs.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "error while getting existing contexts")
|
return errors.Wrap(err, "error while getting existing contexts")
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ func RunRemove(dockerCli command.Cli, opts RemoveOptions, names []string) error
|
||||||
if name == "default" {
|
if name == "default" {
|
||||||
errs = append(errs, `default: context "default" cannot be removed`)
|
errs = append(errs, `default: context "default" cannot be removed`)
|
||||||
} else if err := doRemove(dockerCli, name, name == currentCtx, opts.Force); err != nil {
|
} else if err := doRemove(dockerCli, name, name == currentCtx, opts.Force); err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("%s: %s", name, err))
|
errs = append(errs, err.Error())
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
fmt.Fprintln(dockerCli.Out(), name)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ func RunRemove(dockerCli command.Cli, opts RemoveOptions, names []string) error
|
||||||
func doRemove(dockerCli command.Cli, name string, isCurrent, force bool) error {
|
func doRemove(dockerCli command.Cli, name string, isCurrent, force bool) error {
|
||||||
if isCurrent {
|
if isCurrent {
|
||||||
if !force {
|
if !force {
|
||||||
return errors.New("context is in use, set -f flag to force remove")
|
return errors.Errorf("context %q is in use, set -f flag to force remove", name)
|
||||||
}
|
}
|
||||||
// fallback to DOCKER_HOST
|
// fallback to DOCKER_HOST
|
||||||
cfg := dockerCli.ConfigFile()
|
cfg := dockerCli.ConfigFile()
|
||||||
|
|
|
@ -6,8 +6,9 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/cli/context/store"
|
"github.com/docker/docker/errdefs"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
is "gotest.tools/v3/assert/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRemove(t *testing.T) {
|
func TestRemove(t *testing.T) {
|
||||||
|
@ -18,7 +19,7 @@ func TestRemove(t *testing.T) {
|
||||||
_, err := cli.ContextStore().GetMetadata("current")
|
_, err := cli.ContextStore().GetMetadata("current")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
_, err = cli.ContextStore().GetMetadata("other")
|
_, err = cli.ContextStore().GetMetadata("other")
|
||||||
assert.Check(t, store.IsErrContextDoesNotExist(err))
|
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveNotAContext(t *testing.T) {
|
func TestRemoveNotAContext(t *testing.T) {
|
||||||
|
@ -38,7 +39,7 @@ func TestRemoveCurrent(t *testing.T) {
|
||||||
createTestContext(t, cli, "other")
|
createTestContext(t, cli, "other")
|
||||||
cli.SetCurrentContext("current")
|
cli.SetCurrentContext("current")
|
||||||
err := RunRemove(cli, RemoveOptions{}, []string{"current"})
|
err := RunRemove(cli, RemoveOptions{}, []string{"current"})
|
||||||
assert.ErrorContains(t, err, "current: context is in use, set -f flag to force remove")
|
assert.ErrorContains(t, err, `context "current" is in use, set -f flag to force remove`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveCurrentForce(t *testing.T) {
|
func TestRemoveCurrentForce(t *testing.T) {
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/cli/context/store"
|
|
||||||
"github.com/docker/cli/cli/flags"
|
"github.com/docker/cli/cli/flags"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/docker/pkg/homedir"
|
"github.com/docker/docker/pkg/homedir"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
|
@ -47,7 +47,7 @@ func TestUse(t *testing.T) {
|
||||||
func TestUseNoExist(t *testing.T) {
|
func TestUseNoExist(t *testing.T) {
|
||||||
cli := makeFakeCli(t)
|
cli := makeFakeCli(t)
|
||||||
err := newUseCommand(cli).RunE(nil, []string{"test"})
|
err := newUseCommand(cli).RunE(nil, []string{"test"})
|
||||||
assert.Check(t, store.IsErrContextDoesNotExist(err))
|
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestUseDefaultWithoutConfigFile verifies that the CLI does not create
|
// TestUseDefaultWithoutConfigFile verifies that the CLI does not create
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli/context/docker"
|
"github.com/docker/cli/cli/context/docker"
|
||||||
"github.com/docker/cli/cli/context/store"
|
"github.com/docker/cli/cli/context/store"
|
||||||
cliflags "github.com/docker/cli/cli/flags"
|
cliflags "github.com/docker/cli/cli/flags"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -107,7 +106,7 @@ func (s *ContextStoreWithDefault) List() ([]store.Metadata, error) {
|
||||||
// CreateOrUpdate is not allowed for the default context and fails
|
// CreateOrUpdate is not allowed for the default context and fails
|
||||||
func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
|
func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
|
||||||
if meta.Name == DefaultContextName {
|
if meta.Name == DefaultContextName {
|
||||||
return errors.New("default context cannot be created nor updated")
|
return errdefs.InvalidParameter(errors.New("default context cannot be created nor updated"))
|
||||||
}
|
}
|
||||||
return s.Store.CreateOrUpdate(meta)
|
return s.Store.CreateOrUpdate(meta)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +114,7 @@ func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
|
||||||
// Remove is not allowed for the default context and fails
|
// Remove is not allowed for the default context and fails
|
||||||
func (s *ContextStoreWithDefault) Remove(name string) error {
|
func (s *ContextStoreWithDefault) Remove(name string) error {
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
return errors.New("default context cannot be removed")
|
return errdefs.InvalidParameter(errors.New("default context cannot be removed"))
|
||||||
}
|
}
|
||||||
return s.Store.Remove(name)
|
return s.Store.Remove(name)
|
||||||
}
|
}
|
||||||
|
@ -135,7 +134,7 @@ func (s *ContextStoreWithDefault) GetMetadata(name string) (store.Metadata, erro
|
||||||
// ResetTLSMaterial is not implemented for default context and fails
|
// ResetTLSMaterial is not implemented for default context and fails
|
||||||
func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.ContextTLSData) error {
|
func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.ContextTLSData) error {
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
return errors.New("The default context store does not support ResetTLSMaterial")
|
return errdefs.InvalidParameter(errors.New("default context cannot be edited"))
|
||||||
}
|
}
|
||||||
return s.Store.ResetTLSMaterial(name, data)
|
return s.Store.ResetTLSMaterial(name, data)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +142,7 @@ func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.Cont
|
||||||
// ResetEndpointTLSMaterial is not implemented for default context and fails
|
// ResetEndpointTLSMaterial is not implemented for default context and fails
|
||||||
func (s *ContextStoreWithDefault) ResetEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
|
func (s *ContextStoreWithDefault) ResetEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
|
||||||
if contextName == DefaultContextName {
|
if contextName == DefaultContextName {
|
||||||
return errors.New("The default context store does not support ResetEndpointTLSMaterial")
|
return errdefs.InvalidParameter(errors.New("default context cannot be edited"))
|
||||||
}
|
}
|
||||||
return s.Store.ResetEndpointTLSMaterial(contextName, endpointName, data)
|
return s.Store.ResetEndpointTLSMaterial(contextName, endpointName, data)
|
||||||
}
|
}
|
||||||
|
@ -176,29 +175,13 @@ func (s *ContextStoreWithDefault) GetTLSData(contextName, endpointName, fileName
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil {
|
if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil {
|
||||||
return nil, &noDefaultTLSDataError{endpointName: endpointName, fileName: fileName}
|
return nil, errdefs.NotFound(errors.Errorf("TLS data for %s/%s/%s does not exist", DefaultContextName, endpointName, fileName))
|
||||||
}
|
}
|
||||||
return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
|
return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
|
||||||
|
|
||||||
}
|
}
|
||||||
return s.Store.GetTLSData(contextName, endpointName, fileName)
|
return s.Store.GetTLSData(contextName, endpointName, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
type noDefaultTLSDataError struct {
|
|
||||||
endpointName string
|
|
||||||
fileName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *noDefaultTLSDataError) Error() string {
|
|
||||||
return fmt.Sprintf("tls data for %s/%s/%s does not exist", DefaultContextName, e.endpointName, e.fileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotFound satisfies interface github.com/docker/docker/errdefs.ErrNotFound
|
|
||||||
func (e *noDefaultTLSDataError) NotFound() {}
|
|
||||||
|
|
||||||
// IsTLSDataDoesNotExist satisfies github.com/docker/cli/cli/context/store.tlsDataDoesNotExist
|
|
||||||
func (e *noDefaultTLSDataError) IsTLSDataDoesNotExist() {}
|
|
||||||
|
|
||||||
// GetStorageInfo implements store.Store's GetStorageInfo
|
// GetStorageInfo implements store.Store's GetStorageInfo
|
||||||
func (s *ContextStoreWithDefault) GetStorageInfo(contextName string) store.StorageInfo {
|
func (s *ContextStoreWithDefault) GetStorageInfo(contextName string) store.StorageInfo {
|
||||||
if contextName == DefaultContextName {
|
if contextName == DefaultContextName {
|
||||||
|
|
|
@ -8,8 +8,10 @@ import (
|
||||||
"github.com/docker/cli/cli/context/docker"
|
"github.com/docker/cli/cli/context/docker"
|
||||||
"github.com/docker/cli/cli/context/store"
|
"github.com/docker/cli/cli/context/store"
|
||||||
cliflags "github.com/docker/cli/cli/flags"
|
cliflags "github.com/docker/cli/cli/flags"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
"github.com/docker/go-connections/tlsconfig"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
is "gotest.tools/v3/assert/cmp"
|
||||||
"gotest.tools/v3/golden"
|
"gotest.tools/v3/golden"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -153,6 +155,7 @@ func TestErrCreateDefault(t *testing.T) {
|
||||||
Metadata: testContext{Bar: "baz"},
|
Metadata: testContext{Bar: "baz"},
|
||||||
Name: "default",
|
Name: "default",
|
||||||
})
|
})
|
||||||
|
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
|
||||||
assert.Error(t, err, "default context cannot be created nor updated")
|
assert.Error(t, err, "default context cannot be created nor updated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +163,7 @@ func TestErrRemoveDefault(t *testing.T) {
|
||||||
meta := testDefaultMetadata()
|
meta := testDefaultMetadata()
|
||||||
s := testStore(t, meta, store.ContextTLSData{})
|
s := testStore(t, meta, store.ContextTLSData{})
|
||||||
err := s.Remove("default")
|
err := s.Remove("default")
|
||||||
|
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
|
||||||
assert.Error(t, err, "default context cannot be removed")
|
assert.Error(t, err, "default context cannot be removed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,5 +171,5 @@ func TestErrTLSDataError(t *testing.T) {
|
||||||
meta := testDefaultMetadata()
|
meta := testDefaultMetadata()
|
||||||
s := testStore(t, meta, store.ContextTLSData{})
|
s := testStore(t, meta, store.ContextTLSData{})
|
||||||
_, err := s.GetTLSData("default", "noop", "noop")
|
_, err := s.GetTLSData("default", "noop", "noop")
|
||||||
assert.Check(t, store.IsErrTLSDataDoesNotExist(err))
|
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
"gotest.tools/v3/assert/cmp"
|
"gotest.tools/v3/assert/cmp"
|
||||||
)
|
)
|
||||||
|
@ -22,7 +23,7 @@ func testMetadata(name string) Metadata {
|
||||||
func TestMetadataGetNotExisting(t *testing.T) {
|
func TestMetadataGetNotExisting(t *testing.T) {
|
||||||
testee := metadataStore{root: t.TempDir(), config: testCfg}
|
testee := metadataStore{root: t.TempDir(), config: testCfg}
|
||||||
_, err := testee.get("noexist")
|
_, err := testee.get("noexist")
|
||||||
assert.Assert(t, IsErrContextDoesNotExist(err))
|
assert.ErrorType(t, err, errdefs.IsNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMetadataCreateGetRemove(t *testing.T) {
|
func TestMetadataCreateGetRemove(t *testing.T) {
|
||||||
|
@ -41,7 +42,7 @@ func TestMetadataCreateGetRemove(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
// create a new instance to check it does not depend on some sort of state
|
// create a new instance to check it does not depend on some sort of state
|
||||||
testee = metadataStore{root: testDir, config: testCfg}
|
testee = metadataStore{root: testDir, config: testCfg}
|
||||||
meta, err := testee.get(contextdirOf("test-context"))
|
meta, err := testee.get("test-context")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.DeepEqual(t, meta, testMeta)
|
assert.DeepEqual(t, meta, testMeta)
|
||||||
|
|
||||||
|
@ -49,14 +50,14 @@ func TestMetadataCreateGetRemove(t *testing.T) {
|
||||||
|
|
||||||
err = testee.createOrUpdate(expected2)
|
err = testee.createOrUpdate(expected2)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
meta, err = testee.get(contextdirOf("test-context"))
|
meta, err = testee.get("test-context")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.DeepEqual(t, meta, expected2)
|
assert.DeepEqual(t, meta, expected2)
|
||||||
|
|
||||||
assert.NilError(t, testee.remove(contextdirOf("test-context")))
|
assert.NilError(t, testee.remove("test-context"))
|
||||||
assert.NilError(t, testee.remove(contextdirOf("test-context"))) // support duplicate remove
|
assert.NilError(t, testee.remove("test-context")) // support duplicate remove
|
||||||
_, err = testee.get(contextdirOf("test-context"))
|
_, err = testee.get("test-context")
|
||||||
assert.Assert(t, IsErrContextDoesNotExist(err))
|
assert.ErrorType(t, err, errdefs.IsNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMetadataRespectJsonAnnotation(t *testing.T) {
|
func TestMetadataRespectJsonAnnotation(t *testing.T) {
|
||||||
|
@ -121,7 +122,7 @@ func TestWithEmbedding(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.NilError(t, testee.createOrUpdate(Metadata{Metadata: testCtxMeta, Name: "test"}))
|
assert.NilError(t, testee.createOrUpdate(Metadata{Metadata: testCtxMeta, Name: "test"}))
|
||||||
res, err := testee.get(contextdirOf("test"))
|
res, err := testee.get("test")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, testCtxMeta, res.Metadata)
|
assert.Equal(t, testCtxMeta, res.Metadata)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,14 @@ package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/fvbommel/sortorder"
|
"github.com/fvbommel/sortorder"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -55,11 +56,21 @@ func parseTypedOrMap(payload []byte, getter TypeGetter) (interface{}, error) {
|
||||||
return reflect.ValueOf(typed).Elem().Interface(), nil
|
return reflect.ValueOf(typed).Elem().Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *metadataStore) get(id contextdir) (Metadata, error) {
|
func (s *metadataStore) get(name string) (Metadata, error) {
|
||||||
contextDir := s.contextDir(id)
|
m, err := s.getByID(contextdirOf(name))
|
||||||
bytes, err := os.ReadFile(filepath.Join(contextDir, metaFile))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Metadata{}, convertContextDoesNotExist(err)
|
return m, errors.Wrapf(err, "load context %q", name)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *metadataStore) getByID(id contextdir) (Metadata, error) {
|
||||||
|
bytes, err := os.ReadFile(filepath.Join(s.contextDir(id), metaFile))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
return Metadata{}, errdefs.NotFound(errors.Wrap(err, "context does not exist"))
|
||||||
|
}
|
||||||
|
return Metadata{}, err
|
||||||
}
|
}
|
||||||
var untyped untypedContextMetadata
|
var untyped untypedContextMetadata
|
||||||
r := Metadata{
|
r := Metadata{
|
||||||
|
@ -80,9 +91,11 @@ func (s *metadataStore) get(id contextdir) (Metadata, error) {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *metadataStore) remove(id contextdir) error {
|
func (s *metadataStore) remove(name string) error {
|
||||||
contextDir := s.contextDir(id)
|
if err := os.RemoveAll(s.contextDir(contextdirOf(name))); err != nil {
|
||||||
return os.RemoveAll(contextDir)
|
return errors.Wrapf(err, "failed to remove metadata")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *metadataStore) list() ([]Metadata, error) {
|
func (s *metadataStore) list() ([]Metadata, error) {
|
||||||
|
@ -95,9 +108,12 @@ func (s *metadataStore) list() ([]Metadata, error) {
|
||||||
}
|
}
|
||||||
var res []Metadata
|
var res []Metadata
|
||||||
for _, dir := range ctxDirs {
|
for _, dir := range ctxDirs {
|
||||||
c, err := s.get(contextdir(dir))
|
c, err := s.getByID(contextdir(dir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
if os.IsNotExist(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, errors.Wrap(err, "failed to read metadata")
|
||||||
}
|
}
|
||||||
res = append(res, c)
|
res = append(res, c)
|
||||||
}
|
}
|
||||||
|
@ -131,20 +147,13 @@ func listRecursivelyMetadataDirs(root string) ([]string, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, s := range subs {
|
for _, s := range subs {
|
||||||
result = append(result, fmt.Sprintf("%s/%s", fi.Name(), s))
|
result = append(result, filepath.Join(fi.Name(), s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertContextDoesNotExist(err error) error {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return &contextDoesNotExistError{}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type untypedContextMetadata struct {
|
type untypedContextMetadata struct {
|
||||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||||
Endpoints map[string]json.RawMessage `json:"endpoints,omitempty"`
|
Endpoints map[string]json.RawMessage `json:"endpoints,omitempty"`
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
_ "crypto/sha256" // ensure ids can be computed
|
_ "crypto/sha256" // ensure ids can be computed
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
@ -94,11 +93,11 @@ type ContextTLSData struct {
|
||||||
|
|
||||||
// New creates a store from a given directory.
|
// New creates a store from a given directory.
|
||||||
// If the directory does not exist or is empty, initialize it
|
// If the directory does not exist or is empty, initialize it
|
||||||
func New(dir string, cfg Config) Store {
|
func New(dir string, cfg Config) *ContextStore {
|
||||||
metaRoot := filepath.Join(dir, metadataDir)
|
metaRoot := filepath.Join(dir, metadataDir)
|
||||||
tlsRoot := filepath.Join(dir, tlsDir)
|
tlsRoot := filepath.Join(dir, tlsDir)
|
||||||
|
|
||||||
return &store{
|
return &ContextStore{
|
||||||
meta: &metadataStore{
|
meta: &metadataStore{
|
||||||
root: metaRoot,
|
root: metaRoot,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
|
@ -109,12 +108,14 @@ func New(dir string, cfg Config) Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type store struct {
|
// ContextStore implements Store.
|
||||||
|
type ContextStore struct {
|
||||||
meta *metadataStore
|
meta *metadataStore
|
||||||
tls *tlsStore
|
tls *tlsStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) List() ([]Metadata, error) {
|
// List return all contexts.
|
||||||
|
func (s *ContextStore) List() ([]Metadata, error) {
|
||||||
return s.meta.list()
|
return s.meta.list()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,73 +132,82 @@ func Names(s Lister) ([]string, error) {
|
||||||
return names, nil
|
return names, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) CreateOrUpdate(meta Metadata) error {
|
// CreateOrUpdate creates or updates metadata for the context.
|
||||||
|
func (s *ContextStore) CreateOrUpdate(meta Metadata) error {
|
||||||
return s.meta.createOrUpdate(meta)
|
return s.meta.createOrUpdate(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) Remove(name string) error {
|
// Remove deletes the context with the given name, if found.
|
||||||
id := contextdirOf(name)
|
func (s *ContextStore) Remove(name string) error {
|
||||||
if err := s.meta.remove(id); err != nil {
|
if err := s.meta.remove(name); err != nil {
|
||||||
return patchErrContextName(err, name)
|
return errors.Wrapf(err, "failed to remove context %s", name)
|
||||||
}
|
}
|
||||||
return patchErrContextName(s.tls.removeAllContextData(id), name)
|
if err := s.tls.remove(name); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to remove context %s", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetMetadata(name string) (Metadata, error) {
|
// GetMetadata returns the metadata for the context with the given name.
|
||||||
res, err := s.meta.get(contextdirOf(name))
|
// It returns an errdefs.ErrNotFound if the context was not found.
|
||||||
patchErrContextName(err, name)
|
func (s *ContextStore) GetMetadata(name string) (Metadata, error) {
|
||||||
return res, err
|
return s.meta.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ResetTLSMaterial(name string, data *ContextTLSData) error {
|
// ResetTLSMaterial removes TLS data for all endpoints in the context and replaces
|
||||||
id := contextdirOf(name)
|
// it with the new data.
|
||||||
if err := s.tls.removeAllContextData(id); err != nil {
|
func (s *ContextStore) ResetTLSMaterial(name string, data *ContextTLSData) error {
|
||||||
return patchErrContextName(err, name)
|
if err := s.tls.remove(name); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for ep, files := range data.Endpoints {
|
for ep, files := range data.Endpoints {
|
||||||
for fileName, data := range files.Files {
|
for fileName, data := range files.Files {
|
||||||
if err := s.tls.createOrUpdate(id, ep, fileName, data); err != nil {
|
if err := s.tls.createOrUpdate(name, ep, fileName, data); err != nil {
|
||||||
return patchErrContextName(err, name)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ResetEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error {
|
// ResetEndpointTLSMaterial removes TLS data for the given context and endpoint,
|
||||||
id := contextdirOf(contextName)
|
// and replaces it with the new data.
|
||||||
if err := s.tls.removeAllEndpointData(id, endpointName); err != nil {
|
func (s *ContextStore) ResetEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error {
|
||||||
return patchErrContextName(err, contextName)
|
if err := s.tls.removeEndpoint(contextName, endpointName); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for fileName, data := range data.Files {
|
for fileName, data := range data.Files {
|
||||||
if err := s.tls.createOrUpdate(id, endpointName, fileName, data); err != nil {
|
if err := s.tls.createOrUpdate(contextName, endpointName, fileName, data); err != nil {
|
||||||
return patchErrContextName(err, contextName)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ListTLSFiles(name string) (map[string]EndpointFiles, error) {
|
// ListTLSFiles returns the list of TLS files present for each endpoint in the
|
||||||
res, err := s.tls.listContextData(contextdirOf(name))
|
// context.
|
||||||
return res, patchErrContextName(err, name)
|
func (s *ContextStore) ListTLSFiles(name string) (map[string]EndpointFiles, error) {
|
||||||
|
return s.tls.listContextData(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
// GetTLSData reads, and returns the content of the given fileName for an endpoint.
|
||||||
res, err := s.tls.getData(contextdirOf(contextName), endpointName, fileName)
|
// It returns an errdefs.ErrNotFound if the file was not found.
|
||||||
return res, patchErrContextName(err, contextName)
|
func (s *ContextStore) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
||||||
|
return s.tls.getData(contextName, endpointName, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetStorageInfo(contextName string) StorageInfo {
|
// GetStorageInfo returns the paths where the Metadata and TLS data are stored
|
||||||
dir := contextdirOf(contextName)
|
// for the context.
|
||||||
|
func (s *ContextStore) GetStorageInfo(contextName string) StorageInfo {
|
||||||
return StorageInfo{
|
return StorageInfo{
|
||||||
MetadataPath: s.meta.contextDir(dir),
|
MetadataPath: s.meta.contextDir(contextdirOf(contextName)),
|
||||||
TLSPath: s.tls.contextDir(dir),
|
TLSPath: s.tls.contextDir(contextName),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +220,7 @@ func ValidateContextName(name string) error {
|
||||||
return errors.New(`"default" is a reserved context name`)
|
return errors.New(`"default" is a reserved context name`)
|
||||||
}
|
}
|
||||||
if !restrictedNameRegEx.MatchString(name) {
|
if !restrictedNameRegEx.MatchString(name) {
|
||||||
return fmt.Errorf("context name %q is invalid, names are validated against regexp %q", name, restrictedNamePattern)
|
return errors.Errorf("context name %q is invalid, names are validated against regexp %q", name, restrictedNamePattern)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -484,58 +494,18 @@ func importEndpointTLS(tlsData *ContextTLSData, path string, data []byte) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type setContextName interface {
|
// IsErrContextDoesNotExist checks if the given error is a "context does not exist" condition.
|
||||||
setContext(name string)
|
//
|
||||||
}
|
// Deprecated: use github.com/docker/docker/errdefs.IsNotFound()
|
||||||
|
|
||||||
type contextDoesNotExistError struct {
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *contextDoesNotExistError) Error() string {
|
|
||||||
return fmt.Sprintf("context %q does not exist", e.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *contextDoesNotExistError) setContext(name string) {
|
|
||||||
e.name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotFound satisfies interface github.com/docker/docker/errdefs.ErrNotFound
|
|
||||||
func (e *contextDoesNotExistError) NotFound() {}
|
|
||||||
|
|
||||||
type tlsDataDoesNotExist interface {
|
|
||||||
errdefs.ErrNotFound
|
|
||||||
IsTLSDataDoesNotExist()
|
|
||||||
}
|
|
||||||
|
|
||||||
type tlsDataDoesNotExistError struct {
|
|
||||||
context, endpoint, file string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *tlsDataDoesNotExistError) Error() string {
|
|
||||||
return fmt.Sprintf("tls data for %s/%s/%s does not exist", e.context, e.endpoint, e.file)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *tlsDataDoesNotExistError) setContext(name string) {
|
|
||||||
e.context = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotFound satisfies interface github.com/docker/docker/errdefs.ErrNotFound
|
|
||||||
func (e *tlsDataDoesNotExistError) NotFound() {}
|
|
||||||
|
|
||||||
// IsTLSDataDoesNotExist satisfies tlsDataDoesNotExist
|
|
||||||
func (e *tlsDataDoesNotExistError) IsTLSDataDoesNotExist() {}
|
|
||||||
|
|
||||||
// IsErrContextDoesNotExist checks if the given error is a "context does not exist" condition
|
|
||||||
func IsErrContextDoesNotExist(err error) bool {
|
func IsErrContextDoesNotExist(err error) bool {
|
||||||
_, ok := err.(*contextDoesNotExistError)
|
return errdefs.IsNotFound(err)
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrTLSDataDoesNotExist checks if the given error is a "context does not exist" condition
|
// IsErrTLSDataDoesNotExist checks if the given error is a "context does not exist" condition
|
||||||
|
//
|
||||||
|
// Deprecated: use github.com/docker/docker/errdefs.IsNotFound()
|
||||||
func IsErrTLSDataDoesNotExist(err error) bool {
|
func IsErrTLSDataDoesNotExist(err error) bool {
|
||||||
_, ok := err.(tlsDataDoesNotExist)
|
return errdefs.IsNotFound(err)
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type contextdir string
|
type contextdir string
|
||||||
|
@ -543,10 +513,3 @@ type contextdir string
|
||||||
func contextdirOf(name string) contextdir {
|
func contextdirOf(name string) contextdir {
|
||||||
return contextdir(digest.FromString(name).Encoded())
|
return contextdir(digest.FromString(name).Encoded())
|
||||||
}
|
}
|
||||||
|
|
||||||
func patchErrContextName(err error, name string) error {
|
|
||||||
if typed, ok := err.(setContextName); ok {
|
|
||||||
typed.setContext(name)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
is "gotest.tools/v3/assert/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpoint struct {
|
type endpoint struct {
|
||||||
|
@ -100,7 +102,7 @@ func TestRemove(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
assert.NilError(t, s.Remove("source"))
|
assert.NilError(t, s.Remove("source"))
|
||||||
_, err = s.GetMetadata("source")
|
_, err = s.GetMetadata("source")
|
||||||
assert.Check(t, IsErrContextDoesNotExist(err))
|
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
|
||||||
f, err := s.ListTLSFiles("source")
|
f, err := s.ListTLSFiles("source")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, 0, len(f))
|
assert.Equal(t, 0, len(f))
|
||||||
|
@ -115,7 +117,7 @@ func TestListEmptyStore(t *testing.T) {
|
||||||
func TestErrHasCorrectContext(t *testing.T) {
|
func TestErrHasCorrectContext(t *testing.T) {
|
||||||
_, err := New(t.TempDir(), testCfg).GetMetadata("no-exists")
|
_, err := New(t.TempDir(), testCfg).GetMetadata("no-exists")
|
||||||
assert.ErrorContains(t, err, "no-exists")
|
assert.ErrorContains(t, err, "no-exists")
|
||||||
assert.Check(t, IsErrContextDoesNotExist(err))
|
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetectImportContentType(t *testing.T) {
|
func TestDetectImportContentType(t *testing.T) {
|
||||||
|
@ -173,7 +175,7 @@ func TestImportZip(t *testing.T) {
|
||||||
Name: "source",
|
Name: "source",
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
var files = []struct {
|
files := []struct {
|
||||||
Name, Body string
|
Name, Body string
|
||||||
}{
|
}{
|
||||||
{"meta.json", string(meta)},
|
{"meta.json", string(meta)},
|
||||||
|
|
|
@ -19,7 +19,7 @@ func EndpointTypeGetter(name string, getter TypeGetter) NamedTypeGetter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is used to configure the metadata marshaler of the context store
|
// Config is used to configure the metadata marshaler of the context ContextStore
|
||||||
type Config struct {
|
type Config struct {
|
||||||
contextType TypeGetter
|
contextType TypeGetter
|
||||||
endpointTypes map[string]TypeGetter
|
endpointTypes map[string]TypeGetter
|
||||||
|
|
|
@ -6,10 +6,12 @@ import (
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testCtx struct{}
|
type (
|
||||||
type testEP1 struct{}
|
testCtx struct{}
|
||||||
type testEP2 struct{}
|
testEP1 struct{}
|
||||||
type testEP3 struct{}
|
testEP2 struct{}
|
||||||
|
testEP3 struct{}
|
||||||
|
)
|
||||||
|
|
||||||
func TestConfigModification(t *testing.T) {
|
func TestConfigModification(t *testing.T) {
|
||||||
cfg := NewConfig(func() interface{} { return &testCtx{} }, EndpointTypeGetter("ep1", func() interface{} { return &testEP1{} }))
|
cfg := NewConfig(func() interface{} { return &testCtx{} }, EndpointTypeGetter("ep1", func() interface{} { return &testEP1{} }))
|
||||||
|
|
|
@ -3,6 +3,9 @@ package store
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tlsDir = "tls"
|
const tlsDir = "tls"
|
||||||
|
@ -11,69 +14,70 @@ type tlsStore struct {
|
||||||
root string
|
root string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) contextDir(id contextdir) string {
|
func (s *tlsStore) contextDir(name string) string {
|
||||||
return filepath.Join(s.root, string(id))
|
return filepath.Join(s.root, string(contextdirOf(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) endpointDir(contextID contextdir, name string) string {
|
func (s *tlsStore) endpointDir(name, endpointName string) string {
|
||||||
return filepath.Join(s.root, string(contextID), name)
|
return filepath.Join(s.contextDir(name), endpointName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) filePath(contextID contextdir, endpointName, filename string) string {
|
func (s *tlsStore) createOrUpdate(name, endpointName, filename string, data []byte) error {
|
||||||
return filepath.Join(s.root, string(contextID), endpointName, filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tlsStore) createOrUpdate(contextID contextdir, endpointName, filename string, data []byte) error {
|
|
||||||
epdir := s.endpointDir(contextID, endpointName)
|
|
||||||
parentOfRoot := filepath.Dir(s.root)
|
parentOfRoot := filepath.Dir(s.root)
|
||||||
if err := os.MkdirAll(parentOfRoot, 0755); err != nil {
|
if err := os.MkdirAll(parentOfRoot, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(epdir, 0700); err != nil {
|
endpointDir := s.endpointDir(name, endpointName)
|
||||||
|
if err := os.MkdirAll(endpointDir, 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(s.filePath(contextID, endpointName, filename), data, 0600)
|
return os.WriteFile(filepath.Join(endpointDir, filename), data, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) getData(contextID contextdir, endpointName, filename string) ([]byte, error) {
|
func (s *tlsStore) getData(name, endpointName, filename string) ([]byte, error) {
|
||||||
data, err := os.ReadFile(s.filePath(contextID, endpointName, filename))
|
data, err := os.ReadFile(filepath.Join(s.endpointDir(name, endpointName), filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, convertTLSDataDoesNotExist(endpointName, filename, err)
|
if os.IsNotExist(err) {
|
||||||
|
return nil, errdefs.NotFound(errors.Errorf("TLS data for %s/%s/%s does not exist", name, endpointName, filename))
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(err, "failed to read TLS data for endpoint %s", endpointName)
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) remove(contextID contextdir, endpointName, filename string) error {
|
// remove deletes all TLS data for the given context.
|
||||||
err := os.Remove(s.filePath(contextID, endpointName, filename))
|
func (s *tlsStore) remove(name string) error {
|
||||||
if os.IsNotExist(err) {
|
if err := os.RemoveAll(s.contextDir(name)); err != nil {
|
||||||
return nil
|
return errors.Wrapf(err, "failed to remove TLS data")
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) removeAllEndpointData(contextID contextdir, endpointName string) error {
|
func (s *tlsStore) removeEndpoint(name, endpointName string) error {
|
||||||
return os.RemoveAll(s.endpointDir(contextID, endpointName))
|
if err := os.RemoveAll(s.endpointDir(name, endpointName)); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to remove TLS data for endpoint %s", endpointName)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tlsStore) removeAllContextData(contextID contextdir) error {
|
func (s *tlsStore) listContextData(name string) (map[string]EndpointFiles, error) {
|
||||||
return os.RemoveAll(s.contextDir(contextID))
|
contextDir := s.contextDir(name)
|
||||||
}
|
epFSs, err := os.ReadDir(contextDir)
|
||||||
|
|
||||||
func (s *tlsStore) listContextData(contextID contextdir) (map[string]EndpointFiles, error) {
|
|
||||||
epFSs, err := os.ReadDir(s.contextDir(contextID))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return map[string]EndpointFiles{}, nil
|
return map[string]EndpointFiles{}, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, errors.Wrapf(err, "failed to list TLS files for context %s", name)
|
||||||
}
|
}
|
||||||
r := make(map[string]EndpointFiles)
|
r := make(map[string]EndpointFiles)
|
||||||
for _, epFS := range epFSs {
|
for _, epFS := range epFSs {
|
||||||
if epFS.IsDir() {
|
if epFS.IsDir() {
|
||||||
epDir := s.endpointDir(contextID, epFS.Name())
|
fss, err := os.ReadDir(filepath.Join(contextDir, epFS.Name()))
|
||||||
fss, err := os.ReadDir(epDir)
|
if os.IsNotExist(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrapf(err, "failed to list TLS files for endpoint %s", epFS.Name())
|
||||||
}
|
}
|
||||||
var files EndpointFiles
|
var files EndpointFiles
|
||||||
for _, fs := range fss {
|
for _, fs := range fss {
|
||||||
|
@ -89,10 +93,3 @@ func (s *tlsStore) listContextData(contextID contextdir) (map[string]EndpointFil
|
||||||
|
|
||||||
// EndpointFiles is a slice of strings representing file names
|
// EndpointFiles is a slice of strings representing file names
|
||||||
type EndpointFiles []string
|
type EndpointFiles []string
|
||||||
|
|
||||||
func convertTLSDataDoesNotExist(endpoint, file string, err error) error {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return &tlsDataDoesNotExistError{endpoint: endpoint, file: file}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,32 +3,33 @@ package store
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTlsCreateUpdateGetRemove(t *testing.T) {
|
func TestTlsCreateUpdateGetRemove(t *testing.T) {
|
||||||
testee := tlsStore{root: t.TempDir()}
|
testee := tlsStore{root: t.TempDir()}
|
||||||
_, err := testee.getData("test-ctx", "test-ep", "test-data")
|
|
||||||
assert.Equal(t, true, IsErrTLSDataDoesNotExist(err))
|
|
||||||
|
|
||||||
err = testee.createOrUpdate("test-ctx", "test-ep", "test-data", []byte("data"))
|
const contextName = "test-ctx"
|
||||||
|
|
||||||
|
_, err := testee.getData(contextName, "test-ep", "test-data")
|
||||||
|
assert.ErrorType(t, err, errdefs.IsNotFound)
|
||||||
|
|
||||||
|
err = testee.createOrUpdate(contextName, "test-ep", "test-data", []byte("data"))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
data, err := testee.getData("test-ctx", "test-ep", "test-data")
|
data, err := testee.getData(contextName, "test-ep", "test-data")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, string(data), "data")
|
assert.Equal(t, string(data), "data")
|
||||||
err = testee.createOrUpdate("test-ctx", "test-ep", "test-data", []byte("data2"))
|
err = testee.createOrUpdate(contextName, "test-ep", "test-data", []byte("data2"))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
data, err = testee.getData("test-ctx", "test-ep", "test-data")
|
data, err = testee.getData(contextName, "test-ep", "test-data")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, string(data), "data2")
|
assert.Equal(t, string(data), "data2")
|
||||||
|
|
||||||
err = testee.remove("test-ctx", "test-ep", "test-data")
|
err = testee.removeEndpoint(contextName, "test-ep")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
err = testee.remove("test-ctx", "test-ep", "test-data")
|
_, err = testee.getData(contextName, "test-ep", "test-data")
|
||||||
assert.NilError(t, err)
|
assert.ErrorType(t, err, errdefs.IsNotFound)
|
||||||
|
|
||||||
_, err = testee.getData("test-ctx", "test-ep", "test-data")
|
|
||||||
assert.Equal(t, true, IsErrTLSDataDoesNotExist(err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTlsListAndBatchRemove(t *testing.T) {
|
func TestTlsListAndBatchRemove(t *testing.T) {
|
||||||
|
@ -45,26 +46,27 @@ func TestTlsListAndBatchRemove(t *testing.T) {
|
||||||
"ep2": {"f1", "f2", "f3"},
|
"ep2": {"f1", "f2", "f3"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contextName = "test-ctx"
|
||||||
for name, files := range all {
|
for name, files := range all {
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
err := testee.createOrUpdate("test-ctx", name, file, []byte("data"))
|
err := testee.createOrUpdate(contextName, name, file, []byte("data"))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resAll, err := testee.listContextData("test-ctx")
|
resAll, err := testee.listContextData(contextName)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.DeepEqual(t, resAll, all)
|
assert.DeepEqual(t, resAll, all)
|
||||||
|
|
||||||
err = testee.removeAllEndpointData("test-ctx", "ep3")
|
err = testee.removeEndpoint(contextName, "ep3")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
resEp1ep2, err := testee.listContextData("test-ctx")
|
resEp1ep2, err := testee.listContextData(contextName)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.DeepEqual(t, resEp1ep2, ep1ep2)
|
assert.DeepEqual(t, resEp1ep2, ep1ep2)
|
||||||
|
|
||||||
err = testee.removeAllContextData("test-ctx")
|
err = testee.remove(contextName)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
resEmpty, err := testee.listContextData("test-ctx")
|
resEmpty, err := testee.listContextData(contextName)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.DeepEqual(t, resEmpty, map[string]EndpointFiles{})
|
assert.DeepEqual(t, resEmpty, map[string]EndpointFiles{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,14 +45,14 @@ func (data *TLSData) ToStoreTLSData() *store.EndpointTLSData {
|
||||||
func LoadTLSData(s store.Reader, contextName, endpointName string) (*TLSData, error) {
|
func LoadTLSData(s store.Reader, contextName, endpointName string) (*TLSData, error) {
|
||||||
tlsFiles, err := s.ListTLSFiles(contextName)
|
tlsFiles, err := s.ListTLSFiles(contextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to retrieve context tls files for context %q", contextName)
|
return nil, errors.Wrapf(err, "failed to retrieve TLS files for context %q", contextName)
|
||||||
}
|
}
|
||||||
if epTLSFiles, ok := tlsFiles[endpointName]; ok {
|
if epTLSFiles, ok := tlsFiles[endpointName]; ok {
|
||||||
var tlsData TLSData
|
var tlsData TLSData
|
||||||
for _, f := range epTLSFiles {
|
for _, f := range epTLSFiles {
|
||||||
data, err := s.GetTLSData(contextName, endpointName, f)
|
data, err := s.GetTLSData(contextName, endpointName, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to retrieve context tls data for file %q of context %q", f, contextName)
|
return nil, errors.Wrapf(err, "failed to retrieve TLS data (%s) for context %q", f, contextName)
|
||||||
}
|
}
|
||||||
switch f {
|
switch f {
|
||||||
case caKey:
|
case caKey:
|
||||||
|
@ -62,7 +62,7 @@ func LoadTLSData(s store.Reader, contextName, endpointName string) (*TLSData, er
|
||||||
case keyKey:
|
case keyKey:
|
||||||
tlsData.Key = data
|
tlsData.Key = data
|
||||||
default:
|
default:
|
||||||
logrus.Warnf("unknown file %s in context %s tls bundle", f, contextName)
|
logrus.Warnf("unknown file in context %s TLS bundle: %s", contextName, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &tlsData, nil
|
return &tlsData, nil
|
||||||
|
|
Loading…
Reference in New Issue