lxd icon indicating copy to clipboard operation
lxd copied to clipboard

Derive a context for use in operations

Open markylaing opened this issue 1 month ago • 11 comments

Operations should never be using the request context inside their run function body. The request context may have been cancelled before the operation is started.

When calling operations.OperationCreate, a context is passed in which is used to set the operation Requestor. The original context is not persisted beyond this.

This PR changes the operations.Operation to remove the cancel.Canceller in favour of using a cancellable context. The operation context is just a background context with some key information copied from the input context (e.g. the Requestor). Operations can still monitor the daemon shutdown context via their state field if necessary.

I've then updated all operations in LXD to use (Operation).Context() wherever a context.Context argument is called for inside an operation.

This is another part of https://github.com/canonical/lxd/issues/16613#issuecomment-3547843653

markylaing avatar Nov 21 '25 16:11 markylaing

Ok this one is ready for review now

markylaing avatar Dec 03 '25 14:12 markylaing

Just marking as draft while I wait for tests to pass.

markylaing avatar Dec 04 '25 14:12 markylaing

Tests passing now

markylaing avatar Dec 04 '25 17:12 markylaing

I'm not sure if we even need cancel.HTTPRequestCanceller anywhere in the code base. Although I notice, with dismay, that its part of the public SDK via BackupFileRequest and ImageFileRequest structs.

Just looked into this. What a nightmare. We can't change this really without introducing a context.Context parameter across the whole client interface.

markylaing avatar Dec 08 '25 09:12 markylaing

I'm not sure if we even need cancel.HTTPRequestCanceller anywhere in the code base. Although I notice, with dismay, that its part of the public SDK via BackupFileRequest and ImageFileRequest structs.

Just looked into this. What a nightmare. We can't change this really without introducing a context.Context parameter across the whole client interface.

At the very least we should aim to de-couple it from the Operation and allow for cancel.HTTPRequestCanceller to be cancelled by a context (from the Operation).

tomponline avatar Dec 08 '25 09:12 tomponline

introducing a context.Context parameter across the whole client interface

This has been on the "TODO" list for quite some time too.

tomponline avatar Dec 08 '25 09:12 tomponline

introducing a context.Context parameter across the whole client interface

This has been on the "TODO" list for quite some time too.

Shall we bite the bullet? I'm making the same change everywhere else. Of course this is a big breaking change on the client. We can wait until after the next LTS if preferred.

markylaing avatar Dec 08 '25 10:12 markylaing

introducing a context.Context parameter across the whole client interface

This has been on the "TODO" list for quite some time too.

Shall we bite the bullet? I'm making the same change everywhere else. Of course this is a big breaking change on the client. We can wait until after the next LTS if preferred.

Lets discuss in the team meeting.

It shouldn't need to hold this change up though as we should be able to untangle cancel.HTTPRequestCanceller and Operation at least.

tomponline avatar Dec 08 '25 10:12 tomponline

This PR is now updated to:

  1. Add a context to an operations' main "run" hook. This context contains the operation requestor and can be cancelled in some situations.
  2. Change how operations are instantiated. We now how CreateUserOperation and CreateServerOperation, with the former requiring a request.Requestor to ensure that the owner of the operation is explicitly set for auditing and access control purposes.
  3. Remove the channel that is returned from operation.Cancel. As far as I can tell this was not used. Callers should use op.Wait.
  4. Cancel image download operations via a HTTPRequestCanceller that automatically cancels requests when a given context is cancelled.

I have not added a context argument to any other hooks other than the "run" hook. It seemed redundant in the "cancel" hook, and the onConnect hook has an *http.Request argument which has it's own context.

markylaing avatar Dec 10 '25 14:12 markylaing

Test failures fixed. Opened a new issue for the underlying problem: https://github.com/canonical/lxd/issues/17220

markylaing avatar Dec 10 '25 17:12 markylaing

@markylaing this is looking really great, its going to be much easier to use and reason about operations once we get your work merged. Thanks!

tomponline avatar Dec 11 '25 09:12 tomponline

@tomponline tests finally ran and passed. I've also changed the operation delete endpoint to emit the lifecycle event before waiting on the operation.

Ready for review when you're ready 😌

markylaing avatar Dec 15 '25 19:12 markylaing

@markylaing btw is UpdateResources() unused?

tomponline avatar Dec 16 '25 13:12 tomponline

@markylaing btw is UpdateResources() unused?

I'll check

markylaing avatar Dec 16 '25 13:12 markylaing