Browse Source

Added ability to specify multiple ifaces and iface regexes

Allows for even more flexibility when selecting the network interface
that flannel should be using

Addresses #620
matt 7 years ago
parent
commit
448d6f850b
5 changed files with 68 additions and 11 deletions
  1. 2 2
      Documentation/configuration.md
  2. 57 9
      main.go
  3. 4 0
      subnet/etcdv2/local_manager.go
  4. 4 0
      subnet/kube/kube.go
  5. 1 0
      subnet/subnet.go

+ 2 - 2
Documentation/configuration.md

@@ -53,8 +53,8 @@ The following configuration illustrates the use of most options with `udp` backe
 --etcd-certfile="": SSL certification file used to secure etcd communication.
 --etcd-cafile="": SSL Certificate Authority file used to secure etcd communication.
 --kube-subnet-mgr: Contact the Kubernetes API for subnet assignment instead of etcd.
---iface="": interface to use (IP or name) for inter-host communication. Defaults to the interface for the default route on the machine.
---iface-regex="": regex expression to match the first interface to use (IP or name) for inter-host communication. If unspecified, will default to the interface for the default route on the machine. This option is superseded by the iface option and will not be used if the iface option is also specified.
+--iface="": interface to use (IP or name) for inter-host communication. Defaults to the interface for the default route on the machine. This can be specified multiple times to check each option in order. Returns the first match found.
+--iface-regex="": regex expression to match the first interface to use (IP or name) for inter-host communication. If unspecified, will default to the interface for the default route on the machine. This can be specified multiple times to check each regex in order. Returns the first match found. This option is superseded by the iface option and will only be used if nothing matches any option specified in the iface options.
 --subnet-file=/run/flannel/subnet.env: filename where env variables (subnet and MTU values) will be written to.
 --subnet-lease-renew-margin=60: subnet lease renewal margin, in minutes.
 --ip-masq=false: setup IP masquerade for traffic destined for outside the flannel network. Flannel assumes that the default policy is ACCEPT in the NAT POSTROUTING chain.

+ 57 - 9
main.go

@@ -56,6 +56,17 @@ import (
 	"github.com/coreos/go-systemd/daemon"
 )
 
+type flagSlice []string
+
+func (t *flagSlice) String() string {
+	return fmt.Sprintf("%v", *t)
+}
+
+func (t *flagSlice) Set(val string) error {
+	*t = append(*t, val)
+	return nil
+}
+
 type CmdLineOpts struct {
 	etcdEndpoints          string
 	etcdPrefix             string
@@ -69,8 +80,8 @@ type CmdLineOpts struct {
 	kubeSubnetMgr          bool
 	kubeApiUrl             string
 	kubeConfigFile         string
-	iface                  string
-	ifaceRegex             string
+	iface                  flagSlice
+	ifaceRegex             flagSlice
 	ipMasq                 bool
 	subnetFile             string
 	subnetDir              string
@@ -95,8 +106,8 @@ func init() {
 	flannelFlags.StringVar(&opts.etcdCAFile, "etcd-cafile", "", "SSL Certificate Authority file used to secure etcd communication")
 	flannelFlags.StringVar(&opts.etcdUsername, "etcd-username", "", "username for BasicAuth to etcd")
 	flannelFlags.StringVar(&opts.etcdPassword, "etcd-password", "", "password for BasicAuth to etcd")
-	flannelFlags.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
-	flannelFlags.StringVar(&opts.ifaceRegex, "iface-regex", "", "regex expression to match the first interface to use (IP or name) for inter-host communication. Skipped if the iface option is also specified")
+	flannelFlags.Var(&opts.iface, "iface", "interface to use (IP or name) for inter-host communication. Can be specified multiple times to check each option in order. Returns the first match found.")
+	flannelFlags.Var(&opts.ifaceRegex, "iface-regex", "regex expression to match the first interface to use (IP or name) for inter-host communication. Can be specified multiple times to check each regex in order. Returns the first match found. Regexes are checked after specific interfaces specified by the iface option have already been checked.")
 	flannelFlags.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet, MTU, ... ) will be written to")
 	flannelFlags.StringVar(&opts.publicIP, "public-ip", "", "IP accessible by other nodes for inter-host communication")
 	flannelFlags.IntVar(&opts.subnetLeaseRenewMargin, "subnet-lease-renew-margin", 60, "subnet lease renewal margin, in minutes.")
@@ -164,10 +175,47 @@ func main() {
 	flagutil.SetFlagsFromEnv(flannelFlags, "FLANNELD")
 
 	// Work out which interface to use
-	extIface, err := LookupExtIface(opts.iface, opts.ifaceRegex)
-	if err != nil {
-		log.Error("Failed to find interface to use: ", err)
-		os.Exit(1)
+	var extIface *backend.ExternalInterface
+	var err error
+	// Check the default interface only if no interfaces are specified
+	if len(opts.iface) == 0 && len(opts.ifaceRegex) == 0 {
+		extIface, err = LookupExtIface("", "")
+		if err != nil {
+			log.Error("Failed to find any valid interface to use: ", err)
+			os.Exit(1)
+		}
+	} else {
+		// Check explicitly specified interfaces
+		for _, iface := range opts.iface {
+			extIface, err = LookupExtIface(iface, "")
+			if err != nil {
+				log.Infof("Could not find valid interface matching %s: %s", iface, err)
+			}
+
+			if extIface != nil {
+				break
+			}
+		}
+
+		// Check interfaces that match any specified regexes
+		if extIface == nil {
+			for _, ifaceRegex := range opts.ifaceRegex {
+				extIface, err = LookupExtIface("", ifaceRegex)
+				if err != nil {
+					log.Infof("Could not find valid interface matching %s: %s", ifaceRegex, err)
+				}
+
+				if extIface != nil {
+					break
+				}
+			}
+		}
+
+		if extIface == nil {
+			// Exit if any of the specified interfaces do not match
+			log.Error("Failed to find interface to use that matches the interfaces and/or regexes provided")
+			os.Exit(1)
+		}
 	}
 
 	sm, err := newSubnetManager()
@@ -175,7 +223,7 @@ func main() {
 		log.Error("Failed to create SubnetManager: ", err)
 		os.Exit(1)
 	}
-	log.Infof("Created subnet manager: %+v", sm)
+	log.Infof("Created subnet manager: %s", sm.Name())
 
 	// Register for SIGINT and SIGTERM
 	log.Info("Installing signal handlers")

+ 4 - 0
subnet/etcdv2/local_manager.go

@@ -504,3 +504,7 @@ func (m *LocalManager) ListReservations(ctx context.Context) ([]Reservation, err
 
 	return rsvs, nil
 }
+
+func (m *LocalManager) Name() string {
+	return fmt.Sprintf("Etcd Local Manager with Previous Subnet: %s", m.previousSubnet.String())
+}

+ 4 - 0
subnet/kube/kube.go

@@ -326,3 +326,7 @@ func (ksm *kubeSubnetManager) RemoveReservation(ctx context.Context, subnet ip.I
 func (ksm *kubeSubnetManager) ListReservations(ctx context.Context) ([]subnet.Reservation, error) {
 	return nil, ErrUnimplemented
 }
+
+func (ksm *kubeSubnetManager) Name() string {
+	return fmt.Sprintf("Kubernetes Subnet Manager - %s", ksm.nodeName)
+}

+ 1 - 0
subnet/subnet.go

@@ -134,4 +134,5 @@ type Manager interface {
 	AddReservation(ctx context.Context, r *Reservation) error
 	RemoveReservation(ctx context.Context, subnet ip.IP4Net) error
 	ListReservations(ctx context.Context) ([]Reservation, error)
+	Name() string
 }