2017-11-02 10:07:10 +00:00
|
|
|
package cluster
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-11-17 21:33:07 +00:00
|
|
|
"os"
|
2017-11-30 15:53:11 +00:00
|
|
|
"path/filepath"
|
2017-11-17 21:33:07 +00:00
|
|
|
"strings"
|
|
|
|
"syscall"
|
2017-11-02 10:07:10 +00:00
|
|
|
|
|
|
|
"github.com/rancher/rke/hosts"
|
|
|
|
"github.com/rancher/rke/pki"
|
|
|
|
"github.com/rancher/rke/services"
|
2017-11-13 21:28:38 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-11-17 21:33:07 +00:00
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
"golang.org/x/crypto/ssh/terminal"
|
2017-11-02 10:07:10 +00:00
|
|
|
)
|
|
|
|
|
2017-11-21 20:26:26 +00:00
|
|
|
const (
|
|
|
|
DefaultSSHKeyPath = "/.ssh/id_rsa"
|
|
|
|
)
|
|
|
|
|
2017-11-02 10:07:10 +00:00
|
|
|
func (c *Cluster) TunnelHosts() error {
|
2017-11-21 20:26:26 +00:00
|
|
|
key, err := checkEncryptedKey(c.SSHKeyPath)
|
2017-11-17 21:33:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to parse the private key: %v", err)
|
|
|
|
}
|
2017-11-02 10:07:10 +00:00
|
|
|
for i := range c.EtcdHosts {
|
2017-11-17 21:33:07 +00:00
|
|
|
err := c.EtcdHosts[i].TunnelUp(key)
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to set up SSH tunneling for Etcd hosts: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := range c.ControlPlaneHosts {
|
2017-11-17 21:33:07 +00:00
|
|
|
err := c.ControlPlaneHosts[i].TunnelUp(key)
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to set up SSH tunneling for Control hosts: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := range c.WorkerHosts {
|
2017-11-17 21:33:07 +00:00
|
|
|
err := c.WorkerHosts[i].TunnelUp(key)
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to set up SSH tunneling for Worker hosts: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cluster) InvertIndexHosts() error {
|
2017-11-30 23:16:45 +00:00
|
|
|
c.EtcdHosts = make([]*hosts.Host, 0)
|
|
|
|
c.WorkerHosts = make([]*hosts.Host, 0)
|
|
|
|
c.ControlPlaneHosts = make([]*hosts.Host, 0)
|
2017-11-28 17:45:24 +00:00
|
|
|
for _, host := range c.Nodes {
|
2017-11-30 23:16:45 +00:00
|
|
|
newHost := hosts.Host{
|
|
|
|
RKEConfigNode: host,
|
|
|
|
}
|
2017-11-02 10:07:10 +00:00
|
|
|
for _, role := range host.Role {
|
2017-11-28 17:45:24 +00:00
|
|
|
logrus.Debugf("Host: " + host.Address + " has role: " + role)
|
2017-11-02 10:07:10 +00:00
|
|
|
switch role {
|
|
|
|
case services.ETCDRole:
|
2017-11-30 23:16:45 +00:00
|
|
|
c.EtcdHosts = append(c.EtcdHosts, &newHost)
|
2017-11-02 10:07:10 +00:00
|
|
|
case services.ControlRole:
|
2017-11-30 23:16:45 +00:00
|
|
|
newHost.IsControl = true
|
|
|
|
c.ControlPlaneHosts = append(c.ControlPlaneHosts, &newHost)
|
2017-11-02 10:07:10 +00:00
|
|
|
case services.WorkerRole:
|
2017-11-30 23:16:45 +00:00
|
|
|
newHost.IsWorker = true
|
|
|
|
c.WorkerHosts = append(c.WorkerHosts, &newHost)
|
2017-11-02 10:07:10 +00:00
|
|
|
default:
|
2017-11-28 17:45:24 +00:00
|
|
|
return fmt.Errorf("Failed to recognize host [%s] role %s", host.Address, role)
|
2017-11-02 10:07:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-11-09 19:50:49 +00:00
|
|
|
func (c *Cluster) SetUpHosts() error {
|
2017-11-14 18:11:21 +00:00
|
|
|
if c.Authentication.Strategy == X509AuthenticationProvider {
|
2017-11-02 10:07:10 +00:00
|
|
|
logrus.Infof("[certificates] Deploying kubernetes certificates to Cluster nodes")
|
|
|
|
err := pki.DeployCertificatesOnMasters(c.ControlPlaneHosts, c.Certificates)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = pki.DeployCertificatesOnWorkers(c.WorkerHosts, c.Certificates)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-11-15 01:12:33 +00:00
|
|
|
err = pki.DeployAdminConfig(c.Certificates[pki.KubeAdminCommonName].Config, c.LocalKubeConfigPath)
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
logrus.Infof("[certificates] Successfully deployed kubernetes certificates to Cluster nodes")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2017-11-17 21:33:07 +00:00
|
|
|
|
2017-11-26 20:09:26 +00:00
|
|
|
func CheckEtcdHostsChanged(kubeCluster, currentCluster *Cluster) error {
|
2017-11-26 23:27:39 +00:00
|
|
|
if currentCluster != nil {
|
|
|
|
etcdChanged := hosts.IsHostListChanged(currentCluster.EtcdHosts, kubeCluster.EtcdHosts)
|
|
|
|
if etcdChanged {
|
|
|
|
return fmt.Errorf("Adding or removing Etcd nodes is not supported")
|
|
|
|
}
|
2017-11-26 20:09:26 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-11-21 20:26:26 +00:00
|
|
|
func checkEncryptedKey(sshKeyPath string) (ssh.Signer, error) {
|
2017-11-17 21:33:07 +00:00
|
|
|
logrus.Infof("[ssh] Checking private key")
|
2017-11-21 20:26:26 +00:00
|
|
|
key, err := hosts.ParsePrivateKey(privateKeyPath(sshKeyPath))
|
2017-11-17 21:33:07 +00:00
|
|
|
if err != nil {
|
|
|
|
if strings.Contains(err.Error(), "decode encrypted private keys") {
|
|
|
|
fmt.Printf("Passphrase for Private SSH Key: ")
|
|
|
|
passphrase, err := terminal.ReadPassword(int(syscall.Stdin))
|
|
|
|
fmt.Printf("\n")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-11-21 20:26:26 +00:00
|
|
|
key, err = hosts.ParsePrivateKeyWithPassPhrase(privateKeyPath(sshKeyPath), passphrase)
|
2017-11-17 21:33:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return key, nil
|
|
|
|
}
|
|
|
|
|
2017-11-21 20:26:26 +00:00
|
|
|
func privateKeyPath(sshKeyPath string) string {
|
|
|
|
if len(sshKeyPath) == 0 {
|
|
|
|
return os.Getenv("HOME") + DefaultSSHKeyPath
|
2017-11-30 15:53:11 +00:00
|
|
|
} else if sshKeyPath[:2] == "~/" {
|
|
|
|
return filepath.Join(os.Getenv("HOME"), sshKeyPath[2:])
|
2017-11-21 20:26:26 +00:00
|
|
|
}
|
|
|
|
return sshKeyPath
|
2017-11-17 21:33:07 +00:00
|
|
|
}
|