client: Add crio client package
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
parent
4fadbea75d
commit
2e3d5240c2
6 changed files with 202 additions and 28 deletions
103
client/client.go
Normal file
103
client/client.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-o/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path)
|
||||||
|
)
|
||||||
|
|
||||||
|
// CrioClient is an interface to get information from crio daemon endpoint.
|
||||||
|
type CrioClient interface {
|
||||||
|
DaemonInfo() (types.CrioInfo, error)
|
||||||
|
ContainerInfo(string) (*types.ContainerInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type crioClientImpl struct {
|
||||||
|
client *http.Client
|
||||||
|
crioSocketPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
||||||
|
if len(addr) > maxUnixSocketPathSize {
|
||||||
|
return fmt.Errorf("Unix socket path %q is too long", addr)
|
||||||
|
}
|
||||||
|
// No need for compression in local communications.
|
||||||
|
tr.DisableCompression = true
|
||||||
|
tr.Dial = func(_, _ string) (net.Conn, error) {
|
||||||
|
return net.DialTimeout(proto, addr, 32*time.Second)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a crio client
|
||||||
|
func New(crioSocketPath string) (CrioClient, error) {
|
||||||
|
tr := new(http.Transport)
|
||||||
|
configureUnixTransport(tr, "unix", crioSocketPath)
|
||||||
|
c := &http.Client{
|
||||||
|
Transport: tr,
|
||||||
|
}
|
||||||
|
return &crioClientImpl{
|
||||||
|
client: c,
|
||||||
|
crioSocketPath: crioSocketPath,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *crioClientImpl) getRequest(path string) (*http.Request, error) {
|
||||||
|
req, err := http.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// For local communications over a unix socket, it doesn't matter what
|
||||||
|
// the host is. We just need a valid and meaningful host name.
|
||||||
|
req.Host = "crio"
|
||||||
|
req.URL.Host = c.crioSocketPath
|
||||||
|
req.URL.Scheme = "http"
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DaemonInfo return cri-o daemon info from the cri-o
|
||||||
|
// info endpoint.
|
||||||
|
func (c *crioClientImpl) DaemonInfo() (types.CrioInfo, error) {
|
||||||
|
info := types.CrioInfo{}
|
||||||
|
req, err := c.getRequest("/info")
|
||||||
|
if err != nil {
|
||||||
|
return info, err
|
||||||
|
}
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return info, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
|
||||||
|
return info, err
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerInfo returns container info by querying
|
||||||
|
// the cri-o container endpoint.
|
||||||
|
func (c *crioClientImpl) ContainerInfo(id string) (*types.ContainerInfo, error) {
|
||||||
|
req, err := c.getRequest("/containers/" + id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
cInfo := types.ContainerInfo{}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&cInfo); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &cInfo, nil
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -8,6 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-o/client"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
remocommandconsts "k8s.io/apimachinery/pkg/util/remotecommand"
|
remocommandconsts "k8s.io/apimachinery/pkg/util/remotecommand"
|
||||||
|
@ -21,6 +23,7 @@ var containerCommand = cli.Command{
|
||||||
Aliases: []string{"ctr"},
|
Aliases: []string{"ctr"},
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
createContainerCommand,
|
createContainerCommand,
|
||||||
|
inspectContainerCommand,
|
||||||
startContainerCommand,
|
startContainerCommand,
|
||||||
stopContainerCommand,
|
stopContainerCommand,
|
||||||
removeContainerCommand,
|
removeContainerCommand,
|
||||||
|
@ -617,3 +620,37 @@ func ListContainers(client pb.RuntimeServiceClient, opts listOptions) error {
|
||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
31
cmd/crioctl/info.go
Normal file
31
cmd/crioctl/info.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
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
|
||||||
|
},
|
||||||
|
}
|
|
@ -91,6 +91,7 @@ func main() {
|
||||||
containerCommand,
|
containerCommand,
|
||||||
runtimeVersionCommand,
|
runtimeVersionCommand,
|
||||||
imageCommand,
|
imageCommand,
|
||||||
|
infoCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
|
|
|
@ -9,32 +9,12 @@ import (
|
||||||
"github.com/go-zoo/bone"
|
"github.com/go-zoo/bone"
|
||||||
"github.com/kubernetes-incubator/cri-o/libkpod/sandbox"
|
"github.com/kubernetes-incubator/cri-o/libkpod/sandbox"
|
||||||
"github.com/kubernetes-incubator/cri-o/oci"
|
"github.com/kubernetes-incubator/cri-o/oci"
|
||||||
|
"github.com/kubernetes-incubator/cri-o/types"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerInfo stores information about containers
|
func (s *Server) getInfo() types.CrioInfo {
|
||||||
type ContainerInfo struct {
|
return types.CrioInfo{
|
||||||
Name string `json:"name"`
|
|
||||||
Pid int `json:"pid"`
|
|
||||||
Image string `json:"image"`
|
|
||||||
CreatedTime int64 `json:"created_time"`
|
|
||||||
Labels map[string]string `json:"labels"`
|
|
||||||
Annotations map[string]string `json:"annotations"`
|
|
||||||
LogPath string `json:"log_path"`
|
|
||||||
Root string `json:"root"`
|
|
||||||
Sandbox string `json:"sandbox"`
|
|
||||||
IP string `json:"ip_address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CrioInfo stores information about the crio daemon
|
|
||||||
type CrioInfo struct {
|
|
||||||
StorageDriver string `json:"storage_driver"`
|
|
||||||
StorageRoot string `json:"storage_root"`
|
|
||||||
CgroupDriver string `json:"cgroup_driver"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) getInfo() CrioInfo {
|
|
||||||
return CrioInfo{
|
|
||||||
StorageDriver: s.config.Config.Storage,
|
StorageDriver: s.config.Config.Storage,
|
||||||
StorageRoot: s.config.Config.Root,
|
StorageRoot: s.config.Config.Root,
|
||||||
CgroupDriver: s.config.Config.CgroupManager,
|
CgroupDriver: s.config.Config.CgroupManager,
|
||||||
|
@ -47,25 +27,25 @@ var (
|
||||||
errSandboxNotFound = errors.New("sandbox for container not found")
|
errSandboxNotFound = errors.New("sandbox for container not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) getContainerInfo(id string, getContainerFunc func(id string) *oci.Container, getInfraContainerFunc func(id string) *oci.Container, getSandboxFunc func(id string) *sandbox.Sandbox) (ContainerInfo, error) {
|
func (s *Server) getContainerInfo(id string, getContainerFunc func(id string) *oci.Container, getInfraContainerFunc func(id string) *oci.Container, getSandboxFunc func(id string) *sandbox.Sandbox) (types.ContainerInfo, error) {
|
||||||
ctr := getContainerFunc(id)
|
ctr := getContainerFunc(id)
|
||||||
if ctr == nil {
|
if ctr == nil {
|
||||||
ctr = getInfraContainerFunc(id)
|
ctr = getInfraContainerFunc(id)
|
||||||
if ctr == nil {
|
if ctr == nil {
|
||||||
return ContainerInfo{}, errCtrNotFound
|
return types.ContainerInfo{}, errCtrNotFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(mrunalp): should we call UpdateStatus()?
|
// TODO(mrunalp): should we call UpdateStatus()?
|
||||||
ctrState := ctr.State()
|
ctrState := ctr.State()
|
||||||
if ctrState == nil {
|
if ctrState == nil {
|
||||||
return ContainerInfo{}, errCtrStateNil
|
return types.ContainerInfo{}, errCtrStateNil
|
||||||
}
|
}
|
||||||
sb := getSandboxFunc(ctr.Sandbox())
|
sb := getSandboxFunc(ctr.Sandbox())
|
||||||
if sb == nil {
|
if sb == nil {
|
||||||
logrus.Debugf("can't find sandbox %s for container %s", ctr.Sandbox(), id)
|
logrus.Debugf("can't find sandbox %s for container %s", ctr.Sandbox(), id)
|
||||||
return ContainerInfo{}, errSandboxNotFound
|
return types.ContainerInfo{}, errSandboxNotFound
|
||||||
}
|
}
|
||||||
return ContainerInfo{
|
return types.ContainerInfo{
|
||||||
Name: ctr.Name(),
|
Name: ctr.Name(),
|
||||||
Pid: ctrState.Pid,
|
Pid: ctrState.Pid,
|
||||||
Image: ctr.Image(),
|
Image: ctr.Image(),
|
||||||
|
|
22
types/types.go
Normal file
22
types/types.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
// ContainerInfo stores information about containers
|
||||||
|
type ContainerInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Pid int `json:"pid"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
CreatedTime int64 `json:"created_time"`
|
||||||
|
Labels map[string]string `json:"labels"`
|
||||||
|
Annotations map[string]string `json:"annotations"`
|
||||||
|
LogPath string `json:"log_path"`
|
||||||
|
Root string `json:"root"`
|
||||||
|
Sandbox string `json:"sandbox"`
|
||||||
|
IP string `json:"ip_address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrioInfo stores information about the crio daemon
|
||||||
|
type CrioInfo struct {
|
||||||
|
StorageDriver string `json:"storage_driver"`
|
||||||
|
StorageRoot string `json:"storage_root"`
|
||||||
|
CgroupDriver string `json:"cgroup_driver"`
|
||||||
|
}
|
Loading…
Reference in a new issue