1 // Package raw wraps SSH commands necessary for K8s inspection.
11 "golang.org/x/crypto/ssh"
12 kh "golang.org/x/crypto/ssh/knownhosts"
19 controlplane = "controlplane"
23 knownHostsFile = "~/.ssh/known_hosts"
26 // Raw implements Informer interface.
31 // GetAPIParams returns parameters of running Kubernetes API servers.
32 // It queries only cluster nodes with "controlplane" role.
33 func (r *Raw) GetAPIParams() ([]string, error) {
34 return getProcessParams(check.APIProcess)
37 // GetSchedulerParams returns parameters of running Kubernetes scheduler.
38 // It queries only cluster nodes with "controlplane" role.
39 func (r *Raw) GetSchedulerParams() ([]string, error) {
40 return getProcessParams(check.SchedulerProcess)
43 func getProcessParams(process check.Command) ([]string, error) {
44 nodes, err := config.GetNodesInfo()
46 return []string{}, err
49 for _, node := range nodes {
50 if isControlplaneNode(node.Role) {
51 cmd, err := getInspectCmdOutput(node, process)
53 return []string{}, err
57 i := bytes.Index(cmd, []byte(process.String()))
59 return []string{}, fmt.Errorf("missing %s command", process)
61 return btos(cmd[i+len(process.String()):]), nil
66 return []string{}, nil
69 func isControlplaneNode(roles []string) bool {
70 for _, role := range roles {
71 if role == controlplane {
78 func getInspectCmdOutput(node config.NodeInfo, cmd check.Command) ([]byte, error) {
79 path, err := expandPath(node.SSHKeyPath)
84 pubKey, err := parsePublicKey(path)
89 khPath, err := expandPath(knownHostsFile)
94 hostKeyCallback, err := kh.New(khPath)
99 config := &ssh.ClientConfig{
101 Auth: []ssh.AuthMethod{pubKey},
102 HostKeyCallback: hostKeyCallback,
105 conn, err := ssh.Dial("tcp", node.Address+":"+node.Port, config)
111 out, err := runCommand(fmt.Sprintf("docker inspect %s --format {{.Args}}", cmd), conn)
118 func expandPath(path string) (string, error) {
119 if len(path) == 0 || path[0] != '~' {
123 usr, err := user.Current()
127 return filepath.Join(usr.HomeDir, path[1:]), nil
130 func parsePublicKey(path string) (ssh.AuthMethod, error) {
131 key, err := ioutil.ReadFile(path)
135 signer, err := ssh.ParsePrivateKey(key)
139 return ssh.PublicKeys(signer), nil
142 func runCommand(cmd string, conn *ssh.Client) ([]byte, error) {
143 sess, err := conn.NewSession()
148 out, err := sess.Output(cmd)
155 // btos converts slice of bytes to slice of strings split by white space characters.
156 func btos(in []byte) []string {
158 for _, b := range bytes.Fields(in) {
159 out = append(out, string(b))