mirror of https://github.com/docker/compose.git
Store context type in metadata to make retrocompatibility with previous contexts easier (potentially switching back and forth)
This commit is contained in:
parent
8930563a25
commit
e7682682fb
|
@ -79,7 +79,7 @@ func runList(ctx context.Context) error {
|
|||
fmt.Fprintf(w,
|
||||
format,
|
||||
contextName,
|
||||
c.Type,
|
||||
c.Type(),
|
||||
c.Metadata.Description,
|
||||
getEndpoint("docker", c.Endpoints),
|
||||
getEndpoint("kubernetes", c.Endpoints),
|
||||
|
|
|
@ -49,13 +49,13 @@ func New(ctx context.Context) (*Client, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
service, err := backend.Get(ctx, cc.Type)
|
||||
service, err := backend.Get(ctx, cc.Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
backendType: cc.Type,
|
||||
backendType: cc.Type(),
|
||||
bs: service,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package store
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// DockerContext represents the docker context metadata
|
||||
type DockerContext struct {
|
||||
Name string `json:",omitempty"`
|
||||
Metadata ContextMetadata `json:",omitempty"`
|
||||
Endpoints map[string]interface{} `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Type the context type
|
||||
func (m *DockerContext) Type() string {
|
||||
if m.Metadata.Type == "" {
|
||||
return defaultContextType
|
||||
}
|
||||
return m.Metadata.Type
|
||||
}
|
||||
|
||||
// ContextMetadata is represtentation of the data we put in a context
|
||||
// metadata
|
||||
type ContextMetadata struct {
|
||||
Type string
|
||||
Description string
|
||||
StackOrchestrator string
|
||||
AdditionalFields map[string]interface{}
|
||||
}
|
||||
|
||||
// AciContext is the context for the ACI backend
|
||||
type AciContext struct {
|
||||
SubscriptionID string `json:",omitempty"`
|
||||
Location string `json:",omitempty"`
|
||||
ResourceGroup string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// MobyContext is the context for the moby backend
|
||||
type MobyContext struct{}
|
||||
|
||||
// ExampleContext is the context for the example backend
|
||||
type ExampleContext struct{}
|
||||
|
||||
// MarshalJSON implements custom JSON marshalling
|
||||
func (dc ContextMetadata) MarshalJSON() ([]byte, error) {
|
||||
s := map[string]interface{}{}
|
||||
if dc.Description != "" {
|
||||
s["Description"] = dc.Description
|
||||
}
|
||||
if dc.StackOrchestrator != "" {
|
||||
s["StackOrchestrator"] = dc.StackOrchestrator
|
||||
}
|
||||
if dc.Type != "" {
|
||||
s["Type"] = dc.Type
|
||||
}
|
||||
if dc.AdditionalFields != nil {
|
||||
for k, v := range dc.AdditionalFields {
|
||||
s[k] = v
|
||||
}
|
||||
}
|
||||
return json.Marshal(s)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON marshalling
|
||||
func (dc *ContextMetadata) UnmarshalJSON(payload []byte) error {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(payload, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range data {
|
||||
switch k {
|
||||
case "Description":
|
||||
dc.Description = v.(string)
|
||||
case "StackOrchestrator":
|
||||
dc.StackOrchestrator = v.(string)
|
||||
case "Type":
|
||||
dc.Type = v.(string)
|
||||
default:
|
||||
if dc.AdditionalFields == nil {
|
||||
dc.AdditionalFields = make(map[string]interface{})
|
||||
}
|
||||
dc.AdditionalFields[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type ContextTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *ContextTestSuite) TestDockerContextMetadataKeepAdditionalFields() {
|
||||
c := ContextMetadata{
|
||||
Description: "test",
|
||||
Type: "aci",
|
||||
StackOrchestrator: "swarm",
|
||||
AdditionalFields: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
}
|
||||
jsonBytes, err := json.Marshal(c)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(string(jsonBytes)).To(Equal(`{"Description":"test","StackOrchestrator":"swarm","Type":"aci","foo":"bar"}`))
|
||||
|
||||
var c2 ContextMetadata
|
||||
err = json.Unmarshal(jsonBytes, &c2)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(c2.AdditionalFields["foo"]).To(Equal("bar"))
|
||||
Expect(c2.Type).To(Equal("aci"))
|
||||
Expect(c2.StackOrchestrator).To(Equal("swarm"))
|
||||
Expect(c2.Description).To(Equal("test"))
|
||||
}
|
||||
|
||||
func TestPs(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
suite.Run(t, new(ContextTestSuite))
|
||||
}
|
|
@ -72,7 +72,7 @@ func ContextStore(ctx context.Context) Store {
|
|||
type Store interface {
|
||||
// Get returns the context with name, it returns an error if the context
|
||||
// doesn't exist
|
||||
Get(name string) (*Metadata, error)
|
||||
Get(name string) (*DockerContext, error)
|
||||
// GetEndpoint sets the `v` parameter to the value of the endpoint for a
|
||||
// particular context type
|
||||
GetEndpoint(name string, v interface{}) error
|
||||
|
@ -80,7 +80,7 @@ type Store interface {
|
|||
// same name exists already.
|
||||
Create(name string, contextType string, description string, data interface{}) error
|
||||
// List returns the list of created contexts
|
||||
List() ([]*Metadata, error)
|
||||
List() ([]*DockerContext, error)
|
||||
// Remove removes a context by name from the context store
|
||||
Remove(name string) error
|
||||
}
|
||||
|
@ -104,34 +104,6 @@ const (
|
|||
ExampleContextType = "example"
|
||||
)
|
||||
|
||||
// Metadata represents the docker context metadata
|
||||
type Metadata struct {
|
||||
Name string `json:",omitempty"`
|
||||
Type string `json:",omitempty"`
|
||||
Metadata ContextMetadata `json:",omitempty"`
|
||||
Endpoints map[string]interface{} `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ContextMetadata is represtentation of the data we put in a context
|
||||
// metadata
|
||||
type ContextMetadata struct {
|
||||
Description string `json:",omitempty"`
|
||||
StackOrchestrator string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// AciContext is the context for the ACI backend
|
||||
type AciContext struct {
|
||||
SubscriptionID string `json:",omitempty"`
|
||||
Location string `json:",omitempty"`
|
||||
ResourceGroup string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// MobyContext is the context for the moby backend
|
||||
type MobyContext struct{}
|
||||
|
||||
// ExampleContext is the context for the example backend
|
||||
type ExampleContext struct{}
|
||||
|
||||
type store struct {
|
||||
root string
|
||||
}
|
||||
|
@ -175,7 +147,7 @@ func New(opts ...Opt) (Store, error) {
|
|||
}
|
||||
|
||||
// Get returns the context with the given name
|
||||
func (s *store) Get(name string) (*Metadata, error) {
|
||||
func (s *store) Get(name string) (*DockerContext, error) {
|
||||
meta := filepath.Join(s.root, contextsDir, metadataDir, contextDirOf(name), metaFile)
|
||||
m, err := read(meta)
|
||||
if os.IsNotExist(err) {
|
||||
|
@ -192,14 +164,15 @@ func (s *store) GetEndpoint(name string, data interface{}) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := meta.Endpoints[meta.Type]; !ok {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "endpoint of type %q", meta.Type)
|
||||
contextType := meta.Type()
|
||||
if _, ok := meta.Endpoints[contextType]; !ok {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "endpoint of type %q", contextType)
|
||||
}
|
||||
|
||||
dstPtrValue := reflect.ValueOf(data)
|
||||
dstValue := reflect.Indirect(dstPtrValue)
|
||||
|
||||
val := reflect.ValueOf(meta.Endpoints[meta.Type])
|
||||
val := reflect.ValueOf(meta.Endpoints[contextType])
|
||||
valIndirect := reflect.Indirect(val)
|
||||
|
||||
if dstValue.Type() != valIndirect.Type() {
|
||||
|
@ -211,13 +184,13 @@ func (s *store) GetEndpoint(name string, data interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func read(meta string) (*Metadata, error) {
|
||||
func read(meta string) (*DockerContext, error) {
|
||||
bytes, err := ioutil.ReadFile(meta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var metadata Metadata
|
||||
var metadata DockerContext
|
||||
if err := json.Unmarshal(bytes, &metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -270,10 +243,10 @@ func (s *store) Create(name string, contextType string, description string, data
|
|||
return err
|
||||
}
|
||||
|
||||
meta := Metadata{
|
||||
meta := DockerContext{
|
||||
Name: name,
|
||||
Type: contextType,
|
||||
Metadata: ContextMetadata{
|
||||
Type: contextType,
|
||||
Description: description,
|
||||
},
|
||||
Endpoints: map[string]interface{}{
|
||||
|
@ -290,14 +263,14 @@ func (s *store) Create(name string, contextType string, description string, data
|
|||
return ioutil.WriteFile(filepath.Join(metaDir, metaFile), bytes, 0644)
|
||||
}
|
||||
|
||||
func (s *store) List() ([]*Metadata, error) {
|
||||
func (s *store) List() ([]*DockerContext, error) {
|
||||
root := filepath.Join(s.root, contextsDir, metadataDir)
|
||||
c, err := ioutil.ReadDir(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []*Metadata
|
||||
var result []*DockerContext
|
||||
for _, fi := range c {
|
||||
if fi.IsDir() {
|
||||
meta := filepath.Join(root, fi.Name(), metaFile)
|
||||
|
|
|
@ -104,7 +104,7 @@ func (suite *StoreTestSuite) TestGet() {
|
|||
require.Equal(suite.T(), "test", meta.Name)
|
||||
|
||||
require.Equal(suite.T(), "description", meta.Metadata.Description)
|
||||
require.Equal(suite.T(), "type", meta.Type)
|
||||
require.Equal(suite.T(), "type", meta.Type())
|
||||
}
|
||||
|
||||
func (suite *StoreTestSuite) TestRemoveNotFound() {
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const defaultContextType = "docker"
|
||||
|
||||
// Represents a context as created by the docker cli
|
||||
type defaultContext struct {
|
||||
Metadata ContextMetadata
|
||||
|
@ -31,7 +33,7 @@ type endpoint struct {
|
|||
DefaultNamespace string
|
||||
}
|
||||
|
||||
func dockerDefaultContext() (*Metadata, error) {
|
||||
func dockerDefaultContext() (*DockerContext, error) {
|
||||
cmd := exec.Command("docker-classic", "context", "inspect", "default")
|
||||
var stdout bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
|
@ -52,9 +54,8 @@ func dockerDefaultContext() (*Metadata, error) {
|
|||
|
||||
defaultCtx := ctx[0]
|
||||
|
||||
meta := Metadata{
|
||||
meta := DockerContext{
|
||||
Name: "default",
|
||||
Type: "docker",
|
||||
Endpoints: map[string]interface{}{
|
||||
"docker": Endpoint{
|
||||
Host: defaultCtx.Endpoints.Docker.Host,
|
||||
|
@ -65,6 +66,7 @@ func dockerDefaultContext() (*Metadata, error) {
|
|||
},
|
||||
},
|
||||
Metadata: ContextMetadata{
|
||||
Type: defaultContextType,
|
||||
Description: "Current DOCKER_HOST based configuration",
|
||||
StackOrchestrator: defaultCtx.Metadata.StackOrchestrator,
|
||||
},
|
||||
|
|
|
@ -36,7 +36,7 @@ func (cp *contextsProxy) List(ctx context.Context, request *contextsv1.ListReque
|
|||
for _, c := range contexts {
|
||||
result.Contexts = append(result.Contexts, &contextsv1.Context{
|
||||
Name: c.Name,
|
||||
ContextType: c.Type,
|
||||
ContextType: c.Type(),
|
||||
Current: c.Name == configFile.CurrentContext,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue