Add flavor extra_specs#817
Conversation
d67e89a to
8de585f
Compare
eshulman2
left a comment
There was a problem hiding this comment.
Thanks for the PR, generally LGTM except for the missing interface aliases.
| return deletes | ||
| } | ||
|
|
||
| func (actuator flavorActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller generic.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { |
There was a problem hiding this comment.
flavorActuator now implements ReconcileResourceActuator via GetResourceReconcilers, but the type alias and compile-time assertion are missing. Compare securitygroup/actuator.go which has:
reconcileResourceActuator = interfaces.ReconcileResourceActuator[orcObjectPT, orcObjectT, osResourceT]
// ...
var _ reconcileResourceActuator = securityGroupActuator{}The resourceReconciler alias was added, but reconcileResourceActuator wasn't. Please add:
reconcileResourceActuator = generic.ReconcileResourceActuator[orcObjectPT, orcObjectT, osResourceT]var _ reconcileResourceActuator = flavorActuator{}There was a problem hiding this comment.
To be fair, this was not a big problem. This compile-time assertions are there to help developers and provide quicker feedback loop to ensure the actuator satisfies the interface. It has no functional use.
| } | ||
| } | ||
|
|
||
| func TestExtraSpecUpdates(t *testing.T) { |
There was a problem hiding this comment.
Nice to have: would be great to add a test covering the entire logic of the update function eg. what happens if update succeed but delete fails, etc
| // +kubebuilder:validation:MaxItems:=128 | ||
| // +listType=atomic | ||
| // +optional | ||
| ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"` |
There was a problem hiding this comment.
The []ExtraSpec slice has no uniqueness constraint on name. If a user specifies the same name twice, extraSpecsToMap silently uses the last value - no error or warning at admission time.
A CEL validation rule on the field would catch this at admission time:
// +kubebuilder:validation:XValidation:rule="self.all(x, self.filter(y, y.name == x.name).size() == 1)",message="extraSpecs names must be unique"
ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"`There was a problem hiding this comment.
Thinking about it, we should probably change the the list type to map.
// extraSpecs is a map of key-value pairs that define extra specifications for the flavor.
// +kubebuilder:validation:MaxItems:=128
// +listType=map
// +listMapKey=name
// +optional
ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"`| // +listType=atomic | ||
| // +optional | ||
| ExtraSpecs []VolumeTypeExtraSpec `json:"extraSpecs,omitempty"` | ||
| ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"` |
There was a problem hiding this comment.
same as above:
The []ExtraSpec slice has no uniqueness constraint on name. If a user specifies the same name twice, extraSpecsToMap silently uses the last value - no error or warning at admission time.
A CEL validation rule on the field would catch this at admission time:
// +kubebuilder:validation:XValidation:rule="self.all(x, self.filter(y, y.name == x.name).size() == 1)",message="extraSpecs names must be unique"
ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"`There was a problem hiding this comment.
There too, this should be change to a map list type, but this should be done in a separate PR.
We'll still need to revert the changes and keep the VolumeTypeExtraSpec type.
Signed-off-by: Roman Hros <roman.hros@dnation.cloud>
8de585f to
597bac6
Compare
Thank you for the review, I added everything requested |
|
@mandre can you please approve the workflow, then I'll re-review |
|
@chess-knight apologies for the lack of input on your PR, I was quite busy lately. I'll review very soon, stay tuned. |
mandre
left a comment
There was a problem hiding this comment.
Oof, this was much more work than I originally expected due to the fact this is actually a separate API call. There are a few critical changes we need to make (use a separate FlavorExtraSpecs stuct, and drop the change from CreateResource) before we can merge.
| // description contains a free form description of the flavor. | ||
| // +kubebuilder:validation:MinLength:=1 | ||
| // +kubebuilder:validation:MaxLength:=65535 | ||
| // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="description is immutable" |
There was a problem hiding this comment.
Just noting that the description should in theory be mutable (https://docs.openstack.org/api-ref/compute/#update-flavor-description) but this is clearly out of scope for this PR.
There was a problem hiding this comment.
Yes, I know about mutable description, but as you said i didn't want to change it with this PR.
| if len(resource.ExtraSpecs) > 0 { | ||
| extraSpecs := extraSpecsToMap(resource.ExtraSpecs) | ||
|
|
||
| _, err = actuator.osClient.CreateFlavorExtraSpecs(ctx, osResource.ID, flavors.ExtraSpecsOpts(extraSpecs)) |
There was a problem hiding this comment.
We can't create the extra spec in CreateResource because this is a different API call that might fail. This should be handled in a separate reconciliation, and we should rely on updateResource instead (or better even, call it reconcileExtraSpecs).
| // +kubebuilder:validation:MaxLength:=64 | ||
| type KeystoneName string | ||
|
|
||
| type ExtraSpec struct { |
There was a problem hiding this comment.
I'm unsure about making the ExtraSpec a common type. The different projects might enforce different rules.
For instance, nova allows spaces in flavors extraspec keys while cinder does not for volumetypes extraspec keys.
BTW, we should add CEL validations for those.
| // +kubebuilder:validation:MaxItems:=128 | ||
| // +listType=atomic | ||
| // +optional | ||
| ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"` |
There was a problem hiding this comment.
Thinking about it, we should probably change the the list type to map.
// extraSpecs is a map of key-value pairs that define extra specifications for the flavor.
// +kubebuilder:validation:MaxItems:=128
// +listType=map
// +listMapKey=name
// +optional
ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"`| // +listType=atomic | ||
| // +optional | ||
| ExtraSpecs []VolumeTypeExtraSpec `json:"extraSpecs,omitempty"` | ||
| ExtraSpecs []ExtraSpec `json:"extraSpecs,omitempty"` |
There was a problem hiding this comment.
There too, this should be change to a map list type, but this should be done in a separate PR.
We'll still need to revert the changes and keep the VolumeTypeExtraSpec type.
| return progress.WrapError(actuator.osClient.DeleteFlavor(ctx, flavor.ID)) | ||
| } | ||
|
|
||
| func (actuator flavorActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { |
There was a problem hiding this comment.
Let's rename this function to reconcileExtraSpecs, as this is a single concern reconciler.
| } | ||
|
|
||
| if len(updates) > 0 { | ||
| _, err := actuator.osClient.CreateFlavorExtraSpecs( |
There was a problem hiding this comment.
OK, it seems (from the gophercloud comment at least) that nova does an upsert.
The nova doc doesn't state it explicitly.
Add
Flavorextra_specs.Also, create common type
ExtraSpecand use it for theFlavorandVolumeType.Closes #738