diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/adapter/containers.go | 150 | ||||
-rw-r--r-- | pkg/adapter/containers_remote.go | 30 | ||||
-rw-r--r-- | pkg/adapter/sigproxy.go | 36 | ||||
-rw-r--r-- | pkg/adapter/terminal.go | 159 | ||||
-rw-r--r-- | pkg/registrar/registrar_test.go | 318 | ||||
-rw-r--r-- | pkg/varlinkapi/config.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/containers.go | 23 | ||||
-rw-r--r-- | pkg/varlinkapi/containers_create.go | 212 | ||||
-rw-r--r-- | pkg/varlinkapi/events.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/images.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/mount.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/pods.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/remote_client.go | 29 | ||||
-rw-r--r-- | pkg/varlinkapi/system.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/transfers.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/util.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/volumes.go | 2 |
17 files changed, 635 insertions, 340 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 932d209cd..1bca99cec 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -5,12 +5,17 @@ package adapter import ( "context" "fmt" + "io/ioutil" + "os" + "path/filepath" "strconv" + "strings" "sync" "syscall" "time" "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/adapter/shortcuts" "github.com/pkg/errors" @@ -154,3 +159,148 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) } return nil } + +// CreateContainer creates a libpod container +func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) { + results := shared.NewIntermediateLayer(&c.PodmanCommand) + ctr, _, err := shared.CreateContainer(ctx, &results, r.Runtime) + return ctr.ID(), err +} + +// Run a libpod container +func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) { + results := shared.NewIntermediateLayer(&c.PodmanCommand) + + ctr, createConfig, err := shared.CreateContainer(ctx, &results, r.Runtime) + if err != nil { + return exitCode, err + } + + if logrus.GetLevel() == logrus.DebugLevel { + cgroupPath, err := ctr.CGroupPath() + if err == nil { + logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath) + } + } + + // Handle detached start + if createConfig.Detach { + // if the container was created as part of a pod, also start its dependencies, if any. + if err := ctr.Start(ctx, c.IsSet("pod")); err != nil { + // This means the command did not exist + exitCode = 127 + if strings.Index(err.Error(), "permission denied") > -1 { + exitCode = 126 + } + return exitCode, err + } + + fmt.Printf("%s\n", ctr.ID()) + exitCode = 0 + return exitCode, nil + } + + outputStream := os.Stdout + errorStream := os.Stderr + inputStream := os.Stdin + + // If -i is not set, clear stdin + if !c.Bool("interactive") { + inputStream = nil + } + + // If attach is set, clear stdin/stdout/stderr and only attach requested + if c.IsSet("attach") || c.IsSet("a") { + outputStream = nil + errorStream = nil + if !c.Bool("interactive") { + inputStream = nil + } + + attachTo := c.StringSlice("attach") + for _, stream := range attachTo { + switch strings.ToLower(stream) { + case "stdout": + outputStream = os.Stdout + case "stderr": + errorStream = os.Stderr + case "stdin": + inputStream = os.Stdin + default: + return exitCode, errors.Wrapf(libpod.ErrInvalidArg, "invalid stream %q for --attach - must be one of stdin, stdout, or stderr", stream) + } + } + } + // if the container was created as part of a pod, also start its dependencies, if any. + if err := StartAttachCtr(ctx, ctr, outputStream, errorStream, inputStream, c.String("detach-keys"), c.Bool("sig-proxy"), true, c.IsSet("pod")); err != nil { + // We've manually detached from the container + // Do not perform cleanup, or wait for container exit code + // Just exit immediately + if errors.Cause(err) == libpod.ErrDetach { + exitCode = 0 + return exitCode, nil + } + // This means the command did not exist + exitCode = 127 + if strings.Index(err.Error(), "permission denied") > -1 { + exitCode = 126 + } + if c.IsSet("rm") { + if deleteError := r.Runtime.RemoveContainer(ctx, ctr, true, false); deleteError != nil { + logrus.Errorf("unable to remove container %s after failing to start and attach to it", ctr.ID()) + } + } + return exitCode, err + } + + if ecode, err := ctr.Wait(); err != nil { + if errors.Cause(err) == libpod.ErrNoSuchCtr { + // The container may have been removed + // Go looking for an exit file + config, err := r.Runtime.GetConfig() + if err != nil { + return exitCode, err + } + ctrExitCode, err := ReadExitFile(config.TmpDir, ctr.ID()) + if err != nil { + logrus.Errorf("Cannot get exit code: %v", err) + exitCode = 127 + } else { + exitCode = ctrExitCode + } + } + } else { + exitCode = int(ecode) + } + + if c.IsSet("rm") { + r.Runtime.RemoveContainer(ctx, ctr, false, true) + } + + return exitCode, nil +} + +// ReadExitFile reads a container's exit file +func ReadExitFile(runtimeTmp, ctrID string) (int, error) { + exitFile := filepath.Join(runtimeTmp, "exits", fmt.Sprintf("%s-old", ctrID)) + + logrus.Debugf("Attempting to read container %s exit code from file %s", ctrID, exitFile) + + // Check if it exists + if _, err := os.Stat(exitFile); err != nil { + return 0, errors.Wrapf(err, "error getting exit file for container %s", ctrID) + } + + // File exists, read it in and convert to int + statusStr, err := ioutil.ReadFile(exitFile) + if err != nil { + return 0, errors.Wrapf(err, "error reading exit file for container %s", ctrID) + } + + exitCode, err := strconv.Atoi(string(statusStr)) + if err != nil { + return 0, errors.Wrapf(err, "error parsing exit code for container %s", ctrID) + } + + return exitCode, nil +} diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 2982d6cbb..3730827c7 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -262,3 +262,33 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) } return nil } + +// CreateContainer creates a container from the cli over varlink +func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) { + if !c.Bool("detach") { + // TODO need to add attach when that function becomes available + return "", errors.New("the remote client only supports detached containers") + } + results := shared.NewIntermediateLayer(&c.PodmanCommand) + return iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink()) +} + +// Run creates a container overvarlink and then starts it +func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) { + // TODO the exit codes for run need to be figured out for remote connections + if !c.Bool("detach") { + return 0, errors.New("the remote client only supports detached containers") + } + results := shared.NewIntermediateLayer(&c.PodmanCommand) + cid, err := iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink()) + if err != nil { + return 0, err + } + fmt.Println(cid) + _, err = iopodman.StartContainer().Call(r.Conn, cid) + return 0, err +} + +func ReadExitFile(runtimeTmp, ctrID string) (int, error) { + return 0, libpod.ErrNotImplemented +} diff --git a/pkg/adapter/sigproxy.go b/pkg/adapter/sigproxy.go new file mode 100644 index 000000000..af968cb89 --- /dev/null +++ b/pkg/adapter/sigproxy.go @@ -0,0 +1,36 @@ +package adapter + +import ( + "os" + "syscall" + + "github.com/containers/libpod/libpod" + "github.com/docker/docker/pkg/signal" + "github.com/sirupsen/logrus" +) + +// ProxySignals ... +func ProxySignals(ctr *libpod.Container) { + sigBuffer := make(chan os.Signal, 128) + signal.CatchAll(sigBuffer) + + logrus.Debugf("Enabling signal proxying") + + go func() { + for s := range sigBuffer { + // Ignore SIGCHLD and SIGPIPE - these are mostly likely + // intended for the podman command itself. + if s == signal.SIGCHLD || s == signal.SIGPIPE { + continue + } + + if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil { + logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err) + signal.StopCatch(sigBuffer) + syscall.Kill(syscall.Getpid(), s.(syscall.Signal)) + } + } + }() + + return +} diff --git a/pkg/adapter/terminal.go b/pkg/adapter/terminal.go new file mode 100644 index 000000000..0b608decf --- /dev/null +++ b/pkg/adapter/terminal.go @@ -0,0 +1,159 @@ +package adapter + +import ( + "context" + "fmt" + "os" + gosignal "os/signal" + + "github.com/containers/libpod/libpod" + "github.com/docker/docker/pkg/signal" + "github.com/docker/docker/pkg/term" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/crypto/ssh/terminal" + "k8s.io/client-go/tools/remotecommand" +) + +// RawTtyFormatter ... +type RawTtyFormatter struct { +} + +// StartAttachCtr starts and (if required) attaches to a container +func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error { + resize := make(chan remotecommand.TerminalSize) + + haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) + + // Check if we are attached to a terminal. If we are, generate resize + // events, and set the terminal to raw mode + if haveTerminal && ctr.Spec().Process.Terminal { + logrus.Debugf("Handling terminal attach") + + subCtx, cancel := context.WithCancel(ctx) + defer cancel() + + resizeTty(subCtx, resize) + + oldTermState, err := term.SaveState(os.Stdin.Fd()) + if err != nil { + return errors.Wrapf(err, "unable to save terminal state") + } + + logrus.SetFormatter(&RawTtyFormatter{}) + term.SetRawTerminal(os.Stdin.Fd()) + + defer restoreTerminal(oldTermState) + } + + streams := new(libpod.AttachStreams) + streams.OutputStream = stdout + streams.ErrorStream = stderr + streams.InputStream = stdin + streams.AttachOutput = true + streams.AttachError = true + streams.AttachInput = true + + if stdout == nil { + logrus.Debugf("Not attaching to stdout") + streams.AttachOutput = false + } + if stderr == nil { + logrus.Debugf("Not attaching to stderr") + streams.AttachError = false + } + if stdin == nil { + logrus.Debugf("Not attaching to stdin") + streams.AttachInput = false + } + + if !startContainer { + if sigProxy { + ProxySignals(ctr) + } + + return ctr.Attach(streams, detachKeys, resize) + } + + attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, recursive) + if err != nil { + return err + } + + if sigProxy { + ProxySignals(ctr) + } + + if stdout == nil && stderr == nil { + fmt.Printf("%s\n", ctr.ID()) + } + + err = <-attachChan + if err != nil { + return errors.Wrapf(err, "error attaching to container %s", ctr.ID()) + } + + return nil +} + +// getResize returns a TerminalSize command matching stdin's current +// size on success, and nil on errors. +func getResize() *remotecommand.TerminalSize { + winsize, err := term.GetWinsize(os.Stdin.Fd()) + if err != nil { + logrus.Warnf("Could not get terminal size %v", err) + return nil + } + return &remotecommand.TerminalSize{ + Width: winsize.Width, + Height: winsize.Height, + } +} + +// Helper for prepareAttach - set up a goroutine to generate terminal resize events +func resizeTty(ctx context.Context, resize chan remotecommand.TerminalSize) { + sigchan := make(chan os.Signal, 1) + gosignal.Notify(sigchan, signal.SIGWINCH) + go func() { + defer close(resize) + // Update the terminal size immediately without waiting + // for a SIGWINCH to get the correct initial size. + resizeEvent := getResize() + for { + if resizeEvent == nil { + select { + case <-ctx.Done(): + return + case <-sigchan: + resizeEvent = getResize() + } + } else { + select { + case <-ctx.Done(): + return + case <-sigchan: + resizeEvent = getResize() + case resize <- *resizeEvent: + resizeEvent = nil + } + } + } + }() +} + +func restoreTerminal(state *term.State) error { + logrus.SetFormatter(&logrus.TextFormatter{}) + return term.RestoreTerminal(os.Stdin.Fd(), state) +} + +// Format ... +func (f *RawTtyFormatter) Format(entry *logrus.Entry) ([]byte, error) { + textFormatter := logrus.TextFormatter{} + bytes, err := textFormatter.Format(entry) + + if err == nil { + bytes = append(bytes, '\r') + } + + return bytes, err +} diff --git a/pkg/registrar/registrar_test.go b/pkg/registrar/registrar_test.go index 0c1ef312a..50af95915 100644 --- a/pkg/registrar/registrar_test.go +++ b/pkg/registrar/registrar_test.go @@ -1,119 +1,213 @@ -package registrar +package registrar_test import ( - "reflect" "testing" -) - -func TestReserve(t *testing.T) { - r := NewRegistrar() - - obj := "test1" - if err := r.Reserve("test", obj); err != nil { - t.Fatal(err) - } - - if err := r.Reserve("test", obj); err != nil { - t.Fatal(err) - } - - obj2 := "test2" - err := r.Reserve("test", obj2) - if err == nil { - t.Fatalf("expected error when reserving an already reserved name to another object") - } - if err != ErrNameReserved { - t.Fatal("expected `ErrNameReserved` error when attempting to reserve an already reserved name") - } -} - -func TestRelease(t *testing.T) { - r := NewRegistrar() - obj := "testing" - - if err := r.Reserve("test", obj); err != nil { - t.Fatal(err) - } - r.Release("test") - r.Release("test") // Ensure there is no panic here - if err := r.Reserve("test", obj); err != nil { - t.Fatal(err) - } -} - -func TestGetNames(t *testing.T) { - r := NewRegistrar() - obj := "testing" - names := []string{"test1", "test2"} - - for _, name := range names { - if err := r.Reserve(name, obj); err != nil { - t.Fatal(err) - } - } - r.Reserve("test3", "other") - - names2, err := r.GetNames(obj) - if err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(names, names2) { - t.Fatalf("Exepected: %v, Got: %v", names, names2) - } -} + "github.com/containers/libpod/pkg/registrar" + . "github.com/containers/libpod/test/framework" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) -func TestDelete(t *testing.T) { - r := NewRegistrar() - obj := "testing" - names := []string{"test1", "test2"} - for _, name := range names { - if err := r.Reserve(name, obj); err != nil { - t.Fatal(err) - } - } - - r.Reserve("test3", "other") - r.Delete(obj) - - _, err := r.GetNames(obj) - if err == nil { - t.Fatal("expected error getting names for deleted key") - } - - if err != ErrNoSuchKey { - t.Fatal("expected `ErrNoSuchKey`") - } +// TestRegistrar runs the created specs +func TestRegistrar(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Registrar") } -func TestGet(t *testing.T) { - r := NewRegistrar() - obj := "testing" - name := "test" - - _, err := r.Get(name) - if err == nil { - t.Fatal("expected error when key does not exist") - } - if err != ErrNameNotReserved { - t.Fatal(err) - } - - if err := r.Reserve(name, obj); err != nil { - t.Fatal(err) - } - - if _, err = r.Get(name); err != nil { - t.Fatal(err) - } - - r.Delete(obj) - _, err = r.Get(name) - if err == nil { - t.Fatal("expected error when key does not exist") - } - if err != ErrNameNotReserved { - t.Fatal(err) - } -} +// nolint: gochecknoglobals +var t *TestFramework + +var _ = BeforeSuite(func() { + t = NewTestFramework(NilFunc, NilFunc) + t.Setup() +}) + +var _ = AfterSuite(func() { + t.Teardown() +}) + +// The actual test suite +var _ = t.Describe("Registrar", func() { + // Constant test data needed by some tests + const ( + testKey = "testKey" + testName = "testName" + anotherKey = "anotherKey" + ) + + // The system under test + var sut *registrar.Registrar + + // Prepare the system under test and register a test name and key before + // each test + BeforeEach(func() { + sut = registrar.NewRegistrar() + Expect(sut.Reserve(testName, testKey)).To(BeNil()) + }) + + t.Describe("Reserve", func() { + It("should succeed to reserve a new registrar", func() { + // Given + // When + err := sut.Reserve("name", "key") + + // Then + Expect(err).To(BeNil()) + }) + + It("should succeed to reserve a registrar twice", func() { + // Given + // When + err := sut.Reserve(testName, testKey) + + // Then + Expect(err).To(BeNil()) + }) + + It("should fail to reserve an already reserved registrar", func() { + // Given + // When + err := sut.Reserve(testName, anotherKey) + + // Then + Expect(err).NotTo(BeNil()) + Expect(err).To(Equal(registrar.ErrNameReserved)) + }) + }) + + t.Describe("Release", func() { + It("should succeed to release a registered registrar multiple times", func() { + // Given + // When + // Then + sut.Release(testName) + sut.Release(testName) + }) + + It("should succeed to release a unknown registrar multiple times", func() { + // Given + // When + // Then + sut.Release(anotherKey) + sut.Release(anotherKey) + }) + + It("should succeed to release and re-register a registrar", func() { + // Given + // When + sut.Release(testName) + err := sut.Reserve(testName, testKey) + + // Then + Expect(err).To(BeNil()) + }) + }) + + t.Describe("GetNames", func() { + It("should succeed to retrieve a single name for a registrar", func() { + // Given + // When + names, err := sut.GetNames(testKey) + + // Then + Expect(err).To(BeNil()) + Expect(len(names)).To(Equal(1)) + Expect(names[0]).To(Equal(testName)) + }) + + It("should succeed to retrieve all names for a registrar", func() { + // Given + testNames := []string{"test1", "test2"} + for _, name := range testNames { + Expect(sut.Reserve(name, anotherKey)).To(BeNil()) + } + + // When + names, err := sut.GetNames(anotherKey) + + // Then + Expect(err).To(BeNil()) + Expect(len(names)).To(Equal(2)) + Expect(names).To(Equal(testNames)) + }) + }) + + t.Describe("GetNames", func() { + It("should succeed to retrieve a single name for a registrar", func() { + // Given + // When + names, err := sut.GetNames(testKey) + + // Then + Expect(err).To(BeNil()) + Expect(len(names)).To(Equal(1)) + Expect(names[0]).To(Equal(testName)) + }) + + It("should succeed to retrieve all names for a registrar", func() { + // Given + anotherKey := "anotherKey" + testNames := []string{"test1", "test2"} + for _, name := range testNames { + Expect(sut.Reserve(name, anotherKey)).To(BeNil()) + } + + // When + names, err := sut.GetNames(anotherKey) + + // Then + Expect(err).To(BeNil()) + Expect(len(names)).To(Equal(2)) + Expect(names).To(Equal(testNames)) + }) + }) + + t.Describe("Delete", func() { + It("should succeed to delete a registrar", func() { + // Given + // When + sut.Delete(testKey) + + // Then + names, err := sut.GetNames(testKey) + Expect(len(names)).To(BeZero()) + Expect(err).To(Equal(registrar.ErrNoSuchKey)) + }) + }) + + t.Describe("Get", func() { + It("should succeed to get a key for a registrar", func() { + // Given + // When + key, err := sut.Get(testName) + + // Then + Expect(err).To(BeNil()) + Expect(key).To(Equal(testKey)) + }) + + It("should fail to get a key for a not existing registrar", func() { + // Given + // When + key, err := sut.Get("notExistingName") + + // Then + Expect(key).To(BeEmpty()) + Expect(err).To(Equal(registrar.ErrNameNotReserved)) + }) + }) + + t.Describe("GetAll", func() { + It("should succeed to get all names", func() { + // Given + // When + names := sut.GetAll() + + // Then + Expect(len(names)).To(Equal(1)) + Expect(len(names[testKey])).To(Equal(1)) + Expect(names[testKey][0]).To(Equal(testName)) + }) + }) +}) diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go index f557d04e5..e75170547 100644 --- a/pkg/varlinkapi/config.go +++ b/pkg/varlinkapi/config.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index 7a6ae3507..ac1352dac 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( @@ -583,27 +585,6 @@ func (i *LibpodAPI) GetContainerStatsWithHistory(call iopodman.VarlinkCall, prev return call.ReplyGetContainerStatsWithHistory(cStats) } -// ContainerStatsToLibpodContainerStats converts the varlink containerstats to a libpod -// container stats -func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) libpod.ContainerStats { - cstats := libpod.ContainerStats{ - ContainerID: stats.Id, - Name: stats.Name, - CPU: stats.Cpu, - CPUNano: uint64(stats.Cpu_nano), - SystemNano: uint64(stats.System_nano), - MemUsage: uint64(stats.Mem_usage), - MemLimit: uint64(stats.Mem_limit), - MemPerc: stats.Mem_perc, - NetInput: uint64(stats.Net_input), - NetOutput: uint64(stats.Net_output), - BlockInput: uint64(stats.Block_input), - BlockOutput: uint64(stats.Block_output), - PIDs: uint64(stats.Pids), - } - return cstats -} - // GetContainersLogs is the varlink endpoint to obtain one or more container logs func (i *LibpodAPI) GetContainersLogs(call iopodman.VarlinkCall, names []string, follow, latest bool, since string, tail int64, timestamps bool) error { var wg sync.WaitGroup diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go index 8990ac001..6b23dce5e 100644 --- a/pkg/varlinkapi/containers_create.go +++ b/pkg/varlinkapi/containers_create.go @@ -1,220 +1,18 @@ +// +build varlink + package varlinkapi import ( - "context" - "encoding/json" - "fmt" - "os" - "strings" - "syscall" - + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/varlink" - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/inspect" - "github.com/containers/libpod/pkg/namespaces" - "github.com/containers/libpod/pkg/rootless" - cc "github.com/containers/libpod/pkg/spec" - "github.com/containers/libpod/pkg/util" - "github.com/docker/docker/pkg/signal" - "github.com/sirupsen/logrus" ) // CreateContainer ... func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.Create) error { - rtc, err := i.Runtime.GetConfig() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - ctx := getContext() - - newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - data, err := newImage.Inspect(ctx) - - createConfig, err := varlinkCreateToCreateConfig(ctx, config, i.Runtime, config.Image, data) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) + generic := shared.VarlinkCreateToGeneric(config) + ctr, _, err := shared.CreateContainer(getContext(), &generic, i.Runtime) if err != nil { return call.ReplyErrorOccurred(err.Error()) } - - // TODO fix when doing remote client and dealing with the ability to create a container - // within a non-existing pod (i.e. --pod new:foobar) - options, err := createConfig.GetContainerCreateOptions(i.Runtime, nil) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - ctr, err := i.Runtime.NewContainer(ctx, runtimeSpec, options...) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - createConfigJSON, err := json.Marshal(createConfig) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - logrus.Debug("new container created ", ctr.ID()) - return call.ReplyCreateContainer(ctr.ID()) } - -// varlinkCreateToCreateConfig takes the varlink input struct and maps it to a pointer -// of a CreateConfig, which eventually can be used to create the OCI spec. -func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) { - idmappings, err := util.ParseIDMapping(create.Uidmap, create.Gidmap, create.Subuidname, create.Subgidname) - if err != nil { - return nil, err - } - inputCommand := create.Command - entrypoint := create.Entrypoint - - // ENTRYPOINT - // User input entrypoint takes priority over image entrypoint - if len(entrypoint) == 0 { - entrypoint = data.Config.Entrypoint - } - // if entrypoint=, we need to clear the entrypoint - if len(entrypoint) == 1 && strings.Join(create.Entrypoint, "") == "" { - entrypoint = []string{} - } - // Build the command - // If we have an entry point, it goes first - command := entrypoint - if len(inputCommand) > 0 { - // User command overrides data CMD - command = append(command, inputCommand...) - } else if len(data.Config.Cmd) > 0 && len(command) == 0 { - // If not user command, add CMD - command = append(command, data.Config.Cmd...) - } - - stopSignal := syscall.SIGTERM - if create.Stop_signal > 0 { - stopSignal, err = signal.ParseSignal(fmt.Sprintf("%d", create.Stop_signal)) - if err != nil { - return nil, err - } - } - - user := create.User - if user == "" { - user = data.Config.User - } - - // EXPOSED PORTS - portBindings, err := cc.ExposedPorts(create.Exposed_ports, create.Publish, create.Publish_all, data.Config.ExposedPorts) - if err != nil { - return nil, err - } - - // NETWORK MODE - networkMode := create.Net_mode - if networkMode == "" { - if rootless.IsRootless() { - networkMode = "slirp4netns" - } else { - networkMode = "bridge" - } - } - - // WORKING DIR - workDir := create.Work_dir - if workDir == "" { - workDir = "/" - } - - imageID := data.ID - var ImageVolumes map[string]struct{} - if data != nil && create.Image_volume_type != "ignore" { - ImageVolumes = data.Config.Volumes - } - - config := &cc.CreateConfig{ - Runtime: runtime, - BuiltinImgVolumes: ImageVolumes, - ConmonPidFile: create.Conmon_pidfile, - ImageVolumeType: create.Image_volume_type, - CapAdd: create.Cap_add, - CapDrop: create.Cap_drop, - CgroupParent: create.Cgroup_parent, - Command: command, - Detach: create.Detach, - Devices: create.Devices, - DNSOpt: create.Dns_opt, - DNSSearch: create.Dns_search, - DNSServers: create.Dns_servers, - Entrypoint: create.Entrypoint, - Env: create.Env, - GroupAdd: create.Group_add, - Hostname: create.Hostname, - HostAdd: create.Host_add, - IDMappings: idmappings, - Image: imageName, - ImageID: imageID, - Interactive: create.Interactive, - Labels: create.Labels, - LogDriver: create.Log_driver, - LogDriverOpt: create.Log_driver_opt, - Name: create.Name, - Network: networkMode, - IpcMode: namespaces.IpcMode(create.Ipc_mode), - NetMode: namespaces.NetworkMode(networkMode), - UtsMode: namespaces.UTSMode(create.Uts_mode), - PidMode: namespaces.PidMode(create.Pid_mode), - Pod: create.Pod, - Privileged: create.Privileged, - Publish: create.Publish, - PublishAll: create.Publish_all, - PortBindings: portBindings, - Quiet: create.Quiet, - ReadOnlyRootfs: create.Readonly_rootfs, - Resources: cc.CreateResourceConfig{ - BlkioWeight: uint16(create.Resources.Blkio_weight), - BlkioWeightDevice: create.Resources.Blkio_weight_device, - CPUShares: uint64(create.Resources.Cpu_shares), - CPUPeriod: uint64(create.Resources.Cpu_period), - CPUsetCPUs: create.Resources.Cpuset_cpus, - CPUsetMems: create.Resources.Cpuset_mems, - CPUQuota: create.Resources.Cpu_quota, - CPURtPeriod: uint64(create.Resources.Cpu_rt_period), - CPURtRuntime: create.Resources.Cpu_rt_runtime, - CPUs: create.Resources.Cpus, - DeviceReadBps: create.Resources.Device_read_bps, - DeviceReadIOps: create.Resources.Device_write_bps, - DeviceWriteBps: create.Resources.Device_read_iops, - DeviceWriteIOps: create.Resources.Device_write_iops, - DisableOomKiller: create.Resources.Disable_oomkiller, - ShmSize: create.Resources.Shm_size, - Memory: create.Resources.Memory, - MemoryReservation: create.Resources.Memory_reservation, - MemorySwap: create.Resources.Memory_swap, - MemorySwappiness: int(create.Resources.Memory_swappiness), - KernelMemory: create.Resources.Kernel_memory, - OomScoreAdj: int(create.Resources.Oom_score_adj), - PidsLimit: create.Resources.Pids_limit, - Ulimit: create.Resources.Ulimit, - }, - Rm: create.Rm, - StopSignal: stopSignal, - StopTimeout: uint(create.Stop_timeout), - Sysctl: create.Sys_ctl, - Tmpfs: create.Tmpfs, - Tty: create.Tty, - User: user, - UsernsMode: namespaces.UsernsMode(create.Userns_mode), - Volumes: create.Volumes, - WorkDir: workDir, - } - - return config, nil -} diff --git a/pkg/varlinkapi/events.go b/pkg/varlinkapi/events.go index 47c628ead..1e5696fbe 100644 --- a/pkg/varlinkapi/events.go +++ b/pkg/varlinkapi/events.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 2e72ec65b..470eadaeb 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/mount.go b/pkg/varlinkapi/mount.go index 3b4fe87e3..63ce44291 100644 --- a/pkg/varlinkapi/mount.go +++ b/pkg/varlinkapi/mount.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go index c79cee4c2..ac8e24747 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/remote_client.go b/pkg/varlinkapi/remote_client.go new file mode 100644 index 000000000..dd0613494 --- /dev/null +++ b/pkg/varlinkapi/remote_client.go @@ -0,0 +1,29 @@ +// +build varlink remoteclient + +package varlinkapi + +import ( + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod" +) + +// ContainerStatsToLibpodContainerStats converts the varlink containerstats to a libpod +// container stats +func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) libpod.ContainerStats { + cstats := libpod.ContainerStats{ + ContainerID: stats.Id, + Name: stats.Name, + CPU: stats.Cpu, + CPUNano: uint64(stats.Cpu_nano), + SystemNano: uint64(stats.System_nano), + MemUsage: uint64(stats.Mem_usage), + MemLimit: uint64(stats.Mem_limit), + MemPerc: stats.Mem_perc, + NetInput: uint64(stats.Net_input), + NetOutput: uint64(stats.Net_output), + BlockInput: uint64(stats.Block_input), + BlockOutput: uint64(stats.Block_output), + PIDs: uint64(stats.Pids), + } + return cstats +} diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go index 816143e9f..7f436a954 100644 --- a/pkg/varlinkapi/system.go +++ b/pkg/varlinkapi/system.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go index 9a97bc810..96f76bcdc 100644 --- a/pkg/varlinkapi/transfers.go +++ b/pkg/varlinkapi/transfers.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go index 7e487c03a..3c4b9b79a 100644 --- a/pkg/varlinkapi/util.go +++ b/pkg/varlinkapi/util.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go index 02874d2b1..19ba38e7c 100644 --- a/pkg/varlinkapi/volumes.go +++ b/pkg/varlinkapi/volumes.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( |