2017-10-29 09:45:21 +00:00
|
|
|
package services
|
|
|
|
|
|
|
|
import (
|
2017-11-14 18:11:21 +00:00
|
|
|
"fmt"
|
2018-01-11 01:00:14 +00:00
|
|
|
"time"
|
2017-11-14 18:11:21 +00:00
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
"context"
|
|
|
|
|
2018-01-11 01:00:14 +00:00
|
|
|
etcdclient "github.com/coreos/etcd/client"
|
2017-10-29 09:45:21 +00:00
|
|
|
"github.com/docker/docker/api/types/container"
|
2017-10-31 13:55:35 +00:00
|
|
|
"github.com/rancher/rke/docker"
|
2017-10-29 09:45:21 +00:00
|
|
|
"github.com/rancher/rke/hosts"
|
2018-01-09 22:10:56 +00:00
|
|
|
"github.com/rancher/rke/log"
|
2018-01-16 23:10:14 +00:00
|
|
|
"github.com/rancher/rke/pki"
|
2017-12-05 16:55:58 +00:00
|
|
|
"github.com/rancher/types/apis/management.cattle.io/v3"
|
2018-01-11 01:00:14 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-10-29 09:45:21 +00:00
|
|
|
)
|
|
|
|
|
2018-01-31 17:50:55 +00:00
|
|
|
func RunEtcdPlane(ctx context.Context, etcdHosts []*hosts.Host, etcdService v3.ETCDService, localConnDialerFactory hosts.DialerFactory, prsMap map[string]v3.PrivateRegistry) error {
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "[%s] Building up Etcd Plane..", ETCDRole)
|
2017-11-15 01:12:33 +00:00
|
|
|
initCluster := getEtcdInitialCluster(etcdHosts)
|
2017-10-29 09:45:21 +00:00
|
|
|
for _, host := range etcdHosts {
|
2018-01-31 17:50:55 +00:00
|
|
|
|
2018-01-16 23:10:14 +00:00
|
|
|
nodeName := pki.GetEtcdCrtName(host.InternalAddress)
|
|
|
|
imageCfg, hostCfg := buildEtcdConfig(host, etcdService, initCluster, nodeName)
|
2018-01-31 17:50:55 +00:00
|
|
|
err := docker.DoRunContainer(ctx, host.DClient, imageCfg, hostCfg, EtcdContainerName, host.Address, ETCDRole, prsMap)
|
2017-10-29 09:45:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "[%s] Successfully started Etcd Plane..", ETCDRole)
|
2017-10-29 09:45:21 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-01-19 01:48:51 +00:00
|
|
|
func RemoveEtcdPlane(ctx context.Context, etcdHosts []*hosts.Host, force bool) error {
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "[%s] Tearing down Etcd Plane..", ETCDRole)
|
2017-11-20 18:08:50 +00:00
|
|
|
for _, host := range etcdHosts {
|
2018-01-09 22:10:56 +00:00
|
|
|
err := docker.DoRemoveContainer(ctx, host.DClient, EtcdContainerName, host.Address)
|
2017-11-20 18:08:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-01-19 01:48:51 +00:00
|
|
|
if !host.IsWorker || !host.IsControl || force {
|
|
|
|
// remove unschedulable kubelet on etcd host
|
|
|
|
if err := removeKubelet(ctx, host); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := removeKubeproxy(ctx, host); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := removeNginxProxy(ctx, host); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := removeSidekick(ctx, host); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-20 18:08:50 +00:00
|
|
|
}
|
2018-01-23 23:02:22 +00:00
|
|
|
log.Infof(ctx, "[%s] Successfully tore down Etcd Plane..", ETCDRole)
|
2017-11-20 18:08:50 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-01-16 23:10:14 +00:00
|
|
|
func buildEtcdConfig(host *hosts.Host, etcdService v3.ETCDService, initCluster, nodeName string) (*container.Config, *container.HostConfig) {
|
2018-01-11 01:00:14 +00:00
|
|
|
clusterState := "new"
|
|
|
|
if host.ExistingEtcdCluster {
|
|
|
|
clusterState = "existing"
|
|
|
|
}
|
2017-10-29 09:45:21 +00:00
|
|
|
imageCfg := &container.Config{
|
2017-11-02 10:07:10 +00:00
|
|
|
Image: etcdService.Image,
|
2017-10-29 09:45:21 +00:00
|
|
|
Cmd: []string{"/usr/local/bin/etcd",
|
2017-11-28 17:45:24 +00:00
|
|
|
"--name=etcd-" + host.HostnameOverride,
|
2017-10-29 09:45:21 +00:00
|
|
|
"--data-dir=/etcd-data",
|
2018-01-16 23:10:14 +00:00
|
|
|
"--advertise-client-urls=https://" + host.InternalAddress + ":2379,https://" + host.InternalAddress + ":4001",
|
|
|
|
"--listen-client-urls=https://0.0.0.0:2379",
|
|
|
|
"--initial-advertise-peer-urls=https://" + host.InternalAddress + ":2380",
|
|
|
|
"--listen-peer-urls=https://0.0.0.0:2380",
|
2017-10-29 09:45:21 +00:00
|
|
|
"--initial-cluster-token=etcd-cluster-1",
|
2017-11-15 01:12:33 +00:00
|
|
|
"--initial-cluster=" + initCluster,
|
2018-01-16 23:10:14 +00:00
|
|
|
"--initial-cluster-state=" + clusterState,
|
|
|
|
"--peer-client-cert-auth",
|
|
|
|
"--client-cert-auth",
|
|
|
|
"--trusted-ca-file=" + pki.GetCertPath(pki.CACertName),
|
|
|
|
"--peer-trusted-ca-file=" + pki.GetCertPath(pki.CACertName),
|
|
|
|
"--cert-file=" + pki.GetCertPath(nodeName),
|
|
|
|
"--key-file=" + pki.GetKeyPath(nodeName),
|
|
|
|
"--peer-cert-file=" + pki.GetCertPath(nodeName),
|
|
|
|
"--peer-key-file=" + pki.GetKeyPath(nodeName),
|
|
|
|
},
|
2017-10-29 09:45:21 +00:00
|
|
|
}
|
|
|
|
hostCfg := &container.HostConfig{
|
|
|
|
RestartPolicy: container.RestartPolicy{Name: "always"},
|
|
|
|
Binds: []string{
|
2018-01-25 21:29:21 +00:00
|
|
|
"/var/lib/etcd:/etcd-data:z",
|
|
|
|
"/etc/kubernetes:/etc/kubernetes:z",
|
2018-01-16 23:10:14 +00:00
|
|
|
},
|
2018-01-15 21:01:58 +00:00
|
|
|
NetworkMode: "host",
|
2017-10-29 09:45:21 +00:00
|
|
|
}
|
2017-11-14 18:11:21 +00:00
|
|
|
for arg, value := range etcdService.ExtraArgs {
|
|
|
|
cmd := fmt.Sprintf("--%s=%s", arg, value)
|
2017-11-30 23:16:45 +00:00
|
|
|
imageCfg.Entrypoint = append(imageCfg.Entrypoint, cmd)
|
2017-11-14 18:11:21 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 13:55:35 +00:00
|
|
|
return imageCfg, hostCfg
|
2017-10-29 09:45:21 +00:00
|
|
|
}
|
|
|
|
|
2018-01-16 23:10:14 +00:00
|
|
|
func AddEtcdMember(ctx context.Context, etcdHost *hosts.Host, etcdHosts []*hosts.Host, localConnDialerFactory hosts.DialerFactory, cert, key []byte) error {
|
2018-01-11 01:00:14 +00:00
|
|
|
log.Infof(ctx, "[add/%s] Adding member [etcd-%s] to etcd cluster", ETCDRole, etcdHost.HostnameOverride)
|
2018-01-16 23:10:14 +00:00
|
|
|
peerURL := fmt.Sprintf("https://%s:2380", etcdHost.InternalAddress)
|
2018-01-11 01:00:14 +00:00
|
|
|
added := false
|
|
|
|
for _, host := range etcdHosts {
|
2018-01-16 23:10:14 +00:00
|
|
|
etcdClient, err := getEtcdClient(ctx, host, localConnDialerFactory, cert, key)
|
2018-01-11 01:00:14 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Debugf("Failed to create etcd client for host [%s]: %v", host.Address, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
memAPI := etcdclient.NewMembersAPI(etcdClient)
|
|
|
|
if _, err := memAPI.Add(ctx, peerURL); err != nil {
|
|
|
|
logrus.Debugf("Failed to list etcd members from host [%s]: %v", host.Address, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
added = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if !added {
|
|
|
|
return fmt.Errorf("Failed to add etcd member [etcd-%s] from etcd cluster", etcdHost.HostnameOverride)
|
|
|
|
}
|
|
|
|
log.Infof(ctx, "[add/%s] Successfully Added member [etcd-%s] to etcd cluster", ETCDRole, etcdHost.HostnameOverride)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-01-16 23:10:14 +00:00
|
|
|
func RemoveEtcdMember(ctx context.Context, etcdHost *hosts.Host, etcdHosts []*hosts.Host, localConnDialerFactory hosts.DialerFactory, cert, key []byte) error {
|
2018-01-11 01:00:14 +00:00
|
|
|
log.Infof(ctx, "[remove/%s] Removing member [etcd-%s] from etcd cluster", ETCDRole, etcdHost.HostnameOverride)
|
|
|
|
var mID string
|
|
|
|
removed := false
|
|
|
|
for _, host := range etcdHosts {
|
2018-01-16 23:10:14 +00:00
|
|
|
etcdClient, err := getEtcdClient(ctx, host, localConnDialerFactory, cert, key)
|
2018-01-11 01:00:14 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Debugf("Failed to create etcd client for host [%s]: %v", host.Address, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
memAPI := etcdclient.NewMembersAPI(etcdClient)
|
|
|
|
members, err := memAPI.List(ctx)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Debugf("Failed to list etcd members from host [%s]: %v", host.Address, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, member := range members {
|
|
|
|
if member.Name == fmt.Sprintf("etcd-%s", etcdHost.HostnameOverride) {
|
|
|
|
mID = member.ID
|
|
|
|
break
|
|
|
|
}
|
2017-10-29 09:45:21 +00:00
|
|
|
}
|
2018-01-11 01:00:14 +00:00
|
|
|
if err := memAPI.Remove(ctx, mID); err != nil {
|
|
|
|
logrus.Debugf("Failed to list etcd members from host [%s]: %v", host.Address, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
removed = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if !removed {
|
|
|
|
return fmt.Errorf("Failed to delete etcd member [etcd-%s] from etcd cluster", etcdHost.HostnameOverride)
|
2017-10-29 09:45:21 +00:00
|
|
|
}
|
2018-01-11 01:00:14 +00:00
|
|
|
log.Infof(ctx, "[remove/%s] Successfully removed member [etcd-%s] from etcd cluster", ETCDRole, etcdHost.HostnameOverride)
|
|
|
|
return nil
|
2017-10-29 09:45:21 +00:00
|
|
|
}
|
2017-11-15 01:12:33 +00:00
|
|
|
|
2018-01-31 17:50:55 +00:00
|
|
|
func ReloadEtcdCluster(ctx context.Context, etcdHosts []*hosts.Host, etcdService v3.ETCDService, localConnDialerFactory hosts.DialerFactory, cert, key []byte, prsMap map[string]v3.PrivateRegistry) error {
|
2018-01-11 01:00:14 +00:00
|
|
|
readyEtcdHosts := []*hosts.Host{}
|
|
|
|
for _, host := range etcdHosts {
|
|
|
|
if !host.ToAddEtcdMember {
|
|
|
|
readyEtcdHosts = append(readyEtcdHosts, host)
|
|
|
|
host.ExistingEtcdCluster = true
|
2017-11-15 01:12:33 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-11 01:00:14 +00:00
|
|
|
initCluster := getEtcdInitialCluster(readyEtcdHosts)
|
|
|
|
for _, host := range readyEtcdHosts {
|
2018-01-16 23:10:14 +00:00
|
|
|
imageCfg, hostCfg := buildEtcdConfig(host, etcdService, initCluster, pki.GetEtcdCrtName(host.InternalAddress))
|
2018-01-31 17:50:55 +00:00
|
|
|
if err := docker.DoRunContainer(ctx, host.DClient, imageCfg, hostCfg, EtcdContainerName, host.Address, ETCDRole, prsMap); err != nil {
|
2018-01-11 01:00:14 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
2018-01-16 23:10:14 +00:00
|
|
|
var healthy bool
|
2018-01-11 01:00:14 +00:00
|
|
|
for _, host := range readyEtcdHosts {
|
2018-01-16 23:10:14 +00:00
|
|
|
if healthy = isEtcdHealthy(ctx, localConnDialerFactory, host, cert, key); healthy {
|
2018-01-11 01:00:14 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2018-01-16 23:10:14 +00:00
|
|
|
if !healthy {
|
|
|
|
return fmt.Errorf("[etcd] Etcd Cluster is not healthy")
|
|
|
|
}
|
2018-01-11 01:00:14 +00:00
|
|
|
return nil
|
2017-11-15 01:12:33 +00:00
|
|
|
}
|