Add support for network data templating for VMs
Network templated will be sourced from a secret, secret reference is specified in a VINO CR per each VINO node. Change-Id: I7720783c25e722fd952ecfd660f12b3492fb83b1
This commit is contained in:
parent
868789f047
commit
fc0e10f285
@ -149,6 +149,15 @@ spec:
|
||||
name:
|
||||
description: Parameter for Node master or worker-standard
|
||||
type: string
|
||||
networkDataTemplate:
|
||||
description: NetworkDataTemplate reference a Secret containing
|
||||
a template key
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
type: object
|
||||
networkInterfaces:
|
||||
description: NetworkInterface define interface on the VM
|
||||
properties:
|
||||
|
@ -21,6 +21,17 @@ rules:
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- airship.airshipit.org
|
||||
resources:
|
||||
|
8
config/samples/network-template-secret.yaml
Normal file
8
config/samples/network-template-secret.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: test-template
|
||||
namespace: default
|
||||
type: Opaque
|
||||
stringData:
|
||||
template: REPLACEME
|
@ -31,3 +31,7 @@ spec:
|
||||
nodes:
|
||||
- name: "worker"
|
||||
count: 3
|
||||
networkDataTemplate:
|
||||
name: "test-template"
|
||||
namespace: "default"
|
||||
|
||||
|
@ -688,6 +688,19 @@ DiskDrivesTemplate
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>networkDataTemplate</code><br>
|
||||
<em>
|
||||
<a href="#airship.airshipit.org/v1.NamespacedName">
|
||||
NamespacedName
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>NetworkDataTemplate reference a Secret containing a template key</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -83,12 +83,14 @@ type VMRoutes struct {
|
||||
//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"`
|
||||
LibvirtTemplateDefinition NamespacedName `json:"libvirtTemplate,omitempty"`
|
||||
NetworkInterface *NetworkInterface `json:"networkInterfaces,omitempty"`
|
||||
DiskDrives *DiskDrivesTemplate `json:"diskDrives,omitempty"`
|
||||
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
|
||||
NetworkDataTemplate NamespacedName `json:"networkDataTemplate,omitempty"`
|
||||
}
|
||||
|
||||
// VMNodeFlavor labels for node to be annotated
|
||||
|
@ -282,7 +282,7 @@ func (in *NodeSet) DeepCopyInto(out *NodeSet) {
|
||||
*out = new(VMNodeFlavor)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
out.LibvirtTemplateDefinition = in.LibvirtTemplateDefinition
|
||||
out.LibvirtTemplate = in.LibvirtTemplate
|
||||
if in.NetworkInterface != nil {
|
||||
in, out := &in.NetworkInterface, &out.NetworkInterface
|
||||
*out = new(NetworkInterface)
|
||||
@ -293,6 +293,7 @@ func (in *NodeSet) DeepCopyInto(out *NodeSet) {
|
||||
*out = new(DiskDrivesTemplate)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
out.NetworkDataTemplate = in.NetworkDataTemplate
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSet.
|
||||
|
@ -1,8 +1,26 @@
|
||||
/*
|
||||
|
||||
|
||||
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
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
|
||||
@ -97,7 +115,7 @@ func (r *VinoReconciler) createBMHperPod(ctx context.Context, vino *vinov1.Vino,
|
||||
return err
|
||||
}
|
||||
|
||||
netData, netDataNs, err := r.reconcileBMHNetworkData(ctx, vino)
|
||||
netData, netDataNs, err := r.reconcileBMHNetworkData(ctx, node, vino, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -168,8 +186,62 @@ func (r *VinoReconciler) reconcileBMHCredentials(ctx context.Context, vino *vino
|
||||
return "credentials", nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (r *VinoReconciler) reconcileBMHNetworkData(_ context.Context, vino *vinov1.Vino) (string, string, error) {
|
||||
// TODO implement this
|
||||
return "network-data", getRuntimeNamespace(), nil
|
||||
func (r *VinoReconciler) reconcileBMHNetworkData(
|
||||
ctx context.Context,
|
||||
node vinov1.NodeSet,
|
||||
vino *vinov1.Vino,
|
||||
values interface{}) (string, string, error) {
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: node.NetworkDataTemplate.Name,
|
||||
Namespace: node.NetworkDataTemplate.Namespace,
|
||||
},
|
||||
}
|
||||
|
||||
logger := logr.FromContext(ctx).WithValues("vino node", node.Name, "vino", client.ObjectKeyFromObject(vino))
|
||||
|
||||
objKey := client.ObjectKeyFromObject(secret)
|
||||
logger.Info("Looking for secret with network template for vino node", "secret", objKey)
|
||||
if err := r.Get(ctx, objKey, secret); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
rawTmpl, ok := secret.Data[TemplateDefaultKey]
|
||||
if !ok {
|
||||
return "", "", fmt.Errorf("network template secret %v has no key '%s'", objKey, TemplateDefaultKey)
|
||||
}
|
||||
|
||||
tpl, err := template.New("net-template").Parse(string(rawTmpl))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
err = tpl.Execute(buf, values)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%s-%s-%s", vino.Namespace, vino.Name, node.Name)
|
||||
|
||||
ns := getRuntimeNamespace()
|
||||
netSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: ns,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"networkData": buf.String(),
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
}
|
||||
|
||||
objKey = client.ObjectKeyFromObject(netSecret)
|
||||
|
||||
logger.Info("Creating network secret for vino node", "secret", objKey)
|
||||
|
||||
if err := applyRuntimeObject(ctx, objKey, netSecret, r.Client); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return name, ns, nil
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
|
||||
|
||||
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
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
@ -28,6 +44,10 @@ var _ = Describe("Test BMH reconciliation", func() {
|
||||
{
|
||||
Name: "worker",
|
||||
Count: 3,
|
||||
NetworkDataTemplate: vinov1.NamespacedName{
|
||||
Name: "default-template",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -63,6 +83,17 @@ var _ = Describe("Test BMH reconciliation", func() {
|
||||
},
|
||||
}
|
||||
|
||||
networkTmplSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default-template",
|
||||
Namespace: "default",
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
Data: map[string][]byte{
|
||||
TemplateDefaultKey: []byte("REPLACEME"),
|
||||
},
|
||||
}
|
||||
|
||||
node1 := &corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node01",
|
||||
@ -92,7 +123,7 @@ var _ = Describe("Test BMH reconciliation", func() {
|
||||
|
||||
fake.NewClientBuilder()
|
||||
reconciler := &VinoReconciler{
|
||||
Client: fake.NewFakeClient(podList, node1, node2, vino),
|
||||
Client: fake.NewFakeClient(podList, node1, node2, vino, networkTmplSecret),
|
||||
}
|
||||
|
||||
l := zap.New(zap.UseDevMode(true))
|
||||
@ -107,8 +138,18 @@ var _ = Describe("Test BMH reconciliation", func() {
|
||||
Namespace: "vino-system",
|
||||
},
|
||||
}
|
||||
|
||||
networkSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default-vino-worker",
|
||||
Namespace: "vino-system",
|
||||
},
|
||||
}
|
||||
|
||||
Expect(reconciler.Get(ctx, client.ObjectKeyFromObject(bmh), bmh)).Should(Succeed())
|
||||
Expect(bmh.Spec.BMC.Address).To(Equal("redfish+http://10.0.0.2:8000/redfish/v1/Systems/worker-1"))
|
||||
Expect(reconciler.Get(ctx, client.ObjectKeyFromObject(networkSecret), networkSecret)).Should(Succeed())
|
||||
Expect(networkSecret.StringData["networkData"]).To(Equal("REPLACEME"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -42,164 +42,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DaemonSetTemplateDefaultDataKey = "template"
|
||||
DaemonSetTemplateDefaultName = "vino-daemonset-template"
|
||||
TemplateDefaultKey = "template"
|
||||
DaemonSetTemplateDefaultName = "vino-daemonset-template"
|
||||
|
||||
ContainerNameLibvirt = "libvirt"
|
||||
ConfigMapKeyVinoSpec = "vino-spec"
|
||||
|
||||
// TODO (alexanderhughes) Enable this section of code when ready to integrate the BMH creation
|
||||
// sushyDataContent = `
|
||||
//{
|
||||
// "username": "foo",
|
||||
// "password": "bar",
|
||||
//}`
|
||||
//
|
||||
// networkDataContent = `
|
||||
//{
|
||||
// "links": [
|
||||
// {
|
||||
// "id": "eno4",
|
||||
// "name": "eno4",
|
||||
// "type": "phy",
|
||||
// "mtu": 1500
|
||||
// },
|
||||
// {
|
||||
// "id": "enp59s0f1",
|
||||
// "name": "enp59s0f1",
|
||||
// "type": "phy",
|
||||
// "mtu": 9100
|
||||
// },
|
||||
// {
|
||||
// "id": "enp216s0f0",
|
||||
// "name": "enp216s0f0",
|
||||
// "type": "phy",
|
||||
// "mtu": 9100
|
||||
// },
|
||||
// {
|
||||
// "id": "bond0",
|
||||
// "name": "bond0",
|
||||
// "type": "bond",
|
||||
// "bond_links": [
|
||||
// "enp59s0f1",
|
||||
// "enp216s0f0"
|
||||
// ],
|
||||
// "bond_mode": "802.3ad",
|
||||
// "bond_xmit_hash_policy": "layer3+4",
|
||||
// "bond_miimon": 100,
|
||||
// "mtu": 9100
|
||||
// },
|
||||
// {
|
||||
// "id": "bond0.41",
|
||||
// "name": "bond0.41",
|
||||
// "type": "vlan",
|
||||
// "vlan_link": "bond0",
|
||||
// "vlan_id": 41,
|
||||
// "mtu": 9100,
|
||||
// "vlan_mac_address": null
|
||||
// },
|
||||
// {
|
||||
// "id": "bond0.42",
|
||||
// "name": "bond0.42",
|
||||
// "type": "vlan",
|
||||
// "vlan_link": "bond0",
|
||||
// "vlan_id": 42,
|
||||
// "mtu": 9100,
|
||||
// "vlan_mac_address": null
|
||||
// },
|
||||
// {
|
||||
// "id": "bond0.44",
|
||||
// "name": "bond0.44",
|
||||
// "type": "vlan",
|
||||
// "vlan_link": "bond0",
|
||||
// "vlan_id": 44,
|
||||
// "mtu": 9100,
|
||||
// "vlan_mac_address": null
|
||||
// },
|
||||
// {
|
||||
// "id": "bond0.45",
|
||||
// "name": "bond0.45",
|
||||
// "type": "vlan",
|
||||
// "vlan_link": "bond0",
|
||||
// "vlan_id": 45,
|
||||
// "mtu": 9100,
|
||||
// "vlan_mac_address": null
|
||||
// }
|
||||
// ],
|
||||
// "networks": [
|
||||
// {
|
||||
// "id": "oam-ipv6",
|
||||
// "type": "ipv6",
|
||||
// "link": "bond0.41",
|
||||
// "ip_address": "2001:1890:1001:293d::139",
|
||||
// "routes": [
|
||||
// {
|
||||
// "network": "::/0",
|
||||
// "netmask": "::/0",
|
||||
// "gateway": "2001:1890:1001:293d::1"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "id": "oam-ipv4",
|
||||
// "type": "ipv4",
|
||||
// "link": "bond0.41",
|
||||
// "ip_address": "32.68.51.139",
|
||||
// "netmask": "255.255.255.128",
|
||||
// "dns_nameservers": [
|
||||
// "135.188.34.124",
|
||||
// "135.38.244.16",
|
||||
// "135.188.34.84"
|
||||
// ],
|
||||
// "routes": [
|
||||
// {
|
||||
// "network": "0.0.0.0",
|
||||
// "netmask": "0.0.0.0",
|
||||
// "gateway": "32.68.51.129"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "id": "pxe-ipv6",
|
||||
// "link": "eno4",
|
||||
// "type": "ipv6",
|
||||
// "ip_address": "fd00:900:100:138::11"
|
||||
// },
|
||||
// {
|
||||
// "id": "pxe-ipv4",
|
||||
// "link": "eno4",
|
||||
// "type": "ipv4",
|
||||
// "ip_address": "172.30.0.11",
|
||||
// "netmask": "255.255.255.128"
|
||||
// },
|
||||
// {
|
||||
// "id": "storage-ipv6",
|
||||
// "link": "bond0.42",
|
||||
// "type": "ipv6",
|
||||
// "ip_address": "fd00:900:100:139::15"
|
||||
// },
|
||||
// {
|
||||
// "id": "storage-ipv4",
|
||||
// "link": "bond0.42",
|
||||
// "type": "ipv4",
|
||||
// "ip_address": "172.31.1.15",
|
||||
// "netmask": "255.255.255.128"
|
||||
// },
|
||||
// {
|
||||
// "id": "ksn-ipv6",
|
||||
// "link": "bond0.44",
|
||||
// "type": "ipv6",
|
||||
// "ip_address": "fd00:900:100:13a::11"
|
||||
// },
|
||||
// {
|
||||
// "id": "ksn-ipv4",
|
||||
// "link": "bond0.44",
|
||||
// "type": "ipv4",
|
||||
// "ip_address": "172.29.0.11",
|
||||
// "netmask": "255.255.255.128"
|
||||
// }
|
||||
// ]
|
||||
//}`
|
||||
)
|
||||
|
||||
// VinoReconciler reconciles a Vino object
|
||||
@ -212,6 +59,7 @@ type VinoReconciler struct {
|
||||
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=vinoes/status,verbs=get;update;patch
|
||||
// +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
|
||||
|
||||
func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
logger := logr.FromContext(ctx)
|
||||
@ -615,10 +463,10 @@ func (r *VinoReconciler) daemonSet(ctx context.Context, vino *vinov1.Vino) (*app
|
||||
return nil, err
|
||||
}
|
||||
|
||||
template, exist := cm.Data[DaemonSetTemplateDefaultDataKey]
|
||||
template, exist := cm.Data[TemplateDefaultKey]
|
||||
if !exist {
|
||||
logger.Info("malformed template provided data doesn't have key " + DaemonSetTemplateDefaultDataKey)
|
||||
return nil, fmt.Errorf("malformed template provided data doesn't have key " + DaemonSetTemplateDefaultDataKey)
|
||||
logger.Info("malformed template provided data doesn't have key " + TemplateDefaultKey)
|
||||
return nil, fmt.Errorf("malformed template provided data doesn't have key " + TemplateDefaultKey)
|
||||
}
|
||||
|
||||
ds := &appsv1.DaemonSet{}
|
||||
|
@ -14,6 +14,7 @@ function vinoDebugInfo () {
|
||||
|
||||
kubectl apply -f config/samples/vino_cr.yaml
|
||||
kubectl apply -f config/samples/ippool.yaml
|
||||
kubectl apply -f config/samples/network-template-secret.yaml
|
||||
|
||||
# Remove logs collection from here, when we will have zuul collect logs job
|
||||
until [[ $(kubectl get vino vino-test-cr 2>/dev/null) ]]; do
|
||||
@ -43,9 +44,10 @@ if ! kubectl -n vino-system rollout status ds default-vino-test-cr --timeout=10s
|
||||
vinoDebugInfo
|
||||
fi
|
||||
|
||||
|
||||
bmhCount=$(kubectl get baremetalhosts -n vino-system -o name | wc -l)
|
||||
|
||||
# with this setup set up, exactly 3 BMHs must have been created by VINO controller
|
||||
|
||||
[[ "$bmhCount" -eq "3" ]]
|
||||
|
||||
kubectl get secret -o yaml -n vino-system default-vino-test-cr-worker
|
||||
|
Loading…
x
Reference in New Issue
Block a user