Skip to content

Commit

Permalink
fix: fallback from bulk delete to delete single object
Browse files Browse the repository at this point in the history
This is useful in case if one object deletion fails, in bulkdelete also all others fail, but when deleting single object, only the one fails
  • Loading branch information
bl4ko committed Apr 24, 2024
1 parent ade649d commit 951f76a
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 26 deletions.
2 changes: 1 addition & 1 deletion cmd/netbox-ssot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func main() {
}
wg.Wait()

// Orphan manager cleanup
// Orphan manager cleanup on successful run and if enabled
if config.Netbox.RemoveOrphans && successfullRun {
ssotLogger.Info(mainCtx, "Cleaning up orphaned objects...")
err = netboxInventory.DeleteOrphans(mainCtx)
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ github.com/PaloAltoNetworks/pango v0.10.2 h1:Tjn6vIzzAq6Dd7N0mDuiP8w8pz8k5W9zz/T
github.com/PaloAltoNetworks/pango v0.10.2/go.mod h1:GztcRnVLur7G+VFG7Z5ZKNFgScLtsycwPMp1qVebE5g=
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
github.com/cisco-en-programmability/dnacenter-go-sdk/v5 v5.0.25 h1:H9i9u7ADeiuMzfkJIzQUg/noTWA82DmAehcAwlIfBPE=
github.com/cisco-en-programmability/dnacenter-go-sdk/v5 v5.0.25/go.mod h1:4Km+JuiyL/LsNRvO4dMWUSUVbnNBRmbwzJMU1oUbn0E=
github.com/cisco-en-programmability/dnacenter-go-sdk/v5 v5.0.26 h1:qLIr8VW60CKwjNJydytrnukETVb0FSZKTO/QKqE9STA=
github.com/cisco-en-programmability/dnacenter-go-sdk/v5 v5.0.26/go.mod h1:4Km+JuiyL/LsNRvO4dMWUSUVbnNBRmbwzJMU1oUbn0E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down
8 changes: 5 additions & 3 deletions internal/netbox/inventory/delete_items.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ func (nbi *NetboxInventory) DeleteOrphans(ctx context.Context) error {
if len(ids) != 0 {
nbi.Logger.Infof(ctx, "Deleting orphaned objects of type %s", objectAPIPath)
nbi.Logger.Debugf(ctx, "Ids of objects to be deleted: %v", ids)
err := nbi.NetboxAPI.BulkDeleteObjects(ctx, objectAPIPath, ids)
if err != nil {
return err
for id := range ids {
err := nbi.NetboxAPI.DeleteObject(ctx, objectAPIPath, id)
if err != nil {
nbi.Logger.Errorf(nbi.Ctx, "delete objects: %s", err)

Check warning on line 21 in internal/netbox/inventory/delete_items.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/inventory/delete_items.go#L18-L21

Added lines #L18 - L21 were not covered by tests
}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions internal/netbox/service/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,20 @@ func (api *NetboxClient) BulkDeleteObjects(ctx context.Context, objectPath strin

return nil
}

// Function that deletes objectas on path objectPath.
// It deletes a single object at a time. It is alternative to bulk delete
// because if one delete fails other still go.
func (api *NetboxClient) DeleteObject(ctx context.Context, objectPath string, id int) error {
api.Logger.Debugf(ctx, "Deleting object with id %d on route %s", id, objectPath)

Check warning on line 209 in internal/netbox/service/rest.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/service/rest.go#L208-L209

Added lines #L208 - L209 were not covered by tests

response, err := api.doRequest(MethodDelete, fmt.Sprintf("%s%d/", objectPath, id), nil)
if err != nil {
return err

Check warning on line 213 in internal/netbox/service/rest.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/service/rest.go#L211-L213

Added lines #L211 - L213 were not covered by tests
}

if response.StatusCode != http.StatusNoContent {
return fmt.Errorf("unexpected status code: %d: %s", response.StatusCode, response.Body)

Check warning on line 217 in internal/netbox/service/rest.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/service/rest.go#L216-L217

Added lines #L216 - L217 were not covered by tests
}
return nil

Check warning on line 219 in internal/netbox/service/rest.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/service/rest.go#L219

Added line #L219 was not covered by tests
}
47 changes: 27 additions & 20 deletions internal/source/fmc/fmc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,29 @@ import (
"fmt"
"io"
"net/http"
"time"

"github.com/bl4ko/netbox-ssot/internal/constants"
)

type fmcClient struct {
HTTPClient *http.Client
BaseURL string
Username string
Password string
AccessToken string
RefreshToken string
HTTPClient *http.Client
BaseURL string
Username string
Password string
AccessToken string
RefreshToken string
DefaultTimeout time.Duration
}

func newFMCClient(username string, password string, httpScheme string, hostname string, port int, httpClient *http.Client) (*fmcClient, error) {

Check warning on line 25 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L25

Added line #L25 was not covered by tests
// First we obtain access and refresh token
c := &fmcClient{
HTTPClient: httpClient,
BaseURL: fmt.Sprintf("%s://%s:%d/api", httpScheme, hostname, port),
Username: username,
Password: password,
HTTPClient: httpClient,
BaseURL: fmt.Sprintf("%s://%s:%d/api", httpScheme, hostname, port),
Username: username,
Password: password,
DefaultTimeout: time.Second * constants.DefaultAPITimeout,

Check warning on line 32 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L27-L32

Added lines #L27 - L32 were not covered by tests
}

aToken, rToken, err := c.Authenticate()
Expand All @@ -40,8 +45,8 @@ func newFMCClient(username string, password string, httpScheme string, hostname

// Authenticate performs authentication on FMC API. If successful it returns access and refresh tokens.
func (fmcc fmcClient) Authenticate() (string, string, error) {
ctx := context.Background()
defer ctx.Done()
ctx, cancel := context.WithTimeout(context.Background(), fmcc.DefaultTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/fmc_platform/v1/auth/generatetoken", fmcc.BaseURL), nil)
if err != nil {
return "", "", fmt.Errorf("new request with context: %w", err)

Check warning on line 52 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L47-L52

Added lines #L47 - L52 were not covered by tests
Expand Down Expand Up @@ -97,6 +102,8 @@ type Device struct {
}

func (fmcc *fmcClient) MakeRequest(ctx context.Context, method, path string, body io.Reader) (*http.Response, error) {
ctx, cancel := context.WithTimeout(ctx, fmcc.DefaultTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, method, fmt.Sprintf("%s/%s", fmcc.BaseURL, path), body)
if err != nil {
return nil, err

Check warning on line 109 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L104-L109

Added lines #L104 - L109 were not covered by tests
Expand All @@ -112,7 +119,7 @@ func (fmcc *fmcClient) GetDomains() ([]Domain, error) {
domains := []Domain{}
ctx := context.Background()
for {
apiResponse, err := fmcc.MakeRequest(ctx, http.MethodGet, "fmc_platform/v1/info/domain", nil)
apiResponse, err := fmcc.MakeRequest(ctx, http.MethodGet, fmt.Sprintf("fmc_platform/v1/info/domain?offset=%d&limit=%d", offset, limit), nil)
if err != nil {
return nil, fmt.Errorf("make request for domains: %w", err)

Check warning on line 124 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L116-L124

Added lines #L116 - L124 were not covered by tests
}
Expand All @@ -134,7 +141,7 @@ func (fmcc *fmcClient) GetDomains() ([]Domain, error) {
domains = append(domains, marshaledResponse.Items...)

Check warning on line 141 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L140-L141

Added lines #L140 - L141 were not covered by tests
}

if marshaledResponse.Paging.Count < marshaledResponse.Paging.Limit {
if len(marshaledResponse.Items) < limit {
break

Check warning on line 145 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L144-L145

Added lines #L144 - L145 were not covered by tests
}
offset += limit

Check warning on line 147 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L147

Added line #L147 was not covered by tests
Expand All @@ -147,7 +154,7 @@ func (fmcc *fmcClient) GetDevices(domainUUID string) ([]Device, error) {
limit := 25
devices := []Device{}
ctx := context.Background()
devicesURL := fmt.Sprintf("fmc_config/v1/domain/%s/devices/devicerecords", domainUUID)
devicesURL := fmt.Sprintf("fmc_config/v1/domain/%s/devices/devicerecords?offset=%d&limit=%d", domainUUID, offset, limit)
for {
apiResponse, err := fmcc.MakeRequest(ctx, http.MethodGet, devicesURL, nil)
if err != nil {
Expand All @@ -171,7 +178,7 @@ func (fmcc *fmcClient) GetDevices(domainUUID string) ([]Device, error) {
devices = append(devices, marshaledResponse.Items...)

Check warning on line 178 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L177-L178

Added lines #L177 - L178 were not covered by tests
}

if marshaledResponse.Paging.Count < marshaledResponse.Paging.Limit {
if len(marshaledResponse.Items) < limit {
break

Check warning on line 182 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L181-L182

Added lines #L181 - L182 were not covered by tests
}
offset += limit

Check warning on line 184 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L184

Added line #L184 was not covered by tests
Expand All @@ -190,7 +197,7 @@ func (fmcc *fmcClient) GetDevicePhysicalInterfaces(domainUUID string, deviceID s
limit := 25
pIfaces := []PhysicalInterface{}
ctx := context.Background()
pInterfacesURL := fmt.Sprintf("fmc_config/v1/domain/%s/devices/devicerecords/%s/physicalinterfaces", domainUUID, deviceID)
pInterfacesURL := fmt.Sprintf("fmc_config/v1/domain/%s/devices/devicerecords/%s/physicalinterfaces?offset=%d&limit=%d", domainUUID, deviceID, offset, limit)
for {
apiResponse, err := fmcc.MakeRequest(ctx, http.MethodGet, pInterfacesURL, nil)
if err != nil {
Expand All @@ -214,7 +221,7 @@ func (fmcc *fmcClient) GetDevicePhysicalInterfaces(domainUUID string, deviceID s
pIfaces = append(pIfaces, marshaledResponse.Items...)

Check warning on line 221 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L220-L221

Added lines #L220 - L221 were not covered by tests
}

if marshaledResponse.Paging.Count < marshaledResponse.Paging.Limit {
if len(marshaledResponse.Items) < limit {
break

Check warning on line 225 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L224-L225

Added lines #L224 - L225 were not covered by tests
}
offset += limit

Check warning on line 227 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L227

Added line #L227 was not covered by tests
Expand All @@ -233,7 +240,7 @@ func (fmcc *fmcClient) GetDeviceVLANInterfaces(domainUUID string, deviceID strin
limit := 25
vlanIfaces := []VlanInterface{}
ctx := context.Background()
pInterfacesURL := fmt.Sprintf("fmc_config/v1/domain/%s/devices/devicerecords/%s/vlaninterfaces", domainUUID, deviceID)
pInterfacesURL := fmt.Sprintf("fmc_config/v1/domain/%s/devices/devicerecords/%s/vlaninterfaces?offset=%d&limit=%d", domainUUID, deviceID, offset, limit)
for {
apiResponse, err := fmcc.MakeRequest(ctx, http.MethodGet, pInterfacesURL, nil)
if err != nil {
Expand All @@ -257,7 +264,7 @@ func (fmcc *fmcClient) GetDeviceVLANInterfaces(domainUUID string, deviceID strin
vlanIfaces = append(vlanIfaces, marshaledResponse.Items...)

Check warning on line 264 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L263-L264

Added lines #L263 - L264 were not covered by tests
}

if marshaledResponse.Paging.Count < marshaledResponse.Paging.Limit {
if len(marshaledResponse.Items) < limit {
break

Check warning on line 268 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L267-L268

Added lines #L267 - L268 were not covered by tests
}
offset += limit

Check warning on line 270 in internal/source/fmc/fmc_client.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_client.go#L270

Added line #L270 was not covered by tests
Expand Down

0 comments on commit 951f76a

Please sign in to comment.