Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 63 additions & 0 deletions cmd/client/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/json"
"fmt"
"log"
"net"
Expand Down Expand Up @@ -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})
Expand All @@ -47,6 +81,7 @@ func main() {

app.Commands = []cli.Command{
runtimeVersionCommand,
createPodSandboxCommand,
pullImageCommand,
}

Expand Down Expand Up @@ -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
},
}
54 changes: 54 additions & 0 deletions cmd/client/podsandboxconfig.json
Original file line number Diff line number Diff line change
@@ -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
}
},
"labels": {
"group": "test"
},
"annotations": {
"owner": "hmeng"
},
"linux": {
"cgroup_parent": "/sys/fs/cgroup/test",
"namespace_options": {
"host_network": true,
"host_pid": true,
"host_ipc": true
}
}
}
50 changes: 37 additions & 13 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refer to #12 if you're dealing with images

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out.
I have not reached that far yet. Currently, I am just trying to process each field inside PodSandboxConfig.

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)
}
113 changes: 108 additions & 5 deletions server/runtime.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package server

import (
"fmt"
"os"
"path/filepath"

pb "github.com/kubernetes/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
Expand Down Expand Up @@ -37,16 +39,117 @@ 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()
if name == "" {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should require name to be set

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I thought so.
But inside api.pb.go, those json tags are omitempty. So I am not 100% sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can remove the extra code here.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because is everything is optional in proto for compat with v3

On Jul 22, 2016, at 3:07 PM, hmeng-19 notifications@github.com wrote:

In server/runtime.go:

  • // process req.Name
  • name := req.GetConfig().GetName()
  • var podSandboxDir string
  • if name == "" {
    Yeah. I thought so.
    But inside api.pb.go, those json tags are omitempty. So I am not 100% sure.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Got it.

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
}

// creates a spec Generator with the default spec.
g := generate.New()

// TODO: Customize the config per the settings in the req
// 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)
}

// TODO: construct /etc/resolv.conf based on dnsOpts.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to construct /etc/resolv.conf to be mounted. (I looked at existing kubelet code).
For e.g. create this file somewhere under the sandbox directory and add a bind mount to /etc/resolv.conf in the container.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrunalp , sounds good.
Do you think I should work on it with a separate PR? I kind of want to do that.
Keeping rebasing the current PR on master involves merging conflicts.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind doing this in a later PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrunalp , great.
Then let me know if there is anything I should fix before the PR is ready to be merged.
I will start working on a new PR to parse dns options and cpu settings.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hmeng-19 It is okay, I'll merge this and then we can address the TODOs in follow on PRs.

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?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read this document to understand how the conversion works. Basically we need to set shares, quota and period.
http://kubernetes.io/docs/user-guide/compute-resources/

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 nil, err
return &pb.CreatePodSandboxResponse{PodSandboxId: &name}, nil
}

// StopPodSandbox stops the sandbox. If there are any running containers in the
Expand Down
15 changes: 12 additions & 3 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -50,3 +53,9 @@ func (r *runcRuntime) Version() (string, error) {
}
return runtimeVersion, nil
}

type sandbox struct {
name string
logDir string
labels map[string]string
}
Loading