-
Notifications
You must be signed in to change notification settings - Fork 673
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
Minimum validation for multitenant formations #5199
Changes from 12 commits
33e92e2
af4d90b
eaefaa4
5f17ce6
b77d367
3c7242c
ad697f8
bdd4434
4e40584
7416311
47e715c
27b29cb
d6453e6
51e2338
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -596,6 +596,16 @@ func ResourceIBMDatabaseInstance() *schema.Resource { | |
Computed: true, | ||
Description: "Can memory scale down as well as up.", | ||
}, | ||
"cpu_enforcement_ratio_ceiling_mb": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Description: "The amount of memory required before the cpu/memory ratio is no longer enforced. (multitenant only).", | ||
}, | ||
"cpu_enforcement_ratio_mb": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Description: "The maximum memory allowed per CPU until the ratio ceiling is reached. (multitenant only).", | ||
}, | ||
}, | ||
}, | ||
}, | ||
|
@@ -987,21 +997,23 @@ type Group struct { | |
} | ||
|
||
type GroupResource struct { | ||
Units string | ||
Allocation int | ||
Minimum int | ||
Maximum int | ||
StepSize int | ||
IsAdjustable bool | ||
IsOptional bool | ||
CanScaleDown bool | ||
Units string | ||
Allocation int | ||
Minimum int | ||
Maximum int | ||
StepSize int | ||
IsAdjustable bool | ||
IsOptional bool | ||
CanScaleDown bool | ||
CPUEnforcementRatioCeilingMb int | ||
CPUEnforcementRatioMb int | ||
} | ||
|
||
type HostFlavorGroupResource struct { | ||
ID string | ||
} | ||
|
||
func getDefaultScalingGroups(_service string, _plan string, meta interface{}) (groups []clouddatabasesv5.Group, err error) { | ||
func getDefaultScalingGroups(_service string, _plan string, _hostFlavor string, meta interface{}) (groups []clouddatabasesv5.Group, err error) { | ||
cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() | ||
if err != nil { | ||
return groups, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) | ||
|
@@ -1033,6 +1045,9 @@ func getDefaultScalingGroups(_service string, _plan string, meta interface{}) (g | |
} | ||
|
||
getDefaultScalingGroupsOptions := cloudDatabasesClient.NewGetDefaultScalingGroupsOptions(service) | ||
if _hostFlavor != "" { | ||
getDefaultScalingGroupsOptions.SetHostFlavor(_hostFlavor) | ||
} | ||
|
||
getDefaultScalingGroupsResponse, _, err := cloudDatabasesClient.GetDefaultScalingGroups(getDefaultScalingGroupsOptions) | ||
if err != nil { | ||
|
@@ -1043,7 +1058,7 @@ func getDefaultScalingGroups(_service string, _plan string, meta interface{}) (g | |
} | ||
|
||
func getInitialNodeCount(service string, plan string, meta interface{}) (int, error) { | ||
groups, err := getDefaultScalingGroups(service, plan, meta) | ||
groups, err := getDefaultScalingGroups(service, plan, "", meta) | ||
|
||
if err != nil { | ||
return 0, err | ||
|
@@ -2702,14 +2717,16 @@ func normalizeGroups(_groups []clouddatabasesv5.Group) (groups []Group) { | |
} | ||
|
||
group.Memory = &GroupResource{ | ||
Units: *g.Memory.Units, | ||
Allocation: int(*g.Memory.AllocationMb), | ||
Minimum: int(*g.Memory.MinimumMb), | ||
Maximum: int(*g.Memory.MaximumMb), | ||
StepSize: int(*g.Memory.StepSizeMb), | ||
IsAdjustable: *g.Memory.IsAdjustable, | ||
IsOptional: *g.Memory.IsOptional, | ||
CanScaleDown: *g.Memory.CanScaleDown, | ||
Units: *g.Memory.Units, | ||
Allocation: int(*g.Memory.AllocationMb), | ||
Minimum: int(*g.Memory.MinimumMb), | ||
Maximum: int(*g.Memory.MaximumMb), | ||
StepSize: int(*g.Memory.StepSizeMb), | ||
IsAdjustable: *g.Memory.IsAdjustable, | ||
IsOptional: *g.Memory.IsOptional, | ||
CanScaleDown: *g.Memory.CanScaleDown, | ||
CPUEnforcementRatioCeilingMb: getCPUEnforcementRatioCeilingMb(g.Memory), | ||
CPUEnforcementRatioMb: getCPUEnforcementRatioMb(g.Memory), | ||
} | ||
|
||
group.Disk = &GroupResource{ | ||
|
@@ -2745,6 +2762,22 @@ func normalizeGroups(_groups []clouddatabasesv5.Group) (groups []Group) { | |
return groups | ||
} | ||
|
||
func getCPUEnforcementRatioCeilingMb(groupMemory *clouddatabasesv5.GroupMemory) int { | ||
if groupMemory.CPUEnforcementRatioCeilingMb != nil { | ||
return int(*groupMemory.CPUEnforcementRatioCeilingMb) | ||
} | ||
|
||
return 0 | ||
} | ||
|
||
func getCPUEnforcementRatioMb(groupMemory *clouddatabasesv5.GroupMemory) int { | ||
if groupMemory.CPUEnforcementRatioMb != nil { | ||
return int(*groupMemory.CPUEnforcementRatioMb) | ||
} | ||
|
||
return 0 | ||
} | ||
|
||
func expandGroups(_groups []interface{}) []*Group { | ||
if len(_groups) == 0 { | ||
return nil | ||
|
@@ -2837,6 +2870,33 @@ func validateGroupHostFlavor(groupId string, resourceName string, group *Group) | |
return nil | ||
} | ||
|
||
func validateMultitenantMemoryCpu(resourceDefaults *Group, group *Group, cpuEnforcementRatioCeiling int, cpuEnforcementRatioMb int) error { | ||
// TODO: Replace this with cpuEnforcementRatioCeiling when it is fixed | ||
cpuEnforcementRatioCeilingTemp := 16384 | ||
|
||
if resourceDefaults.Members == nil { | ||
return nil | ||
} | ||
|
||
if group.Memory.Allocation < resourceDefaults.Memory.Minimum/resourceDefaults.Members.Allocation { | ||
return fmt.Errorf("We were unable to complete your request: group.memory requires a minimum of %d megabytes. Try again with valid values or contact support if the issue persists.", resourceDefaults.Memory.Minimum/resourceDefaults.Members.Allocation) | ||
} | ||
|
||
if group.CPU == nil { | ||
return nil | ||
} | ||
|
||
if group.CPU != nil && group.CPU.Allocation > 2 { | ||
return nil | ||
} | ||
|
||
if group.CPU != nil && group.Memory.Allocation*resourceDefaults.Members.Allocation < cpuEnforcementRatioCeilingTemp*resourceDefaults.Members.Allocation && group.Memory.Allocation*resourceDefaults.Members.Allocation > group.CPU.Allocation*cpuEnforcementRatioMb { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this validation useful, since you are not going to have any fractional values in |
||
return fmt.Errorf("We were unable to complete your request: group.memory %d with group.cpu %d is not valid. Try again with valid values or contact support if the issue persists.", group.Memory.Allocation, group.CPU.Allocation) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) (err error) { | ||
instanceID := diff.Id() | ||
service := diff.Get("service").(string) | ||
|
@@ -2846,11 +2906,23 @@ func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta inter | |
var currentGroups []Group | ||
var groupList []clouddatabasesv5.Group | ||
var groupIds []string | ||
groups := expandGroups(group.(*schema.Set).List()) | ||
var memberGroup *Group | ||
for _, g := range groups { | ||
if g.ID == "member" { | ||
memberGroup = g | ||
break | ||
} | ||
} | ||
|
||
if instanceID != "" { | ||
groupList, err = getGroups(instanceID, meta) | ||
} else { | ||
groupList, err = getDefaultScalingGroups(service, plan, meta) | ||
if memberGroup.HostFlavor != nil { | ||
groupList, err = getDefaultScalingGroups(service, plan, memberGroup.HostFlavor.ID, meta) | ||
} else { | ||
groupList, err = getDefaultScalingGroups(service, plan, "", meta) | ||
} | ||
} | ||
|
||
if err != nil { | ||
|
@@ -2861,6 +2933,8 @@ func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta inter | |
|
||
tfGroups := expandGroups(group.(*schema.Set).List()) | ||
|
||
cpuEnforcementRatioCeiling, cpuEnforcementRatioMb := getCpuEnforcementRatios(service, plan, meta, group) | ||
|
||
// validate group_ids are unique | ||
groupIds = make([]string, 0, len(tfGroups)) | ||
for _, g := range tfGroups { | ||
|
@@ -2892,15 +2966,15 @@ func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta inter | |
// set current nodeCount | ||
nodeCount := groupDefaults.Members.Allocation | ||
|
||
if group.Members != nil { | ||
err = validateGroupScaling(groupId, "members", group.Members.Allocation, groupDefaults.Members, 1) | ||
if group.HostFlavor != nil && group.HostFlavor.ID != "" && group.HostFlavor.ID != "multitenant" { | ||
err = validateGroupHostFlavor(groupId, "host_flavor", group) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if group.HostFlavor != nil && group.HostFlavor.ID != "" && group.HostFlavor.ID != "multitenant" { | ||
err = validateGroupHostFlavor(groupId, "host_flavor", group) | ||
if group.Members != nil { | ||
err = validateGroupScaling(groupId, "members", group.Members.Allocation, groupDefaults.Members, 1) | ||
if err != nil { | ||
return err | ||
} | ||
|
@@ -2911,6 +2985,13 @@ func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta inter | |
if err != nil { | ||
return err | ||
} | ||
|
||
if group.HostFlavor != nil && group.HostFlavor.ID != "" && group.HostFlavor.ID == "multitenant" && cpuEnforcementRatioCeiling != 0 && cpuEnforcementRatioMb != 0 { | ||
err = validateMultitenantMemoryCpu(groupDefaults, group, cpuEnforcementRatioCeiling, cpuEnforcementRatioMb) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
|
||
if group.Disk != nil { | ||
|
@@ -2932,6 +3013,41 @@ func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta inter | |
return nil | ||
} | ||
|
||
func getCpuEnforcementRatios(service string, plan string, meta interface{}, group interface{}) (cpuEnforcementRatioCeiling int, cpuEnforcementRatioMb int) { | ||
var currentGroups []Group | ||
defaultList, err := getDefaultScalingGroups(service, plan, "multitenant", meta) | ||
|
||
if err != nil { | ||
return 0, 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be better to propagate the error upward from here, rather than returning 0, 0. Something like |
||
} | ||
|
||
currentGroups = normalizeGroups(defaultList) | ||
tfGroups := expandGroups(group.(*schema.Set).List()) | ||
|
||
// Get default or current group scaling values | ||
for _, group := range tfGroups { | ||
if group == nil { | ||
break | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would |
||
} | ||
|
||
groupId := group.ID | ||
var groupDefaults *Group | ||
for _, g := range currentGroups { | ||
if g.ID == groupId { | ||
groupDefaults = &g | ||
break | ||
} | ||
} | ||
|
||
if groupDefaults.Memory != nil { | ||
return groupDefaults.Memory.CPUEnforcementRatioCeilingMb, groupDefaults.Memory.CPUEnforcementRatioMb | ||
} | ||
|
||
} | ||
|
||
return 0, 0 | ||
} | ||
|
||
func validateUsersDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) (err error) { | ||
service := diff.Get("service").(string) | ||
|
||
|
@@ -2972,7 +3088,7 @@ func validateUsersDiff(_ context.Context, diff *schema.ResourceDiff, meta interf | |
|
||
// TODO: Use Capability API | ||
// RBAC roles supported for Redis 6.0 and above | ||
if service == "databases-for-redis" && !(version > 0 && version < 6) { | ||
if (service == "databases-for-redis") && !(version > 0 && version < 6) { | ||
err = change.New.ValidateRBACRole() | ||
} else if service == "databases-for-mongodb" && change.New.Type == "ops_manager" { | ||
err = change.New.ValidateOpsManagerRole() | ||
|
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.
should be something like
group.CPU.Allocation >= EnforcementRatioCeiling/EnforcementRatio