From 819d76b6fd9cc47493718b674f15b441ea7063d6 Mon Sep 17 00:00:00 2001 From: Haiyan Meng Date: Tue, 19 Jul 2016 21:30:05 -0400 Subject: [PATCH] Add first version of createPodSandbox Signed-off-by: Haiyan Meng --- Godeps/Godeps.json | 2 +- cmd/client/main.go | 63 +++++++++ cmd/client/podsandboxconfig.json | 54 ++++++++ cmd/server/main.go | 50 +++++-- server/runtime.go | 123 +++++++++++++++++- server/server.go | 15 ++- .../ocitools/generate/generate.go | 77 +++++++++++ 7 files changed, 361 insertions(+), 23 deletions(-) create mode 100644 cmd/client/podsandboxconfig.json diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e36efe21..f677a48b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -277,7 +277,7 @@ }, { "ImportPath": "github.com/opencontainers/ocitools/generate", - "Rev": "cc6b67605256c65ba19da6a201e3b0f264b8ba40" + "Rev": "3c4fc86f2c260090282737419c83c43c47630df8" }, { "ImportPath": "github.com/opencontainers/runc/libcontainer/user", diff --git a/cmd/client/main.go b/cmd/client/main.go index 6d123ebe..ca6a4a77 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "fmt" "log" "net" @@ -30,6 +31,39 @@ func getClientConnection() (*grpc.ClientConn, error) { return conn, nil } +func loadPodSandboxConfig(path string) (*pb.PodSandboxConfig, error) { + f, err := os.Open(path) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("pod sandbox config at %s not found", path) + } + return nil, err + } + defer f.Close() + + var config pb.PodSandboxConfig + if err := json.NewDecoder(f).Decode(&config); err != nil { + return nil, err + } + return &config, nil +} + +// CreatePodSandbox sends a CreatePodSandboxRequest to the server, and parses +// the returned CreatePodSandboxResponse. +func CreatePodSandbox(client pb.RuntimeServiceClient, path string) error { + config, err := loadPodSandboxConfig(path) + if err != nil { + return err + } + + r, err := client.CreatePodSandbox(context.Background(), &pb.CreatePodSandboxRequest{Config: config}) + if err != nil { + return err + } + fmt.Println(r) + return nil +} + // Version sends a VersionRequest to the server, and parses the returned VersionResponse. func Version(client pb.RuntimeServiceClient, version string) error { r, err := client.Version(context.Background(), &pb.VersionRequest{Version: &version}) @@ -47,6 +81,7 @@ func main() { app.Commands = []cli.Command{ runtimeVersionCommand, + createPodSandboxCommand, pullImageCommand, } @@ -105,3 +140,31 @@ var runtimeVersionCommand = cli.Command{ return nil }, } + +var createPodSandboxCommand = cli.Command{ + Name: "createpodsandbox", + Usage: "create a pod sandbox", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "config", + Value: "config.json", + Usage: "the path of a pod sandbox config file", + }, + }, + Action: func(context *cli.Context) error { + // Set up a connection to the server. + conn, err := getClientConnection() + if err != nil { + return fmt.Errorf("Failed to connect: %v", err) + } + defer conn.Close() + client := pb.NewRuntimeServiceClient(conn) + + // Test RuntimeServiceClient.CreatePodSandbox + err = CreatePodSandbox(client, context.String("config")) + if err != nil { + return fmt.Errorf("Creating the pod sandbox failed: %v", err) + } + return nil + }, +} diff --git a/cmd/client/podsandboxconfig.json b/cmd/client/podsandboxconfig.json new file mode 100644 index 00000000..c3715456 --- /dev/null +++ b/cmd/client/podsandboxconfig.json @@ -0,0 +1,54 @@ +{ + "name": "podsandbox1", + "hostname": "ocic_host", + "log_directory": ".", + "dns_options": { + "servers": [ + "server1.redhat.com", + "server2.redhat.com" + ], + "searches": [ + "8.8.8.8" + ] + }, + "port_mappings": [ + { + "name": "port_map1", + "protocol": 1, + "container_port": 80, + "host_port": 4888, + "host_ip": "192.168.0.33" + }, + { + "name": "port_map2", + "protocol": 2, + "container_port": 81, + "host_port": 4889, + "host_ip": "192.168.0.33" + } + ], + "resources": { + "cpu": { + "limits": 50000000, + "requests": 20000000 + }, + "memory": { + "limits": 500000000000, + "requests": 200000000000 + } + }, + "lables": { + "group": "test" + }, + "annotations": { + "owner": "hmeng" + }, + "linux": { + "cgroup_parent": "/sys/fs/cgroup/test", + "namespace_options": { + "host_network": true, + "host_pid": true, + "host_ipc": true + } + } +} diff --git a/cmd/server/main.go b/cmd/server/main.go index bfe35abc..7d82047a 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -7,6 +7,7 @@ import ( "github.com/kubernetes/kubernetes/pkg/kubelet/api/v1alpha1/runtime" "github.com/mrunalp/ocid/server" + "github.com/urfave/cli" "google.golang.org/grpc" ) @@ -15,22 +16,45 @@ const ( ) func main() { - // Remove the socket if it already exists - if _, err := os.Stat(unixDomainSocket); err == nil { - if err := os.Remove(unixDomainSocket); err != nil { + app := cli.NewApp() + app.Name = "ocic" + app.Usage = "client for ocid" + + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "sandboxdir", + Value: "/var/lib/ocid/sandbox", + Usage: "ocid pod sandbox dir", + }, + } + + app.Action = func(c *cli.Context) error { + // Remove the socket if it already exists + if _, err := os.Stat(unixDomainSocket); err == nil { + if err := os.Remove(unixDomainSocket); err != nil { + log.Fatal(err) + } + } + lis, err := net.Listen("unix", unixDomainSocket) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + + s := grpc.NewServer() + + sandboxDir := c.String("sandboxdir") + service, err := server.New("", sandboxDir) + if err != nil { log.Fatal(err) } + + runtime.RegisterRuntimeServiceServer(s, service) + runtime.RegisterImageServiceServer(s, service) + s.Serve(lis) + return nil } - lis, err := net.Listen("unix", unixDomainSocket) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - s := grpc.NewServer() - service, err := server.New("") - if err != nil { + + if err := app.Run(os.Args); err != nil { log.Fatal(err) } - runtime.RegisterRuntimeServiceServer(s, service) - runtime.RegisterImageServiceServer(s, service) - s.Serve(lis) } diff --git a/server/runtime.go b/server/runtime.go index cc7e1fdb..041bbf81 100644 --- a/server/runtime.go +++ b/server/runtime.go @@ -1,6 +1,9 @@ package server import ( + "fmt" + "io/ioutil" + "os" "path/filepath" pb "github.com/kubernetes/kubernetes/pkg/kubelet/api/v1alpha1/runtime" @@ -37,16 +40,124 @@ 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 - // TODO: Parametrize as a global argument to ocid - ocidSandboxDir := "/var/lib/ocid/sandbox" - podSandboxDir := filepath.Join(ocidSandboxDir, req.GetConfig().GetName()) + if err := os.MkdirAll(s.sandboxDir, 0755); err != nil { + return nil, err + } + // process req.Name + name := req.GetConfig().GetName() + var podSandboxDir string + + if name == "" { + podSandboxDir, err := ioutil.TempDir(s.sandboxDir, "") + if err != nil { + return nil, err + } + name = filepath.Base(podSandboxDir) + } else { + 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 + } + + } + + // creates a spec Generator with the default spec. g := generate.New() - // TODO: Customize the config per the settings in the req - err = g.SaveToFile(filepath.Join(podSandboxDir, "config.json")) + // process req.Hostname + hostname := req.GetConfig().GetHostname() + if hostname != "" { + g.SetHostname(hostname) + } - return nil, err + // process req.LogDirectory + logDir := req.GetConfig().GetLogDirectory() + if logDir == "" { + logDir = fmt.Sprintf("/var/log/ocid/pods/%s", name) + } + + // TODO: construct /etc/resolv.conf based on dnsOpts. + dnsOpts := req.GetConfig().GetDnsOptions() + fmt.Println(dnsOpts) + + // TODO: the unit of cpu here is cores. How to map it into specs.Spec.Linux.Resouces.CPU? + cpu := req.GetConfig().GetResources().GetCpu() + if cpu != nil { + limits := cpu.GetLimits() + requests := cpu.GetRequests() + fmt.Println(limits) + fmt.Println(requests) + } + + memory := req.GetConfig().GetResources().GetMemory() + if memory != nil { + // limits sets specs.Spec.Linux.Resouces.Memory.Limit + limits := memory.GetLimits() + if limits != 0 { + g.SetLinuxResourcesMemoryLimit(uint64(limits)) + } + + // requests sets specs.Spec.Linux.Resouces.Memory.Reservation + requests := memory.GetRequests() + if requests != 0 { + g.SetLinuxResourcesMemoryReservation(uint64(requests)) + } + } + + labels := req.GetConfig().GetLabels() + s.sandboxes = append(s.sandboxes, &sandbox{ + name: name, + logDir: logDir, + labels: labels, + }) + + annotations := req.GetConfig().GetAnnotations() + for k, v := range annotations { + err := g.AddAnnotation(fmt.Sprintf("%s=%s", k, v)) + if err != nil { + return nil, err + } + } + + // TODO: double check cgroupParent. + cgroupParent := req.GetConfig().GetLinux().GetCgroupParent() + if cgroupParent != "" { + g.SetLinuxCgroupsPath(cgroupParent) + } + + // set up namespaces + if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostNetwork() == false { + err := g.AddOrReplaceLinuxNamespace("network", "") + if err != nil { + return nil, err + } + } + + if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostPid() == false { + err := g.AddOrReplaceLinuxNamespace("pid", "") + if err != nil { + return nil, err + } + } + + if req.GetConfig().GetLinux().GetNamespaceOptions().GetHostIpc() == false { + err := g.AddOrReplaceLinuxNamespace("ipc", "") + if err != nil { + return nil, err + } + } + + err = g.SaveToFile(filepath.Join(podSandboxDir, "config.json")) + if err != nil { + return nil, err + } + + return &pb.CreatePodSandboxResponse{PodSandboxId: &name}, nil } // StopPodSandbox stops the sandbox. If there are any running containers in the diff --git a/server/server.go b/server/server.go index 217169ee..68381254 100644 --- a/server/server.go +++ b/server/server.go @@ -6,16 +6,19 @@ const ( // Server implements the RuntimeService and ImageService type Server struct { - runtime ociRuntime + runtime ociRuntime + sandboxDir string + sandboxes []*sandbox } // New creates a new Server with options provided -func New(runtimePath string) (*Server, error) { +func New(runtimePath, sandboxDir string) (*Server, error) { // TODO(runcom): runtimePath arg is unused but it might be useful // if we're willing to open the doors to other runtimes in the future. r := &runcRuntime{} return &Server{ - runtime: r, + runtime: r, + sandboxDir: sandboxDir, }, nil } @@ -50,3 +53,9 @@ func (r *runcRuntime) Version() (string, error) { } return runtimeVersion, nil } + +type sandbox struct { + name string + logDir string + labels map[string]string +} diff --git a/vendor/github.com/opencontainers/ocitools/generate/generate.go b/vendor/github.com/opencontainers/ocitools/generate/generate.go index 848cf83e..829cc19d 100644 --- a/vendor/github.com/opencontainers/ocitools/generate/generate.go +++ b/vendor/github.com/opencontainers/ocitools/generate/generate.go @@ -342,6 +342,83 @@ func (g Generator) SetLinuxMountLabel(label string) { g.spec.Linux.MountLabel = label } +// SetLinuxResourcesCPUShares sets g.spec.Linux.Resources.CPU.Shares. +func (g Generator) SetLinuxResourcesCPUShares(shares uint64) { + g.spec.Linux.Resources.CPU.Shares = &shares +} + +// SetLinuxResourcesCPUQuota sets g.spec.Linux.Resources.CPU.Quota. +func (g Generator) SetLinuxResourcesCPUQuota(quota uint64) { + g.spec.Linux.Resources.CPU.Quota = "a +} + +// SetLinuxResourcesCPUPeriod sets g.spec.Linux.Resources.CPU.Period. +func (g Generator) SetLinuxResourcesCPUPeriod(period uint64) { + g.spec.Linux.Resources.CPU.Period = &period +} + +// SetLinuxResourcesCPURealtimeRuntime sets g.spec.Linux.Resources.CPU.RealtimeRuntime. +func (g Generator) SetLinuxResourcesCPURealtimeRuntime(time uint64) { + g.spec.Linux.Resources.CPU.RealtimeRuntime = &time +} + +// SetLinuxResourcesCPURealtimePeriod sets g.spec.Linux.Resources.CPU.RealtimePeriod. +func (g Generator) SetLinuxResourcesCPURealtimePeriod(period uint64) { + g.spec.Linux.Resources.CPU.RealtimePeriod = &period +} + +// SetLinuxResourcesCPUCpus sets g.spec.Linux.Resources.CPU.Cpus. +func (g Generator) SetLinuxResourcesCPUCpus(cpus string) { + g.spec.Linux.Resources.CPU.Cpus = &cpus +} + +// SetLinuxResourcesCPUMems sets g.spec.Linux.Resources.CPU.Mems. +func (g Generator) SetLinuxResourcesCPUMems(mems string) { + g.spec.Linux.Resources.CPU.Mems = &mems +} + +// SetLinuxResourcesMemoryLimit sets g.spec.Linux.Resources.Memory.Limit. +func (g Generator) SetLinuxResourcesMemoryLimit(limit uint64) { + if g.spec.Linux == nil { + g.spec.Linux = &rspec.Linux{} + } + + if g.spec.Linux.Resources == nil { + g.spec.Linux.Resources = &rspec.Resources{} + } + + if g.spec.Linux.Resources.Memory == nil { + g.spec.Linux.Resources.Memory = &rspec.Memory{} + } + + g.spec.Linux.Resources.Memory.Limit = &limit +} + +// SetLinuxResourcesMemoryReservation sets g.spec.Linux.Resources.Memory.Reservation. +func (g Generator) SetLinuxResourcesMemoryReservation(reservation uint64) { + g.spec.Linux.Resources.Memory.Reservation = &reservation +} + +// SetLinuxResourcesMemorySwap sets g.spec.Linux.Resources.Memory.Swap. +func (g Generator) SetLinuxResourcesMemorySwap(swap uint64) { + g.spec.Linux.Resources.Memory.Swap = &swap +} + +// SetLinuxResourcesMemoryKernel sets g.spec.Linux.Resources.Memory.Kernel. +func (g Generator) SetLinuxResourcesMemoryKernel(kernel uint64) { + g.spec.Linux.Resources.Memory.Kernel = &kernel +} + +// SetLinuxResourcesMemoryKernelTCP sets g.spec.Linux.Resources.Memory.KernelTCP. +func (g Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP uint64) { + g.spec.Linux.Resources.Memory.KernelTCP = &kernelTCP +} + +// SetLinuxResourcesMemorySwappiness sets g.spec.Linux.Resources.Memory.Swappiness. +func (g Generator) SetLinuxResourcesMemorySwappiness(swappiness uint64) { + g.spec.Linux.Resources.Memory.Swappiness = &swappiness +} + // ClearLinuxSysctl clears g.spec.Linux.Sysctl. func (g Generator) ClearLinuxSysctl() { g.spec.Linux.Sysctl = make(map[string]string)