From 6f55a79609a82848bf353591e3014f502a34318d Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Fri, 11 Jun 2021 17:10:23 -0400 Subject: [PATCH] ignore vlan attachment API responses "422 Virtual network foo already ..." Signed-off-by: Marques Johansson --- pkg/clients/metal.go | 18 ++++++++++++++++++ pkg/controller/ports/assignment/managed.go | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pkg/clients/metal.go b/pkg/clients/metal.go index 4e83318..9b7e0fe 100644 --- a/pkg/clients/metal.go +++ b/pkg/clients/metal.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "github.com/crossplane/crossplane-runtime/pkg/resource" "github.com/packethost/packngo" @@ -42,6 +43,11 @@ type Client struct { Client *packngo.Client } +const ( + errVirtualNetworkAlreadyContents = " already " + errVirtualNetworkAlreadyPrefix = "Virtual network" +) + // NewCredentialsFromJSON parses JSON bytes returning an Equinix Metal Credentials configuration func NewCredentialsFromJSON(j []byte) (*Credentials, error) { config := &Credentials{} @@ -113,3 +119,15 @@ func IsNotFound(err error) bool { } return false } + +// IsAlreadyDone returns true if, during VLAN assignment operations, the API +// returns an error like "422 Virtual network 1182 already assigned" or "422 +// Virtual network 1182 already unassigned" +func IsAlreadyDone(err error) bool { + if e, ok := err.(*packngo.ErrorResponse); ok && e.Response != nil { + return e.Response.StatusCode == http.StatusUnprocessableEntity && + strings.Contains(e.Response.Status, errVirtualNetworkAlreadyContents) && + strings.HasPrefix(e.Response.Status, errVirtualNetworkAlreadyPrefix) + } + return false +} diff --git a/pkg/controller/ports/assignment/managed.go b/pkg/controller/ports/assignment/managed.go index 479ca8c..2e15805 100644 --- a/pkg/controller/ports/assignment/managed.go +++ b/pkg/controller/ports/assignment/managed.go @@ -144,7 +144,7 @@ func (e *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext } a.Status.SetConditions(xpv1.Creating()) _, _, err := e.client.Assign(&packngo.PortAssignRequest{PortID: meta.GetExternalName(a), VirtualNetworkID: a.Spec.ForProvider.VirtualNetworkID}) - return managed.ExternalCreation{}, errors.Wrap(err, errCreateAssignment) + return managed.ExternalCreation{}, errors.Wrap(resource.Ignore(packetclient.IsAlreadyDone, err), errCreateAssignment) } func (e *external) Update(ctx context.Context, mg resource.Managed) (managed.ExternalUpdate, error) { @@ -159,5 +159,5 @@ func (e *external) Delete(ctx context.Context, mg resource.Managed) error { } a.SetConditions(xpv1.Deleting()) _, _, err := e.client.Unassign(&packngo.PortAssignRequest{PortID: meta.GetExternalName(a), VirtualNetworkID: a.Spec.ForProvider.VirtualNetworkID}) - return errors.Wrap(resource.Ignore(packetclient.IsNotFound, err), errDeleteAssignment) + return errors.Wrap(resource.IgnoreAny(err, packetclient.IsNotFound, packetclient.IsAlreadyDone), errDeleteAssignment) }