mirror of
https://github.com/docker/compose.git
synced 2025-07-21 12:44:54 +02:00
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
33
.golangci.yml
Normal file
33
.golangci.yml
Normal file
@ -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
|
cache-clear: # Clear the builder cache
|
||||||
@docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h
|
@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
|
help: ## Show help
|
||||||
@echo Please specify a build target. The choices are:
|
@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}'
|
@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) {
|
func createACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) (c containerinstance.ContainerGroup, err error) {
|
||||||
containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
|
containerGroupsClient := getContainerGroupsClient(aciContext.SubscriptionID)
|
||||||
if err != nil {
|
|
||||||
return c, fmt.Errorf("cannot get container group client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the container group already exists
|
// Check if the container group already exists
|
||||||
_, err = containerGroupsClient.Get(ctx, aciContext.ResourceGroup, *groupDefinition.Name)
|
_, err = containerGroupsClient.Get(ctx, aciContext.ResourceGroup, *groupDefinition.Name)
|
||||||
@ -96,28 +93,6 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group
|
|||||||
return containerGroup, err
|
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) {
|
func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) {
|
||||||
containerClient := getContainerClient(aciContext.SubscriptionID)
|
containerClient := getContainerClient(aciContext.SubscriptionID)
|
||||||
rows, cols := getTermSize()
|
rows, cols := getTermSize()
|
||||||
@ -233,11 +208,11 @@ func getACIContainerLogs(ctx context.Context, aciContext store.AciContext, conta
|
|||||||
return *logs.Content, err
|
return *logs.Content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainerGroupsClient(subscriptionID string) (containerinstance.ContainerGroupsClient, error) {
|
func getContainerGroupsClient(subscriptionID string) containerinstance.ContainerGroupsClient {
|
||||||
auth, _ := auth.NewAuthorizerFromCLI()
|
auth, _ := auth.NewAuthorizerFromCLI()
|
||||||
containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID)
|
containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID)
|
||||||
containerGroupsClient.Authorizer = auth
|
containerGroupsClient.Authorizer = auth
|
||||||
return containerGroupsClient, nil
|
return containerGroupsClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainerClient(subscriptionID string) containerinstance.ContainerClient {
|
func getContainerClient(subscriptionID string) containerinstance.ContainerClient {
|
||||||
|
@ -36,6 +36,7 @@ func getter() interface{} {
|
|||||||
return &store.AciContext{}
|
return &store.AciContext{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates a backend that can manage containers on ACI
|
||||||
func New(ctx context.Context) (containers.ContainerService, error) {
|
func New(ctx context.Context) (containers.ContainerService, error) {
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
contextStore, err := store.New()
|
contextStore, err := store.New()
|
||||||
|
@ -21,8 +21,10 @@ const (
|
|||||||
volumeDriveroptsAccountNameKey = "storage_account_name"
|
volumeDriveroptsAccountNameKey = "storage_account_name"
|
||||||
volumeDriveroptsAccountKeyKey = "storage_account_key"
|
volumeDriveroptsAccountKeyKey = "storage_account_key"
|
||||||
singleContainerName = "single--container--aci"
|
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) {
|
func ToContainerGroup(aciContext store.AciContext, p compose.Project) (containerinstance.ContainerGroup, error) {
|
||||||
project := projectAciHelper(p)
|
project := projectAciHelper(p)
|
||||||
containerGroupName := strings.ToLower(project.Name)
|
containerGroupName := strings.ToLower(project.Name)
|
||||||
@ -98,8 +100,8 @@ func (p projectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, err
|
|||||||
var secretVolumes []containerinstance.Volume
|
var secretVolumes []containerinstance.Volume
|
||||||
for secretName, filepathToRead := range p.Secrets {
|
for secretName, filepathToRead := range p.Secrets {
|
||||||
var data []byte
|
var data []byte
|
||||||
if strings.HasPrefix(filepathToRead.File, compose.SecretInlineMark) {
|
if strings.HasPrefix(filepathToRead.File, secretInlineMark) {
|
||||||
data = []byte(filepathToRead.File[len(compose.SecretInlineMark):])
|
data = []byte(filepathToRead.File[len(secretInlineMark):])
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
data, err = ioutil.ReadFile(filepathToRead.File)
|
data, err = ioutil.ReadFile(filepathToRead.File)
|
||||||
|
@ -7,43 +7,46 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrNoType = errors.New("backend: no type")
|
errNoType = errors.New("backend: no type")
|
||||||
ErrNoName = errors.New("backend: no name")
|
errNoName = errors.New("backend: no name")
|
||||||
ErrTypeRegistered = errors.New("backend: already registered")
|
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
|
name string
|
||||||
backendType string
|
backendType string
|
||||||
init InitFunc
|
init initFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
var backends = struct {
|
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 == "" {
|
if name == "" {
|
||||||
panic(ErrNoName)
|
panic(errNoName)
|
||||||
}
|
}
|
||||||
if backendType == "" {
|
if backendType == "" {
|
||||||
panic(ErrNoType)
|
panic(errNoType)
|
||||||
}
|
}
|
||||||
for _, b := range backends.r {
|
for _, b := range backends.r {
|
||||||
if b.backendType == backendType {
|
if b.backendType == backendType {
|
||||||
panic(ErrTypeRegistered)
|
panic(errTypeRegistered)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backends.r = append(backends.r, &Backend{
|
backends.r = append(backends.r, ®isteredBackend{
|
||||||
name,
|
name,
|
||||||
backendType,
|
backendType,
|
||||||
init,
|
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) {
|
func Get(ctx context.Context, backendType string) (interface{}, error) {
|
||||||
for _, b := range backends.r {
|
for _, b := range backends.r {
|
||||||
if b.backendType == backendType {
|
if b.backendType == backendType {
|
||||||
|
@ -38,9 +38,7 @@ import (
|
|||||||
"github.com/docker/api/context/store"
|
"github.com/docker/api/context/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CliContext struct {
|
// ContextCommand manages contexts
|
||||||
}
|
|
||||||
|
|
||||||
func ContextCommand() *cobra.Command {
|
func ContextCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "context",
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -17,6 +18,7 @@ type execOpts struct {
|
|||||||
Tty bool
|
Tty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecCommand runs a command in a running container
|
||||||
func ExecCommand() *cobra.Command {
|
func ExecCommand() *cobra.Command {
|
||||||
var opts execOpts
|
var opts execOpts
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
@ -52,7 +54,9 @@ func runExec(ctx context.Context, opts execOpts, name string, command string) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
con.Reset()
|
if err := con.Reset(); err != nil {
|
||||||
|
fmt.Println("Unable to close the console")
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stdout = con
|
stdout = con
|
||||||
|
@ -16,6 +16,7 @@ type logsOpts struct {
|
|||||||
Tail string
|
Tail string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogsCommand fetches and shows logs of a container
|
||||||
func LogsCommand() *cobra.Command {
|
func LogsCommand() *cobra.Command {
|
||||||
var opts logsOpts
|
var opts logsOpts
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/docker/api/client"
|
"github.com/docker/api/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PsCommand lists containers
|
||||||
var PsCommand = cobra.Command{
|
var PsCommand = cobra.Command{
|
||||||
Use: "ps",
|
Use: "ps",
|
||||||
Short: "List containers",
|
Short: "List containers",
|
||||||
|
@ -36,6 +36,7 @@ import (
|
|||||||
"github.com/docker/api/client"
|
"github.com/docker/api/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Command runs a container
|
||||||
func Command() *cobra.Command {
|
func Command() *cobra.Command {
|
||||||
var opts runOpts
|
var opts runOpts
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -20,6 +20,7 @@ type serveOpts struct {
|
|||||||
address string
|
address string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServeCommand returns the command to serve the API
|
||||||
func ServeCommand() *cobra.Command {
|
func ServeCommand() *cobra.Command {
|
||||||
var opts serveOpts
|
var opts serveOpts
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
@ -42,9 +43,10 @@ func runServe(ctx context.Context, opts serveOpts) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "listen unix socket")
|
return errors.Wrap(err, "listen unix socket")
|
||||||
}
|
}
|
||||||
|
// nolint
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
p := proxy.NewContainerApi()
|
p := proxy.NewContainerAPI()
|
||||||
|
|
||||||
containersv1.RegisterContainersServer(s, p)
|
containersv1.RegisterContainersServer(s, p)
|
||||||
cliv1.RegisterCliServer(s, &cliServer{
|
cliv1.RegisterCliServer(s, &cliServer{
|
||||||
|
@ -51,7 +51,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type mainOpts struct {
|
type mainOpts struct {
|
||||||
apicontext.ContextFlags
|
apicontext.Flags
|
||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +99,6 @@ func main() {
|
|||||||
cmd.ContextCommand(),
|
cmd.ContextCommand(),
|
||||||
&cmd.PsCommand,
|
&cmd.PsCommand,
|
||||||
cmd.ServeCommand(),
|
cmd.ServeCommand(),
|
||||||
&cmd.ExampleCommand,
|
|
||||||
run.Command(),
|
run.Command(),
|
||||||
cmd.ExecCommand(),
|
cmd.ExecCommand(),
|
||||||
cmd.LogsCommand(),
|
cmd.LogsCommand(),
|
||||||
|
@ -41,7 +41,7 @@ import (
|
|||||||
"github.com/docker/api/context/store"
|
"github.com/docker/api/context/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// New returns a GRPC client
|
// New returns a backend client
|
||||||
func New(ctx context.Context) (*Client, error) {
|
func New(ctx context.Context) (*Client, error) {
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
s := store.ContextStore(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 {
|
type Client struct {
|
||||||
backendv1.BackendClient
|
backendv1.BackendClient
|
||||||
cliv1.CliClient
|
cliv1.CliClient
|
||||||
@ -78,6 +79,7 @@ type Client struct {
|
|||||||
cc containers.ContainerService
|
cc containers.ContainerService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainerService returns the backend service for the current context
|
||||||
func (c *Client) ContainerService() containers.ContainerService {
|
func (c *Client) ContainerService() containers.ContainerService {
|
||||||
return c.cc
|
return c.cc
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,14 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var supportedFilenames = []string{
|
||||||
SecretInlineMark = "inline:"
|
|
||||||
)
|
|
||||||
|
|
||||||
var SupportedFilenames = []string{
|
|
||||||
"compose.yml",
|
"compose.yml",
|
||||||
"compose.yaml",
|
"compose.yaml",
|
||||||
"docker-compose.yml",
|
"docker-compose.yml",
|
||||||
"docker-compose.yaml",
|
"docker-compose.yaml",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectOptions configures a compose project
|
||||||
type ProjectOptions struct {
|
type ProjectOptions struct {
|
||||||
Name string
|
Name string
|
||||||
WorkDir string
|
WorkDir string
|
||||||
@ -32,6 +29,7 @@ type ProjectOptions struct {
|
|||||||
Environment []string
|
Environment []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Project represents a compose project with a name
|
||||||
type Project struct {
|
type Project struct {
|
||||||
types.Config
|
types.Config
|
||||||
projectDir string
|
projectDir string
|
||||||
@ -100,7 +98,7 @@ func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
var candidates []string
|
var candidates []string
|
||||||
for _, n := range SupportedFilenames {
|
for _, n := range supportedFilenames {
|
||||||
f := filepath.Join(pwd, n)
|
f := filepath.Join(pwd, n)
|
||||||
if _, err := os.Stat(f); err == nil {
|
if _, err := os.Stat(f); err == nil {
|
||||||
candidates = append(candidates, f)
|
candidates = append(candidates, f)
|
||||||
@ -116,7 +114,7 @@ func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
|
|||||||
}
|
}
|
||||||
parent := filepath.Dir(pwd)
|
parent := filepath.Dir(pwd)
|
||||||
if parent == 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
|
pwd = parent
|
||||||
}
|
}
|
||||||
@ -129,12 +127,11 @@ func parseConfigs(configPaths []string) ([]types.ConfigFile, error) {
|
|||||||
var err error
|
var err error
|
||||||
if f == "-" {
|
if f == "-" {
|
||||||
return []types.ConfigFile{}, errors.New("reading compose file from stdin is not supported")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
Status string
|
||||||
Image string
|
Image string
|
||||||
Command string
|
Command string
|
||||||
CpuTime uint64
|
CPUTime uint64
|
||||||
MemoryUsage uint64
|
MemoryUsage uint64
|
||||||
MemoryLimit uint64
|
MemoryLimit uint64
|
||||||
PidsCurrent uint64
|
PidsCurrent uint64
|
||||||
@ -37,6 +37,7 @@ type ContainerConfig struct {
|
|||||||
Ports []Port
|
Ports []Port
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogsRequest contains configuration about a log request
|
||||||
type LogsRequest struct {
|
type LogsRequest struct {
|
||||||
Follow bool
|
Follow bool
|
||||||
Tail string
|
Tail string
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LoadConfigFile loads the docker configuration
|
||||||
func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error) {
|
func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error) {
|
||||||
filename := filepath.Join(configDir, configFileName)
|
filename := filepath.Join(configDir, configFileName)
|
||||||
configFile := &ConfigFile{
|
configFile := &ConfigFile{
|
||||||
@ -45,6 +46,7 @@ func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't read %s: %w", filename, err)
|
return nil, fmt.Errorf("can't read %s: %w", filename, err)
|
||||||
}
|
}
|
||||||
|
// nolint
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
err = json.NewDecoder(file).Decode(&configFile)
|
err = json.NewDecoder(file).Decode(&configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -59,6 +61,7 @@ func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error
|
|||||||
return configFile, nil
|
return configFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigFile contains the current context from the docker configuration file
|
||||||
type ConfigFile struct {
|
type ConfigFile struct {
|
||||||
Filename string `json:"-"` // Note: for internal use only
|
Filename string `json:"-"` // Note: for internal use only
|
||||||
CurrentContext string `json:"currentContext,omitempty"`
|
CurrentContext string `json:"currentContext,omitempty"`
|
||||||
|
@ -6,10 +6,13 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"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{}
|
type currentContextKey struct{}
|
||||||
|
|
||||||
|
// WithCurrentContext sets the name of the current docker context
|
||||||
func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context {
|
func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context {
|
||||||
return context.WithValue(ctx, currentContextKey{}, contextName)
|
return context.WithValue(ctx, currentContextKey{}, contextName)
|
||||||
}
|
}
|
||||||
|
@ -41,12 +41,14 @@ const (
|
|||||||
configFileDir = ".docker"
|
configFileDir = ".docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContextFlags struct {
|
// Flags are the global cli flags
|
||||||
|
type Flags struct {
|
||||||
Config string
|
Config string
|
||||||
Context 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.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")
|
flags.StringVarP(&c.Context, "context", "c", os.Getenv("DOCKER_CONTEXT"), "context")
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,18 @@ const (
|
|||||||
|
|
||||||
type contextStoreKey struct{}
|
type contextStoreKey struct{}
|
||||||
|
|
||||||
|
// WithContextStore adds the store to the context
|
||||||
func WithContextStore(ctx context.Context, store Store) context.Context {
|
func WithContextStore(ctx context.Context, store Store) context.Context {
|
||||||
return context.WithValue(ctx, contextStoreKey{}, store)
|
return context.WithValue(ctx, contextStoreKey{}, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContextStore returns the store from the context
|
||||||
func ContextStore(ctx context.Context) Store {
|
func ContextStore(ctx context.Context) Store {
|
||||||
s, _ := ctx.Value(contextStoreKey{}).(Store)
|
s, _ := ctx.Value(contextStoreKey{}).(Store)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store
|
// Store is the context store
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// Get returns the context with name, it returns an error if the context
|
// Get returns the context with name, it returns an error if the context
|
||||||
// doesn't exist
|
// doesn't exist
|
||||||
@ -74,16 +76,18 @@ type store struct {
|
|||||||
root string
|
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) {
|
return func(s *store) {
|
||||||
s.root = root
|
s.root = root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a configured context store
|
// New returns a configured context store with $HOME/.docker as root
|
||||||
func New(opts ...StoreOpt) (Store, error) {
|
func New(opts ...Opt) (Store, error) {
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -182,7 +186,7 @@ func (s *store) Create(name string, data TypedContext) error {
|
|||||||
dir := contextdirOf(name)
|
dir := contextdirOf(name)
|
||||||
metaDir := filepath.Join(s.root, contextsDir, metadataDir, dir)
|
metaDir := filepath.Join(s.root, contextsDir, metadataDir, dir)
|
||||||
if _, err := os.Stat(metaDir); !os.IsNotExist(err) {
|
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)
|
err := os.Mkdir(metaDir, 0755)
|
||||||
@ -191,15 +195,15 @@ func (s *store) Create(name string, data TypedContext) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if data.Data == nil {
|
if data.Data == nil {
|
||||||
data.Data = DummyContext{}
|
data.Data = dummyContext{}
|
||||||
}
|
}
|
||||||
|
|
||||||
meta := Metadata{
|
meta := Metadata{
|
||||||
Name: name,
|
Name: name,
|
||||||
Metadata: data,
|
Metadata: data,
|
||||||
Endpoints: map[string]interface{}{
|
Endpoints: map[string]interface{}{
|
||||||
"docker": DummyContext{},
|
"docker": dummyContext{},
|
||||||
(data.Type): DummyContext{},
|
(data.Type): dummyContext{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,8 +241,9 @@ func contextdirOf(name string) string {
|
|||||||
return digest.FromString(name).Encoded()
|
return digest.FromString(name).Encoded()
|
||||||
}
|
}
|
||||||
|
|
||||||
type DummyContext struct{}
|
type dummyContext struct{}
|
||||||
|
|
||||||
|
// Metadata represents the docker context metadata
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
Name string `json:",omitempty"`
|
Name string `json:",omitempty"`
|
||||||
Metadata TypedContext `json:",omitempty"`
|
Metadata TypedContext `json:",omitempty"`
|
||||||
@ -257,12 +262,14 @@ type untypedContext struct {
|
|||||||
Type string `json:",omitempty"`
|
Type string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TypedContext is a context with a type (moby, aci, etc...)
|
||||||
type TypedContext struct {
|
type TypedContext struct {
|
||||||
Type string `json:",omitempty"`
|
Type string `json:",omitempty"`
|
||||||
Description string `json:",omitempty"`
|
Description string `json:",omitempty"`
|
||||||
Data interface{} `json:",omitempty"`
|
Data interface{} `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AciContext is the context for ACI
|
||||||
type AciContext struct {
|
type AciContext struct {
|
||||||
SubscriptionID string `json:",omitempty"`
|
SubscriptionID string `json:",omitempty"`
|
||||||
Location 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) {
|
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() {
|
func (suite *StoreTestSuite) TestCreate() {
|
||||||
|
@ -13,14 +13,10 @@ type containerService struct{}
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
backend.Register("example", "example", func(ctx context.Context) (interface{}, error) {
|
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) {
|
func (cs *containerService) List(ctx context.Context) ([]containers.Container, error) {
|
||||||
return []containers.Container{
|
return []containers.Container{
|
||||||
{
|
{
|
||||||
|
@ -10,22 +10,25 @@ import (
|
|||||||
|
|
||||||
type clientKey struct{}
|
type clientKey struct{}
|
||||||
|
|
||||||
|
// WithClient adds the client to the context
|
||||||
func WithClient(ctx context.Context, c *client.Client) (context.Context, error) {
|
func WithClient(ctx context.Context, c *client.Client) (context.Context, error) {
|
||||||
return context.WithValue(ctx, clientKey{}, c), nil
|
return context.WithValue(ctx, clientKey{}, c), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client returns the client from the context
|
||||||
func Client(ctx context.Context) *client.Client {
|
func Client(ctx context.Context) *client.Client {
|
||||||
c, _ := ctx.Value(clientKey{}).(*client.Client)
|
c, _ := ctx.Value(clientKey{}).(*client.Client)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContainerApi() v1.ContainersServer {
|
// NewContainerAPI creates a proxy container server
|
||||||
return &proxyContainerApi{}
|
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)
|
client := Client(ctx)
|
||||||
|
|
||||||
c, err := client.ContainerService().List(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
|
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)
|
client := Client(ctx)
|
||||||
|
|
||||||
err := client.ContainerService().Run(ctx, containers.ContainerConfig{
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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")
|
return nil, errors.New("missing metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
key := md[apicontext.KEY]
|
key := md[apicontext.Key]
|
||||||
|
|
||||||
if len(key) == 1 {
|
if len(key) == 1 {
|
||||||
s, err := store.New()
|
s, err := store.New()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user