Build and install from GOPATH
* Rename 'vendor/src' -> 'vendor' * Ignore vendor/ instead of vendor/src/ for lint * Rename 'cmd/client' -> 'cmd/ocic' to make it 'go install'able * Rename 'cmd/server' -> 'cmd/ocid' to make it 'go install'able * Update Makefile to build and install from GOPATH * Update tests to locate ocid/ocic in GOPATH/bin * Search for binaries in GOPATH/bin instead of PATH * Install tools using `go get -u`, so they are updated on each run Signed-off-by: Jonathan Yu <jawnsy@redhat.com>
This commit is contained in:
parent
9da2882d49
commit
6c9628cdb1
1111 changed files with 70 additions and 61 deletions
530
cmd/ocic/container.go
Normal file
530
cmd/ocic/container.go
Normal file
|
@ -0,0 +1,530 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var containerCommand = cli.Command{
|
||||
Name: "container",
|
||||
Aliases: []string{"ctr"},
|
||||
Subcommands: []cli.Command{
|
||||
createContainerCommand,
|
||||
startContainerCommand,
|
||||
stopContainerCommand,
|
||||
removeContainerCommand,
|
||||
containerStatusCommand,
|
||||
listContainersCommand,
|
||||
execSyncCommand,
|
||||
},
|
||||
}
|
||||
|
||||
type createOptions struct {
|
||||
// configPath is path to the config for container
|
||||
configPath string
|
||||
// name sets the container name
|
||||
name string
|
||||
// podID of the container
|
||||
podID string
|
||||
// labels for the container
|
||||
labels map[string]string
|
||||
}
|
||||
|
||||
var createContainerCommand = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "create a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "pod",
|
||||
Usage: "the id of the pod sandbox to which the container belongs",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config",
|
||||
Value: "config.json",
|
||||
Usage: "the path of a container config file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "the name of the container",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "add key=value labels to the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
if !context.IsSet("pod") {
|
||||
return fmt.Errorf("Please specify the id of the pod sandbox to which the container belongs via the --pod option")
|
||||
}
|
||||
|
||||
opts := createOptions{
|
||||
configPath: context.String("config"),
|
||||
name: context.String("name"),
|
||||
podID: context.String("pod"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
// Test RuntimeServiceClient.CreateContainer
|
||||
err = CreateContainer(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var startContainerCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = StartContainer(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Starting the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stopContainerCommand = cli.Command{
|
||||
Name: "stop",
|
||||
Usage: "stop a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = StopContainer(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Stopping the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var removeContainerCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "remove a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = RemoveContainer(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Removing the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var containerStatusCommand = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "get the status of a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = ContainerStatus(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting the status of the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var execSyncCommand = cli.Command{
|
||||
Name: "execsync",
|
||||
Usage: "exec a command synchronously in a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
cli.Int64Flag{
|
||||
Name: "timeout",
|
||||
Value: 0,
|
||||
Usage: "timeout for the command",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = ExecSync(client, context.String("id"), context.Args(), context.Int64("timeout"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("execing command in container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type listOptions struct {
|
||||
// id of the container
|
||||
id string
|
||||
// podID of the container
|
||||
podID string
|
||||
// state of the container
|
||||
state string
|
||||
// quiet is for listing just container IDs
|
||||
quiet bool
|
||||
// labels are selectors for the container
|
||||
labels map[string]string
|
||||
}
|
||||
|
||||
var listContainersCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list containers",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "list only container IDs",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "filter by container id",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "pod",
|
||||
Value: "",
|
||||
Usage: "filter by container pod id",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "state",
|
||||
Value: "",
|
||||
Usage: "filter by container state",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "filter by key=value label",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
opts := listOptions{
|
||||
id: context.String("id"),
|
||||
podID: context.String("pod"),
|
||||
state: context.String("state"),
|
||||
quiet: context.Bool("quiet"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
err = ListContainers(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing containers failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// CreateContainer sends a CreateContainerRequest to the server, and parses
|
||||
// the returned CreateContainerResponse.
|
||||
func CreateContainer(client pb.RuntimeServiceClient, opts createOptions) error {
|
||||
config, err := loadContainerConfig(opts.configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Override the name by the one specified through CLI
|
||||
if opts.name != "" {
|
||||
config.Metadata.Name = &opts.name
|
||||
}
|
||||
|
||||
for k, v := range opts.labels {
|
||||
config.Labels[k] = v
|
||||
}
|
||||
|
||||
r, err := client.CreateContainer(context.Background(), &pb.CreateContainerRequest{
|
||||
PodSandboxId: &opts.podID,
|
||||
Config: config,
|
||||
// TODO(runcom): this is missing PodSandboxConfig!!!
|
||||
// we should/could find a way to retrieve it from the fs and set it here
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(*r.ContainerId)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartContainer sends a StartContainerRequest to the server, and parses
|
||||
// the returned StartContainerResponse.
|
||||
func StartContainer(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.StartContainer(context.Background(), &pb.StartContainerRequest{
|
||||
ContainerId: &ID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopContainer sends a StopContainerRequest to the server, and parses
|
||||
// the returned StopContainerResponse.
|
||||
func StopContainer(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.StopContainer(context.Background(), &pb.StopContainerRequest{
|
||||
ContainerId: &ID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveContainer sends a RemoveContainerRequest to the server, and parses
|
||||
// the returned RemoveContainerResponse.
|
||||
func RemoveContainer(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.RemoveContainer(context.Background(), &pb.RemoveContainerRequest{
|
||||
ContainerId: &ID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerStatus sends a ContainerStatusRequest to the server, and parses
|
||||
// the returned ContainerStatusResponse.
|
||||
func ContainerStatus(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.ContainerStatus(context.Background(), &pb.ContainerStatusRequest{
|
||||
ContainerId: &ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("ID: %s\n", *r.Status.Id)
|
||||
if r.Status.Metadata != nil {
|
||||
if r.Status.Metadata.Name != nil {
|
||||
fmt.Printf("Name: %s\n", *r.Status.Metadata.Name)
|
||||
}
|
||||
if r.Status.Metadata.Attempt != nil {
|
||||
fmt.Printf("Attempt: %v\n", *r.Status.Metadata.Attempt)
|
||||
}
|
||||
}
|
||||
if r.Status.State != nil {
|
||||
fmt.Printf("Status: %s\n", r.Status.State)
|
||||
}
|
||||
if r.Status.CreatedAt != nil {
|
||||
ctm := time.Unix(0, *r.Status.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
}
|
||||
if r.Status.StartedAt != nil {
|
||||
stm := time.Unix(0, *r.Status.StartedAt)
|
||||
fmt.Printf("Started: %v\n", stm)
|
||||
}
|
||||
if r.Status.FinishedAt != nil {
|
||||
ftm := time.Unix(0, *r.Status.FinishedAt)
|
||||
fmt.Printf("Finished: %v\n", ftm)
|
||||
}
|
||||
if r.Status.ExitCode != nil {
|
||||
fmt.Printf("Exit Code: %v\n", *r.Status.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecSync sends an ExecSyncRequest to the server, and parses
|
||||
// the returned ExecSyncResponse.
|
||||
func ExecSync(client pb.RuntimeServiceClient, ID string, cmd []string, timeout int64) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.ExecSync(context.Background(), &pb.ExecSyncRequest{
|
||||
ContainerId: &ID,
|
||||
Cmd: cmd,
|
||||
Timeout: &timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Stdout:")
|
||||
fmt.Println(string(r.Stdout))
|
||||
fmt.Println("Stderr:")
|
||||
fmt.Println(string(r.Stderr))
|
||||
fmt.Printf("Exit code: %v\n", *r.ExitCode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListContainers sends a ListContainerRequest to the server, and parses
|
||||
// the returned ListContainerResponse.
|
||||
func ListContainers(client pb.RuntimeServiceClient, opts listOptions) error {
|
||||
filter := &pb.ContainerFilter{}
|
||||
if opts.id != "" {
|
||||
filter.Id = &opts.id
|
||||
}
|
||||
if opts.podID != "" {
|
||||
filter.PodSandboxId = &opts.podID
|
||||
}
|
||||
if opts.state != "" {
|
||||
st := pb.ContainerState_CONTAINER_UNKNOWN
|
||||
switch opts.state {
|
||||
case "created":
|
||||
st = pb.ContainerState_CONTAINER_CREATED
|
||||
filter.State = &st
|
||||
case "running":
|
||||
st = pb.ContainerState_CONTAINER_RUNNING
|
||||
filter.State = &st
|
||||
case "stopped":
|
||||
st = pb.ContainerState_CONTAINER_EXITED
|
||||
filter.State = &st
|
||||
default:
|
||||
log.Fatalf("--state should be one of created, running or stopped")
|
||||
}
|
||||
}
|
||||
if opts.labels != nil {
|
||||
filter.LabelSelector = opts.labels
|
||||
}
|
||||
r, err := client.ListContainers(context.Background(), &pb.ListContainersRequest{
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, c := range r.GetContainers() {
|
||||
if opts.quiet {
|
||||
fmt.Println(*c.Id)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("ID: %s\n", *c.Id)
|
||||
fmt.Printf("Pod: %s\n", *c.PodSandboxId)
|
||||
if c.Metadata != nil {
|
||||
if c.Metadata.Name != nil {
|
||||
fmt.Printf("Name: %s\n", *c.Metadata.Name)
|
||||
}
|
||||
if c.Metadata.Attempt != nil {
|
||||
fmt.Printf("Attempt: %v\n", *c.Metadata.Attempt)
|
||||
}
|
||||
}
|
||||
if c.State != nil {
|
||||
fmt.Printf("Status: %s\n", *c.State)
|
||||
}
|
||||
if c.Image != nil {
|
||||
fmt.Printf("Image: %s\n", c.Image.GetImage())
|
||||
}
|
||||
if c.CreatedAt != nil {
|
||||
ctm := time.Unix(0, *c.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
}
|
||||
if c.Labels != nil {
|
||||
fmt.Println("Labels:")
|
||||
for _, k := range getSortedKeys(c.Labels) {
|
||||
fmt.Printf("\t%s -> %s\n", k, c.Labels[k])
|
||||
}
|
||||
}
|
||||
if c.Annotations != nil {
|
||||
fmt.Println("Annotations:")
|
||||
for _, k := range getSortedKeys(c.Annotations) {
|
||||
fmt.Printf("\t%s -> %s\n", k, c.Annotations[k])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
return nil
|
||||
}
|
175
cmd/ocic/image.go
Normal file
175
cmd/ocic/image.go
Normal file
|
@ -0,0 +1,175 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var imageCommand = cli.Command{
|
||||
Name: "image",
|
||||
Subcommands: []cli.Command{
|
||||
pullImageCommand,
|
||||
listImageCommand,
|
||||
imageStatusCommand,
|
||||
removeImageCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var pullImageCommand = cli.Command{
|
||||
Name: "pull",
|
||||
Usage: "pull an image",
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
_, err = PullImage(client, context.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("pulling image failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listImageCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list images",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "list only image IDs",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
r, err := ListImages(client, context.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing images failed: %v", err)
|
||||
}
|
||||
quiet := context.Bool("quiet")
|
||||
for _, image := range r.Images {
|
||||
if quiet {
|
||||
fmt.Printf("%s\n", *image.Id)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("ID: %s\n", *image.Id)
|
||||
for _, tag := range image.RepoTags {
|
||||
fmt.Printf("Tag: %s\n", tag)
|
||||
}
|
||||
for _, digest := range image.RepoDigests {
|
||||
fmt.Printf("Digest: %s\n", digest)
|
||||
}
|
||||
if image.Size_ != nil {
|
||||
fmt.Printf("Size: %d\n", *image.Size_)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var imageStatusCommand = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "return the status of an image",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "id of the image",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
r, err := ImageStatus(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("image status request failed: %v", err)
|
||||
}
|
||||
image := r.Image
|
||||
if image == nil {
|
||||
return fmt.Errorf("no such image present")
|
||||
}
|
||||
fmt.Printf("ID: %s\n", *image.Id)
|
||||
for _, tag := range image.RepoTags {
|
||||
fmt.Printf("Tag: %s\n", tag)
|
||||
}
|
||||
for _, digest := range image.RepoDigests {
|
||||
fmt.Printf("Digest: %s\n", digest)
|
||||
}
|
||||
if image.Size_ != nil {
|
||||
fmt.Printf("Size: %d\n", *image.Size_)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
var removeImageCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "remove an image",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the image",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
_, err = RemoveImage(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing the image failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// PullImage sends a PullImageRequest to the server, and parses
|
||||
// the returned PullImageResponse.
|
||||
func PullImage(client pb.ImageServiceClient, image string) (*pb.PullImageResponse, error) {
|
||||
return client.PullImage(context.Background(), &pb.PullImageRequest{Image: &pb.ImageSpec{Image: &image}})
|
||||
}
|
||||
|
||||
// ListImages sends a ListImagesRequest to the server, and parses
|
||||
// the returned ListImagesResponse.
|
||||
func ListImages(client pb.ImageServiceClient, image string) (*pb.ListImagesResponse, error) {
|
||||
return client.ListImages(context.Background(), &pb.ListImagesRequest{Filter: &pb.ImageFilter{Image: &pb.ImageSpec{Image: &image}}})
|
||||
}
|
||||
|
||||
// ImageStatus sends an ImageStatusRequest to the server, and parses
|
||||
// the returned ImageStatusResponse.
|
||||
func ImageStatus(client pb.ImageServiceClient, image string) (*pb.ImageStatusResponse, error) {
|
||||
return client.ImageStatus(context.Background(), &pb.ImageStatusRequest{Image: &pb.ImageSpec{Image: &image}})
|
||||
}
|
||||
|
||||
// RemoveImage sends a RemoveImageRequest to the server, and parses
|
||||
// the returned RemoveImageResponse.
|
||||
func RemoveImage(client pb.ImageServiceClient, image string) (*pb.RemoveImageResponse, error) {
|
||||
if image == "" {
|
||||
return nil, fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
return client.RemoveImage(context.Background(), &pb.RemoveImageRequest{Image: &pb.ImageSpec{Image: &image}})
|
||||
}
|
95
cmd/ocic/main.go
Normal file
95
cmd/ocic/main.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
"google.golang.org/grpc"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
func getClientConnection(context *cli.Context) (*grpc.ClientConn, error) {
|
||||
conn, err := grpc.Dial(context.GlobalString("connect"), grpc.WithInsecure(), grpc.WithTimeout(context.GlobalDuration("timeout")),
|
||||
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return net.DialTimeout("unix", addr, timeout)
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func openFile(path string) (*os.File, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("config at %s not found", path)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func loadPodSandboxConfig(path string) (*pb.PodSandboxConfig, error) {
|
||||
f, err := openFile(path)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func loadContainerConfig(path string) (*pb.ContainerConfig, error) {
|
||||
f, err := openFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var config pb.ContainerConfig
|
||||
if err := json.NewDecoder(f).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "ocic"
|
||||
app.Usage = "client for ocid"
|
||||
app.Version = "0.0.1"
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
podSandboxCommand,
|
||||
containerCommand,
|
||||
runtimeVersionCommand,
|
||||
imageCommand,
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "connect",
|
||||
Value: "/var/run/ocid.sock",
|
||||
Usage: "Socket to connect to",
|
||||
},
|
||||
cli.DurationFlag{
|
||||
Name: "timeout",
|
||||
Value: 10 * time.Second,
|
||||
Usage: "Timeout of connecting to server",
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
396
cmd/ocic/sandbox.go
Normal file
396
cmd/ocic/sandbox.go
Normal file
|
@ -0,0 +1,396 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var podSandboxCommand = cli.Command{
|
||||
Name: "pod",
|
||||
Subcommands: []cli.Command{
|
||||
runPodSandboxCommand,
|
||||
stopPodSandboxCommand,
|
||||
removePodSandboxCommand,
|
||||
podSandboxStatusCommand,
|
||||
listPodSandboxCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var runPodSandboxCommand = cli.Command{
|
||||
Name: "run",
|
||||
Usage: "run a pod",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config",
|
||||
Value: "",
|
||||
Usage: "the path of a pod sandbox config file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "the name of the pod sandbox",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "add key=value labels to the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
opts := createOptions{
|
||||
configPath: context.String("config"),
|
||||
name: context.String("name"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
// Test RuntimeServiceClient.RunPodSandbox
|
||||
err = RunPodSandbox(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating the pod sandbox failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stopPodSandboxCommand = cli.Command{
|
||||
Name: "stop",
|
||||
Usage: "stop a pod sandbox",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the pod sandbox",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = StopPodSandbox(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("stopping the pod sandbox failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var removePodSandboxCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "remove a pod sandbox",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the pod sandbox",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = RemovePodSandbox(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing the pod sandbox failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var podSandboxStatusCommand = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "return the status of a pod",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the pod",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = PodSandboxStatus(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting the pod sandbox status failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listPodSandboxCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list pod sandboxes",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "filter by pod sandbox id",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "state",
|
||||
Value: "",
|
||||
Usage: "filter by pod sandbox state",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "filter by key=value label",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "list only pod IDs",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
opts := listOptions{
|
||||
id: context.String("id"),
|
||||
state: context.String("state"),
|
||||
quiet: context.Bool("quiet"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
err = ListPodSandboxes(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing pod sandboxes failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// RunPodSandbox sends a RunPodSandboxRequest to the server, and parses
|
||||
// the returned RunPodSandboxResponse.
|
||||
func RunPodSandbox(client pb.RuntimeServiceClient, opts createOptions) error {
|
||||
config, err := loadPodSandboxConfig(opts.configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Override the name by the one specified through CLI
|
||||
if opts.name != "" {
|
||||
config.Metadata.Name = &opts.name
|
||||
}
|
||||
|
||||
for k, v := range opts.labels {
|
||||
config.Labels[k] = v
|
||||
}
|
||||
|
||||
r, err := client.RunPodSandbox(context.Background(), &pb.RunPodSandboxRequest{Config: config})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(*r.PodSandboxId)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopPodSandbox sends a StopPodSandboxRequest to the server, and parses
|
||||
// the returned StopPodSandboxResponse.
|
||||
func StopPodSandbox(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.StopPodSandbox(context.Background(), &pb.StopPodSandboxRequest{PodSandboxId: &ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemovePodSandbox sends a RemovePodSandboxRequest to the server, and parses
|
||||
// the returned RemovePodSandboxResponse.
|
||||
func RemovePodSandbox(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.RemovePodSandbox(context.Background(), &pb.RemovePodSandboxRequest{PodSandboxId: &ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PodSandboxStatus sends a PodSandboxStatusRequest to the server, and parses
|
||||
// the returned PodSandboxStatusResponse.
|
||||
func PodSandboxStatus(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.PodSandboxStatus(context.Background(), &pb.PodSandboxStatusRequest{PodSandboxId: &ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("ID: %s\n", *r.Status.Id)
|
||||
if r.Status.Metadata != nil {
|
||||
if r.Status.Metadata.Name != nil {
|
||||
fmt.Printf("Name: %s\n", *r.Status.Metadata.Name)
|
||||
}
|
||||
if r.Status.Metadata.Uid != nil {
|
||||
fmt.Printf("UID: %s\n", *r.Status.Metadata.Uid)
|
||||
}
|
||||
if r.Status.Metadata.Namespace != nil {
|
||||
fmt.Printf("Namespace: %s\n", *r.Status.Metadata.Namespace)
|
||||
}
|
||||
if r.Status.Metadata.Attempt != nil {
|
||||
fmt.Printf("Attempt: %v\n", *r.Status.Metadata.Attempt)
|
||||
}
|
||||
}
|
||||
if r.Status.State != nil {
|
||||
fmt.Printf("Status: %s\n", r.Status.State)
|
||||
}
|
||||
if r.Status.CreatedAt != nil {
|
||||
ctm := time.Unix(0, *r.Status.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
}
|
||||
if r.Status.Linux != nil {
|
||||
fmt.Printf("Network namespace: %s\n", *r.Status.Linux.Namespaces.Network)
|
||||
}
|
||||
if r.Status.Network != nil {
|
||||
fmt.Printf("IP Address: %v\n", *r.Status.Network.Ip)
|
||||
}
|
||||
if r.Status.Labels != nil {
|
||||
fmt.Println("Labels:")
|
||||
for _, k := range getSortedKeys(r.Status.Labels) {
|
||||
fmt.Printf("\t%s -> %s\n", k, r.Status.Labels[k])
|
||||
}
|
||||
}
|
||||
if r.Status.Annotations != nil {
|
||||
fmt.Println("Annotations:")
|
||||
for _, k := range getSortedKeys(r.Status.Annotations) {
|
||||
fmt.Printf("\t%s -> %s\n", k, r.Status.Annotations[k])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListPodSandboxes sends a ListPodSandboxRequest to the server, and parses
|
||||
// the returned ListPodSandboxResponse.
|
||||
func ListPodSandboxes(client pb.RuntimeServiceClient, opts listOptions) error {
|
||||
filter := &pb.PodSandboxFilter{}
|
||||
if opts.id != "" {
|
||||
filter.Id = &opts.id
|
||||
}
|
||||
if opts.state != "" {
|
||||
st := pb.PodSandboxState_SANDBOX_NOTREADY
|
||||
switch opts.state {
|
||||
case "ready":
|
||||
st = pb.PodSandboxState_SANDBOX_READY
|
||||
filter.State = &st
|
||||
case "notready":
|
||||
st = pb.PodSandboxState_SANDBOX_NOTREADY
|
||||
filter.State = &st
|
||||
default:
|
||||
log.Fatalf("--state should be ready or notready")
|
||||
}
|
||||
}
|
||||
if opts.labels != nil {
|
||||
filter.LabelSelector = opts.labels
|
||||
}
|
||||
r, err := client.ListPodSandbox(context.Background(), &pb.ListPodSandboxRequest{
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, pod := range r.Items {
|
||||
if opts.quiet {
|
||||
fmt.Println(*pod.Id)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("ID: %s\n", *pod.Id)
|
||||
if pod.Metadata != nil {
|
||||
if pod.Metadata.Name != nil {
|
||||
fmt.Printf("Name: %s\n", *pod.Metadata.Name)
|
||||
}
|
||||
if pod.Metadata.Uid != nil {
|
||||
fmt.Printf("UID: %s\n", *pod.Metadata.Uid)
|
||||
}
|
||||
if pod.Metadata.Namespace != nil {
|
||||
fmt.Printf("Namespace: %s\n", *pod.Metadata.Namespace)
|
||||
}
|
||||
if pod.Metadata.Attempt != nil {
|
||||
fmt.Printf("Attempt: %v\n", *pod.Metadata.Attempt)
|
||||
}
|
||||
}
|
||||
fmt.Printf("Status: %s\n", pod.State)
|
||||
ctm := time.Unix(0, *pod.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
if pod.Labels != nil {
|
||||
fmt.Println("Labels:")
|
||||
for _, k := range getSortedKeys(pod.Labels) {
|
||||
fmt.Printf("\t%s -> %s\n", k, pod.Labels[k])
|
||||
}
|
||||
}
|
||||
if pod.Annotations != nil {
|
||||
fmt.Println("Annotations:")
|
||||
for _, k := range getSortedKeys(pod.Annotations) {
|
||||
fmt.Printf("\t%s -> %s\n", k, pod.Annotations[k])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSortedKeys(m map[string]string) []string {
|
||||
var keys []string
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
return keys
|
||||
}
|
41
cmd/ocic/system.go
Normal file
41
cmd/ocic/system.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var runtimeVersionCommand = cli.Command{
|
||||
Name: "runtimeversion",
|
||||
Usage: "get runtime version information",
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
// Test RuntimeServiceClient.Version
|
||||
version := "v1alpha1"
|
||||
err = Version(client, version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting the runtime version failed: %v", err)
|
||||
}
|
||||
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})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("VersionResponse: Version: %s, RuntimeName: %s, RuntimeVersion: %s, RuntimeApiVersion: %s\n", *r.Version, *r.RuntimeName, *r.RuntimeVersion, *r.RuntimeApiVersion)
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue