feat: add CNI, and pod and service CIDR to configurator

This adds more methods to the Cluster interface that allows for more
granular control of the cluster network settings.

Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
Andrew Rynhard
2019-10-07 18:53:23 -07:00
parent b29391f0be
commit 04313bd48c
7 changed files with 165 additions and 7 deletions

View File

@@ -23,6 +23,7 @@ import (
"github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/goroutine"
"github.com/talos-systems/talos/pkg/config"
"github.com/talos-systems/talos/pkg/constants"
tnet "github.com/talos-systems/talos/pkg/net"
)
// Bootkube implements the Service interface. It serves as the concrete type with
@@ -125,11 +126,11 @@ func generateAssets(config config.Configurator) (err error) {
}
apiServers = append(apiServers, u)
_, podCIDR, err := net.ParseCIDR("10.2.0.0/16")
_, podCIDR, err := net.ParseCIDR(config.Cluster().Network().PodCIDR())
if err != nil {
return err
}
_, serviceCIDR, err := net.ParseCIDR("10.3.0.0/24")
_, serviceCIDR, err := net.ParseCIDR(config.Cluster().Network().ServiceCIDR())
if err != nil {
return err
}
@@ -154,6 +155,16 @@ func generateAssets(config config.Configurator) (err error) {
return errors.Wrap(err, "failed to parse Kubernetes key")
}
apiServiceIP, err := tnet.NthIPInNetwork(serviceCIDR, 1)
if err != nil {
return err
}
dnsServiceIP, err := tnet.NthIPInNetwork(serviceCIDR, 10)
if err != nil {
return err
}
conf := asset.Config{
CACert: k8sCA,
CAPrivKey: k8sKey,
@@ -163,11 +174,11 @@ func generateAssets(config config.Configurator) (err error) {
EtcdServers: []*url.URL{etcdServer},
EtcdUseTLS: true,
APIServers: apiServers,
APIServiceIP: net.ParseIP("10.3.0.1"),
DNSServiceIP: net.ParseIP("10.3.0.10"),
APIServiceIP: apiServiceIP,
DNSServiceIP: dnsServiceIP,
PodCIDR: podCIDR,
ServiceCIDR: serviceCIDR,
NetworkProvider: "flannel",
NetworkProvider: config.Cluster().Network().CNI(),
AltNames: altNames,
Images: asset.DefaultImages,
BootstrapSecretsSubdir: "/assets/tls",

View File

@@ -20,6 +20,15 @@ type Cluster interface {
AESCBCEncryptionSecret() string
Config(machine.Type) (string, error)
Etcd() Etcd
Network() Network
}
// Network defines the requirements for a config that pertains to cluster
// network options.
type Network interface {
CNI() string
PodCIDR() string
ServiceCIDR() string
}
// Etcd defines the requirements for a config that pertains to etcd related

View File

@@ -9,6 +9,7 @@ import (
"github.com/talos-systems/talos/pkg/config/cluster"
"github.com/talos-systems/talos/pkg/config/machine"
"github.com/talos-systems/talos/pkg/constants"
"github.com/talos-systems/talos/pkg/crypto/x509"
)
@@ -16,7 +17,7 @@ import (
type ClusterConfig struct {
ControlPlane *ControlPlaneConfig `yaml:"controlPlane"`
ClusterName string `yaml:"clusterName,omitempty"`
Network *ClusterNetworkConfig `yaml:"network,omitempty"`
ClusterNetwork *ClusterNetworkConfig `yaml:"network,omitempty"`
BootstrapToken string `yaml:"token,omitempty"`
CertificateKey string `yaml:"certificateKey"`
ClusterAESCBCEncryptionSecret string `yaml:"aescbcEncryptionSecret"`
@@ -67,6 +68,7 @@ type EtcdConfig struct {
// ClusterNetworkConfig represents kube networking config vals
type ClusterNetworkConfig struct {
CNI string `yaml:"cni"`
DNSDomain string `yaml:"dnsDomain"`
PodSubnet []string `yaml:"podSubnets"`
ServiceSubnet []string `yaml:"serviceSubnets"`
@@ -139,3 +141,35 @@ func (c *ClusterConfig) Secret() string {
}
return parts[1]
}
// Network implements the Configurator interface.
func (c *ClusterConfig) Network() cluster.Network {
return c
}
// CNI implements the Configurator interface.
func (c *ClusterConfig) CNI() string {
if c.ClusterNetwork.CNI == "" {
return constants.DefaultCNI
}
return c.ClusterNetwork.CNI
}
// PodCIDR implements the Configurator interface.
func (c *ClusterConfig) PodCIDR() string {
if len(c.ClusterNetwork.PodSubnet) == 0 {
return constants.DefaultPodCIDR
}
return c.ClusterNetwork.PodSubnet[0]
}
// ServiceCIDR implements the Configurator interface.
func (c *ClusterConfig) ServiceCIDR() string {
if len(c.ClusterNetwork.ServiceSubnet) == 0 {
return constants.DefaultServiceCIDR
}
return c.ClusterNetwork.ServiceSubnet[0]
}

View File

@@ -37,7 +37,7 @@ func initUd(in *Input) (string, error) {
EtcdConfig: &v1alpha1.EtcdConfig{
RootCA: in.Certs.Etcd,
},
Network: &v1alpha1.ClusterNetworkConfig{
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
DNSDomain: in.ServiceDomain,
PodSubnet: in.PodNet,
ServiceSubnet: in.ServiceNet,

View File

@@ -233,6 +233,15 @@ const (
// DefaultLogPath is the default path to the log storage directory.
DefaultLogPath = SystemRunPath + "/log"
// DefaultCNI is the default CNI.
DefaultCNI = "flannel"
// DefaultPodCIDR is the default pod CIDR block.
DefaultPodCIDR = "10.244.0.0/16"
// DefaultServiceCIDR is the default service CIDR block.
DefaultServiceCIDR = "10.96.0.0/12"
)
// See https://linux.die.net/man/3/klogctl

View File

@@ -6,6 +6,8 @@ package net
import (
"net"
"github.com/pkg/errors"
)
// IPAddrs finds and returns a list of non-loopback IPv4 addresses of the
@@ -40,3 +42,24 @@ func FormatAddress(addr string) string {
}
return addr
}
// NthIPInNetwork takes an IPNet and returns the nth IP in it.
func NthIPInNetwork(network *net.IPNet, n int) (net.IP, error) {
ip := network.IP
dst := make([]byte, len(ip))
copy(dst, ip)
for i := 0; i < n; i++ {
for j := len(dst) - 1; j >= 0; j-- {
dst[j]++
if dst[j] > 0 {
break
}
}
}
if network.Contains(dst) {
return dst, nil
}
return nil, errors.New("network does not contain enough IPs")
}

View File

@@ -5,6 +5,8 @@
package net
import (
"net"
"reflect"
"testing"
"gotest.tools/assert"
@@ -23,3 +25,73 @@ func TestFormatAddress(t *testing.T) {
assert.Equal(t, FormatAddress("192.168.1.1"), "192.168.1.1")
assert.Equal(t, FormatAddress("alpha.beta.gamma.com"), "alpha.beta.gamma.com")
}
// nolint: scopelint
func TestNthIPInNetwork(t *testing.T) {
type args struct {
network *net.IPNet
n int
}
tests := []struct {
name string
args args
want net.IP
}{
{
name: "increment IPv4 by 1",
args: args{
network: &net.IPNet{
IP: net.IP{10, 96, 0, 0},
Mask: net.IPMask{255, 255, 255, 0},
},
n: 1,
},
want: net.IP{10, 96, 0, 1},
},
{
name: "increment IPv4 by 10",
args: args{
network: &net.IPNet{
IP: net.IP{10, 96, 0, 0},
Mask: net.IPMask{255, 255, 255, 0},
},
n: 10,
},
want: net.IP{10, 96, 0, 10},
},
{
name: "increment IPv6 by 1",
args: args{
network: &net.IPNet{
IP: net.ParseIP("2001:db8:a0b:12f0::1"),
Mask: net.IPMask{255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
n: 1,
},
want: net.ParseIP("2001:db8:a0b:12f0::2"),
},
{
name: "increment IPv6 by 10",
args: args{
network: &net.IPNet{
IP: net.ParseIP("2001:db8:a0b:12f0::1"),
Mask: net.IPMask{255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
n: 10,
},
want: net.ParseIP("2001:db8:a0b:12f0::b"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NthIPInNetwork(tt.args.network, tt.args.n)
if err != nil {
t.Errorf("%v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NthFromIP() = %v, want %v", got, tt.want)
}
})
}
}