mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-10-23 15:02:50 +00:00
* bump containerd-dev to 2.0.2 Signed-off-by: Avi Deitcher <avi@deitcher.net> * update pkg/init libs to containerd-20 Signed-off-by: Avi Deitcher <avi@deitcher.net> * bump linuxkit CLI containerd deps to 20 Signed-off-by: Avi Deitcher <avi@deitcher.net> * update test/pkg/containerd to work with containerd v2.x tests Signed-off-by: Avi Deitcher <avi@deitcher.net> * update containerd-dev deps Signed-off-by: Avi Deitcher <avi@deitcher.net> * update pkg/init and pkg/containerd dependencies Signed-off-by: Avi Deitcher <avi@deitcher.net> * update test/pkg/containerd deps Signed-off-by: Avi Deitcher <avi@deitcher.net> --------- Signed-off-by: Avi Deitcher <avi@deitcher.net>
232 lines
5.2 KiB
Go
232 lines
5.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/containerd/containerd/v2/client"
|
|
"github.com/containerd/containerd/v2/pkg/cio"
|
|
"github.com/containerd/containerd/v2/pkg/namespaces"
|
|
"github.com/opencontainers/runtime-spec/specs-go"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func parseCmd(ctx context.Context, command string, args []string) (*log.Entry, string, string, string, string) {
|
|
invoked := filepath.Base(os.Args[0])
|
|
flags := flag.NewFlagSet(command, flag.ExitOnError)
|
|
flags.Usage = func() {
|
|
fmt.Printf("USAGE: %s %s [service]\n\n", invoked, command)
|
|
fmt.Printf("Options:\n")
|
|
flags.PrintDefaults()
|
|
}
|
|
|
|
sock := flags.String("sock", defaultSocket, "Path to containerd socket")
|
|
path := flags.String("path", defaultServicesPath, "Path to service configs")
|
|
|
|
dumpSpec := flags.String("dump-spec", "", "Dump container spec to file before start")
|
|
|
|
if err := flags.Parse(args); err != nil {
|
|
log.Fatal("Unable to parse args")
|
|
}
|
|
args = flags.Args()
|
|
|
|
if len(args) != 1 {
|
|
fmt.Println("Please specify the service")
|
|
flags.Usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
service := args[0]
|
|
|
|
log := log.WithFields(log.Fields{
|
|
"service": service,
|
|
})
|
|
|
|
return log, service, *sock, *path, *dumpSpec
|
|
}
|
|
|
|
func stopCmd(ctx context.Context, args []string) {
|
|
log, service, sock, path, _ := parseCmd(ctx, "stop", args)
|
|
|
|
log.Infof("Stopping service: %q", service)
|
|
id, pid, msg, err := stop(ctx, service, sock, path)
|
|
if err != nil {
|
|
log.WithError(err).Fatal(msg)
|
|
}
|
|
|
|
log.Debugf("Stopped %s pid %d", id, pid)
|
|
}
|
|
|
|
func startCmd(ctx context.Context, args []string) {
|
|
log, service, sock, path, dumpSpec := parseCmd(ctx, "start", args)
|
|
|
|
log.Infof("Starting service: %q", service)
|
|
id, pid, msg, err := start(ctx, service, sock, path, dumpSpec)
|
|
if err != nil {
|
|
log.WithError(err).Fatal(msg)
|
|
}
|
|
|
|
log.Debugf("Started %s pid %d", id, pid)
|
|
}
|
|
|
|
func restartCmd(ctx context.Context, args []string) {
|
|
// validate arguments with the command as "restart"
|
|
parseCmd(ctx, "restart", args)
|
|
|
|
stopCmd(ctx, args)
|
|
startCmd(ctx, args)
|
|
}
|
|
|
|
type logio struct {
|
|
config cio.Config
|
|
}
|
|
|
|
func (c *logio) Config() cio.Config {
|
|
return c.config
|
|
}
|
|
|
|
func (c *logio) Cancel() {
|
|
}
|
|
|
|
func (c *logio) Wait() {
|
|
}
|
|
|
|
func (c *logio) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func stop(ctx context.Context, service, sock, basePath string) (string, uint32, string, error) {
|
|
path := filepath.Join(basePath, service)
|
|
|
|
runtimeConfig := getRuntimeConfig(path)
|
|
|
|
cli, err := client.New(sock)
|
|
if err != nil {
|
|
return "", 0, "creating containerd client", err
|
|
}
|
|
|
|
if runtimeConfig.Namespace != "" {
|
|
ctx = namespaces.WithNamespace(ctx, runtimeConfig.Namespace)
|
|
}
|
|
|
|
ctr, err := cli.LoadContainer(ctx, service)
|
|
if err != nil {
|
|
return "", 0, "loading container", err
|
|
}
|
|
|
|
task, err := ctr.Task(ctx, nil)
|
|
if err != nil {
|
|
return "", 0, "fetching task", err
|
|
}
|
|
|
|
id := ctr.ID()
|
|
pid := task.Pid()
|
|
|
|
err = task.Kill(ctx, 9)
|
|
if err != nil {
|
|
return "", 0, "killing task", err
|
|
}
|
|
|
|
_, err = task.Wait(ctx)
|
|
if err != nil {
|
|
return "", 0, "waiting for task to exit", err
|
|
}
|
|
|
|
_, err = task.Delete(ctx)
|
|
if err != nil {
|
|
return "", 0, "deleting task", err
|
|
}
|
|
|
|
err = ctr.Delete(ctx)
|
|
if err != nil {
|
|
return "", 0, "deleting container", err
|
|
}
|
|
|
|
return id, pid, "", nil
|
|
}
|
|
|
|
func start(ctx context.Context, service, sock, basePath, dumpSpec string) (string, uint32, string, error) {
|
|
path := filepath.Join(basePath, service)
|
|
|
|
runtimeConfig := getRuntimeConfig(path)
|
|
|
|
rootfs := filepath.Join(path, "rootfs")
|
|
|
|
if err := prepareFilesystem(path, runtimeConfig); err != nil {
|
|
return "", 0, "preparing filesystem", err
|
|
}
|
|
|
|
cli, err := client.New(sock)
|
|
if err != nil {
|
|
return "", 0, "creating containerd client", err
|
|
}
|
|
|
|
var spec *specs.Spec
|
|
specf, err := os.Open(filepath.Join(path, "config.json"))
|
|
if err != nil {
|
|
return "", 0, "failed to read service spec", err
|
|
}
|
|
if err := json.NewDecoder(specf).Decode(&spec); err != nil {
|
|
return "", 0, "failed to parse service spec", err
|
|
}
|
|
|
|
spec.Root.Path = rootfs
|
|
|
|
if dumpSpec != "" {
|
|
d, err := os.Create(dumpSpec)
|
|
if err != nil {
|
|
return "", 0, "failed to open file for spec dump", err
|
|
}
|
|
enc := json.NewEncoder(d)
|
|
enc.SetIndent("", " ")
|
|
if err := enc.Encode(&spec); err != nil {
|
|
return "", 0, "failed to write spec dump", err
|
|
}
|
|
|
|
}
|
|
|
|
if runtimeConfig.Namespace != "" {
|
|
ctx = namespaces.WithNamespace(ctx, runtimeConfig.Namespace)
|
|
}
|
|
|
|
ctr, err := cli.NewContainer(ctx, service, client.WithSpec(spec))
|
|
if err != nil {
|
|
return "", 0, "failed to create container", err
|
|
}
|
|
|
|
logger := GetLog(varLogDir)
|
|
|
|
io := func(id string) (cio.IO, error) {
|
|
stdoutFile := logger.Path(service + ".out")
|
|
stderrFile := logger.Path(service)
|
|
return &logio{
|
|
cio.Config{
|
|
Stdin: "/dev/null",
|
|
Stdout: stdoutFile,
|
|
Stderr: stderrFile,
|
|
Terminal: false,
|
|
},
|
|
}, nil
|
|
}
|
|
task, err := ctr.NewTask(ctx, io)
|
|
if err != nil {
|
|
// Don't bother to destroy the container here.
|
|
return "", 0, "failed to create task", err
|
|
}
|
|
|
|
if err := prepareProcess(int(task.Pid()), runtimeConfig); err != nil {
|
|
return "", 0, "preparing process", err
|
|
}
|
|
|
|
if err := task.Start(ctx); err != nil {
|
|
// Don't destroy the container here so it can be inspected for debugging.
|
|
return "", 0, "failed to start task", err
|
|
}
|
|
|
|
return ctr.ID(), task.Pid(), "", nil
|
|
}
|