Adding ability to override VM interface
Change-Id: I35cc4368c4f7a0e0642c16d089bda910412a832c
This commit is contained in:
parent
0e2baf38e4
commit
bccf6d68c5
@ -88,6 +88,10 @@ spec:
|
||||
type: object
|
||||
subnet:
|
||||
type: string
|
||||
vmInterfaceName:
|
||||
description: VMinterfaceName defines the interface name to be used
|
||||
as bridge for virtual machines
|
||||
type: string
|
||||
type: object
|
||||
nodeSelector:
|
||||
description: Define nodelabel parameters
|
||||
|
@ -340,6 +340,17 @@ VMRoutes
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>vmInterfaceName</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>VMinterfaceName defines the interface name to be used as bridge for virtual machines</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.13
|
||||
require (
|
||||
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/onsi/ginkgo v1.14.2
|
||||
github.com/onsi/gomega v1.10.2
|
||||
|
@ -31,6 +31,8 @@ const (
|
||||
VinoLabelDSNamespaceSelector = VinoLabel + "/" + "cr-namespace"
|
||||
// VinoFinalizer constant
|
||||
VinoFinalizer = "vino.airshipit.org"
|
||||
// EnvVarVMInterfaceName environment variable that is used to find VM interface to use for vms
|
||||
EnvVarVMInterfaceName = "VM_BRIDGE_INTERFACE"
|
||||
)
|
||||
|
||||
// VinoSpec defines the desired state of Vino
|
||||
@ -40,7 +42,7 @@ type VinoSpec struct {
|
||||
// Define CPU configuration
|
||||
CPUConfiguration *CPUConfiguration `json:"configuration,omitempty"`
|
||||
// Define network parameters
|
||||
Network *Network `json:"networks,omitempty"`
|
||||
Network Network `json:"networks,omitempty"`
|
||||
// Define node details
|
||||
Node []NodeSet `json:"nodes,omitempty"`
|
||||
// DaemonSetOptions defines how vino will spawn daemonset on nodes
|
||||
@ -68,6 +70,8 @@ type Network struct {
|
||||
AllocationStop string `json:"allocationStop,omitempty"`
|
||||
DNSServers []string `json:"dns_servers,omitempty"`
|
||||
Routes *VMRoutes `json:"routes,omitempty"`
|
||||
// VMinterfaceName defines the interface name to be used as bridge for virtual machines
|
||||
VMInterfaceName string `json:"vmInterfaceName,omitempty"`
|
||||
}
|
||||
|
||||
// VMRoutes defined
|
||||
|
@ -315,11 +315,7 @@ func (in *VinoSpec) DeepCopyInto(out *VinoSpec) {
|
||||
*out = new(CPUConfiguration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Network != nil {
|
||||
in, out := &in.Network, &out.Network
|
||||
*out = new(Network)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Network.DeepCopyInto(&out.Network)
|
||||
if in.Node != nil {
|
||||
in, out := &in.Node, &out.Node
|
||||
*out = make([]NodeSet, len(*in))
|
||||
|
@ -514,6 +514,12 @@ func (r *VinoReconciler) decorateDaemonSet(ctx context.Context, ds *appsv1.Daemo
|
||||
}
|
||||
}
|
||||
|
||||
// TODO develop logic to derive all required ENV variables from VINO CR, and pass them
|
||||
// to setENV function instead
|
||||
if vino.Spec.Network.VMInterfaceName != "" {
|
||||
setEnv(ctx, ds, vino)
|
||||
}
|
||||
|
||||
// this will help avoid colisions if we have two vino CRs in the same namespace
|
||||
ds.Spec.Selector.MatchLabels[vinov1.VinoLabelDSNameSelector] = vino.Name
|
||||
ds.Spec.Template.ObjectMeta.Labels[vinov1.VinoLabelDSNameSelector] = vino.Name
|
||||
@ -522,6 +528,32 @@ func (r *VinoReconciler) decorateDaemonSet(ctx context.Context, ds *appsv1.Daemo
|
||||
ds.Spec.Template.ObjectMeta.Labels[vinov1.VinoLabelDSNamespaceSelector] = vino.Namespace
|
||||
}
|
||||
|
||||
func setEnv(ctx context.Context, ds *appsv1.DaemonSet, vino *vinov1.Vino) {
|
||||
for i, c := range ds.Spec.Template.Spec.Containers {
|
||||
var set bool
|
||||
for j, envVar := range c.Env {
|
||||
if envVar.Name == vinov1.EnvVarVMInterfaceName {
|
||||
logr.FromContext(ctx).Info("found env variable with vm interface name on daemonset template, overriding it",
|
||||
"vino instance", vino.Namespace+"/"+vino.Name,
|
||||
"container name", c.Name,
|
||||
"value", envVar.Value,
|
||||
)
|
||||
ds.Spec.Template.Spec.Containers[i].Env[j].Value = vino.Spec.Network.VMInterfaceName
|
||||
set = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !set {
|
||||
ds.Spec.Template.Spec.Containers[i].Env = append(
|
||||
ds.Spec.Template.Spec.Containers[i].Env, corev1.EnvVar{
|
||||
Name: vinov1.EnvVarVMInterfaceName,
|
||||
Value: vino.Spec.Network.VMInterfaceName,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *VinoReconciler) waitDaemonSet(ctx context.Context, ds *appsv1.DaemonSet) error {
|
||||
logger := logr.FromContext(ctx).WithValues(
|
||||
"daemonset", ds.Namespace+"/"+ds.Name)
|
||||
|
180
pkg/controllers/vino_controller_test.go
Normal file
180
pkg/controllers/vino_controller_test.go
Normal file
@ -0,0 +1,180 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
vinov1 "vino/pkg/api/v1"
|
||||
)
|
||||
|
||||
func testDS() *appsv1.DaemonSet {
|
||||
return &appsv1.DaemonSet{Spec: appsv1.DaemonSetSpec{
|
||||
Template: corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{}}}}}
|
||||
}
|
||||
|
||||
func testVINO() *vinov1.Vino {
|
||||
return &vinov1.Vino{
|
||||
ObjectMeta: v1.ObjectMeta{},
|
||||
Spec: vinov1.VinoSpec{
|
||||
Network: vinov1.Network{}}}
|
||||
}
|
||||
|
||||
var _ = Describe("Test Setting Env variables", func() {
|
||||
Context("when daemonset is created", func() {
|
||||
l := logr.Discard()
|
||||
ctx := logr.NewContext(context.Background(), l)
|
||||
Context("no containers defined in damonset", func() {
|
||||
It("does nothing", func() {
|
||||
ds := testDS()
|
||||
setEnv(ctx, ds, testVINO())
|
||||
Expect(ds.Spec.Template.Spec.Containers).To(HaveLen(0))
|
||||
})
|
||||
|
||||
})
|
||||
Context("when daemonset has containers", func() {
|
||||
It("sets env interface variable to every container", func() {
|
||||
vino := testVINO()
|
||||
ifName := "eth0"
|
||||
vino.Spec.Network.VMInterfaceName = ifName
|
||||
ds := testDS()
|
||||
ds.Spec.Template.Spec.Containers = make([]corev1.Container, 3)
|
||||
|
||||
setEnv(ctx, ds, vino)
|
||||
|
||||
for _, container := range ds.Spec.Template.Spec.Containers {
|
||||
Expect(container.Env).To(HaveLen(1))
|
||||
Expect(container.Env[0].Name).To(Equal(vinov1.EnvVarVMInterfaceName))
|
||||
Expect(container.Env[0].Value).To(Equal(ifName))
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
Context("when daemonset has container with wrong env var values", func() {
|
||||
It("overrides that variable in the container", func() {
|
||||
vino := testVINO()
|
||||
ifName := "eth0"
|
||||
vino.Spec.Network.VMInterfaceName = ifName
|
||||
ds := testDS()
|
||||
ds.Spec.Template.Spec.Containers = []corev1.Container{
|
||||
{
|
||||
Env: []corev1.EnvVar{
|
||||
{
|
||||
Name: vinov1.EnvVarVMInterfaceName,
|
||||
Value: "wrong-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
setEnv(ctx, ds, vino)
|
||||
Expect(ds.Spec.Template.Spec.Containers).To(HaveLen(1))
|
||||
container := ds.Spec.Template.Spec.Containers[0]
|
||||
Expect(container.Env).To(HaveLen(1))
|
||||
Expect(container.Env[0].Name).To(Equal(vinov1.EnvVarVMInterfaceName))
|
||||
Expect(container.Env[0].Value).To(Equal(ifName))
|
||||
})
|
||||
})
|
||||
Context("when daemonset containers don't have required variable", func() {
|
||||
It("overrides that variable in the container", func() {
|
||||
vino := testVINO()
|
||||
ifName := "eth0"
|
||||
vino.Spec.Network.VMInterfaceName = ifName
|
||||
ds := testDS()
|
||||
ds.Spec.Template.Spec.Containers = []corev1.Container{
|
||||
{
|
||||
Env: []corev1.EnvVar{
|
||||
{
|
||||
Name: "bar",
|
||||
Value: "wrong-value",
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Value: "wrong-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Env: []corev1.EnvVar{
|
||||
{
|
||||
Name: "foo",
|
||||
Value: "wrong-value",
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
Value: "wrong-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
setEnv(ctx, ds, vino)
|
||||
|
||||
Expect(ds.Spec.Template.Spec.Containers).To(HaveLen(2))
|
||||
for _, container := range ds.Spec.Template.Spec.Containers {
|
||||
Expect(container.Env).To(HaveLen(3))
|
||||
for i, env := range container.Env {
|
||||
if i == len(container.Env)-1 {
|
||||
// only last env holds the correct values
|
||||
Expect(env.Name).To(Equal(vinov1.EnvVarVMInterfaceName))
|
||||
Expect(env.Value).To(Equal(ifName))
|
||||
} else {
|
||||
Expect(env.Name).NotTo(Equal(vinov1.EnvVarVMInterfaceName))
|
||||
Expect(env.Value).NotTo(Equal(ifName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
Context("when daemonset container has many variables", func() {
|
||||
It("it sets required variable only single time", func() {
|
||||
vino := testVINO()
|
||||
ifName := "eth0"
|
||||
vino.Spec.Network.VMInterfaceName = ifName
|
||||
ds := testDS()
|
||||
ds.Spec.Template.Spec.Containers = []corev1.Container{
|
||||
{
|
||||
Env: []corev1.EnvVar{
|
||||
{
|
||||
Name: "foo",
|
||||
Value: "wrong-value",
|
||||
},
|
||||
{
|
||||
Name: vinov1.EnvVarVMInterfaceName,
|
||||
Value: "wrong-value",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "bar",
|
||||
Value: "wrong-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
setEnv(ctx, ds, vino)
|
||||
Expect(ds.Spec.Template.Spec.Containers).To(HaveLen(1))
|
||||
container := ds.Spec.Template.Spec.Containers[0]
|
||||
Expect(container.Env).To(HaveLen(3))
|
||||
for i, env := range container.Env {
|
||||
if i == 1 {
|
||||
// only env var with index 1 holds the correct values
|
||||
Expect(env.Name).To(Equal(vinov1.EnvVarVMInterfaceName))
|
||||
Expect(env.Value).To(Equal(ifName))
|
||||
} else {
|
||||
Expect(env.Name).NotTo(Equal(vinov1.EnvVarVMInterfaceName))
|
||||
Expect(env.Value).NotTo(Equal(ifName))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue
Block a user