mirror of https://github.com/docker/compose.git
Merge pull request #147 from rumpl/feat-better-context
Change the way a context is stored
This commit is contained in:
commit
7b83047dc2
|
@ -1,8 +1,6 @@
|
||||||
**What I did**
|
**What I did**
|
||||||
|
|
||||||
**Related issue**
|
**Related issue**
|
||||||
<-- If this is a bug fix, make sure your description includes "fixes #xxxx", or
|
<-- If this is a bug fix, make sure your description includes "fixes #xxxx", or "closes #xxxx" -->
|
||||||
"closes #xxxx"
|
|
||||||
-->
|
|
||||||
|
|
||||||
**(not mandatory) A picture of a cute animal, if possible in relation with what you did**
|
**(not mandatory) A picture of a cute animal, if possible in relation with what you did**
|
||||||
|
|
|
@ -36,19 +36,15 @@ func init() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getter() interface{} {
|
|
||||||
return &store.AciContext{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a backend that can manage containers
|
// New creates a backend that can manage containers
|
||||||
func New(ctx context.Context) (backend.Service, error) {
|
func New(ctx context.Context) (backend.Service, error) {
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
contextStore := store.ContextStore(ctx)
|
contextStore := store.ContextStore(ctx)
|
||||||
metadata, err := contextStore.Get(currentContext, getter)
|
|
||||||
if err != nil {
|
var aciContext store.AciContext
|
||||||
return nil, errors.Wrap(err, "wrong context type")
|
if err := contextStore.GetEndpoint(currentContext, &aciContext); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
aciContext, _ := metadata.Metadata.Data.(store.AciContext)
|
|
||||||
|
|
||||||
auth, _ := login.NewAuthorizerFromLogin()
|
auth, _ := login.NewAuthorizerFromLogin()
|
||||||
containerGroupsClient := containerinstance.NewContainerGroupsClient(aciContext.SubscriptionID)
|
containerGroupsClient := containerinstance.NewContainerGroupsClient(aciContext.SubscriptionID)
|
||||||
|
|
|
@ -67,9 +67,7 @@ func runCreate(ctx context.Context, opts createOpts, name string, contextType st
|
||||||
return createACIContext(ctx, name, opts)
|
return createACIContext(ctx, name, opts)
|
||||||
default:
|
default:
|
||||||
s := store.ContextStore(ctx)
|
s := store.ContextStore(ctx)
|
||||||
return s.Create(name, store.TypedContext{
|
// TODO: we need to implement different contexts for known backends
|
||||||
Type: contextType,
|
return s.Create(name, contextType, opts.description, store.ExampleContext{})
|
||||||
Description: opts.description,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,19 +29,27 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/api/context/store"
|
"github.com/docker/api/context/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createACIContext(ctx context.Context, name string, opts createOpts) error {
|
func createACIContext(ctx context.Context, name string, opts createOpts) error {
|
||||||
s := store.ContextStore(ctx)
|
s := store.ContextStore(ctx)
|
||||||
return s.Create(name, store.TypedContext{
|
|
||||||
Type: "aci",
|
description := fmt.Sprintf("%s@%s", opts.aciResourceGroup, opts.aciLocation)
|
||||||
Description: opts.description,
|
if opts.description != "" {
|
||||||
Data: store.AciContext{
|
description = fmt.Sprintf("%s (%s)", opts.description, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.Create(
|
||||||
|
name,
|
||||||
|
store.AciContextType,
|
||||||
|
description,
|
||||||
|
store.AciContext{
|
||||||
SubscriptionID: opts.aciSubscriptionID,
|
SubscriptionID: opts.aciSubscriptionID,
|
||||||
Location: opts.aciLocation,
|
Location: opts.aciLocation,
|
||||||
ResourceGroup: opts.aciResourceGroup,
|
ResourceGroup: opts.aciResourceGroup,
|
||||||
},
|
},
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ func runList(ctx context.Context) error {
|
||||||
fmt.Fprintf(w,
|
fmt.Fprintf(w,
|
||||||
format,
|
format,
|
||||||
contextName,
|
contextName,
|
||||||
c.Metadata.Type,
|
c.Type,
|
||||||
c.Metadata.Description,
|
c.Metadata.Description,
|
||||||
getEndpoint("docker", c.Endpoints),
|
getEndpoint("docker", c.Endpoints),
|
||||||
getEndpoint("kubernetes", c.Endpoints),
|
getEndpoint("kubernetes", c.Endpoints),
|
||||||
|
@ -89,15 +89,19 @@ func runList(ctx context.Context) error {
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEndpoint(name string, meta map[string]store.Endpoint) string {
|
func getEndpoint(name string, meta map[string]interface{}) string {
|
||||||
d, ok := meta[name]
|
endpoints, ok := meta[name]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
data, ok := endpoints.(store.Endpoint)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
result := d.Host
|
result := data.Host
|
||||||
if d.DefaultNamespace != "" {
|
if data.DefaultNamespace != "" {
|
||||||
result += fmt.Sprintf(" (%s)", d.DefaultNamespace)
|
result += fmt.Sprintf(" (%s)", data.DefaultNamespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -53,7 +53,7 @@ func runShow(ctx context.Context) error {
|
||||||
// Match behavior of existing CLI
|
// Match behavior of existing CLI
|
||||||
if name != store.DefaultContextName {
|
if name != store.DefaultContextName {
|
||||||
s := store.ContextStore(ctx)
|
s := store.ContextStore(ctx)
|
||||||
if _, err := s.Get(name, nil); err != nil {
|
if _, err := s.Get(name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func runUse(ctx context.Context, name string) error {
|
||||||
s := store.ContextStore(ctx)
|
s := store.ContextStore(ctx)
|
||||||
// Match behavior of existing CLI
|
// Match behavior of existing CLI
|
||||||
if name != store.DefaultContextName {
|
if name != store.DefaultContextName {
|
||||||
if _, err := s.Get(name, nil); err != nil {
|
if _, err := s.Get(name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (cs *cliServer) Contexts(ctx context.Context, request *cliv1.ContextsReques
|
||||||
for _, c := range contexts {
|
for _, c := range contexts {
|
||||||
result.Contexts = append(result.Contexts, &cliv1.Context{
|
result.Contexts = append(result.Contexts, &cliv1.Context{
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
ContextType: c.Metadata.Type,
|
ContextType: c.Type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
|
@ -182,7 +182,7 @@ func execMoby(ctx context.Context) {
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
s := store.ContextStore(ctx)
|
s := store.ContextStore(ctx)
|
||||||
|
|
||||||
_, err := s.Get(currentContext, nil)
|
_, err := s.Get(currentContext)
|
||||||
// Only run original docker command if the current context is not
|
// Only run original docker command if the current context is not
|
||||||
// ours.
|
// ours.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -44,19 +44,18 @@ func New(ctx context.Context) (*Client, error) {
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
s := store.ContextStore(ctx)
|
s := store.ContextStore(ctx)
|
||||||
|
|
||||||
cc, err := s.Get(currentContext, nil)
|
cc, err := s.Get(currentContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
contextType := s.GetType(cc)
|
|
||||||
|
|
||||||
service, err := backend.Get(ctx, contextType)
|
service, err := backend.Get(ctx, cc.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
backendType: contextType,
|
backendType: cc.Type,
|
||||||
bs: service,
|
bs: service,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
|
|
@ -72,18 +72,66 @@ func ContextStore(ctx context.Context) Store {
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// Get returns the context with name, it returns an error if the context
|
// Get returns the context with name, it returns an error if the context
|
||||||
// doesn't exist
|
// doesn't exist
|
||||||
Get(name string, getter func() interface{}) (*Metadata, error)
|
Get(name string) (*Metadata, error)
|
||||||
// GetType returns the type of the context (docker, aci etc)
|
// GetEndpoint sets the `v` parameter to the value of the endpoint for a
|
||||||
GetType(meta *Metadata) string
|
// particular context type
|
||||||
|
GetEndpoint(name string, v interface{}) error
|
||||||
// Create creates a new context, it returns an error if a context with the
|
// Create creates a new context, it returns an error if a context with the
|
||||||
// same name exists already.
|
// same name exists already.
|
||||||
Create(name string, data TypedContext) error
|
Create(name string, contextType string, description string, data interface{}) error
|
||||||
// List returns the list of created contexts
|
// List returns the list of created contexts
|
||||||
List() ([]*Metadata, error)
|
List() ([]*Metadata, error)
|
||||||
// Remove removes a context by name from the context store
|
// Remove removes a context by name from the context store
|
||||||
Remove(name string) error
|
Remove(name string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Endpoint holds the Docker or the Kubernetes endpoint, they both have the
|
||||||
|
// `Host` property, only kubernetes will have the `DefaultNamespace`
|
||||||
|
type Endpoint struct {
|
||||||
|
Host string `json:",omitempty"`
|
||||||
|
DefaultNamespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AciContextType is the endpoint key in the context endpoints for an ACI
|
||||||
|
// backend
|
||||||
|
AciContextType = "aci"
|
||||||
|
// MobyContextType is the endpoint key in the context endpoints for a moby
|
||||||
|
// backend
|
||||||
|
MobyContextType = "moby"
|
||||||
|
// ExampleContextType is the endpoint key in the context endpoints for an
|
||||||
|
// example backend
|
||||||
|
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 {
|
type store struct {
|
||||||
root string
|
root string
|
||||||
}
|
}
|
||||||
|
@ -127,9 +175,9 @@ func New(opts ...Opt) (Store, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the context with the given name
|
// Get returns the context with the given name
|
||||||
func (s *store) Get(name string, getter func() interface{}) (*Metadata, error) {
|
func (s *store) Get(name string) (*Metadata, error) {
|
||||||
meta := filepath.Join(s.root, contextsDir, metadataDir, contextDirOf(name), metaFile)
|
meta := filepath.Join(s.root, contextsDir, metadataDir, contextDirOf(name), metaFile)
|
||||||
m, err := read(meta, getter)
|
m, err := read(meta)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil, errors.Wrap(errdefs.ErrNotFound, objectName(name))
|
return nil, errors.Wrap(errdefs.ErrNotFound, objectName(name))
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -139,73 +187,75 @@ func (s *store) Get(name string, getter func() interface{}) (*Metadata, error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func read(meta string, getter func() interface{}) (*Metadata, error) {
|
func (s *store) GetEndpoint(name string, data interface{}) error {
|
||||||
|
meta, err := s.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, ok := meta.Endpoints[meta.Type]; !ok {
|
||||||
|
return errors.Wrapf(errdefs.ErrNotFound, "endpoint of type %q", meta.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
dstPtrValue := reflect.ValueOf(data)
|
||||||
|
dstValue := reflect.Indirect(dstPtrValue)
|
||||||
|
|
||||||
|
val := reflect.ValueOf(meta.Endpoints[meta.Type])
|
||||||
|
valIndirect := reflect.Indirect(val)
|
||||||
|
|
||||||
|
if dstValue.Type() != valIndirect.Type() {
|
||||||
|
return errdefs.ErrWrongContextType
|
||||||
|
}
|
||||||
|
|
||||||
|
dstValue.Set(valIndirect)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func read(meta string) (*Metadata, error) {
|
||||||
bytes, err := ioutil.ReadFile(meta)
|
bytes, err := ioutil.ReadFile(meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var um untypedMetadata
|
var metadata Metadata
|
||||||
if err := json.Unmarshal(bytes, &um); err != nil {
|
if err := json.Unmarshal(bytes, &metadata); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var uc untypedContext
|
metadata.Endpoints, err = toTypedEndpoints(metadata.Endpoints)
|
||||||
if err := json.Unmarshal(um.Metadata, &uc); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if uc.Type == "" {
|
|
||||||
uc.Type = "docker"
|
|
||||||
}
|
|
||||||
|
|
||||||
var data interface{}
|
return &metadata, nil
|
||||||
if uc.Data != nil {
|
}
|
||||||
data, err = parse(uc.Data, getter)
|
|
||||||
|
func toTypedEndpoints(endpoints map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
result := map[string]interface{}{}
|
||||||
|
for k, v := range endpoints {
|
||||||
|
bytes, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
typeGetters := getters()
|
||||||
|
if _, ok := typeGetters[k]; !ok {
|
||||||
|
result[k] = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return &Metadata{
|
val := typeGetters[k]()
|
||||||
Name: um.Name,
|
err = json.Unmarshal(bytes, &val)
|
||||||
Endpoints: um.Endpoints,
|
if err != nil {
|
||||||
Metadata: TypedContext{
|
|
||||||
StackOrchestrator: uc.StackOrchestrator,
|
|
||||||
Description: uc.Description,
|
|
||||||
Type: uc.Type,
|
|
||||||
Data: data,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(payload []byte, getter func() interface{}) (interface{}, error) {
|
|
||||||
if getter == nil {
|
|
||||||
var res map[string]interface{}
|
|
||||||
if err := json.Unmarshal(payload, &res); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return res, nil
|
|
||||||
|
result[k] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
typed := getter()
|
return result, nil
|
||||||
if err := json.Unmarshal(payload, &typed); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return reflect.ValueOf(typed).Elem().Interface(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetType(meta *Metadata) string {
|
func (s *store) Create(name string, contextType string, description string, data interface{}) error {
|
||||||
for k := range meta.Endpoints {
|
|
||||||
if k != dockerEndpointKey {
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dockerEndpointKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *store) Create(name string, data TypedContext) error {
|
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
return errors.Wrap(errdefs.ErrAlreadyExists, objectName(name))
|
return errors.Wrap(errdefs.ErrAlreadyExists, objectName(name))
|
||||||
}
|
}
|
||||||
|
@ -220,16 +270,15 @@ func (s *store) Create(name string, data TypedContext) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Data == nil {
|
|
||||||
data.Data = dummyContext{}
|
|
||||||
}
|
|
||||||
|
|
||||||
meta := Metadata{
|
meta := Metadata{
|
||||||
Name: name,
|
Name: name,
|
||||||
Metadata: data,
|
Type: contextType,
|
||||||
Endpoints: map[string]Endpoint{
|
Metadata: ContextMetadata{
|
||||||
(dockerEndpointKey): {},
|
Description: description,
|
||||||
(data.Type): {},
|
},
|
||||||
|
Endpoints: map[string]interface{}{
|
||||||
|
(dockerEndpointKey): data,
|
||||||
|
(contextType): data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +301,7 @@ func (s *store) List() ([]*Metadata, error) {
|
||||||
for _, fi := range c {
|
for _, fi := range c {
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
meta := filepath.Join(root, fi.Name(), metaFile)
|
meta := filepath.Join(root, fi.Name(), metaFile)
|
||||||
r, err := read(meta, nil)
|
r, err := read(meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -303,45 +352,19 @@ func createDirIfNotExist(dir string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type dummyContext struct{}
|
// Different context types managed by the store.
|
||||||
|
// TODO(rumpl): we should make this extensible in the future if we want to
|
||||||
// Endpoint holds the Docker or the Kubernetes endpoint
|
// be able to manage other contexts.
|
||||||
type Endpoint struct {
|
func getters() map[string]func() interface{} {
|
||||||
Host string `json:",omitempty"`
|
return map[string]func() interface{}{
|
||||||
DefaultNamespace string `json:",omitempty"`
|
"aci": func() interface{} {
|
||||||
}
|
return &AciContext{}
|
||||||
|
},
|
||||||
// Metadata represents the docker context metadata
|
"moby": func() interface{} {
|
||||||
type Metadata struct {
|
return &MobyContext{}
|
||||||
Name string `json:",omitempty"`
|
},
|
||||||
Metadata TypedContext `json:",omitempty"`
|
"example": func() interface{} {
|
||||||
Endpoints map[string]Endpoint `json:",omitempty"`
|
return &ExampleContext{}
|
||||||
}
|
},
|
||||||
|
}
|
||||||
type untypedMetadata struct {
|
|
||||||
Name string `json:",omitempty"`
|
|
||||||
Metadata json.RawMessage `json:",omitempty"`
|
|
||||||
Endpoints map[string]Endpoint `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type untypedContext struct {
|
|
||||||
StackOrchestrator string `json:",omitempty"`
|
|
||||||
Type string `json:",omitempty"`
|
|
||||||
Description string `json:",omitempty"`
|
|
||||||
Data json.RawMessage `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypedContext is a context with a type (moby, aci, etc...)
|
|
||||||
type TypedContext struct {
|
|
||||||
StackOrchestrator string `json:",omitempty"`
|
|
||||||
Type string `json:",omitempty"`
|
|
||||||
Description string `json:",omitempty"`
|
|
||||||
Data interface{} `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AciContext is the context for ACI
|
|
||||||
type AciContext struct {
|
|
||||||
SubscriptionID string `json:",omitempty"`
|
|
||||||
Location string `json:",omitempty"`
|
|
||||||
ResourceGroup string `json:",omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
@ -62,42 +63,55 @@ func (suite *StoreTestSuite) AfterTest(suiteName, testName string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *StoreTestSuite) TestCreate() {
|
func (suite *StoreTestSuite) TestCreate() {
|
||||||
err := suite.store.Create("test", TypedContext{})
|
err := suite.store.Create("test", "test", "description", ContextMetadata{})
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
|
|
||||||
err = suite.store.Create("test", TypedContext{})
|
err = suite.store.Create("test", "test", "descrsiption", ContextMetadata{})
|
||||||
require.EqualError(suite.T(), err, `context "test": already exists`)
|
require.EqualError(suite.T(), err, `context "test": already exists`)
|
||||||
require.True(suite.T(), errdefs.IsAlreadyExistsError(err))
|
require.True(suite.T(), errdefs.IsAlreadyExistsError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *StoreTestSuite) TestGetEndpoint() {
|
||||||
|
err := suite.store.Create("aci", "aci", "description", AciContext{
|
||||||
|
Location: "eu",
|
||||||
|
})
|
||||||
|
require.Nil(suite.T(), err)
|
||||||
|
|
||||||
|
var ctx AciContext
|
||||||
|
err = suite.store.GetEndpoint("aci", &ctx)
|
||||||
|
assert.Equal(suite.T(), nil, err)
|
||||||
|
assert.Equal(suite.T(), "eu", ctx.Location)
|
||||||
|
|
||||||
|
var exampleCtx ExampleContext
|
||||||
|
err = suite.store.GetEndpoint("aci", &exampleCtx)
|
||||||
|
assert.EqualError(suite.T(), err, "wrong context type")
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *StoreTestSuite) TestGetUnknown() {
|
func (suite *StoreTestSuite) TestGetUnknown() {
|
||||||
meta, err := suite.store.Get("unknown", nil)
|
meta, err := suite.store.Get("unknown")
|
||||||
require.Nil(suite.T(), meta)
|
require.Nil(suite.T(), meta)
|
||||||
require.EqualError(suite.T(), err, `context "unknown": not found`)
|
require.EqualError(suite.T(), err, `context "unknown": not found`)
|
||||||
require.True(suite.T(), errdefs.IsNotFoundError(err))
|
require.True(suite.T(), errdefs.IsNotFoundError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *StoreTestSuite) TestGet() {
|
func (suite *StoreTestSuite) TestGet() {
|
||||||
err := suite.store.Create("test", TypedContext{
|
err := suite.store.Create("test", "type", "description", ContextMetadata{})
|
||||||
Type: "type",
|
|
||||||
Description: "description",
|
|
||||||
})
|
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
|
|
||||||
meta, err := suite.store.Get("test", nil)
|
meta, err := suite.store.Get("test")
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
require.NotNil(suite.T(), meta)
|
require.NotNil(suite.T(), meta)
|
||||||
require.Equal(suite.T(), "test", meta.Name)
|
require.Equal(suite.T(), "test", meta.Name)
|
||||||
|
|
||||||
require.Equal(suite.T(), "description", meta.Metadata.Description)
|
require.Equal(suite.T(), "description", meta.Metadata.Description)
|
||||||
require.Equal(suite.T(), "type", meta.Metadata.Type)
|
require.Equal(suite.T(), "type", meta.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *StoreTestSuite) TestList() {
|
func (suite *StoreTestSuite) TestList() {
|
||||||
err := suite.store.Create("test1", TypedContext{})
|
err := suite.store.Create("test1", "type", "description", ContextMetadata{})
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
|
|
||||||
err = suite.store.Create("test2", TypedContext{})
|
err = suite.store.Create("test2", "type", "description", ContextMetadata{})
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
|
|
||||||
contexts, err := suite.store.List()
|
contexts, err := suite.store.List()
|
||||||
|
@ -116,7 +130,7 @@ func (suite *StoreTestSuite) TestRemoveNotFound() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *StoreTestSuite) TestRemove() {
|
func (suite *StoreTestSuite) TestRemove() {
|
||||||
err := suite.store.Create("testremove", TypedContext{})
|
err := suite.store.Create("testremove", "type", "description", ContextMetadata{})
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
contexts, err := suite.store.List()
|
contexts, err := suite.store.List()
|
||||||
require.Nil(suite.T(), err)
|
require.Nil(suite.T(), err)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
// Represents a context as created by the docker cli
|
// Represents a context as created by the docker cli
|
||||||
type defaultContext struct {
|
type defaultContext struct {
|
||||||
Metadata TypedContext
|
Metadata ContextMetadata
|
||||||
Endpoints endpoints
|
Endpoints endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,20 +54,19 @@ func dockerDefaultContext() (*Metadata, error) {
|
||||||
|
|
||||||
meta := Metadata{
|
meta := Metadata{
|
||||||
Name: "default",
|
Name: "default",
|
||||||
Endpoints: map[string]Endpoint{
|
Type: "docker",
|
||||||
"docker": {
|
Endpoints: map[string]interface{}{
|
||||||
|
"docker": Endpoint{
|
||||||
Host: defaultCtx.Endpoints.Docker.Host,
|
Host: defaultCtx.Endpoints.Docker.Host,
|
||||||
},
|
},
|
||||||
"kubernetes": {
|
"kubernetes": Endpoint{
|
||||||
Host: defaultCtx.Endpoints.Kubernetes.Host,
|
Host: defaultCtx.Endpoints.Kubernetes.Host,
|
||||||
DefaultNamespace: defaultCtx.Endpoints.Kubernetes.DefaultNamespace,
|
DefaultNamespace: defaultCtx.Endpoints.Kubernetes.DefaultNamespace,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Metadata: TypedContext{
|
Metadata: ContextMetadata{
|
||||||
Description: "Current DOCKER_HOST based configuration",
|
Description: "Current DOCKER_HOST based configuration",
|
||||||
Type: "docker",
|
|
||||||
StackOrchestrator: defaultCtx.Metadata.StackOrchestrator,
|
StackOrchestrator: defaultCtx.Metadata.StackOrchestrator,
|
||||||
Data: defaultCtx.Metadata,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,9 @@ var (
|
||||||
ErrNotImplemented = errors.New("not implemented")
|
ErrNotImplemented = errors.New("not implemented")
|
||||||
// ErrParsingFailed is returned when a string cannot be parsed
|
// ErrParsingFailed is returned when a string cannot be parsed
|
||||||
ErrParsingFailed = errors.New("parsing failed")
|
ErrParsingFailed = errors.New("parsing failed")
|
||||||
|
// ErrWrongContextType is returned when the caller tries to get a context
|
||||||
|
// with the wrong type
|
||||||
|
ErrWrongContextType = errors.New("wrong context type")
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsNotFoundError returns true if the unwrapped error is ErrNotFound
|
// IsNotFoundError returns true if the unwrapped error is ErrNotFound
|
||||||
|
|
|
@ -35,9 +35,7 @@ func (sut *CliSuite) BeforeTest(suiteName, testName string) {
|
||||||
)
|
)
|
||||||
require.Nil(sut.T(), err)
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
err = s.Create("example", store.TypedContext{
|
err = s.Create("example", "example", "", store.ContextMetadata{})
|
||||||
Type: "example",
|
|
||||||
})
|
|
||||||
require.Nil(sut.T(), err)
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
sut.storeRoot = dir
|
sut.storeRoot = dir
|
||||||
|
|
Loading…
Reference in New Issue