зеркало из https://github.com/docker/compose-cli.git
Implement simple ACI run
This commit is contained in:
Родитель
600feb1e00
Коммит
3d363643ad
|
@ -0,0 +1,458 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/api/compose"
|
||||
"github.com/docker/api/context/store"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
|
||||
"github.com/Azure/azure-sdk-for-go/services/keyvault/auth"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
|
||||
tm "github.com/buger/goterm"
|
||||
)
|
||||
|
||||
const (
|
||||
AzureFileDriverName = "azure_file"
|
||||
VolumeDriveroptsShareNameKey = "share_name"
|
||||
VolumeDriveroptsAccountNameKey = "storage_account_name"
|
||||
VolumeDriveroptsAccountKeyKey = "storage_account_key"
|
||||
)
|
||||
const singleContainerName = "single--container--aci"
|
||||
|
||||
func CreateACIContainers(ctx context.Context, project compose.Project, aciContext store.AciContext) (c containerinstance.ContainerGroup, err error) {
|
||||
containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return c, fmt.Errorf("cannot get container group client: %v", err)
|
||||
}
|
||||
|
||||
groupDefinition, err := convert(project, aciContext)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Check if the container group already exists
|
||||
_, err = containerGroupsClient.Get(ctx, aciContext.ResourceGroup, *groupDefinition.Name)
|
||||
if err != nil {
|
||||
if err, ok := err.(autorest.DetailedError); ok {
|
||||
if err.StatusCode != http.StatusNotFound {
|
||||
return c, err
|
||||
}
|
||||
} else {
|
||||
return c, err
|
||||
}
|
||||
} else {
|
||||
return c, fmt.Errorf("Container group %q already exists", *groupDefinition.Name)
|
||||
}
|
||||
|
||||
future, err := containerGroupsClient.CreateOrUpdate(
|
||||
ctx,
|
||||
aciContext.ResourceGroup,
|
||||
*groupDefinition.Name,
|
||||
groupDefinition,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
err = future.WaitForCompletionRef(ctx, containerGroupsClient.Client)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
containerGroup, err := future.Result(containerGroupsClient)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
if len(project.Services) > 1 {
|
||||
var commands []string
|
||||
for _, service := range project.Services {
|
||||
commands = append(commands, fmt.Sprintf("echo 127.0.0.1 %s >> /etc/hosts", service.Name))
|
||||
}
|
||||
commands = append(commands, "exit")
|
||||
|
||||
response, err := ExecACIContainer(ctx, "/bin/sh", project.Name, project.Services[0].Name, aciContext)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
err = ExecWebSocketLoopWithCmd(
|
||||
ctx,
|
||||
*response.WebSocketURI,
|
||||
*response.Password,
|
||||
commands,
|
||||
false)
|
||||
if err != nil {
|
||||
return containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return containerGroup, err
|
||||
}
|
||||
|
||||
type ProjectAciHelper compose.Project
|
||||
|
||||
func (p ProjectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, error) {
|
||||
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):])
|
||||
} else {
|
||||
var err error
|
||||
data, err = ioutil.ReadFile(filepathToRead.File)
|
||||
if err != nil {
|
||||
return secretVolumes, err
|
||||
}
|
||||
}
|
||||
if len(data) == 0 {
|
||||
continue
|
||||
}
|
||||
dataStr := base64.StdEncoding.EncodeToString(data)
|
||||
secretVolumes = append(secretVolumes, containerinstance.Volume{
|
||||
Name: to.StringPtr(secretName),
|
||||
Secret: map[string]*string{
|
||||
secretName: &dataStr,
|
||||
},
|
||||
})
|
||||
}
|
||||
return secretVolumes, nil
|
||||
}
|
||||
|
||||
func (p ProjectAciHelper) getAciFileVolumes() (map[string]bool, []containerinstance.Volume, error) {
|
||||
azureFileVolumesMap := make(map[string]bool, len(p.Volumes))
|
||||
var azureFileVolumesSlice []containerinstance.Volume
|
||||
for name, v := range p.Volumes {
|
||||
if v.Driver == AzureFileDriverName {
|
||||
shareName, ok := v.DriverOpts[VolumeDriveroptsShareNameKey]
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("cannot retrieve share name for Azurefile")
|
||||
}
|
||||
accountName, ok := v.DriverOpts[VolumeDriveroptsAccountNameKey]
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("cannot retrieve account name for Azurefile")
|
||||
}
|
||||
accountKey, ok := v.DriverOpts[VolumeDriveroptsAccountKeyKey]
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("cannot retrieve account key for Azurefile")
|
||||
}
|
||||
aciVolume := containerinstance.Volume{
|
||||
Name: to.StringPtr(name),
|
||||
AzureFile: &containerinstance.AzureFileVolume{
|
||||
ShareName: to.StringPtr(shareName),
|
||||
StorageAccountName: to.StringPtr(accountName),
|
||||
StorageAccountKey: to.StringPtr(accountKey),
|
||||
},
|
||||
}
|
||||
azureFileVolumesMap[name] = true
|
||||
azureFileVolumesSlice = append(azureFileVolumesSlice, aciVolume)
|
||||
}
|
||||
}
|
||||
return azureFileVolumesMap, azureFileVolumesSlice, nil
|
||||
}
|
||||
|
||||
type ServiceConfigAciHelper types.ServiceConfig
|
||||
|
||||
func (s ServiceConfigAciHelper) getAciFileVolumeMounts(volumesCache map[string]bool) ([]containerinstance.VolumeMount, error) {
|
||||
var aciServiceVolumes []containerinstance.VolumeMount
|
||||
for _, sv := range s.Volumes {
|
||||
if !volumesCache[sv.Source] {
|
||||
return []containerinstance.VolumeMount{}, fmt.Errorf("could not find volume source %q", sv.Source)
|
||||
}
|
||||
aciServiceVolumes = append(aciServiceVolumes, containerinstance.VolumeMount{
|
||||
Name: to.StringPtr(sv.Source),
|
||||
MountPath: to.StringPtr(sv.Target),
|
||||
})
|
||||
}
|
||||
return aciServiceVolumes, nil
|
||||
}
|
||||
|
||||
func (s ServiceConfigAciHelper) getAciSecretsVolumeMounts() []containerinstance.VolumeMount {
|
||||
var secretVolumeMounts []containerinstance.VolumeMount
|
||||
for _, secret := range s.Secrets {
|
||||
secretsMountPath := "/run/secrets"
|
||||
if secret.Target == "" {
|
||||
secret.Target = secret.Source
|
||||
}
|
||||
// Specifically use "/" here and not filepath.Join() to avoid windows path being sent and used inside containers
|
||||
secretsMountPath = secretsMountPath + "/" + secret.Target
|
||||
vmName := strings.Split(secret.Source, "=")[0]
|
||||
vm := containerinstance.VolumeMount{
|
||||
Name: to.StringPtr(vmName),
|
||||
MountPath: to.StringPtr(secretsMountPath),
|
||||
ReadOnly: to.BoolPtr(true), // TODO Confirm if the secrets are read only
|
||||
}
|
||||
secretVolumeMounts = append(secretVolumeMounts, vm)
|
||||
}
|
||||
return secretVolumeMounts
|
||||
}
|
||||
|
||||
func (s ServiceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (containerinstance.Container, error) {
|
||||
secretVolumeMounts := s.getAciSecretsVolumeMounts()
|
||||
aciServiceVolumes, err := s.getAciFileVolumeMounts(volumesCache)
|
||||
if err != nil {
|
||||
return containerinstance.Container{}, err
|
||||
}
|
||||
allVolumes := append(aciServiceVolumes, secretVolumeMounts...)
|
||||
var volumes *[]containerinstance.VolumeMount
|
||||
if len(allVolumes) == 0 {
|
||||
volumes = nil
|
||||
} else {
|
||||
volumes = &allVolumes
|
||||
}
|
||||
return containerinstance.Container{
|
||||
Name: to.StringPtr(s.Name),
|
||||
ContainerProperties: &containerinstance.ContainerProperties{
|
||||
Image: to.StringPtr(s.Image),
|
||||
Resources: &containerinstance.ResourceRequirements{
|
||||
Limits: &containerinstance.ResourceLimits{
|
||||
MemoryInGB: to.Float64Ptr(1),
|
||||
CPU: to.Float64Ptr(1),
|
||||
},
|
||||
Requests: &containerinstance.ResourceRequests{
|
||||
MemoryInGB: to.Float64Ptr(1),
|
||||
CPU: to.Float64Ptr(1),
|
||||
},
|
||||
},
|
||||
VolumeMounts: volumes,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListACIContainers List available containers
|
||||
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, command, containerGroup string, containerName string, aciContext store.AciContext) (c containerinstance.ContainerExecResponse, err error) {
|
||||
containerClient := getContainerClient(aciContext.SubscriptionID)
|
||||
rows, cols := getTermSize()
|
||||
containerExecRequest := containerinstance.ContainerExecRequest{
|
||||
Command: to.StringPtr(command),
|
||||
TerminalSize: &containerinstance.ContainerExecRequestTerminalSize{
|
||||
Rows: rows,
|
||||
Cols: cols,
|
||||
},
|
||||
}
|
||||
return containerClient.ExecuteCommand(
|
||||
ctx,
|
||||
aciContext.ResourceGroup,
|
||||
containerGroup,
|
||||
containerName,
|
||||
containerExecRequest)
|
||||
}
|
||||
|
||||
func getTermSize() (*int32, *int32) {
|
||||
rows := tm.Height()
|
||||
cols := tm.Width()
|
||||
return to.Int32Ptr(int32(rows)), to.Int32Ptr(int32(cols))
|
||||
}
|
||||
|
||||
func ExecWebSocketLoop(ctx context.Context, wsURL, passwd string) error {
|
||||
return ExecWebSocketLoopWithCmd(ctx, wsURL, passwd, []string{}, true)
|
||||
}
|
||||
|
||||
func ExecWebSocketLoopWithCmd(ctx context.Context, wsURL, passwd string, commands []string, outputEnabled bool) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
conn, _, _, err := ws.DefaultDialer.Dial(ctx, wsURL)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return err
|
||||
}
|
||||
err = wsutil.WriteClientMessage(conn, ws.OpText, []byte(passwd))
|
||||
if err != nil {
|
||||
cancel()
|
||||
return err
|
||||
}
|
||||
lastCommandLen := 0
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for {
|
||||
msg, _, err := wsutil.ReadServerData(conn)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
fmt.Printf("read error: %s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
lines := strings.Split(string(msg), "\n")
|
||||
lastCommandLen = len(lines[len(lines)-1])
|
||||
if outputEnabled {
|
||||
fmt.Printf("%s", msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
rc := make(chan string, 10)
|
||||
if len(commands) > 0 {
|
||||
for _, command := range commands {
|
||||
rc <- command
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
if !scanner.Scan() {
|
||||
close(done)
|
||||
cancel()
|
||||
fmt.Println("exiting...")
|
||||
break
|
||||
}
|
||||
t := scanner.Text()
|
||||
rc <- t
|
||||
cleanLastCommand(lastCommandLen)
|
||||
}
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return nil
|
||||
case line := <-rc:
|
||||
err = wsutil.WriteClientMessage(conn, ws.OpText, []byte(line+"\n"))
|
||||
if err != nil {
|
||||
fmt.Println("write: ", err)
|
||||
return nil
|
||||
}
|
||||
case <-interrupt:
|
||||
fmt.Println("interrupted...")
|
||||
close(done)
|
||||
cancel()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func convert(p compose.Project, aciContext store.AciContext) (containerinstance.ContainerGroup, error) {
|
||||
project := ProjectAciHelper(p)
|
||||
containerGroupName := strings.ToLower(project.Name)
|
||||
volumesCache, volumesSlice, err := project.getAciFileVolumes()
|
||||
if err != nil {
|
||||
return containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
secretVolumes, err := project.getAciSecretVolumes()
|
||||
if err != nil {
|
||||
return containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
allVolumes := append(volumesSlice, secretVolumes...)
|
||||
var volumes *[]containerinstance.Volume
|
||||
if len(allVolumes) == 0 {
|
||||
volumes = nil
|
||||
} else {
|
||||
volumes = &allVolumes
|
||||
}
|
||||
var containers []containerinstance.Container
|
||||
groupDefinition := containerinstance.ContainerGroup{
|
||||
Name: &containerGroupName,
|
||||
Location: &aciContext.Location,
|
||||
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
|
||||
OsType: containerinstance.Linux,
|
||||
Containers: &containers,
|
||||
Volumes: volumes,
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range project.Services {
|
||||
service := ServiceConfigAciHelper(s)
|
||||
if s.Name != singleContainerName {
|
||||
logrus.Debugf("Adding %q\n", service.Name)
|
||||
}
|
||||
containerDefinition, err := service.getAciContainer(volumesCache)
|
||||
if err != nil {
|
||||
return containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
if service.Ports != nil {
|
||||
var containerPorts []containerinstance.ContainerPort
|
||||
var groupPorts []containerinstance.Port
|
||||
for _, portConfig := range service.Ports {
|
||||
if portConfig.Published != 0 && portConfig.Published != portConfig.Target {
|
||||
msg := fmt.Sprintf("Port mapping is not supported with ACI, cannot map port %d to %d for container %s",
|
||||
portConfig.Published, portConfig.Target, service.Name)
|
||||
return groupDefinition, errors.New(msg)
|
||||
}
|
||||
portNumber := int32(portConfig.Target)
|
||||
containerPorts = append(containerPorts, containerinstance.ContainerPort{
|
||||
Port: to.Int32Ptr(portNumber),
|
||||
})
|
||||
groupPorts = append(groupPorts, containerinstance.Port{
|
||||
Port: to.Int32Ptr(portNumber),
|
||||
Protocol: containerinstance.TCP,
|
||||
})
|
||||
}
|
||||
containerDefinition.ContainerProperties.Ports = &containerPorts
|
||||
groupDefinition.ContainerGroupProperties.IPAddress = &containerinstance.IPAddress{
|
||||
Type: containerinstance.Public,
|
||||
Ports: &groupPorts,
|
||||
}
|
||||
}
|
||||
|
||||
containers = append(containers, containerDefinition)
|
||||
}
|
||||
groupDefinition.ContainerGroupProperties.Containers = &containers
|
||||
return groupDefinition, nil
|
||||
}
|
||||
|
||||
func cleanLastCommand(lastCommandLen int) {
|
||||
tm.MoveCursorUp(1)
|
||||
tm.MoveCursorForward(lastCommandLen)
|
||||
if runtime.GOOS != "windows" {
|
||||
for i := 0; i < tm.Width(); i++ {
|
||||
_, _ = tm.Print(" ")
|
||||
}
|
||||
tm.MoveCursorUp(1)
|
||||
}
|
||||
|
||||
tm.Flush()
|
||||
}
|
||||
|
||||
func getContainerGroupsClient(subscriptionID string) (containerinstance.ContainerGroupsClient, error) {
|
||||
auth, _ := auth.NewAuthorizerFromCLI()
|
||||
containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID)
|
||||
containerGroupsClient.Authorizer = auth
|
||||
return containerGroupsClient, nil
|
||||
}
|
||||
|
||||
func getContainerClient(subscriptionID string) containerinstance.ContainerClient {
|
||||
auth, _ := auth.NewAuthorizerFromCLI()
|
||||
containerClient := containerinstance.NewContainerClient(subscriptionID)
|
||||
containerClient.Authorizer = auth
|
||||
return containerClient
|
||||
}
|
|
@ -5,12 +5,16 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/api/context/store"
|
||||
|
||||
"github.com/docker/api/backend"
|
||||
"github.com/docker/api/compose"
|
||||
"github.com/docker/api/containers"
|
||||
apicontext "github.com/docker/api/context"
|
||||
"github.com/docker/api/context/store"
|
||||
)
|
||||
|
||||
type containerService struct {
|
||||
|
@ -86,3 +90,18 @@ func (cs *containerService) List(ctx context.Context) ([]containers.Container, e
|
|||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfig) error {
|
||||
var project compose.Project
|
||||
project.Name = r.ID
|
||||
project.Services = []types.ServiceConfig{
|
||||
{
|
||||
Name: r.ID,
|
||||
Image: r.Image,
|
||||
},
|
||||
}
|
||||
|
||||
logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
|
||||
_, err := CreateACIContainers(ctx, project, cs.ctx)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
"github.com/docker/api/client"
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func RunCommand() *cobra.Command {
|
||||
var opts runOpts
|
||||
cmd := &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Run a container",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runRun(cmd.Context(), args[0], opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringArrayVarP(&opts.publish, "publish", "p", []string{}, "Publish a container's port(s)")
|
||||
cmd.Flags().StringVar(&opts.name, "name", uuid.New().String(), "Assign a name to the container")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runRun(ctx context.Context, image string, opts runOpts) error {
|
||||
c, err := client.New(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := opts.ToContainerConfig(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.ContainerService().Run(ctx, project)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/api/containers"
|
||||
)
|
||||
|
||||
type runOpts struct {
|
||||
name string
|
||||
publish []string
|
||||
}
|
||||
|
||||
func toPorts(ports []string) ([]containers.Port, error) {
|
||||
var result []containers.Port
|
||||
|
||||
for _, port := range ports {
|
||||
parts := strings.Split(port, ":")
|
||||
result = append(result, containers.Port{
|
||||
Source: parts[0],
|
||||
Destination: parts[1],
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *runOpts) ToContainerConfig(image string) (containers.ContainerConfig, error) {
|
||||
publish, err := toPorts(r.publish)
|
||||
if err != nil {
|
||||
return containers.ContainerConfig{}, err
|
||||
}
|
||||
|
||||
return containers.ContainerConfig{
|
||||
ID: r.name,
|
||||
Image: image,
|
||||
Ports: publish,
|
||||
}, nil
|
||||
}
|
15
cli/main.go
15
cli/main.go
|
@ -93,6 +93,14 @@ func main() {
|
|||
},
|
||||
}
|
||||
|
||||
root.AddCommand(
|
||||
cmd.ContextCommand(),
|
||||
&cmd.PsCommand,
|
||||
cmd.ServeCommand(),
|
||||
&cmd.ExampleCommand,
|
||||
cmd.RunCommand(),
|
||||
)
|
||||
|
||||
helpFunc := root.HelpFunc()
|
||||
root.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
||||
if !isOwnCommand(cmd) {
|
||||
|
@ -110,13 +118,6 @@ func main() {
|
|||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
root.AddCommand(
|
||||
cmd.ContextCommand(),
|
||||
&cmd.PsCommand,
|
||||
cmd.ServeCommand(),
|
||||
&cmd.ExampleCommand,
|
||||
)
|
||||
|
||||
ctx, cancel := util.NewSigContext()
|
||||
defer cancel()
|
||||
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
package compose
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/loader"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
SecretInlineMark = "inline:"
|
||||
)
|
||||
|
||||
var SupportedFilenames = []string{
|
||||
"compose.yml",
|
||||
"compose.yaml",
|
||||
"docker-compose.yml",
|
||||
"docker-compose.yaml",
|
||||
}
|
||||
|
||||
type ProjectOptions struct {
|
||||
Name string
|
||||
WorkDir string
|
||||
ConfigPaths []string
|
||||
Environment []string
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
types.Config
|
||||
projectDir string
|
||||
Name string `yaml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// ProjectFromOptions load a compose project based on given options
|
||||
func ProjectFromOptions(options *ProjectOptions) (*Project, error) {
|
||||
configPath, err := getConfigPathFromOptions(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := options.Name
|
||||
if name == "" {
|
||||
r := regexp.MustCompile(`[^a-z0-9\\-_]+`)
|
||||
name = r.ReplaceAllString(strings.ToLower(filepath.Base(options.WorkDir)), "")
|
||||
}
|
||||
configs, err := parseConfigs(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newProject(types.ConfigDetails{
|
||||
WorkingDir: options.WorkDir,
|
||||
ConfigFiles: configs,
|
||||
Environment: getAsEqualsMap(options.Environment),
|
||||
}, name)
|
||||
}
|
||||
|
||||
func newProject(config types.ConfigDetails, name string) (*Project, error) {
|
||||
model, err := loader.Load(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := Project{
|
||||
Config: *model,
|
||||
projectDir: config.WorkingDir,
|
||||
Name: name,
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
|
||||
var paths []string
|
||||
pwd := options.WorkDir
|
||||
|
||||
if len(options.ConfigPaths) != 0 {
|
||||
for _, f := range options.ConfigPaths {
|
||||
if f == "-" {
|
||||
paths = append(paths, f)
|
||||
continue
|
||||
}
|
||||
if !filepath.IsAbs(f) {
|
||||
f = filepath.Join(pwd, f)
|
||||
}
|
||||
if _, err := os.Stat(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paths = append(paths, f)
|
||||
}
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
for {
|
||||
var candidates []string
|
||||
for _, n := range SupportedFilenames {
|
||||
f := filepath.Join(pwd, n)
|
||||
if _, err := os.Stat(f); err == nil {
|
||||
candidates = append(candidates, f)
|
||||
}
|
||||
}
|
||||
if len(candidates) > 0 {
|
||||
winner := candidates[0]
|
||||
if len(candidates) > 1 {
|
||||
logrus.Warnf("Found multiple config files with supported names: %s", strings.Join(candidates, ", "))
|
||||
logrus.Warnf("Using %s\n", winner)
|
||||
}
|
||||
return []string{winner}, nil
|
||||
}
|
||||
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)
|
||||
}
|
||||
pwd = parent
|
||||
}
|
||||
}
|
||||
|
||||
func parseConfigs(configPaths []string) ([]types.ConfigFile, error) {
|
||||
var files []types.ConfigFile
|
||||
for _, f := range configPaths {
|
||||
var b []byte
|
||||
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 != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := loader.ParseYAML(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files = append(files, types.ConfigFile{Filename: f, Config: config})
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// getAsEqualsMap split key=value formatted strings into a key : value map
|
||||
func getAsEqualsMap(em []string) map[string]string {
|
||||
m := make(map[string]string)
|
||||
for _, v := range em {
|
||||
kv := strings.SplitN(v, "=", 2)
|
||||
m[kv[0]] = kv[1]
|
||||
}
|
||||
return m
|
||||
}
|
|
@ -17,6 +17,18 @@ type Container struct {
|
|||
Labels []string
|
||||
}
|
||||
|
||||
type Port struct {
|
||||
Source string
|
||||
Destination string
|
||||
}
|
||||
|
||||
type ContainerConfig struct {
|
||||
ID string
|
||||
Image string
|
||||
Ports []Port
|
||||
}
|
||||
|
||||
type ContainerService interface {
|
||||
List(context.Context) ([]Container, error)
|
||||
Run(context.Context, ContainerConfig) error
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package example
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/api/backend"
|
||||
"github.com/docker/api/containers"
|
||||
|
@ -31,3 +32,8 @@ func (cs *containerService) List(ctx context.Context) ([]containers.Container, e
|
|||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfig) error {
|
||||
fmt.Printf("Running container %q with name %q\n", r.Image, r.ID)
|
||||
return nil
|
||||
}
|
||||
|
|
11
go.mod
11
go.mod
|
@ -4,11 +4,17 @@ go 1.13
|
|||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go v42.0.0+incompatible
|
||||
github.com/Azure/go-autorest/autorest v0.10.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.10.0
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0
|
||||
github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
||||
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
||||
github.com/gobwas/pool v0.2.0 // indirect
|
||||
github.com/gobwas/ws v1.0.3
|
||||
github.com/golang/protobuf v1.4.0
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
|
@ -22,5 +28,4 @@ require (
|
|||
golang.org/x/text v0.3.2 // indirect
|
||||
google.golang.org/grpc v1.29.1
|
||||
google.golang.org/protobuf v1.21.0
|
||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
||||
)
|
||||
|
|
63
go.sum
63
go.sum
|
@ -2,13 +2,11 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
|||
github.com/Azure/azure-sdk-for-go v42.0.0+incompatible h1:yz6sFf5bHZ+gEOQVuK5JhPqTTAmv+OvSLSaqgzqaCwY=
|
||||
github.com/Azure/azure-sdk-for-go v42.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
|
||||
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
|
||||
github.com/Azure/go-autorest/autorest v0.10.0 h1:mvdtztBqcL8se7MdrUweNieTNi4kfNG6GOJuurQJpuY=
|
||||
github.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
|
@ -34,14 +32,18 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 h1:gfAMKE626QEuKG3si0pdTRcr/YEbBoxY+3GOH3gWvl4=
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
|
@ -49,13 +51,13 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
|
|||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae h1:5zRbbF5Gbkl7ZEJrKwYha2JMWgnfpPjSmv8+jCmkeSA=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae/go.mod h1:1PUpzRF1O/65VOqXZuwpCuYY7pJxbIq1jbAvAf62FGM=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -65,10 +67,13 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
|
@ -76,6 +81,12 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.3 h1:ZOigqf7iBxkA4jdQ3am7ATzdlOFp9YzA6NmuvEEZc9g=
|
||||
github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
|
@ -98,19 +109,20 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
|
@ -123,25 +135,24 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw=
|
||||
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -171,9 +182,7 @@ github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLk
|
|||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
|
@ -181,30 +190,30 @@ github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q
|
|||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
|
@ -212,7 +221,6 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -225,11 +233,9 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U=
|
||||
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
|
@ -238,7 +244,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -246,13 +251,10 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -263,6 +265,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
|
@ -282,6 +285,7 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -292,9 +296,10 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/docker/api/client"
|
||||
"github.com/docker/api/containers"
|
||||
v1 "github.com/docker/api/containers/v1"
|
||||
)
|
||||
|
||||
|
@ -45,8 +46,15 @@ func (p *proxyContainerApi) List(ctx context.Context, _ *v1.ListRequest) (*v1.Li
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Create(_ context.Context, _ *v1.CreateRequest) (*v1.CreateResponse, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
func (p *proxyContainerApi) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
|
||||
client := Client(ctx)
|
||||
|
||||
err := client.ContainerService().Run(ctx, containers.ContainerConfig{
|
||||
ID: request.Id,
|
||||
Image: request.Image,
|
||||
})
|
||||
|
||||
return &v1.CreateResponse{}, err
|
||||
}
|
||||
|
||||
func (p *proxyContainerApi) Start(_ context.Context, _ *v1.StartRequest) (*v1.StartResponse, error) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче