github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/defaultcontextstore.go (about)

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