d77f15445ef3690dcbf5a94139ad3412279276c7
[integration.git] / test / security / k8s / src / check / rancher / rancher.go
1 // Package rancher wraps Rancher commands necessary for K8s inspection.
2 package rancher
3
4 import (
5         "bytes"
6         "fmt"
7         "os/exec"
8
9         "check"
10 )
11
12 const (
13         bin                      = "rancher"
14         paramHost                = "--host"
15         cmdHosts                 = "hosts"
16         cmdHostsParams           = "--quiet"
17         cmdDocker                = "docker"
18         cmdDockerCmdPs           = "ps"
19         cmdDockerCmdPsParams     = "--no-trunc"
20         cmdDockerCmdPsFilter     = "--filter"
21         cmdDockerCmdPsFilterArgs = "label=io.rancher.stack_service.name="
22         cmdDockerCmdPsFormat     = "--format"
23         cmdDockerCmdPsFormatArgs = "{{.Command}}"
24 )
25
26 // Rancher implements Informer interface.
27 type Rancher struct {
28         check.Informer
29 }
30
31 // GetAPIParams returns parameters of running Kubernetes API server.
32 // It queries default environment set in configuration file.
33 func (r *Rancher) GetAPIParams() ([]string, error) {
34         return getProcessParams(check.APIProcess, check.APIService)
35 }
36
37 func getProcessParams(process check.Command, service check.Service) ([]string, error) {
38         hosts, err := listHosts()
39         if err != nil {
40                 return []string{}, err
41         }
42
43         for _, host := range hosts {
44                 cmd, err := getPsCmdOutput(host, service)
45                 if err != nil {
46                         return []string{}, err
47                 }
48
49                 if len(cmd) > 0 {
50                         i := bytes.Index(cmd, []byte(process.String()))
51                         if i == -1 {
52                                 return []string{}, fmt.Errorf("missing %s command", process)
53                         }
54                         return btos(cmd[i+len(process.String()):]), nil
55                 }
56         }
57         return []string{}, nil
58 }
59
60 // listHosts lists IDs of active hosts.
61 // It queries default environment set in configuration file.
62 func listHosts() ([]string, error) {
63         cmd := exec.Command(bin, cmdHosts, cmdHostsParams)
64         out, err := cmd.Output()
65         if err != nil {
66                 return nil, err
67         }
68         return btos(out), nil
69 }
70
71 // getPsCmdOutput returns running Kubernetes service command with its parameters.
72 // It queries default environment set in configuration file.
73 func getPsCmdOutput(host string, service check.Service) ([]byte, error) {
74         // Following is equivalent to:
75         // $ rancher --host $HOST \
76         //   docker ps --no-trunc \
77         //   --filter "label=io.rancher.stack_service.name=$SERVICE" \
78         //   --format "{{.Command}}"
79         cmd := exec.Command(bin, paramHost, host,
80                 cmdDocker, cmdDockerCmdPs, cmdDockerCmdPsParams,
81                 cmdDockerCmdPsFilter, cmdDockerCmdPsFilterArgs+service.String(),
82                 cmdDockerCmdPsFormat, cmdDockerCmdPsFormatArgs)
83         out, err := cmd.Output()
84         if err != nil {
85                 return nil, err
86         }
87         return out, nil
88 }
89
90 // btos converts slice of bytes to slice of strings split by white space characters.
91 func btos(in []byte) []string {
92         var out []string
93         for _, b := range bytes.Fields(in) {
94                 out = append(out, string(b))
95         }
96         return out
97 }