2019-03-06 09:01:12 -05:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"github.com/docker/cli/cli/config/configfile"
|
|
|
|
"github.com/docker/cli/cli/context/docker"
|
|
|
|
"github.com/docker/cli/cli/context/store"
|
|
|
|
cliflags "github.com/docker/cli/cli/flags"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// DefaultContextName is the name reserved for the default context (config & env based)
|
|
|
|
DefaultContextName = "default"
|
|
|
|
)
|
|
|
|
|
2019-05-14 11:22:39 -04:00
|
|
|
// DefaultContext contains the default context data for all endpoints
|
2019-03-06 09:01:12 -05:00
|
|
|
type DefaultContext struct {
|
2019-04-18 09:12:30 -04:00
|
|
|
Meta store.Metadata
|
2019-03-06 09:01:12 -05:00
|
|
|
TLS store.ContextTLSData
|
|
|
|
}
|
|
|
|
|
|
|
|
// DefaultContextResolver is a function which resolves the default context base on the configuration and the env variables
|
|
|
|
type DefaultContextResolver func() (*DefaultContext, error)
|
|
|
|
|
|
|
|
// ContextStoreWithDefault implements the store.Store interface with a support for the default context
|
|
|
|
type ContextStoreWithDefault struct {
|
|
|
|
store.Store
|
|
|
|
Resolver DefaultContextResolver
|
|
|
|
}
|
|
|
|
|
2019-05-16 09:47:07 -04:00
|
|
|
// EndpointDefaultResolver is implemented by any EndpointMeta object
|
|
|
|
// which wants to be able to populate the store with whatever their default is.
|
|
|
|
type EndpointDefaultResolver interface {
|
|
|
|
// ResolveDefault returns values suitable for storing in store.Metadata.Endpoints
|
|
|
|
// and store.ContextTLSData.Endpoints. If there is no default then returns nil, nil.
|
|
|
|
ResolveDefault() (interface{}, *store.EndpointTLSData)
|
|
|
|
}
|
|
|
|
|
2019-05-16 09:52:37 -04:00
|
|
|
// ResolveDefaultContext creates a Metadata for the current CLI invocation parameters
|
|
|
|
func ResolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.ConfigFile, storeconfig store.Config, stderr io.Writer) (*DefaultContext, error) {
|
2019-03-06 09:01:12 -05:00
|
|
|
stackOrchestrator, err := GetStackOrchestrator("", "", config.StackOrchestrator, stderr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
contextTLSData := store.ContextTLSData{
|
|
|
|
Endpoints: make(map[string]store.EndpointTLSData),
|
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
contextMetadata := store.Metadata{
|
2019-03-06 09:01:12 -05:00
|
|
|
Endpoints: make(map[string]interface{}),
|
|
|
|
Metadata: DockerContext{
|
|
|
|
Description: "",
|
|
|
|
StackOrchestrator: stackOrchestrator,
|
|
|
|
},
|
|
|
|
Name: DefaultContextName,
|
|
|
|
}
|
|
|
|
|
|
|
|
dockerEP, err := resolveDefaultDockerEndpoint(opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
contextMetadata.Endpoints[docker.DockerEndpoint] = dockerEP.EndpointMeta
|
|
|
|
if dockerEP.TLSData != nil {
|
|
|
|
contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerEP.TLSData.ToStoreTLSData()
|
|
|
|
}
|
|
|
|
|
2019-05-16 10:06:27 -04:00
|
|
|
// We open code the string "kubernetes" below because we
|
|
|
|
// cannot import KubernetesEndpoint from the corresponding
|
|
|
|
// package due to import loops.
|
|
|
|
wantKubernetesEP := stackOrchestrator == OrchestratorKubernetes || stackOrchestrator == OrchestratorAll
|
2019-03-06 09:01:12 -05:00
|
|
|
|
2019-05-16 09:47:07 -04:00
|
|
|
if err := storeconfig.ForeachEndpointType(func(n string, get store.TypeGetter) error {
|
2019-05-16 10:06:27 -04:00
|
|
|
if n == docker.DockerEndpoint { // handled above
|
2019-05-16 09:47:07 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ep := get()
|
|
|
|
if i, ok := ep.(EndpointDefaultResolver); ok {
|
|
|
|
meta, tls := i.ResolveDefault()
|
|
|
|
if meta == nil {
|
2019-05-16 10:06:27 -04:00
|
|
|
if wantKubernetesEP && n == "kubernetes" {
|
|
|
|
return errors.Errorf("default orchestrator is %s but unable to resolve kubernetes endpoint", stackOrchestrator)
|
|
|
|
}
|
2019-05-16 09:47:07 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
contextMetadata.Endpoints[n] = meta
|
|
|
|
if tls != nil {
|
|
|
|
contextTLSData.Endpoints[n] = *tls
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Nothing to be done
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-05-16 10:06:27 -04:00
|
|
|
if _, ok := contextMetadata.Endpoints["kubernetes"]; wantKubernetesEP && !ok {
|
|
|
|
return nil, errors.Errorf("default orchestrator is %s but kubernetes endpoint could not be found", stackOrchestrator)
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:01:12 -05:00
|
|
|
return &DefaultContext{Meta: contextMetadata, TLS: contextTLSData}, nil
|
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// List implements store.Store's List
|
|
|
|
func (s *ContextStoreWithDefault) List() ([]store.Metadata, error) {
|
|
|
|
contextList, err := s.Store.List()
|
2019-03-06 09:01:12 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defaultContext, err := s.Resolver()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return append(contextList, defaultContext.Meta), nil
|
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// CreateOrUpdate is not allowed for the default context and fails
|
|
|
|
func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
|
2019-03-06 09:01:12 -05:00
|
|
|
if meta.Name == DefaultContextName {
|
|
|
|
return errors.New("default context cannot be created nor updated")
|
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.CreateOrUpdate(meta)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// Remove is not allowed for the default context and fails
|
|
|
|
func (s *ContextStoreWithDefault) Remove(name string) error {
|
2019-03-06 09:01:12 -05:00
|
|
|
if name == DefaultContextName {
|
|
|
|
return errors.New("default context cannot be removed")
|
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.Remove(name)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// GetMetadata implements store.Store's GetMetadata
|
|
|
|
func (s *ContextStoreWithDefault) GetMetadata(name string) (store.Metadata, error) {
|
2019-03-06 09:01:12 -05:00
|
|
|
if name == DefaultContextName {
|
|
|
|
defaultContext, err := s.Resolver()
|
|
|
|
if err != nil {
|
2019-04-18 09:12:30 -04:00
|
|
|
return store.Metadata{}, err
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
return defaultContext.Meta, nil
|
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.GetMetadata(name)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// ResetTLSMaterial is not implemented for default context and fails
|
|
|
|
func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.ContextTLSData) error {
|
2019-03-06 09:01:12 -05:00
|
|
|
if name == DefaultContextName {
|
2019-04-18 09:12:30 -04:00
|
|
|
return errors.New("The default context store does not support ResetTLSMaterial")
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.ResetTLSMaterial(name, data)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// ResetEndpointTLSMaterial is not implemented for default context and fails
|
|
|
|
func (s *ContextStoreWithDefault) ResetEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
|
2019-03-06 09:01:12 -05:00
|
|
|
if contextName == DefaultContextName {
|
2019-04-18 09:12:30 -04:00
|
|
|
return errors.New("The default context store does not support ResetEndpointTLSMaterial")
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.ResetEndpointTLSMaterial(contextName, endpointName, data)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// ListTLSFiles implements store.Store's ListTLSFiles
|
|
|
|
func (s *ContextStoreWithDefault) ListTLSFiles(name string) (map[string]store.EndpointFiles, error) {
|
2019-03-06 09:01:12 -05:00
|
|
|
if name == DefaultContextName {
|
|
|
|
defaultContext, err := s.Resolver()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
tlsfiles := make(map[string]store.EndpointFiles)
|
|
|
|
for epName, epTLSData := range defaultContext.TLS.Endpoints {
|
|
|
|
var files store.EndpointFiles
|
|
|
|
for filename := range epTLSData.Files {
|
|
|
|
files = append(files, filename)
|
|
|
|
}
|
|
|
|
tlsfiles[epName] = files
|
|
|
|
}
|
|
|
|
return tlsfiles, nil
|
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.ListTLSFiles(name)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// GetTLSData implements store.Store's GetTLSData
|
|
|
|
func (s *ContextStoreWithDefault) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
2019-03-06 09:01:12 -05:00
|
|
|
if contextName == DefaultContextName {
|
|
|
|
defaultContext, err := s.Resolver()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil {
|
|
|
|
return nil, &noDefaultTLSDataError{endpointName: endpointName, fileName: fileName}
|
|
|
|
}
|
|
|
|
return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
|
|
|
|
|
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.GetTLSData(contextName, endpointName, fileName)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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() {}
|
|
|
|
|
2019-04-18 09:12:30 -04:00
|
|
|
// GetStorageInfo implements store.Store's GetStorageInfo
|
|
|
|
func (s *ContextStoreWithDefault) GetStorageInfo(contextName string) store.StorageInfo {
|
2019-03-06 09:01:12 -05:00
|
|
|
if contextName == DefaultContextName {
|
2019-04-18 09:12:30 -04:00
|
|
|
return store.StorageInfo{MetadataPath: "<IN MEMORY>", TLSPath: "<IN MEMORY>"}
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|
2019-04-18 09:12:30 -04:00
|
|
|
return s.Store.GetStorageInfo(contextName)
|
2019-03-06 09:01:12 -05:00
|
|
|
}
|