-
Notifications
You must be signed in to change notification settings - Fork 3
Allow creating and modifying allocations with backwards-compatibility #52
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
base: main
Are you sure you want to change the base?
Conversation
|
Note-to-self: Look at the REST API introduced by upstream Coldfront to see if it meets the requirements of this issue |
|
@knikolla After reviewing the new Coldfront API in |
While it's under the same URL, it need to be explicitly enabled to register itself under it, so I think we're okay for now. No need to change away from |
| allocation = Allocation.objects.create( | ||
| project=validated_data["project"], | ||
| status=AllocationStatusChoice.objects.get( | ||
| name="Active" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question.
New would be the safe choice.
Otherwise allowing it to be provided as part of the API query during creation and default to New if missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it seems people want to use the API to create Coldfront allocations and have them also create projects on OpenShift and OpenStack, do I also signal allocation_activate if the status choice is Active?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not send a signal when an allocation is created in any state. If someone modifies an allocation to change status, then do send a signal. So if New -> Active = activate or Active -> Denied|Revoked = deactivate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means if someone wants to use the API to create an allocation and have it create a project in the remote cluster, we want them to send 2 requests to the API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is fine.
| "resource", | ||
| "resources_id", | ||
| "status", | ||
| "allocationattribute_set", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way to "rename" how this fields appear in the output? I think allocationattribute_set is too "internal implementation".
| "project_id", | ||
| "description", | ||
| "resource", | ||
| "resources_id", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like that there's both a resource and a resources_id. Can you make this work with just resource by for example accepting an API request to create a resource allocation with
'resource': { 'id': 3 }
73b35ab to
06dbb3d
Compare
| slug_field="name", queryset=AllocationStatusChoice.objects.all() | ||
| ) | ||
|
|
||
| # TODO (Quan): What about default start/end dates? Default quantity? Description? Justification? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default the end date to a year from now, quantity to 1 and Description and Justification to empty strings.
| def get_resource(self, obj: Allocation) -> dict: | ||
| resource = obj.resources.first() | ||
| return {"name": resource.name, "resource_type": resource.resource_type.name} | ||
| # TODO (Quan): If the status is `Active`, do we fire the `activate_allocation` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Responded in a different comment.
|
|
||
| def update(self, allocation: Allocation, validated_data): | ||
| """Only allow updating allocation attributes for now""" | ||
| # TODO (Quan) Do we want to allow updating any other allocation properties? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced about the appropriate way to handle attribute changes. When done through the web dashboard they create a ChangeRequest, whereas modified from here they would modify the attribute directly. This is a flow that we haven't really dealt with as of now. I would say for now disallow changing attributes until we have a clear use case and workflow.
|
@joachimweyl @knikolla Since there is also a need to automate decomissioning projects. Do we want the API to implement a |
Not at the moment. |
|
Note-to-self: The branch containing work on the |
a37b1f4 to
4d2206d
Compare
| fields = ["id", "project", "description", "resources", "status", "attributes"] | ||
|
|
||
| resource = serializers.SerializerMethodField() | ||
| resources = ResourceSerializer(many=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep resource as a single element in the API rather than a resources list. This is not something the Web Dashboard exposes when requesting allocations and is not something the API should expose.
When you save it to the database you can convert it into a list since that's what the model expects.
| project = ProjectSerializer() | ||
| attributes = serializers.SerializerMethodField() | ||
| status = serializers.SerializerMethodField() | ||
| attributes = AllocationAttributeSerializer( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to break the invoicing scripts in a non-backwards compatible way, that's going to make it painful to update, as both the API AND the invoicing scripts will need to be updated at the same time.
May I suggest you either
- preserve the previous format of the
attributesfield for both GET and create operations, OR - keep the previous
attributesas is for GET operations and introduce a new field with a different name alongside it that appears in GET and supports create. - Version the API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will keep the API in a backwards compatible way. To do that, I will have to go against your comment here, since as far as I could tell, SerializerMethodField is read-only, and is the only way for the attributes list to be displayed the way we've had them. A new field requested_attributes will be added.
Same will go for the resource attribute
The more I tried looking for a solution that allows writing and reading through the same field, it seems technically possible, but would require very convoluted code that stretches the intended use of DRF
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@knikolla Actually, the more spend on this, I'm now wondering if it's best to just version the API. I am fine with either making my PR backward-compatible, or to just version the API. May I have your opinion on which option you'd pick and why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@QuanMPhm Make a proposal for how you would version the API.
|
Note to self: The branch containing an API versioning solution is |
To create an allocation, a JSON payload can be uploaded to `/api/allocations`:
{
"attributes": [
{"attribute_type": "OpenShift Limit on CPU Quota", "value": 8},
{"attribute_type": "OpenShift Limit on RAM Quota (MiB)", "value": 16},
],
"project": {"id": project.id},
"resources": [{"id": self.resource.id}],
"status": "New",
}
Updating allocation status is done via a PATCH request
to `/api/allocations/{id}` with a JSON payload:
{
"status": "Active"
}
Certain status transitions trigger signals:
- New -> Active: allocation_activate
- Active -> Denied: allocation_deactivate
4d2206d to
8964950
Compare
Closes #47. After digging around DRF's documentation on serialization, it turned out the code changes would be a bit more complicated than I expected. I will submit a draft for now to demonstrate my current direction.
My draft allows creating new allocations through
api/allocationsby posting a json payload like this:The output from the allocations API has been changed slightly. It now outputs this:
I will implement the "update" feature once given the green light on this approach.