Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 1 | // Package rancher wraps Rancher commands necessary for K8s inspection. |
| 2 | package rancher |
| 3 | |
| 4 | import ( |
| 5 | "bytes" |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 6 | "fmt" |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 7 | "os/exec" |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 8 | |
| 9 | "check" |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 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" |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 21 | cmdDockerCmdPsFilterArgs = "label=io.rancher.stack_service.name=" |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 22 | cmdDockerCmdPsFormat = "--format" |
| 23 | cmdDockerCmdPsFormatArgs = "{{.Command}}" |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 24 | ) |
| 25 | |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 26 | // Rancher implements Informer interface. |
| 27 | type Rancher struct { |
| 28 | check.Informer |
| 29 | } |
| 30 | |
| 31 | // GetAPIParams returns parameters of running Kubernetes API server. |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 32 | // It queries default environment set in configuration file. |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 33 | func (r *Rancher) GetAPIParams() ([]string, error) { |
| 34 | return getProcessParams(check.APIProcess, check.APIService) |
| 35 | } |
| 36 | |
Pawel Wieczorek | 96f4e2f | 2019-09-27 16:10:33 +0200 | [diff] [blame] | 37 | // GetSchedulerParams returns parameters of running Kubernetes scheduler. |
| 38 | // It queries default environment set in configuration file. |
| 39 | func (r *Rancher) GetSchedulerParams() ([]string, error) { |
| 40 | return getProcessParams(check.SchedulerProcess, check.SchedulerService) |
| 41 | } |
| 42 | |
Pawel Wieczorek | 5a61d61 | 2019-09-27 18:26:13 +0200 | [diff] [blame] | 43 | // GetControllerManagerParams returns parameters of running Kubernetes scheduler. |
| 44 | // It queries default environment set in configuration file. |
| 45 | func (r *Rancher) GetControllerManagerParams() ([]string, error) { |
| 46 | return getProcessParams(check.ControllerManagerProcess, check.ControllerManagerService) |
| 47 | } |
| 48 | |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 49 | func getProcessParams(process check.Command, service check.Service) ([]string, error) { |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 50 | hosts, err := listHosts() |
| 51 | if err != nil { |
| 52 | return []string{}, err |
| 53 | } |
| 54 | |
| 55 | for _, host := range hosts { |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 56 | cmd, err := getPsCmdOutput(host, service) |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 57 | if err != nil { |
| 58 | return []string{}, err |
| 59 | } |
| 60 | |
Pawel Wieczorek | 752f7fe | 2019-09-30 14:39:32 +0200 | [diff] [blame] | 61 | cmd = trimOutput(cmd) // TODO: improve `docker ps` query format. |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 62 | if len(cmd) > 0 { |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 63 | i := bytes.Index(cmd, []byte(process.String())) |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 64 | if i == -1 { |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 65 | return []string{}, fmt.Errorf("missing %s command", process) |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 66 | } |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 67 | return btos(cmd[i+len(process.String()):]), nil |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 68 | } |
| 69 | } |
| 70 | return []string{}, nil |
| 71 | } |
| 72 | |
| 73 | // listHosts lists IDs of active hosts. |
| 74 | // It queries default environment set in configuration file. |
| 75 | func 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 Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 84 | // getPsCmdOutput returns running Kubernetes service command with its parameters. |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 85 | // It queries default environment set in configuration file. |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 86 | func getPsCmdOutput(host string, service check.Service) ([]byte, error) { |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 87 | // Following is equivalent to: |
| 88 | // $ rancher --host $HOST \ |
| 89 | // docker ps --no-trunc \ |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 90 | // --filter "label=io.rancher.stack_service.name=$SERVICE" \ |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 91 | // --format "{{.Command}}" |
| 92 | cmd := exec.Command(bin, paramHost, host, |
| 93 | cmdDocker, cmdDockerCmdPs, cmdDockerCmdPsParams, |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 94 | cmdDockerCmdPsFilter, cmdDockerCmdPsFilterArgs+service.String(), |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 95 | cmdDockerCmdPsFormat, cmdDockerCmdPsFormatArgs) |
| 96 | out, err := cmd.Output() |
| 97 | if err != nil { |
| 98 | return nil, err |
| 99 | } |
| 100 | return out, nil |
| 101 | } |
| 102 | |
Pawel Wieczorek | 752f7fe | 2019-09-30 14:39:32 +0200 | [diff] [blame] | 103 | // trimOutput removes trailing new line and brackets from output. |
| 104 | func 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 Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 111 | // btos converts slice of bytes to slice of strings split by white space characters. |
| 112 | func 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 | } |