mirror of https://github.com/docker/compose.git
Add comments on exported items, remove example command
Also add `make lint` to run the linter
This commit is contained in:
parent
29737c2a23
commit
24c035e822
|
@ -0,0 +1,33 @@
|
|||
linters:
|
||||
run:
|
||||
concurrency: 2
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- deadcode
|
||||
- errcheck
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
linters-settings:
|
||||
gocyclo:
|
||||
min-complexity: 16
|
||||
lll:
|
||||
line-length: 200
|
||||
issues:
|
||||
exclude-use-default: false
|
8
Makefile
8
Makefile
|
@ -53,8 +53,14 @@ test: ## Run unit tests
|
|||
cache-clear: # Clear the builder cache
|
||||
@docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h
|
||||
|
||||
lint: ## run linter(s)
|
||||
@echo "Linting..."
|
||||
golangci-lint run --timeout 10m0s ./...
|
||||
|
||||
help: ## Show help
|
||||
@echo Please specify a build target. The choices are:
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
.PHONY: all protos cli cross test cache-clear help
|
||||
FORCE:
|
||||
|
||||
.PHONY: all protos cli cross test cache-clear lint help
|
||||
|
|
31
azure/aci.go
31
azure/aci.go
|
@ -30,10 +30,7 @@ func init() {
|
|||
}
|
||||
|
||||
func createACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) (c containerinstance.ContainerGroup, err error) {
|
||||
containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return c, fmt.Errorf("cannot get container group client: %v", err)
|
||||
}
|
||||
containerGroupsClient := getContainerGroupsClient(aciContext.SubscriptionID)
|
||||
|
||||
// Check if the container group already exists
|
||||
_, err = containerGroupsClient.Get(ctx, aciContext.ResourceGroup, *groupDefinition.Name)
|
||||
|
@ -96,28 +93,6 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group
|
|||
return containerGroup, err
|
||||
}
|
||||
|
||||
func listACIContainers(aciContext store.AciContext) (c []containerinstance.ContainerGroup, err error) {
|
||||
ctx := context.TODO()
|
||||
containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return c, fmt.Errorf("cannot get container group client: %v", err)
|
||||
}
|
||||
|
||||
var containers []containerinstance.ContainerGroup
|
||||
result, err := containerGroupsClient.ListByResourceGroup(ctx, aciContext.ResourceGroup)
|
||||
if err != nil {
|
||||
return []containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
for result.NotDone() {
|
||||
containers = append(containers, result.Values()...)
|
||||
if err := result.NextWithContext(ctx); err != nil {
|
||||
return []containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return containers, err
|
||||
}
|
||||
|
||||
func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) {
|
||||
containerClient := getContainerClient(aciContext.SubscriptionID)
|
||||
rows, cols := getTermSize()
|
||||
|
@ -233,11 +208,11 @@ func getACIContainerLogs(ctx context.Context, aciContext store.AciContext, conta
|
|||
return *logs.Content, err
|
||||
}
|
||||
|
||||
func getContainerGroupsClient(subscriptionID string) (containerinstance.ContainerGroupsClient, error) {
|
||||
func getContainerGroupsClient(subscriptionID string) containerinstance.ContainerGroupsClient {
|
||||
auth, _ := auth.NewAuthorizerFromCLI()
|
||||
containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID)
|
||||
containerGroupsClient.Authorizer = auth
|
||||
return containerGroupsClient, nil
|
||||
return containerGroupsClient
|
||||
}
|
||||
|
||||
func getContainerClient(subscriptionID string) containerinstance.ContainerClient {
|
||||
|
|
|
@ -36,6 +36,7 @@ func getter() interface{} {
|
|||
return &store.AciContext{}
|
||||
}
|
||||
|
||||
// New creates a backend that can manage containers on ACI
|
||||
func New(ctx context.Context) (containers.ContainerService, error) {
|
||||
currentContext := apicontext.CurrentContext(ctx)
|
||||
contextStore, err := store.New()
|
||||
|
|
|
@ -21,8 +21,10 @@ const (
|
|||
volumeDriveroptsAccountNameKey = "storage_account_name"
|
||||
volumeDriveroptsAccountKeyKey = "storage_account_key"
|
||||
singleContainerName = "single--container--aci"
|
||||
secretInlineMark = "inline:"
|
||||
)
|
||||
|
||||
// ToContainerGroup converts a compose project into a ACI container group
|
||||
func ToContainerGroup(aciContext store.AciContext, p compose.Project) (containerinstance.ContainerGroup, error) {
|
||||
project := projectAciHelper(p)
|
||||
containerGroupName := strings.ToLower(project.Name)
|
||||
|
@ -98,8 +100,8 @@ func (p projectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, err
|
|||
var secretVolumes []containerinstance.Volume
|
||||
for secretName, filepathToRead := range p.Secrets {
|
||||
var data []byte
|
||||
if strings.HasPrefix(filepathToRead.File, compose.SecretInlineMark) {
|
||||
data = []byte(filepathToRead.File[len(compose.SecretInlineMark):])
|
||||
if strings.HasPrefix(filepathToRead.File, secretInlineMark) {
|
||||
data = []byte(filepathToRead.File[len(secretInlineMark):])
|
||||
} else {
|
||||
var err error
|
||||
data, err = ioutil.ReadFile(filepathToRead.File)
|
||||
|
|
|
@ -7,43 +7,46 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrNoType = errors.New("backend: no type")
|
||||
ErrNoName = errors.New("backend: no name")
|
||||
ErrTypeRegistered = errors.New("backend: already registered")
|
||||
errNoType = errors.New("backend: no type")
|
||||
errNoName = errors.New("backend: no name")
|
||||
errTypeRegistered = errors.New("backend: already registered")
|
||||
)
|
||||
|
||||
type InitFunc func(context.Context) (interface{}, error)
|
||||
type initFunc func(context.Context) (interface{}, error)
|
||||
|
||||
type Backend struct {
|
||||
type registeredBackend struct {
|
||||
name string
|
||||
backendType string
|
||||
init InitFunc
|
||||
init initFunc
|
||||
}
|
||||
|
||||
var backends = struct {
|
||||
r []*Backend
|
||||
r []*registeredBackend
|
||||
}{}
|
||||
|
||||
func Register(name string, backendType string, init InitFunc) {
|
||||
// Register adds a typed backend to the registry
|
||||
func Register(name string, backendType string, init initFunc) {
|
||||
if name == "" {
|
||||
panic(ErrNoName)
|
||||
panic(errNoName)
|
||||
}
|
||||
if backendType == "" {
|
||||
panic(ErrNoType)
|
||||
panic(errNoType)
|
||||
}
|
||||
for _, b := range backends.r {
|
||||
if b.backendType == backendType {
|
||||
panic(ErrTypeRegistered)
|
||||
panic(errTypeRegistered)
|
||||
}
|
||||
}
|
||||
|
||||
backends.r = append(backends.r, &Backend{
|
||||
backends.r = append(backends.r, ®isteredBackend{
|
||||
name,
|
||||
backendType,
|
||||
init,
|
||||
})
|
||||
}
|
||||
|
||||
// Get returns the backend registered for a particular type, it returns
|
||||
// an error if there is no registered backends for the given type.
|
||||
func Get(ctx context.Context, backendType string) (interface{}, error) {
|
||||
for _, b := range backends.r {
|
||||
if b.backendType == backendType {
|
||||
|
|
|
@ -38,9 +38,7 @@ import (
|
|||
"github.com/docker/api/context/store"
|
||||
)
|
||||
|
||||
type CliContext struct {
|
||||
}
|
||||
|
||||
// ContextCommand manages contexts
|
||||
func ContextCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "context",
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2020 Docker Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
v1 "github.com/docker/api/backend/v1"
|
||||
"github.com/docker/api/client"
|
||||
)
|
||||
|
||||
var ExampleCommand = cobra.Command{
|
||||
Use: "example",
|
||||
Short: "sample command using backend, to be removed later",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
c, err := client.New(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot connect to backend")
|
||||
}
|
||||
|
||||
info, err := c.BackendInformation(ctx, &v1.BackendInformationRequest{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch backend information")
|
||||
}
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(info)
|
||||
},
|
||||
}
|
||||
|
||||
type backendAddressKey struct{}
|
||||
|
||||
func BackendAddress(ctx context.Context) (string, error) {
|
||||
v, ok := ctx.Value(backendAddressKey{}).(string)
|
||||
if !ok {
|
||||
return "", errors.New("no backend address key")
|
||||
}
|
||||
return v, nil
|
||||
}
|
|
@ -2,6 +2,7 @@ package cmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -17,6 +18,7 @@ type execOpts struct {
|
|||
Tty bool
|
||||
}
|
||||
|
||||
// ExecCommand runs a command in a running container
|
||||
func ExecCommand() *cobra.Command {
|
||||
var opts execOpts
|
||||
cmd := &cobra.Command{
|
||||
|
@ -52,7 +54,9 @@ func runExec(ctx context.Context, opts execOpts, name string, command string) er
|
|||
return err
|
||||
}
|
||||
defer func() {
|
||||
con.Reset()
|
||||
if err := con.Reset(); err != nil {
|
||||
fmt.Println("Unable to close the console")
|
||||
}
|
||||
}()
|
||||
|
||||
stdout = con
|
||||
|
|
|
@ -16,6 +16,7 @@ type logsOpts struct {
|
|||
Tail string
|
||||
}
|
||||
|
||||
// LogsCommand fetches and shows logs of a container
|
||||
func LogsCommand() *cobra.Command {
|
||||
var opts logsOpts
|
||||
cmd := &cobra.Command{
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/docker/api/client"
|
||||
)
|
||||
|
||||
// PsCommand lists containers
|
||||
var PsCommand = cobra.Command{
|
||||
Use: "ps",
|
||||
Short: "List containers",
|
||||
|
|
|
@ -36,6 +36,7 @@ import (
|
|||
"github.com/docker/api/client"
|
||||
)
|
||||
|
||||
// Command runs a container
|
||||
func Command() *cobra.Command {
|
||||
var opts runOpts
|
||||
cmd := &cobra.Command{
|
||||
|
|
|
@ -20,6 +20,7 @@ type serveOpts struct {
|
|||
address string
|
||||
}
|
||||
|
||||
// ServeCommand returns the command to serve the API
|
||||
func ServeCommand() *cobra.Command {
|
||||
var opts serveOpts
|
||||
cmd := &cobra.Command{
|
||||
|
@ -42,9 +43,10 @@ func runServe(ctx context.Context, opts serveOpts) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "listen unix socket")
|
||||
}
|
||||
// nolint
|
||||
defer listener.Close()
|
||||
|
||||
p := proxy.NewContainerApi()
|
||||
p := proxy.NewContainerAPI()
|
||||
|
||||
containersv1.RegisterContainersServer(s, p)
|
||||
cliv1.RegisterCliServer(s, &cliServer{
|
||||
|
|
|
@ -51,7 +51,7 @@ import (
|
|||
)
|
||||
|
||||
type mainOpts struct {
|
||||
apicontext.ContextFlags
|
||||
apicontext.Flags
|
||||
debug bool
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,6 @@ func main() {
|
|||
cmd.ContextCommand(),
|
||||
&cmd.PsCommand,
|
||||
cmd.ServeCommand(),
|
||||
&cmd.ExampleCommand,
|
||||
run.Command(),
|
||||
cmd.ExecCommand(),
|
||||
cmd.LogsCommand(),
|
||||
|
|
|
@ -41,7 +41,7 @@ import (
|
|||
"github.com/docker/api/context/store"
|
||||
)
|
||||
|
||||
// New returns a GRPC client
|
||||
// New returns a backend client
|
||||
func New(ctx context.Context) (*Client, error) {
|
||||
currentContext := apicontext.CurrentContext(ctx)
|
||||
s := store.ContextStore(ctx)
|
||||
|
@ -68,6 +68,7 @@ func New(ctx context.Context) (*Client, error) {
|
|||
|
||||
}
|
||||
|
||||
// Client is a multi-backend client
|
||||
type Client struct {
|
||||
backendv1.BackendClient
|
||||
cliv1.CliClient
|
||||
|
@ -78,6 +79,7 @@ type Client struct {
|
|||
cc containers.ContainerService
|
||||
}
|
||||
|
||||
// ContainerService returns the backend service for the current context
|
||||
func (c *Client) ContainerService() containers.ContainerService {
|
||||
return c.cc
|
||||
}
|
||||
|
|
|
@ -14,17 +14,14 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
SecretInlineMark = "inline:"
|
||||
)
|
||||
|
||||
var SupportedFilenames = []string{
|
||||
var supportedFilenames = []string{
|
||||
"compose.yml",
|
||||
"compose.yaml",
|
||||
"docker-compose.yml",
|
||||
"docker-compose.yaml",
|
||||
}
|
||||
|
||||
// ProjectOptions configures a compose project
|
||||
type ProjectOptions struct {
|
||||
Name string
|
||||
WorkDir string
|
||||
|
@ -32,6 +29,7 @@ type ProjectOptions struct {
|
|||
Environment []string
|
||||
}
|
||||
|
||||
// Project represents a compose project with a name
|
||||
type Project struct {
|
||||
types.Config
|
||||
projectDir string
|
||||
|
@ -100,7 +98,7 @@ func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
|
|||
|
||||
for {
|
||||
var candidates []string
|
||||
for _, n := range SupportedFilenames {
|
||||
for _, n := range supportedFilenames {
|
||||
f := filepath.Join(pwd, n)
|
||||
if _, err := os.Stat(f); err == nil {
|
||||
candidates = append(candidates, f)
|
||||
|
@ -116,7 +114,7 @@ func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
|
|||
}
|
||||
parent := filepath.Dir(pwd)
|
||||
if parent == pwd {
|
||||
return nil, fmt.Errorf("Can't find a suitable configuration file in this directory or any parent. Is %q the right directory?", pwd)
|
||||
return nil, fmt.Errorf("can't find a suitable configuration file in this directory or any parent. Is %q the right directory?", pwd)
|
||||
}
|
||||
pwd = parent
|
||||
}
|
||||
|
@ -129,12 +127,11 @@ func parseConfigs(configPaths []string) ([]types.ConfigFile, error) {
|
|||
var err error
|
||||
if f == "-" {
|
||||
return []types.ConfigFile{}, errors.New("reading compose file from stdin is not supported")
|
||||
} else {
|
||||
if _, err := os.Stat(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err = ioutil.ReadFile(f)
|
||||
}
|
||||
if _, err := os.Stat(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err = ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
30
consts.go
30
consts.go
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2019 Docker Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
const DockerContextKey = "DOCKER_CONTEXT_KEY"
|
|
@ -11,7 +11,7 @@ type Container struct {
|
|||
Status string
|
||||
Image string
|
||||
Command string
|
||||
CpuTime uint64
|
||||
CPUTime uint64
|
||||
MemoryUsage uint64
|
||||
MemoryLimit uint64
|
||||
PidsCurrent uint64
|
||||
|
@ -37,6 +37,7 @@ type ContainerConfig struct {
|
|||
Ports []Port
|
||||
}
|
||||
|
||||
// LogsRequest contains configuration about a log request
|
||||
type LogsRequest struct {
|
||||
Follow bool
|
||||
Tail string
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
"path/filepath"
|
||||
)
|
||||
|
||||
// LoadConfigFile loads the docker configuration
|
||||
func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error) {
|
||||
filename := filepath.Join(configDir, configFileName)
|
||||
configFile := &ConfigFile{
|
||||
|
@ -45,6 +46,7 @@ func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read %s: %w", filename, err)
|
||||
}
|
||||
// nolint
|
||||
defer file.Close()
|
||||
err = json.NewDecoder(file).Decode(&configFile)
|
||||
if err != nil {
|
||||
|
@ -59,6 +61,7 @@ func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error
|
|||
return configFile, nil
|
||||
}
|
||||
|
||||
// ConfigFile contains the current context from the docker configuration file
|
||||
type ConfigFile struct {
|
||||
Filename string `json:"-"` // Note: for internal use only
|
||||
CurrentContext string `json:"currentContext,omitempty"`
|
||||
|
|
|
@ -6,10 +6,13 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const KEY = "context_key"
|
||||
// Key is the key where the current docker context is stored in the metadata
|
||||
// of a gRPC request
|
||||
const Key = "context_key"
|
||||
|
||||
type currentContextKey struct{}
|
||||
|
||||
// WithCurrentContext sets the name of the current docker context
|
||||
func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context {
|
||||
return context.WithValue(ctx, currentContextKey{}, contextName)
|
||||
}
|
||||
|
|
|
@ -41,12 +41,14 @@ const (
|
|||
configFileDir = ".docker"
|
||||
)
|
||||
|
||||
type ContextFlags struct {
|
||||
// Flags are the global cli flags
|
||||
type Flags struct {
|
||||
Config string
|
||||
Context string
|
||||
}
|
||||
|
||||
func (c *ContextFlags) AddFlags(flags *pflag.FlagSet) {
|
||||
// AddFlags adds persistent (globa) flags
|
||||
func (c *Flags) AddFlags(flags *pflag.FlagSet) {
|
||||
flags.StringVar(&c.Config, "config", filepath.Join(home(), configFileDir), "Location of the client config files `DIRECTORY`")
|
||||
flags.StringVarP(&c.Context, "context", "c", os.Getenv("DOCKER_CONTEXT"), "context")
|
||||
}
|
||||
|
|
|
@ -47,16 +47,18 @@ const (
|
|||
|
||||
type contextStoreKey struct{}
|
||||
|
||||
// WithContextStore adds the store to the context
|
||||
func WithContextStore(ctx context.Context, store Store) context.Context {
|
||||
return context.WithValue(ctx, contextStoreKey{}, store)
|
||||
}
|
||||
|
||||
// ContextStore returns the store from the context
|
||||
func ContextStore(ctx context.Context) Store {
|
||||
s, _ := ctx.Value(contextStoreKey{}).(Store)
|
||||
return s
|
||||
}
|
||||
|
||||
// Store
|
||||
// Store is the context store
|
||||
type Store interface {
|
||||
// Get returns the context with name, it returns an error if the context
|
||||
// doesn't exist
|
||||
|
@ -74,16 +76,18 @@ type store struct {
|
|||
root string
|
||||
}
|
||||
|
||||
type StoreOpt func(*store)
|
||||
// Opt is a functional option for the store
|
||||
type Opt func(*store)
|
||||
|
||||
func WithRoot(root string) StoreOpt {
|
||||
// WithRoot sets a new root to the store
|
||||
func WithRoot(root string) Opt {
|
||||
return func(s *store) {
|
||||
s.root = root
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a configured context store
|
||||
func New(opts ...StoreOpt) (Store, error) {
|
||||
// New returns a configured context store with $HOME/.docker as root
|
||||
func New(opts ...Opt) (Store, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -182,7 +186,7 @@ func (s *store) Create(name string, data TypedContext) error {
|
|||
dir := contextdirOf(name)
|
||||
metaDir := filepath.Join(s.root, contextsDir, metadataDir, dir)
|
||||
if _, err := os.Stat(metaDir); !os.IsNotExist(err) {
|
||||
return fmt.Errorf("Context %q already exists", name)
|
||||
return fmt.Errorf("context %q already exists", name)
|
||||
}
|
||||
|
||||
err := os.Mkdir(metaDir, 0755)
|
||||
|
@ -191,15 +195,15 @@ func (s *store) Create(name string, data TypedContext) error {
|
|||
}
|
||||
|
||||
if data.Data == nil {
|
||||
data.Data = DummyContext{}
|
||||
data.Data = dummyContext{}
|
||||
}
|
||||
|
||||
meta := Metadata{
|
||||
Name: name,
|
||||
Metadata: data,
|
||||
Endpoints: map[string]interface{}{
|
||||
"docker": DummyContext{},
|
||||
(data.Type): DummyContext{},
|
||||
"docker": dummyContext{},
|
||||
(data.Type): dummyContext{},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -237,8 +241,9 @@ func contextdirOf(name string) string {
|
|||
return digest.FromString(name).Encoded()
|
||||
}
|
||||
|
||||
type DummyContext struct{}
|
||||
type dummyContext struct{}
|
||||
|
||||
// Metadata represents the docker context metadata
|
||||
type Metadata struct {
|
||||
Name string `json:",omitempty"`
|
||||
Metadata TypedContext `json:",omitempty"`
|
||||
|
@ -257,12 +262,14 @@ type untypedContext struct {
|
|||
Type string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// TypedContext is a context with a type (moby, aci, etc...)
|
||||
type TypedContext struct {
|
||||
Type string `json:",omitempty"`
|
||||
Description string `json:",omitempty"`
|
||||
Data interface{} `json:",omitempty"`
|
||||
}
|
||||
|
||||
// AciContext is the context for ACI
|
||||
type AciContext struct {
|
||||
SubscriptionID string `json:",omitempty"`
|
||||
Location string `json:",omitempty"`
|
||||
|
|
|
@ -55,7 +55,8 @@ func (suite *StoreTestSuite) BeforeTest(suiteName, testName string) {
|
|||
}
|
||||
|
||||
func (suite *StoreTestSuite) AfterTest(suiteName, testName string) {
|
||||
os.RemoveAll(suite.dir)
|
||||
err := os.RemoveAll(suite.dir)
|
||||
require.Nil(suite.T(), err)
|
||||
}
|
||||
|
||||
func (suite *StoreTestSuite) TestCreate() {
|
||||
|
|
|
@ -13,14 +13,10 @@ type containerService struct{}
|
|||
|
||||
func init() {
|
||||
backend.Register("example", "example", func(ctx context.Context) (interface{}, error) {
|
||||
return New(), nil
|
||||
return &containerService{}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func New() containers.ContainerService {
|
||||
return &containerService{}
|
||||
}
|
||||
|
||||
func (cs *containerService) List(ctx context.Context) ([]containers.Container, error) {
|
||||
return []containers.Container{
|
||||
{
|
||||
|
|
|
@ -10,22 +10,25 @@ import (
|
|||
|
||||
type clientKey struct{}
|
||||
|
||||
// WithClient adds the client to the context
|
||||
func WithClient(ctx context.Context, c *client.Client) (context.Context, error) {
|
||||
return context.WithValue(ctx, clientKey{}, c), nil
|
||||
}
|
||||
|
||||
// Client returns the client from the context
|
||||
func Client(ctx context.Context) *client.Client {
|
||||
c, _ := ctx.Value(clientKey{}).(*client.Client)
|
||||
return c
|
||||
}
|
||||
|
||||
func NewContainerApi() v1.ContainersServer {
|
||||
return &proxyContainerApi{}
|
||||
// NewContainerAPI creates a proxy container server
|
||||
func NewContainerAPI() v1.ContainersServer {
|
||||
return &proxyContainerAPI{}
|
||||
}
|
||||
|
||||
type proxyContainerApi struct{}
|
||||
type proxyContainerAPI struct{}
|
||||
|
||||
func (p *proxyContainerApi) List(ctx context.Context, _ *v1.ListRequest) (*v1.ListResponse, error) {
|
||||
func (p *proxyContainerAPI) List(ctx context.Context, _ *v1.ListRequest) (*v1.ListResponse, error) {
|
||||
client := Client(ctx)
|
||||
|
||||
c, err := client.ContainerService().List(ctx)
|
||||
|
@ -46,7 +49,7 @@ func (p *proxyContainerApi) List(ctx context.Context, _ *v1.ListRequest) (*v1.Li
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
|
||||
func (p *proxyContainerAPI) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
|
||||
client := Client(ctx)
|
||||
|
||||
err := client.ContainerService().Run(ctx, containers.ContainerConfig{
|
||||
|
@ -57,26 +60,26 @@ func (p *proxyContainerApi) Create(ctx context.Context, request *v1.CreateReques
|
|||
return &v1.CreateResponse{}, err
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Start(_ context.Context, _ *v1.StartRequest) (*v1.StartResponse, error) {
|
||||
func (p *proxyContainerAPI) Start(_ context.Context, _ *v1.StartRequest) (*v1.StartResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Stop(_ context.Context, _ *v1.StopRequest) (*v1.StopResponse, error) {
|
||||
func (p *proxyContainerAPI) Stop(_ context.Context, _ *v1.StopRequest) (*v1.StopResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Kill(_ context.Context, _ *v1.KillRequest) (*v1.KillResponse, error) {
|
||||
func (p *proxyContainerAPI) Kill(_ context.Context, _ *v1.KillRequest) (*v1.KillResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Delete(_ context.Context, _ *v1.DeleteRequest) (*v1.DeleteResponse, error) {
|
||||
func (p *proxyContainerAPI) Delete(_ context.Context, _ *v1.DeleteRequest) (*v1.DeleteResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Update(_ context.Context, _ *v1.UpdateRequest) (*v1.UpdateResponse, error) {
|
||||
func (p *proxyContainerAPI) Update(_ context.Context, _ *v1.UpdateRequest) (*v1.UpdateResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Exec(_ context.Context, _ *v1.ExecRequest) (*v1.ExecResponse, error) {
|
||||
func (p *proxyContainerAPI) Exec(_ context.Context, _ *v1.ExecRequest) (*v1.ExecResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ func unaryMeta(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
|
|||
return nil, errors.New("missing metadata")
|
||||
}
|
||||
|
||||
key := md[apicontext.KEY]
|
||||
key := md[apicontext.Key]
|
||||
|
||||
if len(key) == 1 {
|
||||
s, err := store.New()
|
||||
|
|
Loading…
Reference in New Issue