diff --git a/internal/controller/prefixclaim_controller.go b/internal/controller/prefixclaim_controller.go index 1695a98f..b4200407 100644 --- a/internal/controller/prefixclaim_controller.go +++ b/internal/controller/prefixclaim_controller.go @@ -104,7 +104,7 @@ func (r *PrefixClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) // since the parent prefix is not part of the restoration hash computation // we can quickly check to see if the prefix with the restoration hash is matched in NetBox h := generatePrefixRestorationHash(o) - canBeRestored, err := r.NetboxClient.RestoreExistingPrefixByHash(h) + canBeRestored, err := r.NetboxClient.RestoreExistingPrefixByHash(h, o.Spec.PrefixLength) if err != nil { if errReport := r.EventStatusRecorder.Report(ctx, o, netboxv1.ConditionParentPrefixSelectedFalse, corev1.EventTypeWarning, fmt.Errorf("failed to look up prefix by hash: %w", err)); errReport != nil { return ctrl.Result{}, errReport @@ -239,7 +239,7 @@ func (r *PrefixClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) // 5. try to reclaim Prefix using restorationHash h := generatePrefixRestorationHash(o) - prefixModel, err := r.NetboxClient.RestoreExistingPrefixByHash(h) + prefixModel, err := r.NetboxClient.RestoreExistingPrefixByHash(h, o.Spec.PrefixLength) if err != nil { if errReport := r.EventStatusRecorder.Report(ctx, o, netboxv1.ConditionPrefixAssignedFalse, corev1.EventTypeWarning, err); errReport != nil { return ctrl.Result{}, errReport diff --git a/pkg/netbox/api/prefix_claim.go b/pkg/netbox/api/prefix_claim.go index 3eb7254a..59178ce4 100644 --- a/pkg/netbox/api/prefix_claim.go +++ b/pkg/netbox/api/prefix_claim.go @@ -36,7 +36,7 @@ var ( ErrNoPrefixMatchsSizeCriteria = errors.New("no available prefix matches size criteria") ) -func (r *NetboxClient) RestoreExistingPrefixByHash(hash string) (*models.Prefix, error) { +func (r *NetboxClient) RestoreExistingPrefixByHash(hash string, requestedPrefixLength string) (*models.Prefix, error) { customPrefixSearch := newQueryFilterOperation(nil, []CustomFieldEntry{ { key: config.GetOperatorConfig().NetboxRestorationHashFieldName, @@ -53,17 +53,29 @@ func (r *NetboxClient) RestoreExistingPrefixByHash(hash string) (*models.Prefix, return nil, nil } + // Filter for exact prefix length + prefixesWithExactPrefixLength := make([]*models.Prefix, 0) + for _, prefix := range list.Payload.Results { + if strings.Contains(*prefix.Prefix, requestedPrefixLength) { + prefixesWithExactPrefixLength = append(prefixesWithExactPrefixLength, &models.Prefix{ + Prefix: *prefix.Prefix, + }) + } + } + // We should not have more than 1 result... - if len(list.Payload.Results) != 1 { - return nil, fmt.Errorf("incorrect number of restoration results, number of results: %v", len(list.Payload.Results)) + if len(prefixesWithExactPrefixLength) > 1 { + return nil, fmt.Errorf("too many restoration results found in NetBox for hash %s and prefix length %s, number of results: %v", hash, requestedPrefixLength, len(prefixesWithExactPrefixLength)) + } else if len(prefixesWithExactPrefixLength) == 0 { + return nil, fmt.Errorf("no prefix found in NetBox with restoration hash %s and prefix length %s", hash, requestedPrefixLength) } - res := list.Payload.Results[0] - if res.Prefix == nil { - return nil, errors.New("prefix in netbox is nil") + res := prefixesWithExactPrefixLength[0] + if res.Prefix == "" { + return nil, errors.New("prefix in netbox is empty") } return &models.Prefix{ - Prefix: *res.Prefix, + Prefix: res.Prefix, }, nil } diff --git a/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/chainsaw-test.yaml b/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/chainsaw-test.yaml index 103b9ac5..ece8693f 100644 --- a/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/chainsaw-test.yaml +++ b/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/chainsaw-test.yaml @@ -129,6 +129,57 @@ spec: tenant: MY_TENANT customFields: netboxOperatorRestorationHash: 00b8772de73cdac083b0732d5bb85ab4f0caa16c + - name: Apply Prerequisite Prefix for CR 3 + try: + - apply: + file: netbox_v1_prefix_3-wrong-length.yaml + - assert: + resource: + apiVersion: netbox.dev/v1 + kind: Prefix + metadata: + name: prefixclaim-ipv4-parentprefix-restore-3-prefix-with-wrong-length + spec: + comments: your comments + customFields: + netboxOperatorRestorationHash: 1309280893365bfd94710d148379a6f501a46afe + description: some description + prefix: 2.0.3.224/27 + site: MY_SITE + tenant: MY_TENANT + status: + (conditions[?type == 'Ready']): + - status: 'True' + - name: Apply CR 3 + try: + - apply: + file: netbox_v1_prefixclaim_3.yaml + - name: Check CR 3 spec and status, verify mismatched length doesn't assign wrong prefix + try: + - assert: + resource: + apiVersion: netbox.dev/v1 + kind: PrefixClaim + metadata: + labels: + app.kubernetes.io/name: netbox-operator + app.kubernetes.io/managed-by: kustomize + name: prefixclaim-ipv4-parentprefix-restore-3 + spec: + tenant: "MY_TENANT" + site: "MY_SITE" + description: "some description" + comments: "your comments" + preserveInNetbox: false + parentPrefix: "2.0.3.0/24" + prefixLength: "/28" + status: + (conditions[?type == 'PrefixAssigned']): + - reason: PrefixCRNotCreated + message: 'Failed to assign prefix, prefix CR creation skipped: no prefix found in NetBox with restoration hash 1309280893365bfd94710d148379a6f501a46afe and prefix length /28' + status: 'False' + (conditions[?type == 'Ready']): + - status: 'False' - name: Set preserveInNetbox to false description: Set preserveInNetbox to false to clean up the NetBox test instance try: diff --git a/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/netbox_v1_prefix_3-wrong-length.yaml b/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/netbox_v1_prefix_3-wrong-length.yaml new file mode 100644 index 00000000..47f0c164 --- /dev/null +++ b/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/netbox_v1_prefix_3-wrong-length.yaml @@ -0,0 +1,16 @@ +apiVersion: netbox.dev/v1 +kind: Prefix +metadata: + labels: + app.kubernetes.io/name: netbox-operator + app.kubernetes.io/managed-by: kustomize + name: prefixclaim-ipv4-parentprefix-restore-3-prefix-with-wrong-length +spec: + comments: your comments + customFields: + netboxOperatorRestorationHash: 1309280893365bfd94710d148379a6f501a46afe + description: some description + preserveInNetbox: false + site: MY_SITE + tenant: MY_TENANT + prefix: "2.0.3.224/27" # this is the prefix that we expect to mismatch during restore diff --git a/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/netbox_v1_prefixclaim_3.yaml b/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/netbox_v1_prefixclaim_3.yaml new file mode 100644 index 00000000..6324fa8b --- /dev/null +++ b/tests/e2e/Prefix/IPv4/prefixclaim-ipv4-parentprefix-restore/netbox_v1_prefixclaim_3.yaml @@ -0,0 +1,15 @@ +apiVersion: netbox.dev/v1 +kind: PrefixClaim +metadata: + labels: + app.kubernetes.io/name: netbox-operator + app.kubernetes.io/managed-by: kustomize + name: prefixclaim-ipv4-parentprefix-restore-3 +spec: + tenant: "MY_TENANT" + site: "MY_SITE" + description: "some description" + comments: "your comments" + preserveInNetbox: false + parentPrefix: "2.0.3.0/24" + prefixLength: "/28"