Add basic committed resource functionality with reservations#566
Add basic committed resource functionality with reservations#566
Conversation
knowledge with contentChanged
commitments syncer for flavor group CRs commitments API batch change CRs commitments API version endpoint skeletons for API capacity endpoint basic testing
api/v1alpha1/reservation_types.go
Outdated
|
|
||
| // AZ specifies the availability zone for this reservation, if restricted to a specific AZ. | ||
| // +kubebuilder:validation:Optional | ||
| AZ string `json:"az,omitempty"` |
There was a problem hiding this comment.
Can we call that AvailabilityZone instead of AZ?
PhilippMatthes
left a comment
There was a problem hiding this comment.
I don't want to gatekeep anything, so you can bring this to main if you like.
These are my findings from my first session reviewing the code.
Unfortunately I wasn't able to look at everything. Hope this helps!
api/v1alpha1/reservation_types.go
Outdated
|
|
||
| // AZ specifies the availability zone for this reservation, if restricted to a specific AZ. | ||
| // +kubebuilder:validation:Optional | ||
| AZ string `json:"az,omitempty"` |
There was a problem hiding this comment.
Should we type this strongly in the spec? In the hypervisor crd, this is just a label. This is fine, I'm just wondering where we should differentiate between spec and labels.
| - nova-decisions-cleanup-task | ||
| # Endpoints configuration for reservations controller | ||
| endpoints: | ||
| novaExternalScheduler: "http://localhost:8080/scheduler/nova/external" |
There was a problem hiding this comment.
This would call localhost, as in the container itself, right? This works as long as the scheduling controllers are initialized within the same pod. Maybe we can make this more robust by 1. adding a comment indicating this dependency or 2. using kubernetes dns to resolve to the correct service, something like cortex-nova-scheduler.svc....
| var flavorGroupsQuery string | ||
|
|
||
| // flavorGroupIdentifierName specifies the extra_spec key used to group flavors. | ||
| const flavorGroupIdentifierName = "quota:hw_version" |
There was a problem hiding this comment.
I would prefer not pulling this out.
|
|
||
| // The smallest flavor in the group (used for CR size quantification) | ||
| SmallestFlavor FlavorInGroup `json:"smallestFlavor"` | ||
| } |
There was a problem hiding this comment.
For features my main concern is always: does this fit into the kubernetes size limit in the production landscape. But I think, this should be fine. Do you want to check just to be safe?
There was a problem hiding this comment.
yes, checked and looks good
| // flavorGroupIdentifierName specifies the extra_spec key used to group flavors. | ||
| const flavorGroupIdentifierName = "quota:hw_version" | ||
|
|
||
| var flavorGroupLog = ctrl.Log.WithName("flavor_group_extractor") |
There was a problem hiding this comment.
Thanks for using the controller log right away instead of slog. This should be the way to go.
| func (m *ReservationManager) buildReservationCRD( | ||
| log logr.Logger, | ||
| state *CommitmentState, | ||
| slotIndex int, | ||
| deltaMemoryBytes int64, | ||
| flavorGroup compute.FlavorGroupFeature, | ||
| creator string, | ||
| ) *v1alpha1.Reservation { |
There was a problem hiding this comment.
This could be a NewReservation() function without the manager as receiver, unless I'm missing why the nested k8s client is needed here.
| if err != nil { | ||
| resp.RejectionReason = fmt.Sprintf("project with unknown resource name %s: %v", projectID, err) | ||
| requireRollback = true | ||
| break ProcessLoop |
There was a problem hiding this comment.
I have to admit, this is the first time I've seen loop markers in go code, didn't even know they existed 😄 To me this sounds like a nice use case to pull each sub-forloop into a separate routine.
| ) | ||
|
|
||
| touchedReservations = make([]v1alpha1.Reservation, 0) | ||
| removedReservations = make([]v1alpha1.Reservation, 0) |
There was a problem hiding this comment.
You can initialize slices as nil and can still iterate over them + append. For example
var touchedReservations []v1alpha1.Reservation
| reservationToDelete = &existing[len(existing)-1] | ||
| existing = existing[:len(existing)-1] // remove from existing list | ||
| } | ||
| removedReservations = append(removedReservations, *reservationToDelete) |
There was a problem hiding this comment.
I tried to understand this code but I failed. I think what I'm missing here would be some good code comments that tell me what this code does.
| // TODO add domain | ||
|
|
||
| // get existing reservations for rollback | ||
| existing_reservations, err := ListReservationsForCommitment(ctx, api.client, string(commitment.UUID), "") |
There was a problem hiding this comment.
Is this helper really needed? All of its usages get creator = ""
There was a problem hiding this comment.
More importantly, will this hit the controller-runtime cache properly or the apiserver?
There was a problem hiding this comment.
Yes, cache is used correctly.
But I decided to introduce labels already in this PR.. making this code useless
| old := res.DeepCopy() | ||
| patch := client.MergeFrom(old) |
There was a problem hiding this comment.
None of your changes, but we are deep copying after the mutation of the object which will result in an empty diff when merging. Should move this up.
| if _, err := e.DB.Select(&rows, flavorGroupsQuery); err != nil { | ||
| flavorGroupLog.Error(err, "failed to query flavors") | ||
| return nil, err |
There was a problem hiding this comment.
iirc the database can be nil. (See BaseExtractor.ExtractSQL)
| if _, err := e.DB.Select(&rows, flavorGroupsQuery); err != nil { | |
| flavorGroupLog.Error(err, "failed to query flavors") | |
| return nil, err | |
| if e.DB == nil { | |
| return nil, errors.New("database connection is not initialized") | |
| } | |
| if _, err := e.DB.Select(&rows, flavorGroupsQuery); err != nil { | |
| flavorGroupLog.Error(err, "failed to query flavors") | |
| return nil, err |
Test Coverage ReportTest Coverage 📊: 67.9% |
This adds basic committed resource (CR) functionality: