Create generated objects in runtime namespace

This uses the Downward API to inject the runtime namespace of the
controller as an env var, rather than hard-coding it as 'vino-system'.
It then uses the runtime namespace to lookup the default DaemonSet
template, and then to co-locate the generated DaemonSet and bound
ConfigMap with the controller, so that a static service account can
be used by the DaemonSet, regardless of which namespace Vino CRs are
created in. The names of the generated objects are now uniquely
identified by the namespace/name of the Vino CR to avoid conflicts.

Some other future use cases for the injected runtime namespace could
include:

- create ipam CRs in the same namespace as the controller
- tenant namespacing, e.g. add a flag to limit the controller to only
  watch for Vino CRs in the runtime namespace

Signed-off-by: Sean Eagan <seaneagan1@gmail.com>
Change-Id: I47994782342c9c4ef749054017969386cefad3b8
This commit is contained in:
Sean Eagan 2021-02-08 15:49:07 -06:00
parent 817cbfc967
commit 1f360788c1
3 changed files with 30 additions and 17 deletions

View File

@ -37,4 +37,9 @@ spec:
requests:
cpu: 100m
memory: 20Mi
env:
- name: RUNTIME_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
terminationGracePeriodSeconds: 10

View File

@ -19,6 +19,7 @@ package controllers
import (
"context"
"fmt"
"os"
"time"
"github.com/go-logr/logr"
@ -41,9 +42,8 @@ import (
)
const (
DaemonSetTemplateDefaultDataKey = "template"
DaemonSetTemplateDefaultName = "vino-daemonset-template"
DaemonSetTemplateDefaultNamespace = "vino-system"
DaemonSetTemplateDefaultDataKey = "template"
DaemonSetTemplateDefaultName = "vino-daemonset-template"
ContainerNameLibvirt = "libvirt"
ConfigMapKeyVinoSpec = "vino-spec"
@ -246,7 +246,7 @@ func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
}
}
err = r.reconcileConfigMap(ctx, req.NamespacedName, vino)
err = r.reconcileConfigMap(ctx, vino)
if err != nil {
return ctrl.Result{Requeue: true}, err
}
@ -271,8 +271,8 @@ func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
return ctrl.Result{}, nil
}
func (r *VinoReconciler) reconcileConfigMap(ctx context.Context, name types.NamespacedName, vino *vinov1.Vino) error {
err := r.ensureConfigMap(ctx, name, vino)
func (r *VinoReconciler) reconcileConfigMap(ctx context.Context, vino *vinov1.Vino) error {
err := r.ensureConfigMap(ctx, vino)
if err != nil {
err = fmt.Errorf("could not reconcile ConfigMap: %w", err)
apimeta.SetStatusCondition(&vino.Status.Conditions, metav1.Condition{
@ -310,10 +310,10 @@ func (r *VinoReconciler) reconcileConfigMap(ctx context.Context, name types.Name
return nil
}
func (r *VinoReconciler) ensureConfigMap(ctx context.Context, name types.NamespacedName, vino *vinov1.Vino) error {
func (r *VinoReconciler) ensureConfigMap(ctx context.Context, vino *vinov1.Vino) error {
logger := logr.FromContext(ctx)
generatedCM, err := r.buildConfigMap(ctx, name, vino)
generatedCM, err := r.buildConfigMap(ctx, vino)
if err != nil {
return err
}
@ -342,7 +342,7 @@ func (r *VinoReconciler) ensureConfigMap(ctx context.Context, name types.Namespa
return nil
}
func (r *VinoReconciler) buildConfigMap(ctx context.Context, name types.NamespacedName, vino *vinov1.Vino) (
func (r *VinoReconciler) buildConfigMap(ctx context.Context, vino *vinov1.Vino) (
*corev1.ConfigMap, error) {
logr.FromContext(ctx).Info("Generating new config map for vino object")
@ -353,8 +353,8 @@ func (r *VinoReconciler) buildConfigMap(ctx context.Context, name types.Namespac
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name.Name,
Namespace: name.Namespace,
Namespace: getRuntimeNamespace(),
Name: r.getConfigMapName(vino),
},
Data: map[string]string{
ConfigMapKeyVinoSpec: string(data),
@ -362,6 +362,10 @@ func (r *VinoReconciler) buildConfigMap(ctx context.Context, name types.Namespac
}, nil
}
func (r *VinoReconciler) getConfigMapName(vino *vinov1.Vino) string {
return fmt.Sprintf("%s-%s", vino.Namespace, vino.Name)
}
func (r *VinoReconciler) getCurrentConfigMap(ctx context.Context, vino *vinov1.Vino) (*corev1.ConfigMap, error) {
logr.FromContext(ctx).Info("Getting current config map for vino object")
cm := &corev1.ConfigMap{}
@ -470,8 +474,8 @@ func (r *VinoReconciler) decorateDaemonSet(ctx context.Context, ds *appsv1.Daemo
volume := "vino-spec"
ds.Spec.Template.Spec.NodeSelector = vino.Spec.NodeSelector.MatchLabels
ds.Name = vino.Name
ds.Namespace = vino.Namespace
ds.Namespace = getRuntimeNamespace()
ds.Name = fmt.Sprintf("%s-%s", vino.Namespace, vino.Name)
found := false
for _, vol := range ds.Spec.Template.Spec.Volumes {
@ -485,7 +489,7 @@ func (r *VinoReconciler) decorateDaemonSet(ctx context.Context, ds *appsv1.Daemo
Name: volume,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: vino.Name},
LocalObjectReference: corev1.LocalObjectReference{Name: r.getConfigMapName(vino)},
},
},
})
@ -593,7 +597,7 @@ func (r *VinoReconciler) daemonSet(ctx context.Context, vino *vinov1.Vino) (*app
if dsTemplate == (vinov1.NamespacedName{}) {
logger.Info("using default configmap for daemonset template")
dsTemplate.Name = DaemonSetTemplateDefaultName
dsTemplate.Namespace = DaemonSetTemplateDefaultNamespace
dsTemplate.Namespace = getRuntimeNamespace()
}
err := r.Get(ctx, types.NamespacedName{
@ -766,3 +770,7 @@ func applyRuntimeObject(ctx context.Context, key client.ObjectKey, obj client.Ob
return err
}
}
func getRuntimeNamespace() string {
return os.Getenv("RUNTIME_NAMESPACE")
}

View File

@ -29,7 +29,7 @@ if ! kubectl wait --for=condition=Ready vino vino-test-cr --timeout=180s; then
fi
# no need to collect logs on fail, since they are already collected before
until [[ $(kubectl get ds vino-test-cr 2>/dev/null) ]]; do
until [[ $(kubectl -n vino-system get ds default-vino-test-cr 2>/dev/null) ]]; do
count=$((count + 1))
if [[ ${count} -eq "30" ]]; then
echo ' Timed out waiting for vino builder daemonset to exist'
@ -38,6 +38,6 @@ until [[ $(kubectl get ds vino-test-cr 2>/dev/null) ]]; do
fi
sleep 2
done
if ! kubectl rollout status ds vino-test-cr --timeout=10s; then
if ! kubectl -n vino-system rollout status ds default-vino-test-cr --timeout=10s; then
vinoDebugInfo
fi