Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[scd] factor out parameter validation against previous OIR #1090

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 39 additions & 18 deletions pkg/scd/operational_intents_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,36 @@ func checkUpsertPermissionsAndReturnManager(authorizedManager *api.Authorization
return dssmodels.Manager(*authorizedManager.ClientID), nil
}

// validateUpsertRequestAgainstPreviousOIR checks that the client requesting an OIR upsert has the necessary permissions and that the request is valid.
// On success, the version of the OIR is returned:
// - upon initial creation (if no previous OIR exists), it is 0
// - otherwise, it is the version of the previous OIR
func validateUpsertRequestAgainstPreviousOIR(
requestingManager dssmodels.Manager,
providedOVN restapi.EntityOVN,
previousOIR *scdmodels.OperationalIntent,
) error {

if previousOIR != nil {
if previousOIR.Manager != requestingManager {
return stacktrace.NewErrorWithCode(dsserr.PermissionDenied,
"OperationalIntent owned by %s, but %s attempted to modify", previousOIR.Manager, requestingManager)
}
if previousOIR.OVN != scdmodels.OVN(providedOVN) {
return stacktrace.NewErrorWithCode(dsserr.VersionMismatch,
"Current version is %s but client specified version %s", previousOIR.OVN, providedOVN)
}

return nil
}

if providedOVN != "" {
return stacktrace.NewErrorWithCode(dsserr.NotFound, "OperationalIntent does not exist and therefore is not version %s", providedOVN)
}

return nil
}

// upsertOperationalIntentReference inserts or updates an Operational Intent.
// If the ovn argument is empty (""), it will attempt to create a new Operational Intent.
func (a *Server) upsertOperationalIntentReference(ctx context.Context, authorizedManager *api.AuthorizationResult, entityid restapi.EntityID, ovn restapi.EntityOVN, params *restapi.PutOperationalIntentReferenceParameters,
Expand All @@ -496,37 +526,28 @@ func (a *Server) upsertOperationalIntentReference(ctx context.Context, authorize
var responseOK *restapi.ChangeOperationalIntentReferenceResponse
var responseConflict *restapi.AirspaceConflictResponse
action := func(ctx context.Context, r repos.Repository) (err error) {
var version int32 // Version of the Operational Intent (0 means creation requested).

// Lock subscriptions based on the cell to reduce the number of retries under concurrent load.
// See issue #1002 for details.
err = r.LockSubscriptionsOnCells(ctx, validParams.cells)
if err != nil {
return stacktrace.Propagate(err, "Unable to acquire lock")
}

// Get existing OperationalIntent, if any, and validate request
// Get existing OperationalIntent, if any
old, err := r.GetOperationalIntent(ctx, validParams.id)
if err != nil {
return stacktrace.Propagate(err, "Could not get OperationalIntent from repo")
}
if old != nil {
if old.Manager != manager {
return stacktrace.NewErrorWithCode(dsserr.PermissionDenied,
"OperationalIntent owned by %s, but %s attempted to modify", old.Manager, manager)
}
if old.OVN != scdmodels.OVN(ovn) {
return stacktrace.NewErrorWithCode(dsserr.VersionMismatch,
"Current version is %s but client specified version %s", old.OVN, ovn)
}
// Validate the request against the previous OIR and return the current version
// (upon new OIR creation, version is 0)
if err := validateUpsertRequestAgainstPreviousOIR(manager, validParams.ovn, old); err != nil {
return stacktrace.PropagateWithCode(err, stacktrace.GetCode(err), "Request validation failed")
}

// For an OIR being created, version starts at 0
version := int32(0)
if old != nil {
version = int32(old.Version)
} else {
if ovn != "" {
return stacktrace.NewErrorWithCode(dsserr.NotFound, "OperationalIntent does not exist and therefore is not version %s", ovn)
}

version = 0
}

var sub *scdmodels.Subscription
Expand Down
Loading