2017-11-06 20:50:41 +00:00
package cluster
import (
2018-01-09 22:10:56 +00:00
"context"
2017-11-21 23:49:30 +00:00
"fmt"
2018-01-16 18:29:09 +00:00
"net"
2019-04-13 14:43:34 +00:00
"strconv"
2018-01-16 18:29:09 +00:00
"strings"
2017-11-21 23:49:30 +00:00
2018-01-16 18:29:09 +00:00
"github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
"github.com/rancher/rke/docker"
"github.com/rancher/rke/hosts"
2018-01-09 22:10:56 +00:00
"github.com/rancher/rke/log"
2017-11-21 23:49:30 +00:00
"github.com/rancher/rke/pki"
2017-12-16 03:37:45 +00:00
"github.com/rancher/rke/templates"
2018-10-17 22:26:54 +00:00
"github.com/rancher/rke/util"
2018-01-31 17:50:55 +00:00
"github.com/rancher/types/apis/management.cattle.io/v3"
2018-01-16 18:29:09 +00:00
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
2017-11-06 20:50:41 +00:00
)
const (
2017-11-30 14:49:00 +00:00
NetworkPluginResourceName = "rke-network-plugin"
2017-12-05 01:29:29 +00:00
2018-01-18 20:41:04 +00:00
PortCheckContainer = "rke-port-checker"
EtcdPortListenContainer = "rke-etcd-port-listener"
CPPortListenContainer = "rke-cp-port-listener"
WorkerPortListenContainer = "rke-worker-port-listener"
2018-01-16 18:29:09 +00:00
2019-04-13 14:43:34 +00:00
KubeAPIPort = "6443"
EtcdPort1 = "2379"
EtcdPort2 = "2380"
ScedulerPort = "10251"
ControllerPort = "10252"
KubeletPort = "10250"
KubeProxyPort = "10256"
FlannelVxLanPort = 8472
FlannelVxLanNetworkIdentify = 1
2018-01-16 18:29:09 +00:00
2018-02-13 00:47:56 +00:00
ProtocolTCP = "TCP"
ProtocolUDP = "UDP"
2018-11-28 00:23:15 +00:00
NoNetworkPlugin = "none"
2017-12-05 01:29:29 +00:00
FlannelNetworkPlugin = "flannel"
2017-12-12 16:14:18 +00:00
FlannelIface = "flannel_iface"
2018-05-30 08:30:12 +00:00
FlannelBackendType = "flannel_backend_type"
2019-04-13 14:43:34 +00:00
// FlannelBackendPort must be 4789 if using VxLan mode in the cluster with Windows nodes
FlannelBackendPort = "flannel_backend_port"
// FlannelBackendVxLanNetworkIdentify should be greater than or equal to 4096 if using VxLan mode in the cluster with Windows nodes
FlannelBackendVxLanNetworkIdentify = "flannel_backend_vni"
2017-12-05 01:29:29 +00:00
2019-08-08 17:10:44 +00:00
CalicoNetworkPlugin = "calico"
CalicoNodeLabel = "calico-node"
CalicoControllerLabel = "calico-kube-controllers"
CalicoCloudProvider = "calico_cloud_provider"
2017-12-05 01:29:29 +00:00
2018-05-30 08:30:12 +00:00
CanalNetworkPlugin = "canal"
CanalIface = "canal_iface"
CanalFlannelBackendType = "canal_flannel_backend_type"
2019-04-13 14:43:34 +00:00
// CanalFlannelBackendPort must be 4789 if using Flannel VxLan mode in the cluster with Windows nodes
CanalFlannelBackendPort = "canal_flannel_backend_port"
// CanalFlannelBackendVxLanNetworkIdentify should be greater than or equal to 4096 if using Flannel VxLan mode in the cluster with Windows nodes
CanalFlannelBackendVxLanNetworkIdentify = "canal_flannel_backend_vni"
2017-12-06 03:53:51 +00:00
2019-03-07 18:29:46 +00:00
WeaveNetworkPlugin = "weave"
2019-08-08 17:10:44 +00:00
WeaveNetworkAppName = "weave-net"
2017-12-16 03:37:45 +00:00
// List of map keys to be used with network templates
// EtcdEndpoints is the server address for Etcd, used by calico
EtcdEndpoints = "EtcdEndpoints"
// APIRoot is the kubernetes API address
APIRoot = "APIRoot"
// kubernetes client certificates and kubeconfig paths
2018-02-14 20:58:35 +00:00
EtcdClientCert = "EtcdClientCert"
EtcdClientKey = "EtcdClientKey"
EtcdClientCA = "EtcdClientCA"
EtcdClientCertPath = "EtcdClientCertPath"
EtcdClientKeyPath = "EtcdClientKeyPath"
EtcdClientCAPath = "EtcdClientCAPath"
2018-01-16 23:10:14 +00:00
ClientCertPath = "ClientCertPath"
ClientKeyPath = "ClientKeyPath"
ClientCAPath = "ClientCAPath"
KubeCfg = "KubeCfg"
2017-12-16 03:37:45 +00:00
ClusterCIDR = "ClusterCIDR"
// Images key names
2018-05-17 00:27:47 +00:00
Image = "Image"
CNIImage = "CNIImage"
NodeImage = "NodeImage"
ControllersImage = "ControllersImage"
CanalFlannelImg = "CanalFlannelImg"
2019-08-23 16:43:56 +00:00
FlexVolImg = "FlexVolImg"
2018-05-17 00:27:47 +00:00
WeaveLoopbackImage = "WeaveLoopbackImage"
2017-12-16 03:37:45 +00:00
Calicoctl = "Calicoctl"
FlannelInterface = "FlannelInterface"
2018-05-30 08:30:12 +00:00
FlannelBackend = "FlannelBackend"
2018-04-26 03:10:53 +00:00
CanalInterface = "CanalInterface"
2018-07-18 04:29:48 +00:00
WeavePassword = "WeavePassword"
2017-12-16 03:37:45 +00:00
RBACConfig = "RBACConfig"
2018-10-05 00:41:18 +00:00
ClusterVersion = "ClusterVersion"
2017-11-06 20:50:41 +00:00
)
2018-02-13 00:47:56 +00:00
var EtcdPortList = [ ] string {
EtcdPort1 ,
EtcdPort2 ,
}
var ControlPlanePortList = [ ] string {
KubeAPIPort ,
}
var WorkerPortList = [ ] string {
KubeletPort ,
}
2018-06-07 20:47:37 +00:00
var EtcdClientPortList = [ ] string {
EtcdPort1 ,
}
2019-08-08 17:10:44 +00:00
var CalicoNetworkLabels = [ ] string { CalicoNodeLabel , CalicoControllerLabel }
2019-06-17 20:52:15 +00:00
func ( c * Cluster ) deployNetworkPlugin ( ctx context . Context , data map [ string ] interface { } ) error {
2018-01-09 22:10:56 +00:00
log . Infof ( ctx , "[network] Setting up network plugin: %s" , c . Network . Plugin )
2017-11-21 23:49:30 +00:00
switch c . Network . Plugin {
2017-11-28 17:45:24 +00:00
case FlannelNetworkPlugin :
2019-06-17 20:52:15 +00:00
return c . doFlannelDeploy ( ctx , data )
2017-11-28 17:45:24 +00:00
case CalicoNetworkPlugin :
2019-06-17 20:52:15 +00:00
return c . doCalicoDeploy ( ctx , data )
2017-11-28 17:45:24 +00:00
case CanalNetworkPlugin :
2019-06-17 20:52:15 +00:00
return c . doCanalDeploy ( ctx , data )
2017-11-30 11:35:31 +00:00
case WeaveNetworkPlugin :
2019-06-17 20:52:15 +00:00
return c . doWeaveDeploy ( ctx , data )
2018-11-28 00:23:15 +00:00
case NoNetworkPlugin :
log . Infof ( ctx , "[network] Not deploying a cluster network, expecting custom CNI" )
return nil
2017-11-21 23:49:30 +00:00
default :
return fmt . Errorf ( "[network] Unsupported network plugin: %s" , c . Network . Plugin )
}
}
2017-11-08 17:45:51 +00:00
2019-06-17 20:52:15 +00:00
func ( c * Cluster ) doFlannelDeploy ( ctx context . Context , data map [ string ] interface { } ) error {
2019-04-13 14:43:34 +00:00
vni , err := atoiWithDefault ( c . Network . Options [ FlannelBackendVxLanNetworkIdentify ] , FlannelVxLanNetworkIdentify )
if err != nil {
return err
}
port , err := atoiWithDefault ( c . Network . Options [ FlannelBackendPort ] , FlannelVxLanPort )
if err != nil {
return err
}
2018-05-30 08:30:12 +00:00
flannelConfig := map [ string ] interface { } {
2017-12-16 03:37:45 +00:00
ClusterCIDR : c . ClusterCIDR ,
2018-02-05 15:50:39 +00:00
Image : c . SystemImages . Flannel ,
CNIImage : c . SystemImages . FlannelCNI ,
2017-12-16 03:37:45 +00:00
FlannelInterface : c . Network . Options [ FlannelIface ] ,
2018-05-30 08:30:12 +00:00
FlannelBackend : map [ string ] interface { } {
"Type" : c . Network . Options [ FlannelBackendType ] ,
2019-04-13 14:43:34 +00:00
"VNI" : vni ,
"Port" : port ,
2018-05-30 08:30:12 +00:00
} ,
2018-10-05 00:41:18 +00:00
RBACConfig : c . Authorization . Mode ,
2019-02-26 23:14:01 +00:00
ClusterVersion : util . GetTagMajorVersion ( c . Version ) ,
2017-12-16 03:37:45 +00:00
}
2019-06-17 20:52:15 +00:00
pluginYaml , err := c . getNetworkPluginManifest ( flannelConfig , data )
2017-12-16 03:37:45 +00:00
if err != nil {
return err
2017-12-12 16:14:18 +00:00
}
2018-05-07 21:51:09 +00:00
return c . doAddonDeploy ( ctx , pluginYaml , NetworkPluginResourceName , true )
2017-11-21 23:49:30 +00:00
}
2017-11-18 12:51:28 +00:00
2019-06-17 20:52:15 +00:00
func ( c * Cluster ) doCalicoDeploy ( ctx context . Context , data map [ string ] interface { } ) error {
2018-01-16 23:10:14 +00:00
clientConfig := pki . GetConfigPath ( pki . KubeNodeCertName )
2019-08-23 16:43:56 +00:00
2018-05-30 08:30:12 +00:00
calicoConfig := map [ string ] interface { } {
2019-07-11 20:59:03 +00:00
KubeCfg : clientConfig ,
ClusterCIDR : c . ClusterCIDR ,
CNIImage : c . SystemImages . CalicoCNI ,
NodeImage : c . SystemImages . CalicoNode ,
Calicoctl : c . SystemImages . CalicoCtl ,
ControllersImage : c . SystemImages . CalicoControllers ,
CloudProvider : c . Network . Options [ CalicoCloudProvider ] ,
2019-08-23 16:43:56 +00:00
FlexVolImg : c . SystemImages . CalicoFlexVol ,
2019-07-11 20:59:03 +00:00
RBACConfig : c . Authorization . Mode ,
2017-12-16 03:37:45 +00:00
}
2019-06-17 20:52:15 +00:00
pluginYaml , err := c . getNetworkPluginManifest ( calicoConfig , data )
2017-12-16 03:37:45 +00:00
if err != nil {
return err
2017-12-05 01:29:29 +00:00
}
2018-05-07 21:51:09 +00:00
return c . doAddonDeploy ( ctx , pluginYaml , NetworkPluginResourceName , true )
2017-11-21 23:49:30 +00:00
}
2019-06-17 20:52:15 +00:00
func ( c * Cluster ) doCanalDeploy ( ctx context . Context , data map [ string ] interface { } ) error {
2019-04-13 14:43:34 +00:00
flannelVni , err := atoiWithDefault ( c . Network . Options [ CanalFlannelBackendVxLanNetworkIdentify ] , FlannelVxLanNetworkIdentify )
if err != nil {
return err
}
flannelPort , err := atoiWithDefault ( c . Network . Options [ CanalFlannelBackendPort ] , FlannelVxLanPort )
if err != nil {
return err
}
2018-01-16 23:10:14 +00:00
clientConfig := pki . GetConfigPath ( pki . KubeNodeCertName )
2018-05-30 08:30:12 +00:00
canalConfig := map [ string ] interface { } {
2018-01-16 23:10:14 +00:00
ClientCertPath : pki . GetCertPath ( pki . KubeNodeCertName ) ,
2017-12-16 03:37:45 +00:00
APIRoot : "https://127.0.0.1:6443" ,
2018-01-16 23:10:14 +00:00
ClientKeyPath : pki . GetKeyPath ( pki . KubeNodeCertName ) ,
ClientCAPath : pki . GetCertPath ( pki . CACertName ) ,
KubeCfg : clientConfig ,
2017-12-16 03:37:45 +00:00
ClusterCIDR : c . ClusterCIDR ,
2018-02-05 15:50:39 +00:00
NodeImage : c . SystemImages . CanalNode ,
CNIImage : c . SystemImages . CanalCNI ,
CanalFlannelImg : c . SystemImages . CanalFlannel ,
2017-12-16 03:37:45 +00:00
RBACConfig : c . Authorization . Mode ,
2018-04-26 03:10:53 +00:00
CanalInterface : c . Network . Options [ CanalIface ] ,
2019-08-23 16:43:56 +00:00
FlexVolImg : c . SystemImages . CanalFlexVol ,
2018-05-30 08:30:12 +00:00
FlannelBackend : map [ string ] interface { } {
"Type" : c . Network . Options [ CanalFlannelBackendType ] ,
2019-04-13 14:43:34 +00:00
"VNI" : flannelVni ,
"Port" : flannelPort ,
2018-05-30 08:30:12 +00:00
} ,
2017-12-16 03:37:45 +00:00
}
2019-06-17 20:52:15 +00:00
pluginYaml , err := c . getNetworkPluginManifest ( canalConfig , data )
2017-12-16 03:37:45 +00:00
if err != nil {
return err
2017-12-05 01:29:29 +00:00
}
2018-05-07 21:51:09 +00:00
return c . doAddonDeploy ( ctx , pluginYaml , NetworkPluginResourceName , true )
2017-11-06 20:50:41 +00:00
}
2017-12-05 01:29:29 +00:00
2019-06-17 20:52:15 +00:00
func ( c * Cluster ) doWeaveDeploy ( ctx context . Context , data map [ string ] interface { } ) error {
2018-05-30 08:30:12 +00:00
weaveConfig := map [ string ] interface { } {
2018-05-17 00:27:47 +00:00
ClusterCIDR : c . ClusterCIDR ,
2019-03-05 18:50:19 +00:00
WeavePassword : c . Network . Options [ WeavePassword ] ,
2018-05-17 00:27:47 +00:00
Image : c . SystemImages . WeaveNode ,
CNIImage : c . SystemImages . WeaveCNI ,
WeaveLoopbackImage : c . SystemImages . Alpine ,
RBACConfig : c . Authorization . Mode ,
2017-12-16 03:37:45 +00:00
}
2019-06-17 20:52:15 +00:00
pluginYaml , err := c . getNetworkPluginManifest ( weaveConfig , data )
2017-12-16 03:37:45 +00:00
if err != nil {
return err
2017-12-14 21:56:19 +00:00
}
2018-05-07 21:51:09 +00:00
return c . doAddonDeploy ( ctx , pluginYaml , NetworkPluginResourceName , true )
2017-11-30 11:35:31 +00:00
}
2019-06-17 20:52:15 +00:00
func ( c * Cluster ) getNetworkPluginManifest ( pluginConfig , data map [ string ] interface { } ) ( string , error ) {
2017-12-16 03:37:45 +00:00
switch c . Network . Plugin {
2019-08-13 20:34:49 +00:00
case CanalNetworkPlugin , FlannelNetworkPlugin , CalicoNetworkPlugin , WeaveNetworkPlugin :
tmplt , err := templates . GetVersionedTemplates ( c . Network . Plugin , data , c . Version )
if err != nil {
return "" , err
}
return templates . CompileTemplateFromMap ( tmplt , pluginConfig )
2017-12-16 03:37:45 +00:00
default :
return "" , fmt . Errorf ( "[network] Unsupported network plugin: %s" , c . Network . Plugin )
}
}
2018-01-16 18:29:09 +00:00
2018-01-18 20:41:04 +00:00
func ( c * Cluster ) CheckClusterPorts ( ctx context . Context , currentCluster * Cluster ) error {
if currentCluster != nil {
newEtcdHost := hosts . GetToAddHosts ( currentCluster . EtcdHosts , c . EtcdHosts )
newControlPlanHosts := hosts . GetToAddHosts ( currentCluster . ControlPlaneHosts , c . ControlPlaneHosts )
newWorkerHosts := hosts . GetToAddHosts ( currentCluster . WorkerHosts , c . WorkerHosts )
if len ( newEtcdHost ) == 0 &&
len ( newWorkerHosts ) == 0 &&
len ( newControlPlanHosts ) == 0 {
log . Infof ( ctx , "[network] No hosts added existing cluster, skipping port check" )
return nil
}
}
if err := c . deployTCPPortListeners ( ctx , currentCluster ) ; err != nil {
2018-01-16 18:29:09 +00:00
return err
}
if err := c . runServicePortChecks ( ctx ) ; err != nil {
return err
}
2018-05-08 22:30:50 +00:00
// Skip kubeapi check if we are using custom k8s dialer or bastion/jump host
if c . K8sWrapTransport == nil && len ( c . BastionHost . Address ) == 0 {
2018-03-04 12:14:22 +00:00
if err := c . checkKubeAPIPort ( ctx ) ; err != nil {
return err
}
2018-05-08 22:30:50 +00:00
} else {
log . Infof ( ctx , "[network] Skipping kubeapi port check" )
2018-01-16 18:29:09 +00:00
}
2018-03-04 12:14:22 +00:00
2018-01-16 18:29:09 +00:00
return c . removeTCPPortListeners ( ctx )
}
func ( c * Cluster ) checkKubeAPIPort ( ctx context . Context ) error {
log . Infof ( ctx , "[network] Checking KubeAPI port Control Plane hosts" )
for _ , host := range c . ControlPlaneHosts {
2019-05-24 00:17:25 +00:00
logrus . Debugf ( "[network] Checking KubeAPI port [%s] on host: %s" , KubeAPIPort , host . Address )
2018-01-16 18:29:09 +00:00
address := fmt . Sprintf ( "%s:%s" , host . Address , KubeAPIPort )
2019-05-24 00:17:25 +00:00
conn , err := net . Dial ( "tcp" , address )
if err != nil {
return fmt . Errorf ( "[network] Can't access KubeAPI port [%s] on Control Plane host: %s" , KubeAPIPort , host . Address )
2018-01-16 18:29:09 +00:00
}
2019-05-24 00:17:25 +00:00
conn . Close ( )
2018-01-16 18:29:09 +00:00
}
return nil
}
2018-01-18 20:41:04 +00:00
func ( c * Cluster ) deployTCPPortListeners ( ctx context . Context , currentCluster * Cluster ) error {
2018-01-16 18:29:09 +00:00
log . Infof ( ctx , "[network] Deploying port listener containers" )
2018-01-18 20:41:04 +00:00
// deploy ectd listeners
2018-09-20 16:55:20 +00:00
if err := c . deployListenerOnPlane ( ctx , EtcdPortList , c . EtcdHosts , EtcdPortListenContainer ) ; err != nil {
2018-01-18 20:41:04 +00:00
return err
}
// deploy controlplane listeners
2018-09-20 16:55:20 +00:00
if err := c . deployListenerOnPlane ( ctx , ControlPlanePortList , c . ControlPlaneHosts , CPPortListenContainer ) ; err != nil {
2018-01-18 20:41:04 +00:00
return err
}
// deploy worker listeners
2018-09-20 16:55:20 +00:00
if err := c . deployListenerOnPlane ( ctx , WorkerPortList , c . WorkerHosts , WorkerPortListenContainer ) ; err != nil {
2018-01-18 20:41:04 +00:00
return err
}
log . Infof ( ctx , "[network] Port listener containers deployed successfully" )
return nil
}
2018-10-17 22:26:54 +00:00
func ( c * Cluster ) deployListenerOnPlane ( ctx context . Context , portList [ ] string , hostPlane [ ] * hosts . Host , containerName string ) error {
2018-01-19 22:43:19 +00:00
var errgrp errgroup . Group
2018-10-17 22:26:54 +00:00
hostsQueue := util . GetObjectQueue ( hostPlane )
for w := 0 ; w < WorkerThreads ; w ++ {
2018-01-19 22:43:19 +00:00
errgrp . Go ( func ( ) error {
2018-10-17 22:26:54 +00:00
var errList [ ] error
for host := range hostsQueue {
err := c . deployListener ( ctx , host . ( * hosts . Host ) , portList , containerName )
if err != nil {
errList = append ( errList , err )
}
}
return util . ErrList ( errList )
2018-01-19 22:43:19 +00:00
} )
2018-01-16 18:29:09 +00:00
}
2018-01-19 22:43:19 +00:00
return errgrp . Wait ( )
}
2018-10-17 22:26:54 +00:00
2018-01-19 22:43:19 +00:00
func ( c * Cluster ) deployListener ( ctx context . Context , host * hosts . Host , portList [ ] string , containerName string ) error {
2018-01-16 18:29:09 +00:00
imageCfg := & container . Config {
2018-01-30 12:32:50 +00:00
Image : c . SystemImages . Alpine ,
2018-01-16 18:29:09 +00:00
Cmd : [ ] string {
2019-05-24 00:17:25 +00:00
"nc" ,
"-kl" ,
"-p" ,
"1337" ,
"-e" ,
"echo" ,
2018-01-16 18:29:09 +00:00
} ,
ExposedPorts : nat . PortSet {
"1337/tcp" : { } ,
} ,
}
hostCfg := & container . HostConfig {
PortBindings : nat . PortMap {
2018-01-19 22:43:19 +00:00
"1337/tcp" : getPortBindings ( "0.0.0.0" , portList ) ,
2018-01-16 18:29:09 +00:00
} ,
}
2018-01-19 22:43:19 +00:00
logrus . Debugf ( "[network] Starting deployListener [%s] on host [%s]" , containerName , host . Address )
2018-01-31 17:50:55 +00:00
if err := docker . DoRunContainer ( ctx , host . DClient , imageCfg , hostCfg , containerName , host . Address , "network" , c . PrivateRegistriesMap ) ; err != nil {
2018-01-19 22:43:19 +00:00
if strings . Contains ( err . Error ( ) , "bind: address already in use" ) {
logrus . Debugf ( "[network] Service is already up on host [%s]" , host . Address )
return nil
}
return err
2018-01-16 18:29:09 +00:00
}
2018-01-19 22:43:19 +00:00
return nil
2018-01-16 18:29:09 +00:00
}
2018-01-18 20:41:04 +00:00
2018-01-16 18:29:09 +00:00
func ( c * Cluster ) removeTCPPortListeners ( ctx context . Context ) error {
log . Infof ( ctx , "[network] Removing port listener containers" )
2018-01-18 20:41:04 +00:00
if err := removeListenerFromPlane ( ctx , c . EtcdHosts , EtcdPortListenContainer ) ; err != nil {
return err
2018-01-16 18:29:09 +00:00
}
2018-01-18 20:41:04 +00:00
if err := removeListenerFromPlane ( ctx , c . ControlPlaneHosts , CPPortListenContainer ) ; err != nil {
return err
}
if err := removeListenerFromPlane ( ctx , c . WorkerHosts , WorkerPortListenContainer ) ; err != nil {
2018-01-16 18:29:09 +00:00
return err
}
log . Infof ( ctx , "[network] Port listener containers removed successfully" )
return nil
}
2018-01-18 20:41:04 +00:00
func removeListenerFromPlane ( ctx context . Context , hostPlane [ ] * hosts . Host , containerName string ) error {
var errgrp errgroup . Group
2018-10-17 22:26:54 +00:00
hostsQueue := util . GetObjectQueue ( hostPlane )
for w := 0 ; w < WorkerThreads ; w ++ {
2018-01-18 20:41:04 +00:00
errgrp . Go ( func ( ) error {
2018-10-17 22:26:54 +00:00
var errList [ ] error
for host := range hostsQueue {
runHost := host . ( * hosts . Host )
err := docker . DoRemoveContainer ( ctx , runHost . DClient , containerName , runHost . Address )
if err != nil {
errList = append ( errList , err )
}
}
return util . ErrList ( errList )
2018-01-18 20:41:04 +00:00
} )
}
return errgrp . Wait ( )
}
2018-10-17 22:26:54 +00:00
2018-01-16 18:29:09 +00:00
func ( c * Cluster ) runServicePortChecks ( ctx context . Context ) error {
var errgrp errgroup . Group
// check etcd <-> etcd
// one etcd host is a pass
if len ( c . EtcdHosts ) > 1 {
log . Infof ( ctx , "[network] Running etcd <-> etcd port checks" )
2018-10-17 22:26:54 +00:00
hostsQueue := util . GetObjectQueue ( c . EtcdHosts )
for w := 0 ; w < WorkerThreads ; w ++ {
2018-01-16 18:29:09 +00:00
errgrp . Go ( func ( ) error {
2018-10-17 22:26:54 +00:00
var errList [ ] error
for host := range hostsQueue {
2019-01-28 18:57:25 +00:00
err := checkPlaneTCPPortsFromHost ( ctx , host . ( * hosts . Host ) , EtcdPortList , c . EtcdHosts , c . SystemImages . Alpine , c . PrivateRegistriesMap )
2018-10-17 22:26:54 +00:00
if err != nil {
errList = append ( errList , err )
}
}
return util . ErrList ( errList )
2018-01-16 18:29:09 +00:00
} )
}
if err := errgrp . Wait ( ) ; err != nil {
return err
}
}
2018-06-07 20:47:37 +00:00
// check control -> etcd connectivity
2018-03-20 12:56:49 +00:00
log . Infof ( ctx , "[network] Running control plane -> etcd port checks" )
2018-10-17 22:26:54 +00:00
hostsQueue := util . GetObjectQueue ( c . ControlPlaneHosts )
for w := 0 ; w < WorkerThreads ; w ++ {
2018-01-16 18:29:09 +00:00
errgrp . Go ( func ( ) error {
2018-10-17 22:26:54 +00:00
var errList [ ] error
for host := range hostsQueue {
2019-01-28 18:57:25 +00:00
err := checkPlaneTCPPortsFromHost ( ctx , host . ( * hosts . Host ) , EtcdClientPortList , c . EtcdHosts , c . SystemImages . Alpine , c . PrivateRegistriesMap )
2018-10-17 22:26:54 +00:00
if err != nil {
errList = append ( errList , err )
}
}
return util . ErrList ( errList )
2018-01-16 18:29:09 +00:00
} )
}
if err := errgrp . Wait ( ) ; err != nil {
return err
}
// check controle plane -> Workers
2018-03-20 12:56:49 +00:00
log . Infof ( ctx , "[network] Running control plane -> worker port checks" )
2018-10-17 22:26:54 +00:00
hostsQueue = util . GetObjectQueue ( c . ControlPlaneHosts )
for w := 0 ; w < WorkerThreads ; w ++ {
2018-01-16 18:29:09 +00:00
errgrp . Go ( func ( ) error {
2018-10-17 22:26:54 +00:00
var errList [ ] error
for host := range hostsQueue {
2019-01-28 18:57:25 +00:00
err := checkPlaneTCPPortsFromHost ( ctx , host . ( * hosts . Host ) , WorkerPortList , c . WorkerHosts , c . SystemImages . Alpine , c . PrivateRegistriesMap )
2018-10-17 22:26:54 +00:00
if err != nil {
errList = append ( errList , err )
}
}
return util . ErrList ( errList )
2018-01-16 18:29:09 +00:00
} )
}
if err := errgrp . Wait ( ) ; err != nil {
return err
}
// check workers -> control plane
log . Infof ( ctx , "[network] Running workers -> control plane port checks" )
2018-10-17 22:26:54 +00:00
hostsQueue = util . GetObjectQueue ( c . WorkerHosts )
for w := 0 ; w < WorkerThreads ; w ++ {
2018-01-16 18:29:09 +00:00
errgrp . Go ( func ( ) error {
2018-10-17 22:26:54 +00:00
var errList [ ] error
for host := range hostsQueue {
2019-01-28 18:57:25 +00:00
err := checkPlaneTCPPortsFromHost ( ctx , host . ( * hosts . Host ) , ControlPlanePortList , c . ControlPlaneHosts , c . SystemImages . Alpine , c . PrivateRegistriesMap )
2018-10-17 22:26:54 +00:00
if err != nil {
errList = append ( errList , err )
}
}
return util . ErrList ( errList )
2018-01-16 18:29:09 +00:00
} )
}
return errgrp . Wait ( )
}
2019-01-28 18:57:25 +00:00
func checkPlaneTCPPortsFromHost ( ctx context . Context , host * hosts . Host , portList [ ] string , planeHosts [ ] * hosts . Host , image string , prsMap map [ string ] v3 . PrivateRegistry ) error {
2018-04-19 14:03:14 +00:00
var hosts [ ] string
2018-01-16 18:29:09 +00:00
for _ , host := range planeHosts {
2018-01-18 20:41:04 +00:00
hosts = append ( hosts , host . InternalAddress )
2018-01-16 18:29:09 +00:00
}
imageCfg := & container . Config {
Image : image ,
Env : [ ] string {
fmt . Sprintf ( "HOSTS=%s" , strings . Join ( hosts , " " ) ) ,
fmt . Sprintf ( "PORTS=%s" , strings . Join ( portList , " " ) ) ,
} ,
2019-01-28 18:57:25 +00:00
Cmd : [ ] string {
"sh" ,
"-c" ,
"for host in $HOSTS; do for port in $PORTS ; do echo \"Checking host ${host} on port ${port}\" >&1 & nc -w 5 -z $host $port > /dev/null || echo \"${host}:${port}\" >&2 & done; wait; done" ,
} ,
2018-01-16 18:29:09 +00:00
}
2018-01-30 17:12:45 +00:00
hostCfg := & container . HostConfig {
NetworkMode : "host" ,
2018-04-19 14:03:14 +00:00
LogConfig : container . LogConfig {
Type : "json-file" ,
} ,
2018-01-30 17:12:45 +00:00
}
2018-01-16 18:29:09 +00:00
if err := docker . DoRemoveContainer ( ctx , host . DClient , PortCheckContainer , host . Address ) ; err != nil {
return err
}
2018-01-31 17:50:55 +00:00
if err := docker . DoRunContainer ( ctx , host . DClient , imageCfg , hostCfg , PortCheckContainer , host . Address , "network" , prsMap ) ; err != nil {
2018-01-16 18:29:09 +00:00
return err
}
2018-04-19 14:03:14 +00:00
2018-11-24 10:18:24 +00:00
containerLog , _ , logsErr := docker . GetContainerLogsStdoutStderr ( ctx , host . DClient , PortCheckContainer , "all" , true )
2018-07-18 20:44:55 +00:00
if logsErr != nil {
log . Warnf ( ctx , "[network] Failed to get network port check logs: %v" , logsErr )
2018-01-16 18:29:09 +00:00
}
2018-04-19 14:03:14 +00:00
logrus . Debugf ( "[network] containerLog [%s] on host: %s" , containerLog , host . Address )
2018-01-16 18:29:09 +00:00
if err := docker . RemoveContainer ( ctx , host . DClient , host . Address , PortCheckContainer ) ; err != nil {
return err
}
2018-05-02 23:20:56 +00:00
logrus . Debugf ( "[network] Length of containerLog is [%d] on host: %s" , len ( containerLog ) , host . Address )
2018-04-19 14:03:14 +00:00
if len ( containerLog ) > 0 {
portCheckLogs := strings . Join ( strings . Split ( strings . TrimSpace ( containerLog ) , "\n" ) , ", " )
2018-05-22 10:26:42 +00:00
return fmt . Errorf ( "[network] Host [%s] is not able to connect to the following ports: [%s]. Please check network policies and firewall rules" , host . Address , portCheckLogs )
2018-01-16 18:29:09 +00:00
}
return nil
}
2018-01-19 22:43:19 +00:00
func getPortBindings ( hostAddress string , portList [ ] string ) [ ] nat . PortBinding {
portBindingList := [ ] nat . PortBinding { }
for _ , portNumber := range portList {
rawPort := fmt . Sprintf ( "%s:%s:1337/tcp" , hostAddress , portNumber )
portMapping , _ := nat . ParsePortSpec ( rawPort )
portBindingList = append ( portBindingList , portMapping [ 0 ] . Binding )
}
return portBindingList
}
2019-04-13 14:43:34 +00:00
func atoiWithDefault ( val string , defaultVal int ) ( int , error ) {
if val == "" {
return defaultVal , nil
}
ret , err := strconv . Atoi ( val )
if err != nil {
return 0 , err
}
return ret , nil
}