diff --git a/client/client.go b/client/client.go index 6fd5153..5260401 100644 --- a/client/client.go +++ b/client/client.go @@ -1,22 +1,14 @@ package client import ( - "errors" - "fmt" "net/http" "os" - dCliCommand "github.com/docker/cli/cli/command" - dCliConfig "github.com/docker/cli/cli/config" - dContext "github.com/docker/cli/cli/context" - "github.com/docker/cli/cli/context/docker" - dCliContextStore "github.com/docker/cli/cli/context/store" - dClient "github.com/docker/docker/client" - "github.com/moby/term" + "github.com/docker/docker/client" "github.com/sirupsen/logrus" ) -func NewClientWithContext(contextName string) (*dClient.Client, error) { +func NewClientWithContext(contextName string) (*client.Client, error) { context, err := GetContext(contextName) if err != nil { return nil, err @@ -34,142 +26,27 @@ func NewClientWithContext(contextName string) (*dClient.Client, error) { }, } - var clientOpts []dClient.Opt + var clientOpts []client.Opt clientOpts = append(clientOpts, - dClient.WithHTTPClient(httpClient), - dClient.WithHost(helper.Host), - dClient.WithDialContext(helper.Dialer), + client.WithHTTPClient(httpClient), + client.WithHost(helper.Host), + client.WithDialContext(helper.Dialer), ) // FIXME: Maybe don't have this variable here and load it beforehand version := os.Getenv("DOCKER_API_VERSION") if version != "" { - clientOpts = append(clientOpts, dClient.WithVersion(version)) + clientOpts = append(clientOpts, client.WithVersion(version)) } else { - clientOpts = append(clientOpts, dClient.WithAPIVersionNegotiation()) + clientOpts = append(clientOpts, client.WithAPIVersionNegotiation()) } - cl, err := dClient.NewClientWithOpts(clientOpts...) + cl, err := client.NewClientWithOpts(clientOpts...) if err != nil { logrus.Fatalf("unable to create Docker client: %s", err) } return cl, nil } - -func CreateContext(contextName string, user string, port string) error { - host := contextName - if user != "" { - host = fmt.Sprintf("%s@%s", user, host) - } - if port != "" { - host = fmt.Sprintf("%s:%s", host, port) - } - host = fmt.Sprintf("ssh://%s", host) - if err := createNewContext(contextName, host); err != nil { - return err - } - return nil -} - -func createNewContext(name string, host string) error { - s := NewDefaultDockerContextStore() - contextMetadata := newContextMetadata(name) - contextTLSData := dCliContextStore.ContextTLSData{ - Endpoints: make(map[string]dCliContextStore.EndpointTLSData), - } - dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(host) - if err != nil { - return err - } - contextMetadata.Endpoints[docker.DockerEndpoint] = dockerEP - if dockerTLS != nil { - contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerTLS - } - - if err := s.CreateOrUpdate(contextMetadata); err != nil { - return err - } - if err := s.ResetTLSMaterial(name, &contextTLSData); err != nil { - return err - } - return nil -} - -func getDockerEndpoint(host string) (docker.Endpoint, error) { - skipTLSVerify := false - ep := docker.Endpoint{ - EndpointMeta: docker.EndpointMeta{ - Host: host, - SkipTLSVerify: skipTLSVerify, - }, - } - // try to resolve a docker client, validating the configuration - opts, err := ep.ClientOpts() - if err != nil { - return docker.Endpoint{}, err - } - if _, err := dClient.NewClientWithOpts(opts...); err != nil { - return docker.Endpoint{}, err - } - return ep, nil -} - -func newContextMetadata(name string) dCliContextStore.Metadata { - return dCliContextStore.Metadata{ - Endpoints: make(map[string]interface{}), - Name: name, - } -} - -func getDockerEndpointMetadataAndTLS(host string) (docker.EndpointMeta, *dCliContextStore.EndpointTLSData, error) { - ep, err := getDockerEndpoint(host) - if err != nil { - return docker.EndpointMeta{}, nil, err - } - return ep.EndpointMeta, ep.TLSData.ToStoreTLSData(), nil -} - -func GetContext(contextName string) (dCliContextStore.Metadata, error) { - ctx, err := NewDefaultDockerContextStore().GetMetadata(contextName) - if err != nil { - return dCliContextStore.Metadata{}, err - } - return ctx, nil -} - -func GetContextEndpoint(ctx dCliContextStore.Metadata) (string, error) { - // safe to use docker key hardcoded since abra doesn't use k8s... yet... - endpointmeta, ok := ctx.Endpoints["docker"].(dContext.EndpointMetaBase) - if !ok { - err := errors.New("context lacks Docker endpoint") - return "", err - } - return endpointmeta.Host, nil -} - -func NewDefaultDockerContextStore() *dCliCommand.ContextStoreWithDefault { - // Grabbing the stderr from Docker commands - // Much easier to fit this into the code we are using to replicate docker cli commands - _, _, stderr := term.StdStreams() - // TODO: Look into custom docker configs in case users want that - dockerConfig := dCliConfig.LoadDefaultConfigFile(stderr) - contextDir := dCliConfig.ContextStoreDir() - storeConfig := dCliCommand.DefaultContextStoreConfig() - store := newContextStore(contextDir, storeConfig) - - dockerContextStore := &dCliCommand.ContextStoreWithDefault{ - Store: store, - Resolver: func() (*dCliCommand.DefaultContext, error) { - // nil for the Opts because it works without it and its a cli thing - return dCliCommand.ResolveDefaultContext(nil, dockerConfig, storeConfig, stderr) - }, - } - return dockerContextStore -} - -func newContextStore(dir string, config dCliContextStore.Config) dCliContextStore.Store { - return dCliContextStore.New(dir, config) -} diff --git a/client/connection.go b/client/connection.go index c1f7634..bb4e28e 100644 --- a/client/connection.go +++ b/client/connection.go @@ -2,6 +2,9 @@ package client import ( "github.com/docker/cli/cli/connhelper" + "github.com/docker/cli/cli/context/docker" + dCliContextStore "github.com/docker/cli/cli/context/store" + dClient "github.com/docker/docker/client" "github.com/sirupsen/logrus" ) @@ -13,3 +16,30 @@ func newConnectionHelper(daemonURL string) *connhelper.ConnectionHelper { } return helper } + +func getDockerEndpoint(host string) (docker.Endpoint, error) { + skipTLSVerify := false + ep := docker.Endpoint{ + EndpointMeta: docker.EndpointMeta{ + Host: host, + SkipTLSVerify: skipTLSVerify, + }, + } + // try to resolve a docker client, validating the configuration + opts, err := ep.ClientOpts() + if err != nil { + return docker.Endpoint{}, err + } + if _, err := dClient.NewClientWithOpts(opts...); err != nil { + return docker.Endpoint{}, err + } + return ep, nil +} + +func getDockerEndpointMetadataAndTLS(host string) (docker.EndpointMeta, *dCliContextStore.EndpointTLSData, error) { + ep, err := getDockerEndpoint(host) + if err != nil { + return docker.EndpointMeta{}, nil, err + } + return ep.EndpointMeta, ep.TLSData.ToStoreTLSData(), nil +} diff --git a/client/context.go b/client/context.go new file mode 100644 index 0000000..e37d446 --- /dev/null +++ b/client/context.go @@ -0,0 +1,100 @@ +package client + +import ( + "errors" + "fmt" + + command "github.com/docker/cli/cli/command" + dConfig "github.com/docker/cli/cli/config" + context "github.com/docker/cli/cli/context" + "github.com/docker/cli/cli/context/docker" + contextStore "github.com/docker/cli/cli/context/store" + "github.com/moby/term" +) + +type Context = contextStore.Metadata + +func CreateContext(contextName string, user string, port string) error { + host := contextName + if user != "" { + host = fmt.Sprintf("%s@%s", user, host) + } + if port != "" { + host = fmt.Sprintf("%s:%s", host, port) + } + host = fmt.Sprintf("ssh://%s", host) + if err := createContext(contextName, host); err != nil { + return err + } + return nil +} + +// createContext interacts with Docker Context to create a Docker context config +func createContext(name string, host string) error { + s := NewDefaultDockerContextStore() + contextMetadata := contextStore.Metadata{ + Endpoints: make(map[string]interface{}), + Name: name, + } + contextTLSData := contextStore.ContextTLSData{ + Endpoints: make(map[string]contextStore.EndpointTLSData), + } + dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(host) + if err != nil { + return err + } + contextMetadata.Endpoints[docker.DockerEndpoint] = dockerEP + if dockerTLS != nil { + contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerTLS + } + + if err := s.CreateOrUpdate(contextMetadata); err != nil { + return err + } + if err := s.ResetTLSMaterial(name, &contextTLSData); err != nil { + return err + } + return nil +} + +func GetContext(contextName string) (contextStore.Metadata, error) { + ctx, err := NewDefaultDockerContextStore().GetMetadata(contextName) + if err != nil { + return contextStore.Metadata{}, err + } + return ctx, nil +} + +func GetContextEndpoint(ctx contextStore.Metadata) (string, error) { + // safe to use docker key hardcoded since abra doesn't use k8s... yet... + endpointmeta, ok := ctx.Endpoints["docker"].(context.EndpointMetaBase) + if !ok { + err := errors.New("context lacks Docker endpoint") + return "", err + } + return endpointmeta.Host, nil +} + +func newContextStore(dir string, config contextStore.Config) contextStore.Store { + return contextStore.New(dir, config) +} + +func NewDefaultDockerContextStore() *command.ContextStoreWithDefault { + // Grabbing the stderr from Docker commands + // Much easier to fit this into the code we are using to replicate docker cli commands + _, _, stderr := term.StdStreams() + // TODO: Look into custom docker configs in case users want that + dockerConfig := dConfig.LoadDefaultConfigFile(stderr) + contextDir := dConfig.ContextStoreDir() + storeConfig := command.DefaultContextStoreConfig() + store := newContextStore(contextDir, storeConfig) + + dockerContextStore := &command.ContextStoreWithDefault{ + Store: store, + Resolver: func() (*command.DefaultContext, error) { + // nil for the Opts because it works without it and its a cli thing + return command.ResolveDefaultContext(nil, dockerConfig, storeConfig, stderr) + }, + } + return dockerContextStore +} diff --git a/client/client_test.go b/client/context_test.go similarity index 100% rename from client/client_test.go rename to client/context_test.go