Skip to content

Commit

Permalink
[ovn-controller] Don't create ovn-controller ds if no NicMappings set
Browse files Browse the repository at this point in the history
Resolves: OSPRH-7463
  • Loading branch information
averdagu committed Aug 27, 2024
1 parent 7b6c3c9 commit 0b0d702
Show file tree
Hide file tree
Showing 67 changed files with 670 additions and 201 deletions.
17 changes: 17 additions & 0 deletions config/samples/nad_principal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
annotations:
labels:
osp/net: kuttlospbr
service: ovn-controller
name: principal
spec:
config: |
{
"cniVersion": "0.3.1",
"name": "kuttlospbr",
"type": "bridge",
"bridge": "ospbr",
"ipam": {}
}
26 changes: 26 additions & 0 deletions config/samples/nncp_create_bridge.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
labels:
osp/interface: enp6s0
name: enp6s0-crc
spec:
desiredState:
interfaces:
- description: Configuring Bridge
name: osptestbr
mtu: 1500
type: linux-bridge
state: up
bridge:
options:
stp:
enabled: false
ipv4:
address:
- ip: 192.168.222.10
prefix-length: 24
enabled: true
dhcp: false
ipv6:
enabled: false
164 changes: 164 additions & 0 deletions controllers/ovncontroller_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,113 @@ func (r *OVNControllerReconciler) reconcileUpgrade(ctx context.Context) (ctrl.Re
return ctrl.Result{}, nil
}

// use lib_commons.daemonset.GetDaemonSetWithName once
// https://github.com/openstack-k8s-operators/lib-common/pull/551
// is merged
func getDaemonSetWithName(
ctx context.Context,
h *helper.Helper,
name string,
namespace string,
) (*appsv1.DaemonSet, error) {

dset := &appsv1.DaemonSet{}
err := h.GetClient().Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, dset)
if err != nil {
return dset, err
}

return dset, nil
}

func (r *OVNControllerReconciler) ensureCMDeleted(
ctx context.Context,
h *helper.Helper,
instance *ovnv1.OVNController,
) error {
// Delete, if they exist
cms := []string{instance.Name + "-config", instance.Name + "-scripts"}
for _, cmName := range cms {
err := r.deleteConfigMaps(ctx, h, cmName, instance.Namespace)
if err != nil && !k8s_errors.IsNotFound(err) {
return fmt.Errorf("could not delete config map %s: %w", cmName, err)
}

}
return nil
}

func ensureDSDeleted(
ctx context.Context,
h *helper.Helper,
instance *ovnv1.OVNController,
) error {
// Delete, if they exist, ovn and ovs ds
daemonsets := []string{"ovn-controller", "ovn-controller-ovs"}
for _, dsName := range daemonsets {
ds, err := getDaemonSetWithName(ctx, h, dsName, instance.Namespace)
if err != nil && !k8s_errors.IsNotFound(err) {
return fmt.Errorf("error getting %s daemonset: %w", dsName, err)
} else if err != nil && k8s_errors.IsNotFound(err) {
// Already deleted
continue
}

// Delete ds
err = h.GetClient().Delete(ctx, ds)
if err != nil && !k8s_errors.IsNotFound(err) {
return fmt.Errorf("error deleting daemonset %s: %w", ds.Name, err)
}
}

return nil
}

func ensureNADDeleted(
ctx context.Context,
h *helper.Helper,
instance *ovnv1.OVNController,
) error {
// Delete NAD if they exist and controller owns it
nadList := &netattdefv1.NetworkAttachmentDefinitionList{}
err := h.GetClient().List(ctx, nadList)
if err != nil {
return fmt.Errorf("error getting NAD list: %w", err)
}
for _, currentNAD := range nadList.Items {
owners := currentNAD.GetOwnerReferences()
// if owners len is only one, means that if ovn controller is the owner we can
// delete it
if len(owners) == 1 {
if owners[0].Name == instance.Name {
err = h.GetClient().Delete(ctx, &currentNAD)
if err != nil {
return fmt.Errorf("error trying to delete nad %s: %w", currentNAD.Name, err)
}
}
} else if len(owners) > 1 {
// this nad has more than one owner, remove ovn-controller as owner but
// don't delete it
indexToDelete := -1
for j, owner := range owners {
if owner.Name == instance.Name {
indexToDelete = j
break
}
}
if indexToDelete != -1 {
currentNAD.SetOwnerReferences(append(owners[:indexToDelete], owners[indexToDelete+1:]...))
err = h.GetClient().Update(ctx, &currentNAD)
if err != nil {
return fmt.Errorf("error updating NAD %s after ownerReference update: %w", currentNAD.Name, err)
}
}
}
}

return nil
}

func (r *OVNControllerReconciler) reconcileNormal(ctx context.Context, instance *ovnv1.OVNController, helper *helper.Helper) (ctrl.Result, error) {
Log := r.GetLogger(ctx)

Expand All @@ -339,6 +446,41 @@ func (r *OVNControllerReconciler) reconcileNormal(ctx context.Context, instance
return rbacResult, nil
}

// if ovn-controller has no nicMappings, it's useless create daemonset on
// OC nodes, since it won't do anything.
if len(instance.Spec.NicMappings) == 0 {
// Check if DS are created, if so delete the resources associated with it
// Resources associated with ovn-controller:
// - ovncontroller-scripts [cm]
// - ovncontroller-config [cm]
// - ovn-controller [ds]
// - ovn-controller-ovs [ds]
// - job [it gets deleted once it's finished]
err := ensureDSDeleted(ctx, helper, instance)
if err != nil {
return ctrl.Result{}, err
}

err = r.ensureCMDeleted(ctx, helper, instance)
if err != nil {
return ctrl.Result{}, err
}

err = ensureNADDeleted(ctx, helper, instance)
if err != nil {
return ctrl.Result{}, err
}

// Set conditions to true as no more work is needed.
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)
instance.Status.Conditions.MarkTrue(condition.ServiceConfigReadyCondition, condition.ServiceConfigReadyMessage)
instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage)
instance.Status.Conditions.MarkTrue(condition.DeploymentReadyCondition, condition.DeploymentReadyMessage)
instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage)
return ctrl.Result{}, nil
}

// ConfigMap
configMapVars := make(map[string]env.Setter)

Expand Down Expand Up @@ -677,6 +819,28 @@ func (r *OVNControllerReconciler) reconcileNormal(ctx context.Context, instance
return ctrl.Result{}, nil
}

func (r *OVNControllerReconciler) deleteConfigMaps(
ctx context.Context,
h *helper.Helper,
name string,
namespace string,
) error {
serviceCM := &corev1.ConfigMap{}
err := h.GetClient().Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, serviceCM)
if err != nil && !k8s_errors.IsNotFound(err) {
return err
} else if k8s_errors.IsNotFound(err) {
return nil
}

err = h.GetClient().Delete(ctx, serviceCM)
if err != nil && !k8s_errors.IsNotFound(err) {
return fmt.Errorf("error deleting config map %s: %w", serviceCM.Name, err)
}

return nil
}

// generateServiceConfigMaps - create configmaps which hold scripts and service configuration
func (r *OVNControllerReconciler) generateServiceConfigMaps(
ctx context.Context,
Expand Down
9 changes: 9 additions & 0 deletions tests/functional/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,15 @@ func GetOVNDBCluster(name types.NamespacedName) *ovnv1.OVNDBCluster {
return ovn.GetOVNDBCluster(name)
}

// GetConfigMap -
func GetConfigMap(name types.NamespacedName) *corev1.ConfigMap {
cm := &corev1.ConfigMap{}
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, name, cm)).Should(Succeed())
}, timeout, interval).Should(Succeed())
return cm
}

// GetDaemonSet -
func GetDaemonSet(name types.NamespacedName) *appsv1.DaemonSet {
ds := &appsv1.DaemonSet{}
Expand Down
Loading

0 comments on commit 0b0d702

Please sign in to comment.