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