drop crioctl source code

Signed-off-by: Wei Wei <weiwei.inf@gmail.com>
This commit is contained in:
Wei Wei 2017-11-20 13:59:24 +08:00
parent 5f5a7a3648
commit 3006a2159a
13 changed files with 45 additions and 1470 deletions

View File

@ -32,7 +32,6 @@ jobs:
- make .gitvalidation
- make gofmt
- make lint
- make verify
- make testunit
- make docs
- make
@ -42,14 +41,12 @@ jobs:
- make .gitvalidation
- make gofmt
- make lint
- make verify
- make testunit
- make docs
- make
go: 1.9.x
- script:
- make .gitvalidation
- make verify
- make testunit
- make docs
- make

View File

@ -46,7 +46,7 @@ help:
@echo "Usage: make <target>"
@echo
@echo " * 'install' - Install binaries to system locations"
@echo " * 'binaries' - Build crio, conmon, pause, and crioctl"
@echo " * 'binaries' - Build crio, conmon and pause"
@echo " * 'integration' - Execute integration tests"
@echo " * 'clean' - Clean artifacts"
@echo " * 'lint' - Execute the source code linter"
@ -66,9 +66,6 @@ lint: .gopathok
gofmt:
@./hack/verify-gofmt.sh
verify:
@./hack/validate/deprecate-crioctl
conmon:
$(MAKE) -C $@
@ -87,9 +84,6 @@ test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go)
crio: .gopathok $(shell hack/find-godeps.sh $(GOPKGDIR) cmd/crio $(PROJECT))
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS) containers_image_ostree_stub" -o bin/$@ $(PROJECT)/cmd/crio
crioctl: .gopathok $(shell hack/find-godeps.sh $(GOPKGDIR) cmd/crioctl $(PROJECT))
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS) containers_image_ostree_stub" -o bin/$@ $(PROJECT)/cmd/crioctl
crio.conf: crio
./bin/crio --config="" config --default > crio.conf
@ -102,7 +96,7 @@ endif
rm -fr test/testdata/redis-image
find . -name \*~ -delete
find . -name \#\* -delete
rm -f bin/crioctl bin/crio
rm -f bin/crio
make -C conmon clean
make -C pause clean
rm -f test/bin2img/bin2img
@ -124,7 +118,7 @@ testunit:
localintegration: clean binaries test-binaries
./test/test_runner.sh ${TESTFLAGS}
binaries: crio conmon pause crioctl
binaries: crio conmon pause
test-binaries: test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp
MANPAGES_MD := $(wildcard docs/*.md)
@ -142,7 +136,6 @@ install: .gopathok install.bin install.man
install.bin:
install ${SELINUXOPT} -D -m 755 bin/crio $(BINDIR)/crio
install ${SELINUXOPT} -D -m 755 bin/crioctl $(BINDIR)/crioctl
install ${SELINUXOPT} -D -m 755 bin/conmon $(LIBEXECDIR)/crio/conmon
install ${SELINUXOPT} -D -m 755 bin/pause $(LIBEXECDIR)/crio/pause
@ -168,7 +161,6 @@ install.systemd:
uninstall:
rm -f $(BINDIR)/crio
rm -f $(BINDIR)/crioctl
rm -f $(LIBEXECDIR)/crio/conmon
rm -f $(LIBEXECDIR)/crio/pause
for i in $(filter %.1,$(MANPAGES)); do \

View File

@ -28,8 +28,7 @@ storage_driver = "{{ .Storage }}"
storage_option = [
{{ range $opt := .StorageOptions }}{{ printf "\t%q,\n" $opt }}{{ end }}]
# The "crio.api" table contains settings for the kubelet/gRPC
# interface (which is also used by crioctl).
# The "crio.api" table contains settings for the kubelet/gRPC interface.
[crio.api]
# listen is the path to the AF_LOCAL socket on which crio will listen.

View File

@ -1,654 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"strings"
"time"
"github.com/kubernetes-incubator/cri-o/client"
"github.com/urfave/cli"
"golang.org/x/net/context"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)
var containerCommand = cli.Command{
Name: "container",
Aliases: []string{"ctr"},
Subcommands: []cli.Command{
createContainerCommand,
inspectContainerCommand,
startContainerCommand,
stopContainerCommand,
removeContainerCommand,
containerStatusCommand,
listContainersCommand,
execSyncCommand,
execCommand,
},
}
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",
},
cli.Int64Flag{
Name: "timeout",
Value: 10,
Usage: "seconds to wait to kill the container after a graceful stop is requested",
},
},
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"), context.Int64("timeout"))
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
},
}
var execCommand = cli.Command{
Name: "exec",
Usage: "prepare a streaming endpoint to execute a command in the container",
Flags: []cli.Flag{
cli.StringFlag{
Name: "id",
Value: "",
Usage: "id of the container",
},
cli.BoolFlag{
Name: "tty",
Usage: "whether to use tty",
},
cli.BoolFlag{
Name: "stdin",
Usage: "whether to stream to stdin",
},
cli.BoolFlag{
Name: "url",
Usage: "do not exec command, just prepare streaming endpoint",
},
},
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 = Exec(client, context.String("id"), context.Bool("tty"), context.Bool("stdin"), context.Bool("url"), context.Args())
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, timeout int64) error {
if ID == "" {
return fmt.Errorf("ID cannot be empty")
}
_, err := client.StopContainer(context.Background(), &pb.StopContainerRequest{
ContainerId: ID,
Timeout: timeout,
})
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 != "" {
fmt.Printf("Name: %s\n", r.Status.Metadata.Name)
}
fmt.Printf("Attempt: %v\n", r.Status.Metadata.Attempt)
}
// TODO(mzylowski): print it prettier
fmt.Printf("Status: %s\n", r.Status.State)
ctm := time.Unix(0, r.Status.CreatedAt)
fmt.Printf("Created: %v\n", ctm)
stm := time.Unix(0, r.Status.StartedAt)
fmt.Printf("Started: %v\n", stm)
ftm := time.Unix(0, r.Status.FinishedAt)
fmt.Printf("Finished: %v\n", ftm)
fmt.Printf("Exit Code: %v\n", r.Status.ExitCode)
fmt.Printf("Reason: %v\n", r.Status.Reason)
if r.Status.Image != nil {
fmt.Printf("Image: %v\n", r.Status.Image.Image)
}
//
// TODO: https://github.com/kubernetes-incubator/cri-o/issues/531
//
//fmt.Printf("ImageRef: %v\n", r.Status.ImageRef)
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
}
// Exec sends an ExecRequest to the server, and parses
// the returned ExecResponse.
func Exec(client pb.RuntimeServiceClient, ID string, tty bool, stdin bool, urlOnly bool, cmd []string) error {
if ID == "" {
return fmt.Errorf("ID cannot be empty")
}
r, err := client.Exec(context.Background(), &pb.ExecRequest{
ContainerId: ID,
Cmd: cmd,
Tty: tty,
Stdin: stdin,
})
if err != nil {
return err
}
if urlOnly {
fmt.Println("URL:")
fmt.Println(r.Url)
return nil
}
execURL, err := url.Parse(r.Url)
if err != nil {
return err
}
streamExec, err := remotecommand.NewSPDYExecutor(&restclient.Config{}, "GET", execURL)
if err != nil {
return err
}
options := remotecommand.StreamOptions{
Stdout: os.Stdout,
Stderr: os.Stderr,
Tty: tty,
}
if stdin {
options.Stdin = os.Stdin
}
return streamExec.Stream(options)
}
// 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.ContainerStateValue{}
st.State = pb.ContainerState_CONTAINER_UNKNOWN
switch opts.state {
case "created":
st.State = pb.ContainerState_CONTAINER_CREATED
filter.State = st
case "running":
st.State = pb.ContainerState_CONTAINER_RUNNING
filter.State = st
case "stopped":
st.State = 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 != "" {
fmt.Printf("Name: %s\n", c.Metadata.Name)
}
fmt.Printf("Attempt: %v\n", c.Metadata.Attempt)
}
fmt.Printf("Status: %s\n", c.State)
if c.Image != nil {
fmt.Printf("Image: %s\n", c.Image.Image)
}
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
}
var inspectContainerCommand = cli.Command{
Name: "inspect",
Usage: "get container info from crio daemon",
Flags: []cli.Flag{
cli.StringFlag{
Name: "id",
Value: "",
Usage: "id of the container",
},
},
Action: func(context *cli.Context) error {
ID := context.String("id")
if ID == "" {
return fmt.Errorf("ID cannot be empty")
}
c, err := client.New(context.GlobalString("connect"))
if err != nil {
return err
}
cInfo, err := c.ContainerInfo(ID)
if err != nil {
return err
}
jsonBytes, err := json.MarshalIndent(cInfo, "", " ")
if err != nil {
return err
}
fmt.Println(string(jsonBytes))
return nil
},
}

View File

@ -1,173 +0,0 @@
package main
import (
"fmt"
"github.com/urfave/cli"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/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_ != 0 {
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)
}
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}})
}

View File

@ -1,31 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"github.com/kubernetes-incubator/cri-o/client"
"github.com/urfave/cli"
)
var infoCommand = cli.Command{
Name: "info",
Usage: "get crio daemon info",
Action: func(context *cli.Context) error {
c, err := client.New(context.GlobalString("connect"))
if err != nil {
return err
}
di, err := c.DaemonInfo()
if err != nil {
return err
}
jsonBytes, err := json.MarshalIndent(di, "", " ")
if err != nil {
return err
}
fmt.Println(string(jsonBytes))
return nil
},
}

View File

@ -1,113 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"net"
"os"
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"google.golang.org/grpc"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)
// This is populated by the Makefile from the VERSION file
// in the repository
var version = ""
// gitCommit is the commit that the binary is being built from.
// It will be populated by the Makefile.
var gitCommit = ""
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()
var v []string
if version != "" {
v = append(v, version)
}
if gitCommit != "" {
v = append(v, fmt.Sprintf("commit: %s", gitCommit))
}
app.Name = "crioctl"
app.Usage = "client for crio"
app.Version = strings.Join(v, "\n")
app.Commands = []cli.Command{
podSandboxCommand,
containerCommand,
runtimeVersionCommand,
imageCommand,
infoCommand,
}
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "connect",
Value: "/var/run/crio/crio.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)
}
}

View File

@ -1,386 +0,0 @@
package main
import (
"fmt"
"log"
"sort"
"strings"
"time"
"github.com/urfave/cli"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/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 != "" {
fmt.Printf("Name: %s\n", r.Status.Metadata.Name)
}
if r.Status.Metadata.Uid != "" {
fmt.Printf("UID: %s\n", r.Status.Metadata.Uid)
}
if r.Status.Metadata.Namespace != "" {
fmt.Printf("Namespace: %s\n", r.Status.Metadata.Namespace)
}
fmt.Printf("Attempt: %v\n", r.Status.Metadata.Attempt)
}
fmt.Printf("Status: %s\n", r.Status.State)
ctm := time.Unix(0, r.Status.CreatedAt)
fmt.Printf("Created: %v\n", ctm)
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.PodSandboxStateValue{}
st.State = pb.PodSandboxState_SANDBOX_NOTREADY
switch opts.state {
case "ready":
st.State = pb.PodSandboxState_SANDBOX_READY
filter.State = st
case "notready":
st.State = 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 != "" {
fmt.Printf("Name: %s\n", pod.Metadata.Name)
}
if pod.Metadata.Uid != "" {
fmt.Printf("UID: %s\n", pod.Metadata.Uid)
}
if pod.Metadata.Namespace != "" {
fmt.Printf("Namespace: %s\n", pod.Metadata.Namespace)
}
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
}

View File

@ -1,41 +0,0 @@
package main
import (
"fmt"
"github.com/urfave/cli"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/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
}

View File

@ -1 +1 @@
runtime-endpoint: /var/run/crio.sock
runtime-endpoint: /var/run/crio/crio.sock

View File

@ -1,31 +0,0 @@
#!/usr/bin/env bash
# Check that no new tests are being added using crioctl
export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "${SCRIPTDIR}/.validate"
IFS=$'\n'
files=( $(validate_diff --diff-filter=ACMR --name-only -- 'test/*.bats' || true) )
unset IFS
badFiles=()
for f in "${files[@]}"; do
# we use "git show" here to validate that what's committed doesn't contain crioctl calls
if git show "$VALIDATE_HEAD:$f" | grep -q crioctl; then
badFiles+=( "$f" )
fi
done
if [ ${#badFiles[@]} -eq 0 ]; then
echo 'Congratulations! No new tests have been added using crioctl.'
else
{
echo "These files use crioctl instead of crictl:"
echo ""
for f in "${badFiles[@]}"; do
echo " - $f"
done
echo
} >&2
false
fi

View File

@ -7,8 +7,8 @@ This document outlines useful information for ops and dev transfer as it relates
## Abstract
The `crio` daemon is intended to provide the [CRI](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md) socket needed for Kubernetes to use for automating deployment, scaling, and management of containerized applications (See the document for [configuring kubernetes to use CRI-O](./kubernetes.md) for more information on that).
Therefore the `crioctl` command line is a client that interfaces to the same grpc socket as the kubernetes daemon would, for talking to the `crio` daemon.
In many ways `crioctl` is only as feature rich as the Kubernetes CRI requires.
Therefore the [crictl](https://github.com/kubernetes-incubator/cri-tools) command line is a client that interfaces to the same grpc socket as the kubernetes daemon would, for talking to the `crio` daemon.
In many ways [crictl](https://github.com/kubernetes-incubator/cri-tools) is only as feature rich as the Kubernetes CRI requires.
There are additional tools e.g. `kpod` and [`buildah`](https://github.com/projectatomic/buildah) that provide a feature rich set of commands for all operational needs in a Kubernetes environment.
@ -24,12 +24,12 @@ Following provides equivalent with CRI-O tools for gathering information or jump
| Existing Step | CRI-O (and friends) |
| :---: | :---: |
| `docker exec` | [`crioctl ctr exec`](./docs/crio.8.md) |
| `docker exec` | [`crictl exec`](https://github.com/kubernetes-incubator/cri-tools/blob/master/docs/crictl.md) |
| `docker info` | [`kpod info`](./docs/kpod-info.1.md) |
| `docker inspect` | [`kpod inspect`](./docs/kpod-inspect.1.md) |
| `docker logs` | [`kpod logs`](./docs/kpod-logs.1.md) |
| `docker ps` | [`crioctl ctr list`](./docs/crio.8.md) or [`runc list`](https://github.com/opencontainers/runc/blob/master/man/runc-list.8.md) |
| `docker stats` | [`kpod stats`](./docs/kpod-stats.1.md) or `crioctl ctr status`|
| `docker ps` | [`crictl ps`](https://github.com/kubernetes-incubator/cri-tools/blob/master/docs/crictl.md) or [`runc list`](https://github.com/opencontainers/runc/blob/master/man/runc-list.8.md) |
| `docker stats` | [`kpod stats`](./docs/kpod-stats.1.md) |
If you were already using steps like `kubectl exec` (or `oc exec` on OpenShift), they will continue to function the same way.

View File

@ -26,7 +26,7 @@ gcloud compute ssh cri-o
This section will walk you through installing the following components:
* crio - The implementation of the Kubernetes CRI, which manages Pods.
* crioctl - The crio client for testing.
* crictl - The CRI client for testing.
* cni - The Container Network Interface
* runc - The OCI runtime to launch the container
@ -100,6 +100,12 @@ go version
go version go1.7.4 linux/amd64
```
#### Get crictl
```
go get github.com/kubernetes-incubator/cri-tools/cmd/crictl
```
#### Build crio from source
```
@ -130,7 +136,6 @@ Output:
```
install -D -m 755 crio /usr/local/bin/crio
install -D -m 755 crioctl /usr/local/bin/crioctl
install -D -m 755 conmon/conmon /usr/local/libexec/crio/conmon
install -D -m 755 pause/pause /usr/local/libexec/crio/pause
install -d -m 755 /usr/local/share/man/man{1,5,8}
@ -182,12 +187,19 @@ sudo systemctl start crio
#### Ensure the crio service is running
```
sudo crioctl runtimeversion
sudo crictl --runtime-endpoint /var/run/crio/crio.sock info
```
```
VersionResponse: Version: 0.1.0, RuntimeName: runc, RuntimeVersion: 1.0.0-rc4, RuntimeApiVersion: v1alpha1
Version: 0.1.0
RuntimeName: cri-o
RuntimeVersion: 1.9.0-dev
RuntimeApiVersion: v1alpha1
```
> to avoid set --runtime-endpoint when call crictl,
> you can export $CRI_RUNTIME_ENDPOINT=/var/run/crio/crio.sock
> or cp crictl.yaml /etc/crictl.yaml from this repo
### CNI plugins
This tutorial will use the latest version of `CNI` plugins from the master branch and build it from source.
@ -288,13 +300,15 @@ cd $GOPATH/src/github.com/kubernetes-incubator/cri-o
Next create the Pod and capture the Pod ID for later use:
```
POD_ID=$(sudo crioctl pod run --config test/testdata/sandbox_config.json)
POD_ID=$(sudo crictl runs test/testdata/sandbox_config.json)
```
Use the `crioctl` command to get the status of the Pod:
> sudo crictl runs test/testdata/sandbox_config.json
Use the `crictl` command to get the status of the Pod:
```
sudo crioctl pod status --id $POD_ID
sudo crictl inspects --output table $POD_ID
```
Output:
@ -320,25 +334,27 @@ Annotations:
### Create a Redis container inside the Pod
Use the `crioctl` command to pull the redis image, create a redis container from a container configuration and attach it to the Pod created earlier:
Use the `crictl` command to pull the redis image, create a redis container from a container configuration and attach it to the Pod created earlier:
```
sudo crioctl image pull redis:alpine
CONTAINER_ID=$(sudo crioctl ctr create --pod $POD_ID --config test/testdata/container_redis.json)
sudo crictl pull redis:alpine
CONTAINER_ID=$(sudo crictl create $POD_ID test/testdata/container_redis.json test/testdata/sandbox_config.json)
```
The `crioctl ctr create` command will take a few seconds to return because the redis container needs to be pulled.
> sudo crictl create $POD_ID test/testdata/container_redis.json test/testdata/sandbox_config.json
The `crictl create` command will take a few seconds to return because the redis container needs to be pulled.
Start the Redis container:
```
sudo crioctl ctr start --id $CONTAINER_ID
sudo crictl start $CONTAINER_ID
```
Get the status for the Redis container:
```
sudo crioctl ctr status --id $CONTAINER_ID
sudo crictl inspect $CONTAINER_ID
```
Output:
@ -395,25 +411,25 @@ sudo journalctl -u crio --no-pager
### Stop the redis container and delete the Pod
```
sudo crioctl ctr stop --id $CONTAINER_ID
sudo crictl stop $CONTAINER_ID
```
```
sudo crioctl ctr remove --id $CONTAINER_ID
sudo crictl rm $CONTAINER_ID
```
```
sudo crioctl pod stop --id $POD_ID
sudo crictl stops $POD_ID
```
```
sudo crioctl pod remove --id $POD_ID
sudo crictl rms $POD_ID
```
```
sudo crioctl pod list
sudo crictl sandboxes
```
```
sudo crioctl ctr list
sudo crictl ps
```