+
+gateway
string
diff --git a/go.mod b/go.mod
index 429617d..7f18617 100644
--- a/go.mod
+++ b/go.mod
@@ -3,12 +3,16 @@ module vino
go 1.13
require (
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/sprig v2.22.0+incompatible
github.com/evanphx/json-patch v4.9.0+incompatible
github.com/go-logr/logr v0.3.0
github.com/go-logr/zapr v0.2.0
- github.com/metal3-io/baremetal-operator v0.0.0-20210111093319-93a6fd209b9a
github.com/golang/mock v1.4.4
+ github.com/huandu/xstrings v1.3.2 // indirect
github.com/kr/text v0.2.0 // indirect
+ github.com/metal3-io/baremetal-operator v0.0.0-20210111093319-93a6fd209b9a
+ github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/onsi/ginkgo v1.14.2
github.com/onsi/gomega v1.10.2
diff --git a/go.sum b/go.sum
index ee60dd6..c8d5de6 100644
--- a/go.sum
+++ b/go.sum
@@ -53,7 +53,12 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
+github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
@@ -368,6 +373,8 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
+github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
@@ -444,6 +451,8 @@ github.com/metal3-io/baremetal-operator v0.0.0-20210111093319-93a6fd209b9a h1:Gx
github.com/metal3-io/baremetal-operator v0.0.0-20210111093319-93a6fd209b9a/go.mod h1:ydVPYnA+ShdlzVn0DcrRWbhFJwo9OGuEFZJ2GWVSB10=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/copystructure v1.1.1 h1:Bp6x9R1Wn16SIz3OfeDr0b7RnCG2OB66Y7PQyC/cvq4=
+github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
@@ -453,6 +462,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
+github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
diff --git a/main.go b/main.go
index ebfbe6e..152291c 100644
--- a/main.go
+++ b/main.go
@@ -32,6 +32,7 @@ import (
vinov1 "vino/pkg/api/v1"
"vino/pkg/controllers"
+ "vino/pkg/ipam"
)
var (
@@ -80,9 +81,13 @@ func main() {
os.Exit(1)
}
+ ipammer := ipam.NewIpam(ctrl.Log.WithName("IPAM"), mgr.GetClient(),
+ os.Getenv("RUNTIME_NAMESPACE"))
+
if err = (&controllers.VinoReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
+ Ipam: ipammer,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Vino")
os.Exit(1)
diff --git a/pkg/api/v1/vino_types.go b/pkg/api/v1/vino_types.go
index 2b76e33..175579a 100644
--- a/pkg/api/v1/vino_types.go
+++ b/pkg/api/v1/vino_types.go
@@ -44,7 +44,7 @@ type VinoSpec struct {
// Define network parameters
Networks []Network `json:"networks,omitempty"`
// Define node details
- Node []NodeSet `json:"nodes,omitempty"`
+ Nodes []NodeSet `json:"nodes,omitempty"`
// DaemonSetOptions defines how vino will spawn daemonset on nodes
DaemonSetOptions DaemonSetOptions `json:"daemonSetOptions,omitempty"`
// VMBridge defines the single interface name to be used as a bridge for VMs
@@ -78,6 +78,7 @@ type Network struct {
//Network Parameter defined
Name string `json:"name,omitempty"`
SubNet string `json:"subnet,omitempty"`
+ Type string `json:"type,omitempty"`
AllocationStart string `json:"allocationStart,omitempty"`
AllocationStop string `json:"allocationStop,omitempty"`
DNSServers []string `json:"dns_servers,omitempty"`
@@ -86,20 +87,21 @@ type Network struct {
// VMRoutes defined
type VMRoutes struct {
- To string `json:"to,omitempty"`
- Via string `json:"via,omitempty"`
+ Network string `json:"network,omitempty"`
+ Netmask string `json:"netmask,omitempty"`
+ Gateway string `json:"gateway,omitempty"`
}
//NodeSet node definitions
type NodeSet struct {
//Parameter for Node master or worker-standard
- Name string `json:"name,omitempty"`
- Count int `json:"count,omitempty"`
- NodeLabel VMNodeFlavor `json:"labels,omitempty"`
- LibvirtTemplate NamespacedName `json:"libvirtTemplate,omitempty"`
- NetworkInterface *NetworkInterface `json:"networkInterfaces,omitempty"`
- DiskDrives *DiskDrivesTemplate `json:"diskDrives,omitempty"`
- // NetworkDataTemplate reference a Secret containing a template key
+ Name string `json:"name,omitempty"`
+ Count int `json:"count,omitempty"`
+ NodeLabel VMNodeFlavor `json:"labels,omitempty"`
+ LibvirtTemplateDefinition NamespacedName `json:"libvirtTemplate,omitempty"`
+ NetworkInterfaces []NetworkInterface `json:"networkInterfaces,omitempty"`
+ DiskDrives *DiskDrivesTemplate `json:"diskDrives,omitempty"`
+ // NetworkDataTemplate must have a template key
NetworkDataTemplate NamespacedName `json:"networkDataTemplate,omitempty"`
}
diff --git a/pkg/api/v1/zz_generated.deepcopy.go b/pkg/api/v1/zz_generated.deepcopy.go
index dd1c83a..69adb0b 100644
--- a/pkg/api/v1/zz_generated.deepcopy.go
+++ b/pkg/api/v1/zz_generated.deepcopy.go
@@ -308,11 +308,13 @@ func (in *NodeSelector) DeepCopy() *NodeSelector {
func (in *NodeSet) DeepCopyInto(out *NodeSet) {
*out = *in
in.NodeLabel.DeepCopyInto(&out.NodeLabel)
- out.LibvirtTemplate = in.LibvirtTemplate
- if in.NetworkInterface != nil {
- in, out := &in.NetworkInterface, &out.NetworkInterface
- *out = new(NetworkInterface)
- (*in).DeepCopyInto(*out)
+ out.LibvirtTemplateDefinition = in.LibvirtTemplateDefinition
+ if in.NetworkInterfaces != nil {
+ in, out := &in.NetworkInterfaces, &out.NetworkInterfaces
+ *out = make([]NetworkInterface, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
}
if in.DiskDrives != nil {
in, out := &in.DiskDrives, &out.DiskDrives
@@ -463,8 +465,8 @@ func (in *VinoSpec) DeepCopyInto(out *VinoSpec) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
- if in.Node != nil {
- in, out := &in.Node, &out.Node
+ if in.Nodes != nil {
+ in, out := &in.Nodes, &out.Nodes
*out = make([]NodeSet, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
diff --git a/pkg/controllers/bmh.go b/pkg/controllers/bmh.go
index 594642e..305f7e6 100644
--- a/pkg/controllers/bmh.go
+++ b/pkg/controllers/bmh.go
@@ -1,6 +1,4 @@
/*
-
-
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -22,6 +20,7 @@ import (
"fmt"
"text/template"
+ "github.com/Masterminds/sprig"
"github.com/go-logr/logr"
metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
corev1 "k8s.io/api/core/v1"
@@ -32,8 +31,20 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
vinov1 "vino/pkg/api/v1"
+ "vino/pkg/ipam"
)
+type networkTemplateValues struct {
+ Node vinov1.NodeSet // the specific node type to be templated
+ BMHName string
+ Networks []vinov1.Network
+ Generated generatedValues // Host-specific values calculated by ViNO: IP, etc
+}
+
+type generatedValues struct {
+ IPAddresses map[string]string // a map of network names to IP addresses
+}
+
func (r *VinoReconciler) ensureBMHs(ctx context.Context, vino *vinov1.Vino) error {
labelOpt := client.MatchingLabels{
vinov1.VinoLabelDSNameSelector: vino.Name,
@@ -56,7 +67,11 @@ func (r *VinoReconciler) ensureBMHs(ctx context.Context, vino *vinov1.Vino) erro
"pod name",
types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name},
)
- err := r.createBMHperPod(ctx, vino, pod)
+ err := r.createIpamNetworks(ctx, vino)
+ if err != nil {
+ return err
+ }
+ err = r.createBMHperPod(ctx, vino, pod)
if err != nil {
return err
}
@@ -101,8 +116,22 @@ func (r *VinoReconciler) reconcileBMHs(ctx context.Context, vino *vinov1.Vino) e
return nil
}
+func (r *VinoReconciler) createIpamNetworks(ctx context.Context, vino *vinov1.Vino) error {
+ for _, network := range vino.Spec.Networks {
+ subnetRange, err := ipam.NewRange(network.AllocationStart, network.AllocationStop)
+ if err != nil {
+ return err
+ }
+ err = r.Ipam.AddSubnetRange(ctx, network.SubNet, subnetRange)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
func (r *VinoReconciler) createBMHperPod(ctx context.Context, vino *vinov1.Vino, pod corev1.Pod) error {
- for _, node := range vino.Spec.Node {
+ for _, node := range vino.Spec.Nodes {
logger := logr.FromContext(ctx)
logger.Info("Creating BMHs for vino node", "node name", node.Name, "count", node.Count)
prefix := r.getBMHNodePrefix(vino, pod)
@@ -115,7 +144,43 @@ func (r *VinoReconciler) createBMHperPod(ctx context.Context, vino *vinov1.Vino,
return err
}
- netData, netDataNs, err := r.reconcileBMHNetworkData(ctx, node, vino, nil)
+ // Allocate an IP for each of this BMH's network interfaces
+ ipAddresses := map[string]string{}
+ for _, iface := range node.NetworkInterfaces {
+ networkName := iface.NetworkName
+ subnet := ""
+ subnetRange := vinov1.Range{}
+ for _, network := range vino.Spec.Networks {
+ if network.Name == networkName {
+ subnet = network.SubNet
+ subnetRange, err = ipam.NewRange(network.AllocationStart,
+ network.AllocationStop)
+ if err != nil {
+ return err
+ }
+ break
+ }
+ }
+ if subnet == "" {
+ return fmt.Errorf("Interface %s doesn't have a matching network defined", networkName)
+ }
+ ipAllocatedTo := fmt.Sprintf("%s/%s", bmhName, iface.NetworkName)
+ ipAddress, er := r.Ipam.AllocateIP(ctx, subnet, subnetRange, ipAllocatedTo)
+ if er != nil {
+ return er
+ }
+ ipAddresses[networkName] = ipAddress
+ }
+
+ values := networkTemplateValues{
+ Node: node,
+ BMHName: bmhName,
+ Networks: vino.Spec.Networks,
+ Generated: generatedValues{
+ IPAddresses: ipAddresses,
+ },
+ }
+ netData, netDataNs, err := r.reconcileBMHNetworkData(ctx, node, vino, values)
if err != nil {
return err
}
@@ -213,7 +278,7 @@ func (r *VinoReconciler) reconcileBMHNetworkData(
ctx context.Context,
node vinov1.NodeSet,
vino *vinov1.Vino,
- values interface{}) (string, string, error) {
+ values networkTemplateValues) (string, string, error) {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: node.NetworkDataTemplate.Name,
@@ -234,7 +299,7 @@ func (r *VinoReconciler) reconcileBMHNetworkData(
return "", "", fmt.Errorf("network template secret %v has no key '%s'", objKey, TemplateDefaultKey)
}
- tpl, err := template.New("net-template").Parse(string(rawTmpl))
+ tpl, err := template.New("net-template").Funcs(sprig.TxtFuncMap()).Parse(string(rawTmpl))
if err != nil {
return "", "", err
}
@@ -245,7 +310,7 @@ func (r *VinoReconciler) reconcileBMHNetworkData(
return "", "", err
}
- name := fmt.Sprintf("%s-%s-%s", vino.Namespace, vino.Name, node.Name)
+ name := fmt.Sprintf("%s-network-data", values.BMHName)
ns := getRuntimeNamespace()
netSecret := &corev1.Secret{
diff --git a/pkg/controllers/bmh_test.go b/pkg/controllers/bmh_test.go
index f62339c..b12b36a 100644
--- a/pkg/controllers/bmh_test.go
+++ b/pkg/controllers/bmh_test.go
@@ -40,7 +40,7 @@ var _ = Describe("Test BMH reconciliation", func() {
os.Setenv("RUNTIME_NAMESPACE", "vino-system")
defer os.Unsetenv("RUNTIME_NAMESPACE")
vino := testVINO()
- vino.Spec.Node = []vinov1.NodeSet{
+ vino.Spec.Nodes = []vinov1.NodeSet{
{
Name: "worker",
Count: 3,
@@ -141,7 +141,7 @@ var _ = Describe("Test BMH reconciliation", func() {
networkSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
- Name: "default-vino-worker",
+ Name: "default-vino-node01-worker-0-network-data",
Namespace: "vino-system",
},
}
diff --git a/pkg/controllers/vino_controller.go b/pkg/controllers/vino_controller.go
index 4442b0e..a48cb0b 100644
--- a/pkg/controllers/vino_controller.go
+++ b/pkg/controllers/vino_controller.go
@@ -39,6 +39,7 @@ import (
"sigs.k8s.io/yaml"
vinov1 "vino/pkg/api/v1"
+ "vino/pkg/ipam"
)
const (
@@ -53,10 +54,12 @@ const (
type VinoReconciler struct {
client.Client
Scheme *runtime.Scheme
+ Ipam *ipam.Ipam
}
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=vinoes,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=vinoes/status,verbs=get;update;patch
+// +kubebuilder:rbac:groups=airship.airshipit.org,resources=ippools,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups="",resources=pods,verbs=list;watch
// +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch
diff --git a/tools/deployment/test-cr.sh b/tools/deployment/test-cr.sh
index 8ca5473..9c2056b 100755
--- a/tools/deployment/test-cr.sh
+++ b/tools/deployment/test-cr.sh
@@ -50,5 +50,6 @@ bmhCount=$(kubectl get baremetalhosts -n vino-system -o name | wc -l)
[[ "$bmhCount" -eq "3" ]]
-kubectl get secret -o yaml -n vino-system default-vino-test-cr-worker
+kubectl get -o yaml -n vino-system \
+ $(kubectl get secret -o name -n vino-system | grep network-data)
kubectl get secret -o yaml -n vino-system default-vino-test-cr-credentials
|