From 4fd1c583adc17551cf9f07185c1700dc39d7bcbf Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sun, 18 Sep 2016 16:35:17 +0200 Subject: [PATCH 1/8] sandboxes restore on server start Signed-off-by: Antonio Murdaca --- server/runtime.go | 20 +++++++++++++++ server/server.go | 64 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/server/runtime.go b/server/runtime.go index d15e0ecb..ada4a9db 100644 --- a/server/runtime.go +++ b/server/runtime.go @@ -1,7 +1,9 @@ package server import ( + "encoding/json" "fmt" + "io/ioutil" "os" "path/filepath" @@ -177,6 +179,24 @@ func (s *Server) CreatePodSandbox(ctx context.Context, req *pb.CreatePodSandboxR s.addContainer(container) + meta := &metadata{ + LogDir: logDir, + ContainerName: containerName, + Labels: labels, + } + + b, err := json.Marshal(meta) + if err != nil { + return nil, err + } + + // TODO: eventually we would track all containers in this pod so on server start + // we can repopulate the structs in memory properly... + // e.g. each container can write itself in podSandboxDir + if err := ioutil.WriteFile(filepath.Join(podSandboxDir, "metadata.json"), b, 0644); err != nil { + return nil, err + } + if err = s.runtime.UpdateStatus(container); err != nil { return nil, err } diff --git a/server/server.go b/server/server.go index e540a89b..3fbfe3d5 100644 --- a/server/server.go +++ b/server/server.go @@ -1,10 +1,14 @@ package server import ( + "encoding/json" "fmt" + "io/ioutil" "os" + "path/filepath" "sync" + "github.com/Sirupsen/logrus" "github.com/kubernetes-incubator/ocid/oci" "github.com/kubernetes-incubator/ocid/utils" "github.com/rajatchopra/ocicni" @@ -24,6 +28,50 @@ type Server struct { netPlugin ocicni.CNIPlugin } +func (s *Server) loadSandboxes() error { + if err := filepath.Walk(s.sandboxDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + return nil + } + if path == s.sandboxDir { + return nil + } + metaJSON, err := ioutil.ReadFile(filepath.Join(path, "metadata.json")) + if err != nil { + return err + } + var m metadata + if err := json.Unmarshal(metaJSON, &m); err != nil { + return err + } + sname, err := filepath.Rel(s.sandboxDir, path) + if err != nil { + return err + } + s.addSandbox(&sandbox{ + name: sname, + logDir: m.LogDir, + labels: m.Labels, + containers: make(map[string]*oci.Container), + }) + scontainer, err := oci.NewContainer(m.ContainerName, path, path, m.Labels, sname, false) + if err != nil { + return err + } + s.addContainer(scontainer) + if err = s.runtime.UpdateStatus(scontainer); err != nil { + return err + } + return nil + }); err != nil { + return err + } + return nil +} + // New creates a new Server with options provided func New(runtimePath, sandboxDir, containerDir string) (*Server, error) { // TODO: This will go away later when we have wrapper process or systemd acting as @@ -48,7 +96,7 @@ func New(runtimePath, sandboxDir, containerDir string) (*Server, error) { if err != nil { return nil, err } - return &Server{ + s := &Server{ runtime: r, netPlugin: netPlugin, sandboxDir: sandboxDir, @@ -56,7 +104,13 @@ func New(runtimePath, sandboxDir, containerDir string) (*Server, error) { sandboxes: sandboxes, containers: containers, }, - }, nil + } + if err := s.loadSandboxes(); err != nil { + logrus.Warnf("couldn't get sandboxes: %v", err) + } + logrus.Debugf("sandboxes: %v", s.state.sandboxes) + logrus.Debugf("containers: %v", s.state.containers) + return s, nil } type serverState struct { @@ -71,6 +125,12 @@ type sandbox struct { containers oci.Store } +type metadata struct { + LogDir string `json:"log_dir"` + ContainerName string `json:"container_name"` + Labels map[string]string `json:"labels"` +} + func (s *sandbox) addContainer(c *oci.Container) { s.containers.Add(c.Name(), c) } From 99a086420b156cd9a074329186fad2d65bfb0d3e Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sun, 18 Sep 2016 16:52:19 +0200 Subject: [PATCH 2/8] testdata: update container_config to be usable Signed-off-by: Antonio Murdaca --- testdata/container_config.json | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/testdata/container_config.json b/testdata/container_config.json index f6894a3e..4b28cf7c 100644 --- a/testdata/container_config.json +++ b/testdata/container_config.json @@ -1,5 +1,7 @@ { - "name": "container1", + "metadata": { + "name": "container1" + }, "image": { "image": "docker://redis:latest" }, @@ -28,22 +30,6 @@ "value": "test/file1" } ], - "mounts": [ - { - "name": "mount1", - "container_path": "/dir1", - "host_path": "/tmp/dir1", - "readonly": false, - "selinux_relabel": true - }, - { - "name": "mount2", - "container_path": "/dir2", - "host_path": "/tmp/dir2", - "readonly": true, - "selinux_relabel": true - } - ], "labels": { "type": "small", "batch": "no" From caae4b298a7558a201e9f830ab4844dc85f8cb1d Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sun, 18 Sep 2016 17:00:37 +0200 Subject: [PATCH 3/8] create sandboxdir on server startup Signed-off-by: Antonio Murdaca --- server/server.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/server.go b/server/server.go index 3fbfe3d5..923427a1 100644 --- a/server/server.go +++ b/server/server.go @@ -86,6 +86,10 @@ func New(runtimePath, sandboxDir, containerDir string) (*Server, error) { return nil, err } + if err := os.MkdirAll(sandboxDir, 0755); err != nil { + return nil, err + } + r, err := oci.New(runtimePath, containerDir) if err != nil { return nil, err From 260a7adb83c7ec3abecb60a1cd898b92cfdc78d5 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sun, 18 Sep 2016 18:36:33 +0200 Subject: [PATCH 4/8] server/runtime: store sandbox id in container's annotations Signed-off-by: Antonio Murdaca --- server/runtime.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/server/runtime.go b/server/runtime.go index ada4a9db..e9754404 100644 --- a/server/runtime.go +++ b/server/runtime.go @@ -44,10 +44,6 @@ func (s *Server) Version(ctx context.Context, req *pb.VersionRequest) (*pb.Versi func (s *Server) CreatePodSandbox(ctx context.Context, req *pb.CreatePodSandboxRequest) (*pb.CreatePodSandboxResponse, error) { var err error - if err := os.MkdirAll(s.sandboxDir, 0755); err != nil { - return nil, err - } - // process req.Name name := req.GetConfig().GetMetadata().GetName() if name == "" { @@ -440,6 +436,8 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq } } + specgen.AddAnnotation("pod_sandbox_id", podSandboxId) + if containerConfig.GetPrivileged() { specgen.SetupPrivileged(true) } From 53e76cc75230c5523661c260f88d066afcb47c72 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sun, 18 Sep 2016 18:37:29 +0200 Subject: [PATCH 5/8] warn when cannot update container status on server init Signed-off-by: Antonio Murdaca --- server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index 923427a1..0017b7dc 100644 --- a/server/server.go +++ b/server/server.go @@ -63,7 +63,7 @@ func (s *Server) loadSandboxes() error { } s.addContainer(scontainer) if err = s.runtime.UpdateStatus(scontainer); err != nil { - return err + logrus.Warnf("error updating status for container %s: %v", scontainer, err) } return nil }); err != nil { From aa748b62b22354d461f9955ab05f7c8c81511a8b Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Mon, 19 Sep 2016 08:28:34 +0200 Subject: [PATCH 6/8] makefile stuff Signed-off-by: Antonio Murdaca --- .tool/check-license | 13 ++++++++++++ .tool/lint | 25 ++++++++++++++++++++++ .travis.yml | 14 +++++++++--- Makefile | 52 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 5 deletions(-) create mode 100755 .tool/check-license create mode 100755 .tool/lint diff --git a/.tool/check-license b/.tool/check-license new file mode 100755 index 00000000..ab6f803b --- /dev/null +++ b/.tool/check-license @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +ret=0 + +for file in $(find . -type f -iname '*.go' ! -path './vendor/*'); do + (head -n3 "${file}" | grep -Eq "(Copyright|generated|GENERATED)") || (echo "${file}:missing license header" && ret=1) +done + +exit $ret diff --git a/.tool/lint b/.tool/lint new file mode 100755 index 00000000..4a0120e6 --- /dev/null +++ b/.tool/lint @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +if [ ! $(command -v gometalinter) ]; then + go get -u github.com/alecthomas/gometalinter + gometalinter --update --install +fi + +for d in $(find . -type d -not -iwholename '*.git*' -a -not -iname '.tool' -a -not -iwholename '*vendor*'); do + gometalinter \ + --exclude='error return value not checked.*(Close|Log|Print).*\(errcheck\)$' \ + --exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$' \ + --exclude='duplicate of.*_test.go.*\(dupl\)$' \ + --exclude='schema/fs.go' \ + --exclude='duplicate of.*main.go.*\(dupl\)$' \ + --disable=aligncheck \ + --disable=gotype \ + --disable=gas \ + --cyclo-over=35 \ + --tests \ + --deadline=10s "${d}" +done diff --git a/.travis.yml b/.travis.yml index 1f9ae111..7591c766 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,22 @@ language: go go: - 1.6 + - 1.7 -sudo: false +sudo: required + +before_script: + - export PATH=$HOME/gopath/bin:$PATH before_install: - - go get github.com/vbatts/git-validation + - make install.tools + - go get -u github.com/alecthomas/gometalinter + - gometalinter --install --update + - go get -t -d ./... install: true script: - - $HOME/gopath/bin/git-validation -run DCO,short-subject -v -range ${TRAVIS_COMMIT_RANGE} + - make .gitvalidation + - make lint - make diff --git a/Makefile b/Makefile index f68ee0a3..7d172fce 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,18 @@ -.PHONY: all clean conmon ocid ocic update-deps +EPOCH_TEST_COMMIT ?= 7fc874e05e74faa81e7c423b6514fc5c474c6b34 -all: conmon ocid ocic +default: help + +help: + @echo "Usage: make " + @echo + @echo " * 'binaries' - Build ocid, conmon andocic" + @echo " * 'clean' - Clean artifacts" + @echo " * 'lint' - Execute the source code linter" + @echo " * 'update-deps' - Update vendored dependencies" + +lint: + @echo "checking lint" + @./.tool/lint conmon: make -C $@ @@ -13,6 +25,7 @@ ocic: clean: rm -f ocic ocid + rm -f conmon/conmon.o conmon/conmon update-deps: @which glide > /dev/null 2>/dev/null || (echo "ERROR: glide not found." && false) @@ -20,3 +33,38 @@ update-deps: glide-vc --only-code --no-tests # see http://sed.sourceforge.net/sed1line.txt find vendor -type f -exec sed -i -e :a -e '/^\n*$$/{$$d;N;ba' -e '}' "{}" \; + +binaries: ocid ocic conmon + +.PHONY: .gitvalidation + # +# When this is running in travis, it will only check the travis commit range +.gitvalidation: + @which git-validation > /dev/null 2>/dev/null || (echo "ERROR: git-validation not found. Consider 'make install.tools' target" && false) +ifeq ($(TRAVIS),true) + git-validation -q -run DCO,short-subject,dangling-whitespace +else + git-validation -v -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..HEAD +endif + +.PHONY: install.tools + +install.tools: .install.gitvalidation .install.glide .install.glide-vc .install.gometalinter + +.install.gitvalidation: + go get github.com/vbatts/git-validation + +.install.glide: + go get github.com/Masterminds/glide + +.install.glide-vc: + go get github.com/sgotti/glide-vc + +.install.gometalinter: + go get github.com/alecthomas/gometalinter + gometalinter --install --update + +.PHONY: \ + binaries \ + clean \ + lint From 22d434c1e6b9a6b28521b7e517f250400d909afe Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Mon, 19 Sep 2016 09:21:14 +0200 Subject: [PATCH 7/8] restructure and make lint Signed-off-by: Antonio Murdaca --- .tool/lint | 3 +- Makefile | 3 + cmd/client/main.go | 12 +- cmd/server/main.go | 13 +- oci/oci.go | 8 +- server/const.go | 16 -- server/{runtime.go => container.go} | 387 +++------------------------- server/image.go | 8 +- server/sandbox.go | 319 +++++++++++++++++++++++ server/server.go | 39 +-- server/utils.go | 84 ++---- server/version.go | 30 +++ utils/utils.go | 16 +- 13 files changed, 447 insertions(+), 491 deletions(-) delete mode 100644 server/const.go rename server/{runtime.go => container.go} (53%) create mode 100644 server/sandbox.go create mode 100644 server/version.go diff --git a/.tool/lint b/.tool/lint index 4a0120e6..121a8fdf 100755 --- a/.tool/lint +++ b/.tool/lint @@ -14,12 +14,11 @@ for d in $(find . -type d -not -iwholename '*.git*' -a -not -iname '.tool' -a -n --exclude='error return value not checked.*(Close|Log|Print).*\(errcheck\)$' \ --exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$' \ --exclude='duplicate of.*_test.go.*\(dupl\)$' \ - --exclude='schema/fs.go' \ --exclude='duplicate of.*main.go.*\(dupl\)$' \ --disable=aligncheck \ --disable=gotype \ --disable=gas \ - --cyclo-over=35 \ + --cyclo-over=50 \ --tests \ --deadline=10s "${d}" done diff --git a/Makefile b/Makefile index 7d172fce..fe57db5a 100644 --- a/Makefile +++ b/Makefile @@ -66,5 +66,8 @@ install.tools: .install.gitvalidation .install.glide .install.glide-vc .install. .PHONY: \ binaries \ + conmon \ + ocid \ + ocic \ clean \ lint diff --git a/cmd/client/main.go b/cmd/client/main.go index c40c2954..07e26bbf 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -250,12 +250,10 @@ func main() { } } -func PullImage(client pb.ImageServiceClient, image string) error { - _, err := client.PullImage(context.Background(), &pb.PullImageRequest{Image: &pb.ImageSpec{Image: &image}}) - if err != nil { - return err - } - return nil +// PullImage sends a PullImageRequest to the server, and parses +// the returned ContainerStatusResponse. +func PullImage(client pb.ImageServiceClient, image string) (*pb.PullImageResponse, error) { + return client.PullImage(context.Background(), &pb.PullImageRequest{Image: &pb.ImageSpec{Image: &image}}) } // try this with ./ocic pullimage docker://busybox @@ -271,7 +269,7 @@ var pullImageCommand = cli.Command{ defer conn.Close() client := pb.NewImageServiceClient(conn) - err = PullImage(client, context.Args().Get(0)) + _, err = PullImage(client, context.Args().Get(0)) if err != nil { return fmt.Errorf("pulling image failed: %v", err) } diff --git a/cmd/server/main.go b/cmd/server/main.go index 659d2bcf..ddf3e171 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "log" "net" "os" @@ -80,12 +79,12 @@ func main() { // Remove the socket if it already exists if _, err := os.Stat(unixDomainSocket); err == nil { if err := os.Remove(unixDomainSocket); err != nil { - log.Fatal(err) + logrus.Fatal(err) } } lis, err := net.Listen("unix", unixDomainSocket) if err != nil { - log.Fatalf("failed to listen: %v", err) + logrus.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() @@ -94,16 +93,18 @@ func main() { sandboxDir := c.String("sandboxdir") service, err := server.New(c.String("runtime"), sandboxDir, containerDir) if err != nil { - log.Fatal(err) + logrus.Fatal(err) } runtime.RegisterRuntimeServiceServer(s, service) runtime.RegisterImageServiceServer(s, service) - s.Serve(lis) + if err := s.Serve(lis); err != nil { + logrus.Fatal(err) + } return nil } if err := app.Run(os.Args); err != nil { - log.Fatal(err) + logrus.Fatal(err) } } diff --git a/oci/oci.go b/oci/oci.go index 1f5c0816..0187e64d 100644 --- a/oci/oci.go +++ b/oci/oci.go @@ -38,7 +38,7 @@ type Runtime struct { // syncInfo is used to return data from monitor process to daemon type syncInfo struct { - Pid int `"json:pid"` + Pid int `json:"pid"` } // Name returns the name of the OCI Runtime @@ -141,7 +141,7 @@ func (r *Runtime) DeleteContainer(c *Container) error { return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "delete", c.name) } -// updateStatus refreshes the status of the container. +// UpdateStatus refreshes the status of the container. func (r *Runtime) UpdateStatus(c *Container) error { c.stateLock.Lock() defer c.stateLock.Unlock() @@ -161,7 +161,7 @@ func (r *Runtime) UpdateStatus(c *Container) error { return fmt.Errorf("failed to find container exit file: %v", err) } st := fi.Sys().(*syscall.Stat_t) - c.state.Finished = time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec)) + c.state.Finished = time.Unix(st.Ctim.Sec, st.Ctim.Nsec) statusCodeStr, err := ioutil.ReadFile(exitFilePath) if err != nil { @@ -196,7 +196,7 @@ type Container struct { stateLock sync.Mutex } -// ContainerStatus represents the status of a container. +// ContainerState represents the status of a container. type ContainerState struct { specs.State Created time.Time `json:"created"` diff --git a/server/const.go b/server/const.go deleted file mode 100644 index a6738c91..00000000 --- a/server/const.go +++ /dev/null @@ -1,16 +0,0 @@ -package server - -const ( - // According to http://man7.org/linux/man-pages/man5/resolv.conf.5.html: - // "The search list is currently limited to six domains with a total of 256 characters." - maxDNSSearches = 6 -) - -const ( - // by default, cpu.cfs_period_us is set to be 1000000 (i.e., 1s). - defaultCPUCFSPeriod = 1000000 - // the upper limit of cpu.cfs_quota_us is 1000000. - maxCPUCFSQuota = 1000000 - // the lower limit of cpu.cfs_quota_us is 1000. - minCPUCFSQuota = 1000 -) diff --git a/server/runtime.go b/server/container.go similarity index 53% rename from server/runtime.go rename to server/container.go index e9754404..91842ae8 100644 --- a/server/runtime.go +++ b/server/container.go @@ -1,9 +1,7 @@ package server import ( - "encoding/json" "fmt" - "io/ioutil" "os" "path/filepath" @@ -15,327 +13,12 @@ import ( "golang.org/x/net/context" ) -// Version returns the runtime name, runtime version and runtime API version -func (s *Server) Version(ctx context.Context, req *pb.VersionRequest) (*pb.VersionResponse, error) { - version, err := getGPRCVersion() - if err != nil { - return nil, err - } - - runtimeVersion, err := s.runtime.Version() - if err != nil { - return nil, err - } - - // taking const address - rav := runtimeAPIVersion - runtimeName := s.runtime.Name() - - return &pb.VersionResponse{ - Version: &version, - RuntimeName: &runtimeName, - RuntimeVersion: &runtimeVersion, - RuntimeApiVersion: &rav, - }, nil -} - -// CreatePodSandbox creates a pod-level sandbox. -// The definition of PodSandbox is at https://github.com/kubernetes/kubernetes/pull/25899 -func (s *Server) CreatePodSandbox(ctx context.Context, req *pb.CreatePodSandboxRequest) (*pb.CreatePodSandboxResponse, error) { - var err error - - // process req.Name - name := req.GetConfig().GetMetadata().GetName() - if name == "" { - return nil, fmt.Errorf("PodSandboxConfig.Name should not be empty") - } - - podSandboxDir := filepath.Join(s.sandboxDir, name) - if _, err := os.Stat(podSandboxDir); err == nil { - return nil, fmt.Errorf("pod sandbox (%s) already exists", podSandboxDir) - } - - if err := os.MkdirAll(podSandboxDir, 0755); err != nil { - return nil, err - } - - defer func() { - if err != nil { - os.RemoveAll(podSandboxDir) - } - }() - - // creates a spec Generator with the default spec. - g := generate.New() - - // setup defaults for the pod sandbox - g.SetRootPath("/var/lib/ocid/graph/vfs/pause") - g.SetRootReadonly(true) - g.SetProcessArgs([]string{"/pause"}) - - // process req.Hostname - hostname := req.GetConfig().GetHostname() - if hostname != "" { - g.SetHostname(hostname) - } - - // process req.LogDirectory - logDir := req.GetConfig().GetLogDirectory() - if logDir == "" { - logDir = fmt.Sprintf("/var/log/ocid/pods/%s", name) - } - - dnsServers := req.GetConfig().GetDnsOptions().GetServers() - dnsSearches := req.GetConfig().GetDnsOptions().GetSearches() - resolvPath := fmt.Sprintf("%s/resolv.conf", podSandboxDir) - err = parseDNSOptions(dnsServers, dnsSearches, resolvPath) - if err != nil { - err1 := removeFile(resolvPath) - if err1 != nil { - err = err1 - return nil, fmt.Errorf("%v; failed to remove %s: %v", err, resolvPath, err1) - } - return nil, err - } - - g.AddBindMount(resolvPath, "/etc/resolv.conf", "ro") - - labels := req.GetConfig().GetLabels() - s.addSandbox(&sandbox{ - name: name, - logDir: logDir, - labels: labels, - containers: oci.NewMemoryStore(), - }) - - annotations := req.GetConfig().GetAnnotations() - for k, v := range annotations { - g.AddAnnotation(k, v) - } - - cgroupParent := req.GetConfig().GetLinux().GetCgroupParent() - if cgroupParent != "" { - g.SetLinuxCgroupsPath(cgroupParent) - } - - // set up namespaces - if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostNetwork() { - err = g.RemoveLinuxNamespace("network") - if err != nil { - return nil, err - } - } - - if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostPid() { - err = g.RemoveLinuxNamespace("pid") - if err != nil { - return nil, err - } - } - - if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostIpc() { - err = g.RemoveLinuxNamespace("ipc") - if err != nil { - return nil, err - } - } - - err = g.SaveToFile(filepath.Join(podSandboxDir, "config.json")) - if err != nil { - return nil, err - } - - containerName := name + "-infra" - container, err := oci.NewContainer(containerName, podSandboxDir, podSandboxDir, labels, name, false) - if err != nil { - return nil, err - } - - if err = s.runtime.CreateContainer(container); err != nil { - return nil, err - } - - if err = s.runtime.UpdateStatus(container); err != nil { - return nil, err - } - - // Setup the network - podNamespace := "" - netnsPath, err := container.NetNsPath() - if err != nil { - return nil, err - } - if err = s.netPlugin.SetUpPod(netnsPath, podNamespace, name, containerName); err != nil { - return nil, fmt.Errorf("failed to create network for container %s in sandbox %s: %v", containerName, name, err) - } - - if err = s.runtime.StartContainer(container); err != nil { - return nil, err - } - - s.addContainer(container) - - meta := &metadata{ - LogDir: logDir, - ContainerName: containerName, - Labels: labels, - } - - b, err := json.Marshal(meta) - if err != nil { - return nil, err - } - - // TODO: eventually we would track all containers in this pod so on server start - // we can repopulate the structs in memory properly... - // e.g. each container can write itself in podSandboxDir - if err := ioutil.WriteFile(filepath.Join(podSandboxDir, "metadata.json"), b, 0644); err != nil { - return nil, err - } - - if err = s.runtime.UpdateStatus(container); err != nil { - return nil, err - } - - return &pb.CreatePodSandboxResponse{PodSandboxId: &name}, nil -} - -// StopPodSandbox stops the sandbox. If there are any running containers in the -// sandbox, they should be force terminated. -func (s *Server) StopPodSandbox(ctx context.Context, req *pb.StopPodSandboxRequest) (*pb.StopPodSandboxResponse, error) { - sbName := req.PodSandboxId - if *sbName == "" { - return nil, fmt.Errorf("PodSandboxId should not be empty") - } - sb := s.getSandbox(*sbName) - if sb == nil { - return nil, fmt.Errorf("specified sandbox not found: %s", *sbName) - } - - podInfraContainer := *sbName + "-infra" - containersList := sb.containers.List() - for _, c := range containersList { - if podInfraContainer == c.Name() { - podNamespace := "" - netnsPath, err := c.NetNsPath() - if err != nil { - return nil, err - } - if err := s.netPlugin.TearDownPod(netnsPath, podNamespace, *sbName, podInfraContainer); err != nil { - return nil, fmt.Errorf("failed to destroy network for container %s in sandbox %s: %v", c.Name(), *sbName, err) - } - } - if err := s.runtime.StopContainer(c); err != nil { - return nil, fmt.Errorf("failed to stop container %s in sandbox %s: %v", c.Name(), *sbName, err) - } - } - - return &pb.StopPodSandboxResponse{}, nil -} - -// RemovePodSandbox deletes the sandbox. If there are any running containers in the -// sandbox, they should be force deleted. -func (s *Server) RemovePodSandbox(ctx context.Context, req *pb.RemovePodSandboxRequest) (*pb.RemovePodSandboxResponse, error) { - sbName := req.PodSandboxId - if *sbName == "" { - return nil, fmt.Errorf("PodSandboxId should not be empty") - } - sb := s.getSandbox(*sbName) - if sb == nil { - return nil, fmt.Errorf("specified sandbox not found: %s", *sbName) - } - - podInfraContainer := *sbName + "-infra" - - // Delete all the containers in the sandbox - containersList := sb.containers.List() - for _, c := range containersList { - if err := s.runtime.DeleteContainer(c); err != nil { - return nil, fmt.Errorf("failed to delete container %s in sandbox %s: %v", c.Name(), *sbName, err) - } - if podInfraContainer == c.Name() { - continue - } - containerDir := filepath.Join(s.runtime.ContainerDir(), c.Name()) - if err := os.RemoveAll(containerDir); err != nil { - return nil, fmt.Errorf("failed to remove container %s directory: %v", c.Name(), err) - } - } - - // Remove the files related to the sandbox - podSandboxDir := filepath.Join(s.sandboxDir, *sbName) - if err := os.RemoveAll(podSandboxDir); err != nil { - return nil, fmt.Errorf("failed to remove sandbox %s directory: %v", *sbName, err) - } - - return &pb.RemovePodSandboxResponse{}, nil -} - -func int64Ptr(i int64) *int64 { - return &i -} - -func int32Ptr(i int32) *int32 { - return &i -} - -func sPtr(s string) *string { - return &s -} - -// PodSandboxStatus returns the Status of the PodSandbox. -func (s *Server) PodSandboxStatus(ctx context.Context, req *pb.PodSandboxStatusRequest) (*pb.PodSandboxStatusResponse, error) { - sbName := req.PodSandboxId - if *sbName == "" { - return nil, fmt.Errorf("PodSandboxId should not be empty") - } - sb := s.getSandbox(*sbName) - if sb == nil { - return nil, fmt.Errorf("specified sandbox not found: %s", *sbName) - } - - podInfraContainerName := *sbName + "-infra" - podInfraContainer := sb.getContainer(podInfraContainerName) - - cState := s.runtime.ContainerStatus(podInfraContainer) - created := cState.Created.Unix() - - netNsPath, err := podInfraContainer.NetNsPath() - if err != nil { - return nil, err - } - podNamespace := "" - ip, err := s.netPlugin.GetContainerNetworkStatus(netNsPath, podNamespace, *sbName, podInfraContainerName) - if err != nil { - // ignore the error on network status - ip = "" - } - - return &pb.PodSandboxStatusResponse{ - Status: &pb.PodSandboxStatus{ - Id: sbName, - CreatedAt: int64Ptr(created), - Linux: &pb.LinuxPodSandboxStatus{ - Namespaces: &pb.Namespace{ - Network: sPtr(netNsPath), - }, - }, - Network: &pb.PodSandboxNetworkStatus{Ip: &ip}, - }, - }, nil -} - -// ListPodSandbox returns a list of SandBox. -func (s *Server) ListPodSandbox(context.Context, *pb.ListPodSandboxRequest) (*pb.ListPodSandboxResponse, error) { - return nil, nil -} - // CreateContainer creates a new container in specified PodSandbox func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (*pb.CreateContainerResponse, error) { // The id of the PodSandbox - podSandboxId := req.GetPodSandboxId() - if !s.hasSandbox(podSandboxId) { - return nil, fmt.Errorf("the pod sandbox (%s) does not exist", podSandboxId) + podSandboxID := req.GetPodSandboxId() + if !s.hasSandbox(podSandboxID) { + return nil, fmt.Errorf("the pod sandbox (%s) does not exist", podSandboxID) } // The config of the container @@ -360,16 +43,27 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq return nil, err } - imageSpec := containerConfig.GetImage() - if imageSpec == nil { - return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image is nil") + container, err := s.createSandboxContainer(name, podSandboxID, req.GetSandboxConfig(), containerDir, containerConfig) + if err != nil { + return nil, err } - image := imageSpec.GetImage() - if image == "" { - return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image.Image is empty") + if err := s.runtime.CreateContainer(container); err != nil { + return nil, err } + if err := s.runtime.UpdateStatus(container); err != nil { + return nil, err + } + + s.addContainer(container) + + return &pb.CreateContainerResponse{ + ContainerId: &name, + }, nil +} + +func (s *Server) createSandboxContainer(name, podSandboxID string, SandboxConfig *pb.PodSandboxConfig, containerDir string, containerConfig *pb.ContainerConfig) (*oci.Container, error) { // creates a spec Generator with the default spec. specgen := generate.New() @@ -420,8 +114,7 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq } //TODO(hmeng): how to use this info? Do we need to handle relabel a FS with Selinux? - selinuxRelabel := mount.GetSelinuxRelabel() - fmt.Printf("selinuxRelabel: %v\n", selinuxRelabel) + //selinuxRelabel := mount.GetSelinuxRelabel() specgen.AddBindMount(src, dest, options) @@ -436,7 +129,7 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq } } - specgen.AddAnnotation("pod_sandbox_id", podSandboxId) + specgen.AddAnnotation("pod_sandbox_id", podSandboxID) if containerConfig.GetPrivileged() { specgen.SetupPrivileged(true) @@ -543,12 +236,8 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq } } - // The config of the PodSandbox - sandboxConfig := req.GetSandboxConfig() - fmt.Printf("sandboxConfig: %v\n", sandboxConfig) - // Join the namespace paths for the pod sandbox container. - podContainerName := podSandboxId + "-infra" + podContainerName := podSandboxID + "-infra" podInfraContainer := s.state.containers.Get(podContainerName) podInfraState := s.runtime.ContainerStatus(podInfraContainer) @@ -560,37 +249,37 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq "network": "net", } { nsPath := fmt.Sprintf("/proc/%d/ns/%s", podInfraState.Pid, nsFile) - specgen.AddOrReplaceLinuxNamespace(nsType, nsPath) + if err := specgen.AddOrReplaceLinuxNamespace(nsType, nsPath); err != nil { + return nil, err + } } if err := specgen.SaveToFile(filepath.Join(containerDir, "config.json")); err != nil { return nil, err } + imageSpec := containerConfig.GetImage() + if imageSpec == nil { + return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image is nil") + } + + image := imageSpec.GetImage() + if image == "" { + return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image.Image is empty") + } + // TODO: copy the rootfs into the bundle. // Currently, utils.CreateFakeRootfs is used to populate the rootfs. if err := utils.CreateFakeRootfs(containerDir, image); err != nil { return nil, err } - container, err := oci.NewContainer(name, containerDir, logPath, labels, podSandboxId, containerConfig.GetTty()) + container, err := oci.NewContainer(name, containerDir, logPath, labels, podSandboxID, containerConfig.GetTty()) if err != nil { return nil, err } - if err := s.runtime.CreateContainer(container); err != nil { - return nil, err - } - - if err := s.runtime.UpdateStatus(container); err != nil { - return nil, err - } - - s.addContainer(container) - - return &pb.CreateContainerResponse{ - ContainerId: &name, - }, nil + return container, nil } // StartContainer starts the container. diff --git a/server/image.go b/server/image.go index 574d77fc..553af0c0 100644 --- a/server/image.go +++ b/server/image.go @@ -2,6 +2,7 @@ package server import ( "errors" + "io" "os" "path/filepath" @@ -54,7 +55,7 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P return nil, err } - if err := os.Mkdir(filepath.Join(imageStore, tr.StringWithinTransport()), 0755); err != nil { + if err = os.Mkdir(filepath.Join(imageStore, tr.StringWithinTransport()), 0755); err != nil { return nil, err } dir, err := directory.NewReference(filepath.Join(imageStore, tr.StringWithinTransport())) @@ -69,11 +70,12 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P // save blobs (layer + config for docker v2s2, layers only for docker v2s1 [the config is in the manifest]) for _, b := range blobs { // TODO(runcom,nalin): we need do-then-commit to later purge on error - r, _, err := src.GetBlob(b) + var r io.ReadCloser + r, _, err = src.GetBlob(b) if err != nil { return nil, err } - if _, _, err := dest.PutBlob(r, b, -1); err != nil { + if _, _, err = dest.PutBlob(r, b, -1); err != nil { r.Close() return nil, err } diff --git a/server/sandbox.go b/server/sandbox.go new file mode 100644 index 00000000..2baf3242 --- /dev/null +++ b/server/sandbox.go @@ -0,0 +1,319 @@ +package server + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/Sirupsen/logrus" + "github.com/kubernetes-incubator/ocid/oci" + pb "github.com/kubernetes/kubernetes/pkg/kubelet/api/v1alpha1/runtime" + "github.com/opencontainers/ocitools/generate" + "golang.org/x/net/context" +) + +type sandbox struct { + name string + logDir string + labels map[string]string + containers oci.Store +} + +type metadata struct { + LogDir string `json:"log_dir"` + ContainerName string `json:"container_name"` + Labels map[string]string `json:"labels"` +} + +func (s *sandbox) addContainer(c *oci.Container) { + s.containers.Add(c.Name(), c) +} + +func (s *sandbox) getContainer(name string) *oci.Container { + return s.containers.Get(name) +} + +func (s *sandbox) removeContainer(c *oci.Container) { + s.containers.Delete(c.Name()) +} + +// CreatePodSandbox creates a pod-level sandbox. +// The definition of PodSandbox is at https://github.com/kubernetes/kubernetes/pull/25899 +func (s *Server) CreatePodSandbox(ctx context.Context, req *pb.CreatePodSandboxRequest) (*pb.CreatePodSandboxResponse, error) { + // process req.Name + name := req.GetConfig().GetMetadata().GetName() + if name == "" { + return nil, fmt.Errorf("PodSandboxConfig.Name should not be empty") + } + + podSandboxDir := filepath.Join(s.sandboxDir, name) + if _, err := os.Stat(podSandboxDir); err == nil { + return nil, fmt.Errorf("pod sandbox (%s) already exists", podSandboxDir) + } + + if err := os.MkdirAll(podSandboxDir, 0755); err != nil { + return nil, err + } + + var err error + defer func() { + if err != nil { + if err2 := os.RemoveAll(podSandboxDir); err2 != nil { + logrus.Warnf("couldn't cleanup podSandboxDir %s: %v", podSandboxDir, err2) + } + } + }() + + // creates a spec Generator with the default spec. + g := generate.New() + + // setup defaults for the pod sandbox + g.SetRootPath("/var/lib/ocid/graph/vfs/pause") + g.SetRootReadonly(true) + g.SetProcessArgs([]string{"/pause"}) + + // process req.Hostname + hostname := req.GetConfig().GetHostname() + if hostname != "" { + g.SetHostname(hostname) + } + + // process req.LogDirectory + logDir := req.GetConfig().GetLogDirectory() + if logDir == "" { + logDir = fmt.Sprintf("/var/log/ocid/pods/%s", name) + } + + dnsServers := req.GetConfig().GetDnsOptions().GetServers() + dnsSearches := req.GetConfig().GetDnsOptions().GetSearches() + resolvPath := fmt.Sprintf("%s/resolv.conf", podSandboxDir) + err = parseDNSOptions(dnsServers, dnsSearches, resolvPath) + if err != nil { + err1 := removeFile(resolvPath) + if err1 != nil { + err = err1 + return nil, fmt.Errorf("%v; failed to remove %s: %v", err, resolvPath, err1) + } + return nil, err + } + + g.AddBindMount(resolvPath, "/etc/resolv.conf", "ro") + + labels := req.GetConfig().GetLabels() + s.addSandbox(&sandbox{ + name: name, + logDir: logDir, + labels: labels, + containers: oci.NewMemoryStore(), + }) + + annotations := req.GetConfig().GetAnnotations() + for k, v := range annotations { + g.AddAnnotation(k, v) + } + + cgroupParent := req.GetConfig().GetLinux().GetCgroupParent() + if cgroupParent != "" { + g.SetLinuxCgroupsPath(cgroupParent) + } + + // set up namespaces + if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostNetwork() { + err = g.RemoveLinuxNamespace("network") + if err != nil { + return nil, err + } + } + + if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostPid() { + err = g.RemoveLinuxNamespace("pid") + if err != nil { + return nil, err + } + } + + if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostIpc() { + err = g.RemoveLinuxNamespace("ipc") + if err != nil { + return nil, err + } + } + + err = g.SaveToFile(filepath.Join(podSandboxDir, "config.json")) + if err != nil { + return nil, err + } + + containerName := name + "-infra" + container, err := oci.NewContainer(containerName, podSandboxDir, podSandboxDir, labels, name, false) + if err != nil { + return nil, err + } + + if err = s.runtime.CreateContainer(container); err != nil { + return nil, err + } + + if err = s.runtime.UpdateStatus(container); err != nil { + return nil, err + } + + // Setup the network + podNamespace := "" + netnsPath, err := container.NetNsPath() + if err != nil { + return nil, err + } + if err = s.netPlugin.SetUpPod(netnsPath, podNamespace, name, containerName); err != nil { + return nil, fmt.Errorf("failed to create network for container %s in sandbox %s: %v", containerName, name, err) + } + + if err = s.runtime.StartContainer(container); err != nil { + return nil, err + } + + s.addContainer(container) + + meta := &metadata{ + LogDir: logDir, + ContainerName: containerName, + Labels: labels, + } + + b, err := json.Marshal(meta) + if err != nil { + return nil, err + } + + // TODO: eventually we would track all containers in this pod so on server start + // we can repopulate the structs in memory properly... + // e.g. each container can write itself in podSandboxDir + err = ioutil.WriteFile(filepath.Join(podSandboxDir, "metadata.json"), b, 0644) + if err != nil { + return nil, err + } + + if err = s.runtime.UpdateStatus(container); err != nil { + return nil, err + } + + return &pb.CreatePodSandboxResponse{PodSandboxId: &name}, nil +} + +// StopPodSandbox stops the sandbox. If there are any running containers in the +// sandbox, they should be force terminated. +func (s *Server) StopPodSandbox(ctx context.Context, req *pb.StopPodSandboxRequest) (*pb.StopPodSandboxResponse, error) { + sbName := req.PodSandboxId + if *sbName == "" { + return nil, fmt.Errorf("PodSandboxId should not be empty") + } + sb := s.getSandbox(*sbName) + if sb == nil { + return nil, fmt.Errorf("specified sandbox not found: %s", *sbName) + } + + podInfraContainer := *sbName + "-infra" + for _, c := range sb.containers.List() { + if podInfraContainer == c.Name() { + podNamespace := "" + netnsPath, err := c.NetNsPath() + if err != nil { + return nil, err + } + if err := s.netPlugin.TearDownPod(netnsPath, podNamespace, *sbName, podInfraContainer); err != nil { + return nil, fmt.Errorf("failed to destroy network for container %s in sandbox %s: %v", c.Name(), *sbName, err) + } + } + if err := s.runtime.StopContainer(c); err != nil { + return nil, fmt.Errorf("failed to stop container %s in sandbox %s: %v", c.Name(), *sbName, err) + } + } + + return &pb.StopPodSandboxResponse{}, nil +} + +// RemovePodSandbox deletes the sandbox. If there are any running containers in the +// sandbox, they should be force deleted. +func (s *Server) RemovePodSandbox(ctx context.Context, req *pb.RemovePodSandboxRequest) (*pb.RemovePodSandboxResponse, error) { + sbName := req.PodSandboxId + if *sbName == "" { + return nil, fmt.Errorf("PodSandboxId should not be empty") + } + sb := s.getSandbox(*sbName) + if sb == nil { + return nil, fmt.Errorf("specified sandbox not found: %s", *sbName) + } + + podInfraContainer := *sbName + "-infra" + + // Delete all the containers in the sandbox + for _, c := range sb.containers.List() { + if err := s.runtime.DeleteContainer(c); err != nil { + return nil, fmt.Errorf("failed to delete container %s in sandbox %s: %v", c.Name(), *sbName, err) + } + if podInfraContainer == c.Name() { + continue + } + containerDir := filepath.Join(s.runtime.ContainerDir(), c.Name()) + if err := os.RemoveAll(containerDir); err != nil { + return nil, fmt.Errorf("failed to remove container %s directory: %v", c.Name(), err) + } + } + + // Remove the files related to the sandbox + podSandboxDir := filepath.Join(s.sandboxDir, *sbName) + if err := os.RemoveAll(podSandboxDir); err != nil { + return nil, fmt.Errorf("failed to remove sandbox %s directory: %v", *sbName, err) + } + + return &pb.RemovePodSandboxResponse{}, nil +} + +// PodSandboxStatus returns the Status of the PodSandbox. +func (s *Server) PodSandboxStatus(ctx context.Context, req *pb.PodSandboxStatusRequest) (*pb.PodSandboxStatusResponse, error) { + sbName := req.PodSandboxId + if *sbName == "" { + return nil, fmt.Errorf("PodSandboxId should not be empty") + } + sb := s.getSandbox(*sbName) + if sb == nil { + return nil, fmt.Errorf("specified sandbox not found: %s", *sbName) + } + + podInfraContainerName := *sbName + "-infra" + podInfraContainer := sb.getContainer(podInfraContainerName) + + cState := s.runtime.ContainerStatus(podInfraContainer) + created := cState.Created.Unix() + + netNsPath, err := podInfraContainer.NetNsPath() + if err != nil { + return nil, err + } + podNamespace := "" + ip, err := s.netPlugin.GetContainerNetworkStatus(netNsPath, podNamespace, *sbName, podInfraContainerName) + if err != nil { + // ignore the error on network status + ip = "" + } + + return &pb.PodSandboxStatusResponse{ + Status: &pb.PodSandboxStatus{ + Id: sbName, + CreatedAt: int64Ptr(created), + Linux: &pb.LinuxPodSandboxStatus{ + Namespaces: &pb.Namespace{ + Network: sPtr(netNsPath), + }, + }, + Network: &pb.PodSandboxNetworkStatus{Ip: &ip}, + }, + }, nil +} + +// ListPodSandbox returns a list of SandBox. +func (s *Server) ListPodSandbox(context.Context, *pb.ListPodSandboxRequest) (*pb.ListPodSandboxResponse, error) { + return nil, nil +} diff --git a/server/server.go b/server/server.go index 0017b7dc..3c5f06bd 100644 --- a/server/server.go +++ b/server/server.go @@ -29,7 +29,7 @@ type Server struct { } func (s *Server) loadSandboxes() error { - if err := filepath.Walk(s.sandboxDir, func(path string, info os.FileInfo, err error) error { + err := filepath.Walk(s.sandboxDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -44,8 +44,8 @@ func (s *Server) loadSandboxes() error { return err } var m metadata - if err := json.Unmarshal(metaJSON, &m); err != nil { - return err + if err2 := json.Unmarshal(metaJSON, &m); err2 != nil { + return err2 } sname, err := filepath.Rel(s.sandboxDir, path) if err != nil { @@ -55,7 +55,7 @@ func (s *Server) loadSandboxes() error { name: sname, logDir: m.LogDir, labels: m.Labels, - containers: make(map[string]*oci.Container), + containers: oci.NewMemoryStore(), }) scontainer, err := oci.NewContainer(m.ContainerName, path, path, m.Labels, sname, false) if err != nil { @@ -66,10 +66,8 @@ func (s *Server) loadSandboxes() error { logrus.Warnf("error updating status for container %s: %v", scontainer, err) } return nil - }); err != nil { - return err - } - return nil + }) + return err } // New creates a new Server with options provided @@ -122,31 +120,6 @@ type serverState struct { containers oci.Store } -type sandbox struct { - name string - logDir string - labels map[string]string - containers oci.Store -} - -type metadata struct { - LogDir string `json:"log_dir"` - ContainerName string `json:"container_name"` - Labels map[string]string `json:"labels"` -} - -func (s *sandbox) addContainer(c *oci.Container) { - s.containers.Add(c.Name(), c) -} - -func (s *sandbox) getContainer(name string) *oci.Container { - return s.containers.Get(name) -} - -func (s *sandbox) removeContainer(c *oci.Container) { - s.containers.Delete(c.Name()) -} - func (s *Server) addSandbox(sb *sandbox) { s.stateLock.Lock() s.state.sandboxes[sb.name] = sb diff --git a/server/utils.go b/server/utils.go index 0c5c9cdd..12bdc020 100644 --- a/server/utils.go +++ b/server/utils.go @@ -10,9 +10,26 @@ import ( "strings" "github.com/kubernetes-incubator/ocid/utils" - "github.com/opencontainers/ocitools/generate" ) +const ( + // According to http://man7.org/linux/man-pages/man5/resolv.conf.5.html: + // "The search list is currently limited to six domains with a total of 256 characters." + maxDNSSearches = 6 +) + +func int64Ptr(i int64) *int64 { + return &i +} + +func int32Ptr(i int32) *int32 { + return &i +} + +func sPtr(s string) *string { + return &s +} + func getGPRCVersion() (string, error) { _, file, _, ok := runtime.Caller(0) if !ok { @@ -44,10 +61,8 @@ func copyFile(src, dest string) error { } defer out.Close() - if _, err := io.Copy(out, in); err != nil { - return err - } - return nil + _, err = io.Copy(out, in) + return err } func removeFile(path string) error { @@ -94,62 +109,3 @@ func parseDNSOptions(servers, searches []string, path string) error { return nil } - -// kubernetes compute resources - CPU: http://kubernetes.io/docs/user-guide/compute-resources/#meaning-of-cpu -func setResourcesCPU(limits, requests, defaultCores float64, g generate.Generator) error { - if requests > limits { - return fmt.Errorf("CPU.Requests should not be greater than CPU.Limits") - } - - cores := defaultCores - if limits != 0 || requests != 0 { - if limits > requests { - cores = limits - } else { - cores = requests - } - } - - period := uint64(defaultCPUCFSPeriod) - quota := uint64(float64(period) * cores) - - if quota < minCPUCFSQuota { - quota = minCPUCFSQuota - } - - // adjust quota and period for the case where multiple CPUs are requested - // so that cpu.cfs_quota_us <= maxCPUCFSQuota. - for quota > maxCPUCFSQuota { - quota /= 10 - period /= 10 - } - - g.SetLinuxResourcesCPUPeriod(period) - g.SetLinuxResourcesCPUQuota(quota) - return nil -} - -// kubernetes compute resources - Memory: http://kubernetes.io/docs/user-guide/compute-resources/#meaning-of-memory -func setResourcesMemory(limits, requests, defaultMem float64, g generate.Generator) error { - if requests > limits { - return fmt.Errorf("Memory.Requests should not be greater than Memory.Limits") - } - - if limits != 0 { - if requests == 0 { - requests = limits - } - } else { - if requests == 0 { - // set the default values of limits and requests - requests = defaultMem - limits = defaultMem - } else { - limits = requests - } - } - - g.SetLinuxResourcesMemoryLimit(uint64(limits)) - g.SetLinuxResourcesMemoryReservation(uint64(requests)) - return nil -} diff --git a/server/version.go b/server/version.go new file mode 100644 index 00000000..df514990 --- /dev/null +++ b/server/version.go @@ -0,0 +1,30 @@ +package server + +import ( + pb "github.com/kubernetes/kubernetes/pkg/kubelet/api/v1alpha1/runtime" + "golang.org/x/net/context" +) + +// Version returns the runtime name, runtime version and runtime API version +func (s *Server) Version(ctx context.Context, req *pb.VersionRequest) (*pb.VersionResponse, error) { + version, err := getGPRCVersion() + if err != nil { + return nil, err + } + + runtimeVersion, err := s.runtime.Version() + if err != nil { + return nil, err + } + + // taking const address + rav := runtimeAPIVersion + runtimeName := s.runtime.Name() + + return &pb.VersionResponse{ + Version: &version, + RuntimeName: &runtimeName, + RuntimeVersion: &runtimeVersion, + RuntimeApiVersion: &rav, + }, nil +} diff --git a/utils/utils.go b/utils/utils.go index 299bb45b..dd90ec28 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -3,6 +3,7 @@ package utils import ( "bytes" "fmt" + "io" "os" "os/exec" "os/signal" @@ -13,8 +14,11 @@ import ( "github.com/Sirupsen/logrus" ) -const PR_SET_CHILD_SUBREAPER = 36 +// PRSetChildSubreaper is the value of PR_SET_CHILD_SUBREAPER in prctl(2) +const PRSetChildSubreaper = 36 +// ExecCmd executes a command with args and returns its output as a string along +// with an error, if any func ExecCmd(name string, args ...string) (string, error) { cmd := exec.Command(name, args...) var stdout bytes.Buffer @@ -31,7 +35,7 @@ func ExecCmd(name string, args ...string) (string, error) { } // ExecCmdWithStdStreams execute a command with the specified standard streams. -func ExecCmdWithStdStreams(stdin, stdout, stderr *os.File, name string, args ...string) error { +func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, name string, args ...string) error { cmd := exec.Command(name, args...) cmd.Stdin = stdin cmd.Stdout = stdout @@ -47,7 +51,7 @@ func ExecCmdWithStdStreams(stdin, stdout, stderr *os.File, name string, args ... // SetSubreaper sets the value i as the subreaper setting for the calling process func SetSubreaper(i int) error { - return Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0) + return Prctl(PRSetChildSubreaper, uintptr(i), 0, 0, 0) } // Prctl is a way to make the prctl linux syscall @@ -95,10 +99,8 @@ func dockerExport(image string, rootfs string) error { } func dockerRemove(container string) error { - if _, err := ExecCmd("docker", "rm", container); err != nil { - return err - } - return nil + _, err := ExecCmd("docker", "rm", container) + return err } // StartReaper starts a goroutine to reap processes From b053e639956355668dd9e2f80dea56c5d801dc09 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Mon, 19 Sep 2016 09:39:13 +0200 Subject: [PATCH 8/8] restore server rewrite Signed-off-by: Antonio Murdaca --- server/server.go | 80 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/server/server.go b/server/server.go index 3c5f06bd..c2d8c2d8 100644 --- a/server/server.go +++ b/server/server.go @@ -28,46 +28,44 @@ type Server struct { netPlugin ocicni.CNIPlugin } -func (s *Server) loadSandboxes() error { - err := filepath.Walk(s.sandboxDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - return nil - } - if path == s.sandboxDir { - return nil - } - metaJSON, err := ioutil.ReadFile(filepath.Join(path, "metadata.json")) - if err != nil { - return err - } - var m metadata - if err2 := json.Unmarshal(metaJSON, &m); err2 != nil { - return err2 - } - sname, err := filepath.Rel(s.sandboxDir, path) - if err != nil { - return err - } - s.addSandbox(&sandbox{ - name: sname, - logDir: m.LogDir, - labels: m.Labels, - containers: oci.NewMemoryStore(), - }) - scontainer, err := oci.NewContainer(m.ContainerName, path, path, m.Labels, sname, false) - if err != nil { - return err - } - s.addContainer(scontainer) - if err = s.runtime.UpdateStatus(scontainer); err != nil { - logrus.Warnf("error updating status for container %s: %v", scontainer, err) - } - return nil +func (s *Server) loadSandbox(id string) error { + metaJSON, err := ioutil.ReadFile(filepath.Join(s.sandboxDir, id, "metadata.json")) + if err != nil { + return err + } + var m metadata + if err = json.Unmarshal(metaJSON, &m); err != nil { + return err + } + s.addSandbox(&sandbox{ + name: id, + logDir: m.LogDir, + labels: m.Labels, + containers: oci.NewMemoryStore(), }) - return err + sandboxPath := filepath.Join(s.sandboxDir, id) + scontainer, err := oci.NewContainer(m.ContainerName, sandboxPath, sandboxPath, m.Labels, id, false) + if err != nil { + return err + } + s.addContainer(scontainer) + if err = s.runtime.UpdateStatus(scontainer); err != nil { + logrus.Warnf("error updating status for container %s: %v", scontainer, err) + } + return nil +} + +func (s *Server) restore() error { + dir, err := ioutil.ReadDir(s.sandboxDir) + if err != nil { + return err + } + for _, v := range dir { + if err := s.loadSandbox(v.Name()); err != nil { + return err + } + } + return nil } // New creates a new Server with options provided @@ -107,8 +105,8 @@ func New(runtimePath, sandboxDir, containerDir string) (*Server, error) { containers: containers, }, } - if err := s.loadSandboxes(); err != nil { - logrus.Warnf("couldn't get sandboxes: %v", err) + if err := s.restore(); err != nil { + logrus.Warnf("couldn't restore: %v", err) } logrus.Debugf("sandboxes: %v", s.state.sandboxes) logrus.Debugf("containers: %v", s.state.containers)