blob: b5e38222125827f74288a3f8f081089fef03d19c [file] [log] [blame]
Pawel Wieczorek6b223c92019-05-26 15:35:02 +02001// Package rancher wraps Rancher commands necessary for K8s inspection.
2package rancher
3
4import (
5 "bytes"
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +02006 "fmt"
Pawel Wieczorek6b223c92019-05-26 15:35:02 +02007 "os/exec"
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +02008
9 "check"
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020010)
11
12const (
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"
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020021 cmdDockerCmdPsFilterArgs = "label=io.rancher.stack_service.name="
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020022 cmdDockerCmdPsFormat = "--format"
23 cmdDockerCmdPsFormatArgs = "{{.Command}}"
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020024)
25
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020026// Rancher implements Informer interface.
27type Rancher struct {
28 check.Informer
29}
30
31// GetAPIParams returns parameters of running Kubernetes API server.
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020032// It queries default environment set in configuration file.
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020033func (r *Rancher) GetAPIParams() ([]string, error) {
34 return getProcessParams(check.APIProcess, check.APIService)
35}
36
Pawel Wieczorek96f4e2f2019-09-27 16:10:33 +020037// GetSchedulerParams returns parameters of running Kubernetes scheduler.
38// It queries default environment set in configuration file.
39func (r *Rancher) GetSchedulerParams() ([]string, error) {
40 return getProcessParams(check.SchedulerProcess, check.SchedulerService)
41}
42
Pawel Wieczorek5a61d612019-09-27 18:26:13 +020043// GetControllerManagerParams returns parameters of running Kubernetes scheduler.
44// It queries default environment set in configuration file.
45func (r *Rancher) GetControllerManagerParams() ([]string, error) {
46 return getProcessParams(check.ControllerManagerProcess, check.ControllerManagerService)
47}
48
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020049func getProcessParams(process check.Command, service check.Service) ([]string, error) {
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020050 hosts, err := listHosts()
51 if err != nil {
52 return []string{}, err
53 }
54
55 for _, host := range hosts {
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020056 cmd, err := getPsCmdOutput(host, service)
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020057 if err != nil {
58 return []string{}, err
59 }
60
Pawel Wieczorek752f7fe2019-09-30 14:39:32 +020061 cmd = trimOutput(cmd) // TODO: improve `docker ps` query format.
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020062 if len(cmd) > 0 {
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020063 i := bytes.Index(cmd, []byte(process.String()))
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020064 if i == -1 {
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020065 return []string{}, fmt.Errorf("missing %s command", process)
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020066 }
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020067 return btos(cmd[i+len(process.String()):]), nil
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020068 }
69 }
70 return []string{}, nil
71}
72
73// listHosts lists IDs of active hosts.
74// It queries default environment set in configuration file.
75func listHosts() ([]string, error) {
76 cmd := exec.Command(bin, cmdHosts, cmdHostsParams)
77 out, err := cmd.Output()
78 if err != nil {
79 return nil, err
80 }
81 return btos(out), nil
82}
83
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020084// getPsCmdOutput returns running Kubernetes service command with its parameters.
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020085// It queries default environment set in configuration file.
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020086func getPsCmdOutput(host string, service check.Service) ([]byte, error) {
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020087 // Following is equivalent to:
88 // $ rancher --host $HOST \
89 // docker ps --no-trunc \
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020090 // --filter "label=io.rancher.stack_service.name=$SERVICE" \
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020091 // --format "{{.Command}}"
92 cmd := exec.Command(bin, paramHost, host,
93 cmdDocker, cmdDockerCmdPs, cmdDockerCmdPsParams,
Pawel Wieczorek76dd9bf2019-09-26 16:43:01 +020094 cmdDockerCmdPsFilter, cmdDockerCmdPsFilterArgs+service.String(),
Pawel Wieczorek6b223c92019-05-26 15:35:02 +020095 cmdDockerCmdPsFormat, cmdDockerCmdPsFormatArgs)
96 out, err := cmd.Output()
97 if err != nil {
98 return nil, err
99 }
100 return out, nil
101}
102
Pawel Wieczorek752f7fe2019-09-30 14:39:32 +0200103// trimOutput removes trailing new line and brackets from output.
104func trimOutput(b []byte) []byte {
105 b = bytes.TrimSpace(b)
106 b = bytes.TrimPrefix(b, []byte("["))
107 b = bytes.TrimSuffix(b, []byte("]"))
108 return b
109}
110
Pawel Wieczorek6b223c92019-05-26 15:35:02 +0200111// btos converts slice of bytes to slice of strings split by white space characters.
112func btos(in []byte) []string {
113 var out []string
114 for _, b := range bytes.Fields(in) {
115 out = append(out, string(b))
116 }
117 return out
118}