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

[ENG-5196] addon capabilities (in api and implementers' toolkit) #12

Closed
wants to merge 20 commits into from

Conversation

aaxelb
Copy link
Collaborator

@aaxelb aaxelb commented Feb 7, 2024

add the concept of "capabilities" that represent statically declared groups of "operations" for a category of addons.

code organization

  • addon_toolkit: (new) holds declared addon category interfaces (for addon implementers to subclass) and helpful tools for interacting with them
  • addon_service: the existing django app that uses addon_toolkit and available addon implementations

addon implementers should import from addon_toolkit, but not addon_service (to avoid cyclical confusion)

api changes

two new attrs in api (both lists of strings)

  • on authorized-storage-accounts: authorized_capabilities
  • on configured-storage-addons: connected_capabilities
  • for storage addons, currently two possible values in those lists: "access" and "update"

database changes

two new model fields in api (both ArrayField(IntField) with an IntEnum for choices (guaranteed to map to/from the string-based enum used for api values))

  • on AuthorizedStorageAccount: authorized_capabilities
  • on ConfiguredStorageAccount: connected_capabilities

how to...

...add a category of addons (see addon_toolkit.storage for an incomplete example):

  • declare a set of capabilities as enum.Enum with string values
  • declare an addon interface class (decorated with @addon_interface(capabilities=MyCapabiltiesEnum))
  • declare operation stubs on the class (each decorated with @proxy_operation(capability=...) or @redirect_operation(capability=...))

...implement an addon of a given category:

  • make a subclass of the category's interface (e.g. addon_toolkit.storage.StorageAddon)
  • implement any number of operations declared on that interface

future work

  • expose "addon operations" in the api (in ENG-5184, previously "actions")
    • either a new jsonapi type (and relationships) or an agreed-upon json blob (and attributes)
    • decide a consistent way to express/handle operation parameters and return values (...dataclasses?)
    • list available operations for the current user on a given Configured*Addon
    • provide a way to invoke operations and get the result

@aaxelb aaxelb mentioned this pull request Feb 7, 2024
@aaxelb aaxelb force-pushed the feature/capability-operations branch 2 times, most recently from ea018db to f21d344 Compare February 8, 2024 15:24
@aaxelb aaxelb changed the title Feature/capability operations [ENG-5196] addon capabilities (in api and implementers' toolkit) Feb 8, 2024
@aaxelb aaxelb force-pushed the feature/capability-operations branch from 4acb163 to b442bce Compare February 8, 2024 17:04
@aaxelb aaxelb force-pushed the feature/capability-operations branch from d76f372 to 92f07f6 Compare February 9, 2024 13:29
@aaxelb aaxelb marked this pull request as ready for review February 9, 2024 14:10
Copy link
Contributor

@jwalz jwalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still working to groc the toolkit, but here's some quick feedback on everything before that

from addon_service.common.base_model import AddonsServiceBaseModel


class AuthorizedStorageAccount(AddonsServiceBaseModel):
# TODO: authorized_capabilities = ArrayField(...)
authorized_capabilities = ArrayField(
models.IntegerField(choices=IntStorageCapability.as_django_choices()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: would rather enforce this differently, since setting it in choices requires migrations when options change.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough; how about a validator?

@@ -74,6 +76,7 @@ def __init__(self, *args, **kwargs):

def create(self, validate_data):
account_owner = validate_data["account_owner"]
authorized_capabilities = validate_data["authorized_capabilities"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we change validate_data -> validated_data here? feels weird to have a variable with a verb clause as a name (I think my brain just autocorrected this when it first made it in)

__all__ = ("IntStorageCapability",)


class IntStorageCapability(IntEnumForEnum, base_enum=StorageCapability):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose between the dual enums? Feels very complicated. On OSF, I was able to handle the translation from int to string for the API with a single enum here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm maybe it is too complicated, it sure did get finicky... bloomed from a conviction that addon_toolkit should be completely unaware of addon_service's database details like storing enum as int, but also that addon_toolkit.storage should define the source-of-truth StorageCapability enum, and then maybe got overexcited about having a use for __init_subclass__ kwargs

also seemed nice code-aroma to use enums as explicit source-controlled maps between a python-name and both api and database representations -- the single-enum requires the api representation to be the python name... which may be fine, really

for the operations api i did further complicate the idea, but may have better expressed intent?

@aaxelb
Copy link
Collaborator Author

aaxelb commented Mar 13, 2024

included in #16

@aaxelb aaxelb closed this Mar 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants