diff --git a/cmd/main.go b/cmd/main.go index 986b32722..3e247a46e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -32,6 +32,7 @@ import ( "os" "path/filepath" + "github.com/docker/api/context" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -57,11 +58,20 @@ func main() { Name: "debug", Usage: "enable debug output in the logs", }, + context.ConfigFlag, + context.ContextFlag, } app.Before = func(clix *cli.Context) error { if clix.GlobalBool("debug") { logrus.SetLevel(logrus.DebugLevel) } + + context, err := context.GetContext() + if err != nil { + return err + } + fmt.Println(context.Metadata.Type) + // TODO select backend based on context.Metadata.Type or delegate to legacy CLI if == "Moby" return nil } app.Commands = []cli.Command{ diff --git a/context/config.go b/context/config.go new file mode 100644 index 000000000..0a858e24c --- /dev/null +++ b/context/config.go @@ -0,0 +1,38 @@ +package context + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" +) + +func LoadConfigFile() (*ConfigFile, error) { + filename := filepath.Join(ConfigDir, ConfigFileName) + configFile := &ConfigFile{ + Filename: filename, + } + + if _, err := os.Stat(filename); err == nil { + file, err := os.Open(filename) + if err != nil { + return nil, fmt.Errorf("can't read %s: %w", filename, err) + } + defer file.Close() + err = json.NewDecoder(file).Decode(&configFile) + if err != nil { + err = fmt.Errorf("can't read %s: %w", filename, err) + } + return configFile, err + } else if !os.IsNotExist(err) { + // if file is there but we can't stat it for any reason other + // than it doesn't exist then stop + return nil, fmt.Errorf("can't read %s: %w", filename, err) + } + return configFile, nil +} + +type ConfigFile struct { + Filename string `json:"-"` // Note: for internal use only + CurrentContext string `json:"currentContext,omitempty"` +} diff --git a/context/flags.go b/context/flags.go new file mode 100644 index 000000000..b335cbc4a --- /dev/null +++ b/context/flags.go @@ -0,0 +1,33 @@ +package context + +import ( + "path/filepath" + + "github.com/docker/docker/pkg/homedir" + "github.com/urfave/cli" +) + +const ( + // ConfigFileName is the name of config file + ConfigFileName = "config.json" + configFileDir = ".docker" +) + +var ( + ConfigDir string + ConfigFlag = cli.StringFlag{ + Name: "config", + Usage: "Location of client config files", + EnvVar: "DOCKER_CONFIG", + Value: filepath.Join(homedir.Get(), configFileDir), + Destination: &ConfigDir, + } + + ContextName string + ContextFlag = cli.StringFlag{ + Name: "context, c", + Usage: `Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")`, + EnvVar: "DOCKER_CONTEXT", + Destination: &ContextName, + } +) diff --git a/context/store.go b/context/store.go new file mode 100644 index 000000000..8c298fd28 --- /dev/null +++ b/context/store.go @@ -0,0 +1,65 @@ +package context + +import ( + "encoding/json" + "io/ioutil" + "path/filepath" + + "github.com/opencontainers/go-digest" +) + +const ( + contextsDir = "contexts" + metadataDir = "meta" + metaFile = "meta.json" +) + +// ContextStoreDir returns the directory the docker contexts are stored in +func ContextStoreDir() string { + return filepath.Join(ConfigDir, contextsDir) +} + +type Metadata struct { + Name string `json:",omitempty"` + Metadata TypeContext `json:",omitempty"` + Endpoints map[string]interface{} `json:",omitempty"` +} + +type TypeContext struct { + Type string +} + +func GetContext() (*Metadata, error) { + config, err := LoadConfigFile() + if err != nil { + return nil, err + } + r := &Metadata{ + Endpoints: make(map[string]interface{}), + } + + if ContextName == "" { + ContextName = config.CurrentContext + } + if ContextName == "" || ContextName == "default" { + r.Metadata.Type = "Moby" + return r, nil + } + + meta := filepath.Join(ConfigDir, contextsDir, metadataDir, contextdirOf(ContextName), metaFile) + bytes, err := ioutil.ReadFile(meta) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(bytes, r); err != nil { + return r, err + } + + r.Name = ContextName + return r, nil +} + +func contextdirOf(name string) string { + return digest.FromString(name).Encoded() +}