github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/cli/command/defaultcontextstore.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/docker/cli/cli/config/configfile"
     8  	"github.com/docker/cli/cli/context/docker"
     9  	"github.com/docker/cli/cli/context/store"
    10  	cliflags "github.com/docker/cli/cli/flags"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  const (
    15  	// DefaultContextName is the name reserved for the default context (config & env based)
    16  	DefaultContextName = "default"
    17  )
    18  
    19  // DefaultContext contains the default context data for all endpoints
    20  type DefaultContext struct {
    21  	Meta store.Metadata
    22  	TLS  store.ContextTLSData
    23  }
    24  
    25  // DefaultContextResolver is a function which resolves the default context base on the configuration and the env variables
    26  type DefaultContextResolver func() (*DefaultContext, error)
    27  
    28  // ContextStoreWithDefault implements the store.Store interface with a support for the default context
    29  type ContextStoreWithDefault struct {
    30  	store.Store
    31  	Resolver DefaultContextResolver
    32  }
    33  
    34  // EndpointDefaultResolver is implemented by any EndpointMeta object
    35  // which wants to be able to populate the store with whatever their default is.
    36  type EndpointDefaultResolver interface {
    37  	// ResolveDefault returns values suitable for storing in store.Metadata.Endpoints
    38  	// and store.ContextTLSData.Endpoints.
    39  	//
    40  	// An error is only returned for something fatal, not simply
    41  	// the lack of a default (e.g. because the config file which
    42  	// would contain it is missing). If there is no default then
    43  	// returns nil, nil, nil.
    44  	ResolveDefault(Orchestrator) (interface{}, *store.EndpointTLSData, error)
    45  }
    46  
    47  // ResolveDefaultContext creates a Metadata for the current CLI invocation parameters
    48  func ResolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.ConfigFile, storeconfig store.Config, stderr io.Writer) (*DefaultContext, error) {
    49  	stackOrchestrator, err := GetStackOrchestrator("", "", config.StackOrchestrator, stderr)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	contextTLSData := store.ContextTLSData{
    54  		Endpoints: make(map[string]store.EndpointTLSData),
    55  	}
    56  	contextMetadata := store.Metadata{
    57  		Endpoints: make(map[string]interface{}),
    58  		Metadata: DockerContext{
    59  			Description:       "",
    60  			StackOrchestrator: stackOrchestrator,
    61  		},
    62  		Name: DefaultContextName,
    63  	}
    64  
    65  	dockerEP, err := resolveDefaultDockerEndpoint(opts)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	contextMetadata.Endpoints[docker.DockerEndpoint] = dockerEP.EndpointMeta
    70  	if dockerEP.TLSData != nil {
    71  		contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerEP.TLSData.ToStoreTLSData()
    72  	}
    73  
    74  	if err := storeconfig.ForeachEndpointType(func(n string, get store.TypeGetter) error {
    75  		if n == docker.DockerEndpoint { // handled above
    76  			return nil
    77  		}
    78  		ep := get()
    79  		if i, ok := ep.(EndpointDefaultResolver); ok {
    80  			meta, tls, err := i.ResolveDefault(stackOrchestrator)
    81  			if err != nil {
    82  				return err
    83  			}
    84  			if meta == nil {
    85  				return nil
    86  			}
    87  			contextMetadata.Endpoints[n] = meta
    88  			if tls != nil {
    89  				contextTLSData.Endpoints[n] = *tls
    90  			}
    91  		}
    92  		// Nothing to be done
    93  		return nil
    94  	}); err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	return &DefaultContext{Meta: contextMetadata, TLS: contextTLSData}, nil
    99  }
   100  
   101  // List implements store.Store's List
   102  func (s *ContextStoreWithDefault) List() ([]store.Metadata, error) {
   103  	contextList, err := s.Store.List()
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	defaultContext, err := s.Resolver()
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	return append(contextList, defaultContext.Meta), nil
   112  }
   113  
   114  // CreateOrUpdate is not allowed for the default context and fails
   115  func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
   116  	if meta.Name == DefaultContextName {
   117  		return errors.New("default context cannot be created nor updated")
   118  	}
   119  	return s.Store.CreateOrUpdate(meta)
   120  }
   121  
   122  // Remove is not allowed for the default context and fails
   123  func (s *ContextStoreWithDefault) Remove(name string) error {
   124  	if name == DefaultContextName {
   125  		return errors.New("default context cannot be removed")
   126  	}
   127  	return s.Store.Remove(name)
   128  }
   129  
   130  // GetMetadata implements store.Store's GetMetadata
   131  func (s *ContextStoreWithDefault) GetMetadata(name string) (store.Metadata, error) {
   132  	if name == DefaultContextName {
   133  		defaultContext, err := s.Resolver()
   134  		if err != nil {
   135  			return store.Metadata{}, err
   136  		}
   137  		return defaultContext.Meta, nil
   138  	}
   139  	return s.Store.GetMetadata(name)
   140  }
   141  
   142  // ResetTLSMaterial is not implemented for default context and fails
   143  func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.ContextTLSData) error {
   144  	if name == DefaultContextName {
   145  		return errors.New("The default context store does not support ResetTLSMaterial")
   146  	}
   147  	return s.Store.ResetTLSMaterial(name, data)
   148  }
   149  
   150  // ResetEndpointTLSMaterial is not implemented for default context and fails
   151  func (s *ContextStoreWithDefault) ResetEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
   152  	if contextName == DefaultContextName {
   153  		return errors.New("The default context store does not support ResetEndpointTLSMaterial")
   154  	}
   155  	return s.Store.ResetEndpointTLSMaterial(contextName, endpointName, data)
   156  }
   157  
   158  // ListTLSFiles implements store.Store's ListTLSFiles
   159  func (s *ContextStoreWithDefault) ListTLSFiles(name string) (map[string]store.EndpointFiles, error) {
   160  	if name == DefaultContextName {
   161  		defaultContext, err := s.Resolver()
   162  		if err != nil {
   163  			return nil, err
   164  		}
   165  		tlsfiles := make(map[string]store.EndpointFiles)
   166  		for epName, epTLSData := range defaultContext.TLS.Endpoints {
   167  			var files store.EndpointFiles
   168  			for filename := range epTLSData.Files {
   169  				files = append(files, filename)
   170  			}
   171  			tlsfiles[epName] = files
   172  		}
   173  		return tlsfiles, nil
   174  	}
   175  	return s.Store.ListTLSFiles(name)
   176  }
   177  
   178  // GetTLSData implements store.Store's GetTLSData
   179  func (s *ContextStoreWithDefault) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
   180  	if contextName == DefaultContextName {
   181  		defaultContext, err := s.Resolver()
   182  		if err != nil {
   183  			return nil, err
   184  		}
   185  		if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil {
   186  			return nil, &noDefaultTLSDataError{endpointName: endpointName, fileName: fileName}
   187  		}
   188  		return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
   189  
   190  	}
   191  	return s.Store.GetTLSData(contextName, endpointName, fileName)
   192  }
   193  
   194  type noDefaultTLSDataError struct {
   195  	endpointName string
   196  	fileName     string
   197  }
   198  
   199  func (e *noDefaultTLSDataError) Error() string {
   200  	return fmt.Sprintf("tls data for %s/%s/%s does not exist", DefaultContextName, e.endpointName, e.fileName)
   201  }
   202  
   203  // NotFound satisfies interface github.com/docker/docker/errdefs.ErrNotFound
   204  func (e *noDefaultTLSDataError) NotFound() {}
   205  
   206  // IsTLSDataDoesNotExist satisfies github.com/docker/cli/cli/context/store.tlsDataDoesNotExist
   207  func (e *noDefaultTLSDataError) IsTLSDataDoesNotExist() {}
   208  
   209  // GetStorageInfo implements store.Store's GetStorageInfo
   210  func (s *ContextStoreWithDefault) GetStorageInfo(contextName string) store.StorageInfo {
   211  	if contextName == DefaultContextName {
   212  		return store.StorageInfo{MetadataPath: "<IN MEMORY>", TLSPath: "<IN MEMORY>"}
   213  	}
   214  	return s.Store.GetStorageInfo(contextName)
   215  }