Files
kubevpn/pkg/dev/run.go
2023-02-23 21:15:11 +08:00

125 lines
3.4 KiB
Go

package dev
import (
"context"
"fmt"
"io"
"math/rand"
"strings"
"time"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/container"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types"
typescommand "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/jsonmessage"
dockerterm "github.com/moby/term"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/wait"
)
func run(ctx context.Context, runConfig *RunConfig, cli *client.Client) (err error) {
rand.New(rand.NewSource(time.Now().UnixNano()))
var config = runConfig.config
var hostConfig = runConfig.hostConfig
var platform = runConfig.platform
var networkConfig = runConfig.networkingConfig
var name = runConfig.containerName
var needPull bool
var img types.ImageInspect
img, _, err = cli.ImageInspectWithRaw(ctx, config.Image)
if err != nil {
needPull = true
err = nil
}
if platform != nil && platform.Architecture != "" && platform.OS != "" {
if img.Os != platform.OS || img.Architecture != platform.Architecture {
needPull = true
}
}
if needPull {
var readCloser io.ReadCloser
var plat string
if runConfig.platform != nil && runConfig.platform.Architecture != "" && runConfig.platform.OS != "" {
plat = fmt.Sprintf("%s/%s", runConfig.platform.OS, runConfig.platform.Architecture)
}
readCloser, err = cli.ImagePull(ctx, config.Image, types.ImagePullOptions{Platform: plat})
if err != nil {
return fmt.Errorf("can not pull image %s, err: %s, please make sure image is exist and can be pulled from local", config.Image, err)
}
defer readCloser.Close()
_, stdout, _ := dockerterm.StdStreams()
out := streams.NewOut(stdout)
err = jsonmessage.DisplayJSONMessagesToStream(readCloser, out, nil)
if err != nil {
return err
}
}
var create typescommand.CreateResponse
create, err = cli.ContainerCreate(ctx, config, hostConfig, networkConfig, platform, name)
if err != nil {
return fmt.Errorf("failed to create container %s, err: %s", name, err)
}
log.Infof("Created container: %s", name)
if err != nil {
return err
}
err = cli.ContainerStart(ctx, create.ID, types.ContainerStartOptions{})
if err != nil {
return err
}
log.Infof("Wait container %s to be running...", name)
chanStop := make(chan struct{})
var inspect types.ContainerJSON
wait.Until(func() {
inspect, err = cli.ContainerInspect(ctx, create.ID)
if err != nil {
return
}
if inspect.State != nil && inspect.State.Running {
close(chanStop)
}
}, time.Second, chanStop)
// print port mapping to host
var empty = true
var str string
if inspect.NetworkSettings != nil && inspect.NetworkSettings.Ports != nil {
var list []string
for port, bindings := range inspect.NetworkSettings.Ports {
var p []string
for _, binding := range bindings {
if binding.HostPort != "" {
p = append(p, binding.HostPort)
empty = false
}
}
list = append(list, fmt.Sprintf("%s:%s", port, strings.Join(p, ",")))
}
str = fmt.Sprintf("Container %s is running on port %s now", name, strings.Join(list, " "))
}
if !empty {
log.Infoln(str)
} else {
log.Infof("Container %s is running now", name)
}
return nil
}
func terminal(c string, cli *command.DockerCli) error {
options := container.NewExecOptions()
options.Interactive = true
options.TTY = true
options.Container = c
options.Command = []string{"/bin/sh"}
return container.RunExec(cli, options)
}