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 | |
| 37 | func getProcessParams(process check.Command, service check.Service) ([]string, error) { |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 38 | hosts, err := listHosts() |
| 39 | if err != nil { |
| 40 | return []string{}, err |
| 41 | } |
| 42 | |
| 43 | for _, host := range hosts { |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 44 | cmd, err := getPsCmdOutput(host, service) |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 45 | if err != nil { |
| 46 | return []string{}, err |
| 47 | } |
| 48 | |
| 49 | if len(cmd) > 0 { |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 50 | i := bytes.Index(cmd, []byte(process.String())) |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 51 | if i == -1 { |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 52 | return []string{}, fmt.Errorf("missing %s command", process) |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 53 | } |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 54 | return btos(cmd[i+len(process.String()):]), nil |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 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 | |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 71 | // getPsCmdOutput returns running Kubernetes service command with its parameters. |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 72 | // It queries default environment set in configuration file. |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 73 | func getPsCmdOutput(host string, service check.Service) ([]byte, error) { |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 74 | // Following is equivalent to: |
| 75 | // $ rancher --host $HOST \ |
| 76 | // docker ps --no-trunc \ |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 77 | // --filter "label=io.rancher.stack_service.name=$SERVICE" \ |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 78 | // --format "{{.Command}}" |
| 79 | cmd := exec.Command(bin, paramHost, host, |
| 80 | cmdDocker, cmdDockerCmdPs, cmdDockerCmdPsParams, |
Pawel Wieczorek | 76dd9bf | 2019-09-26 16:43:01 +0200 | [diff] [blame] | 81 | cmdDockerCmdPsFilter, cmdDockerCmdPsFilterArgs+service.String(), |
Pawel Wieczorek | 6b223c9 | 2019-05-26 15:35:02 +0200 | [diff] [blame] | 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 | } |