Skip to content

Commit

Permalink
Supplement types of tenant operations to align cluster operations (#545)
Browse files Browse the repository at this point in the history
  • Loading branch information
powerfooI authored Sep 6, 2024
1 parent d4336bf commit 6001e7c
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 21 deletions.
7 changes: 7 additions & 0 deletions api/constants/tenant.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ const (
TenantOpChangePwd types.TenantOperationType = "CHANGE_PASSWORD"
TenantOpUpgrade types.TenantOperationType = "UPGRADE"
TenantOpReplayLog types.TenantOperationType = "REPLAY_LOG"

TenantOpSetUnitNumber types.TenantOperationType = "SET_UNIT_NUMBER"
TenantOpSetConnectWhiteList types.TenantOperationType = "SET_CONNECT_WHITE_LIST"
TenantOpAddResourcePools types.TenantOperationType = "ADD_RESOURCE_POOLS"
TenantOpDeleteResourcePools types.TenantOperationType = "DELETE_RESOURCE_POOLS"
TenantOpModifyResourcePools types.TenantOperationType = "MODIFY_RESOURCE_POOLS"
TenantOpSetCharset types.TenantOperationType = "SET_CHARSET"
)

const (
Expand Down
11 changes: 10 additions & 1 deletion api/v1alpha1/obtenantoperation_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ type OBTenantOperationSpec struct {
ChangePwd *OBTenantOpChangePwdSpec `json:"changePwd,omitempty"`
ReplayUntil *RestoreUntilConfig `json:"replayUntil,omitempty"`
TargetTenant *string `json:"targetTenant,omitempty"`
AuxillaryTenant *string `json:"auxillaryTenant,omitempty"`
AuxiliaryTenant *string `json:"auxiliaryTenant,omitempty"`

// Auxiliary
Force bool `json:"force,omitempty"`
UnitNumber int `json:"unitNumber,omitempty"`
ConnectWhiteList string `json:"connectWhiteList,omitempty"`
Charset string `json:"charset,omitempty"`
ModifyResourcePools []ResourcePoolSpec `json:"modifyResourcePools,omitempty"`
AddResourcePools []ResourcePoolSpec `json:"addResourcePools,omitempty"`
DeleteResourcePools []string `json:"deleteResourcePools,omitempty"`
}

type OBTenantOpSwitchoverSpec struct {
Expand Down
107 changes: 102 additions & 5 deletions api/v1alpha1/obtenantoperation_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/oceanbase/ob-operator/api/constants"
apitypes "github.com/oceanbase/ob-operator/api/types"
oceanbaseconst "github.com/oceanbase/ob-operator/internal/const/oceanbase"
"github.com/oceanbase/ob-operator/internal/const/status/tenantstatus"
)

// log is for logging in this package.
Expand All @@ -50,8 +51,6 @@ func (r *OBTenantOperation) SetupWebhookWithManager(mgr ctrl.Manager) error {
Complete()
}

// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!

//+kubebuilder:webhook:path=/mutate-oceanbase-oceanbase-com-v1alpha1-obtenantoperation,mutating=true,failurePolicy=fail,sideEffects=None,groups=oceanbase.oceanbase.com,resources=obtenantoperations,verbs=create;update,versions=v1alpha1,name=mobtenantoperation.kb.io,admissionReviewVersions=v1

var _ webhook.Defaulter = &OBTenantOperation{}
Expand Down Expand Up @@ -228,10 +227,108 @@ func (r *OBTenantOperation) validateMutation() error {
}
}
default:
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("type"), string(r.Spec.Type)+" type of operation is not supported"))
if r.Spec.TargetTenant == nil {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("targetTenant"), "name of targetTenant is required"))
}
}
if len(allErrs) != 0 {
return allErrs.ToAggregate()
}

obtenant := &OBTenant{}
err := clt.Get(context.Background(), types.NamespacedName{Name: *r.Spec.TargetTenant, Namespace: r.Namespace}, obtenant)
if err != nil {
if !apierrors.IsNotFound(err) {
allErrs = append(allErrs, field.InternalError(field.NewPath("spec").Child("targetTenant"), err))
} else {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("targetTenant"), r.Spec.TargetTenant, "The target tenant does not exist"))
}
}
if len(allErrs) != 0 {
return allErrs.ToAggregate()
}
if len(allErrs) == 0 {
return nil

if obtenant.Status.Status != tenantstatus.Running && !r.Spec.Force {
return field.Invalid(field.NewPath("spec").Child("targetTenant"), r.Spec.TargetTenant, "The target tenant is not in running status")
}

switch r.Spec.Type {
case constants.TenantOpSetUnitNumber:
if r.Spec.UnitNumber == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("unitNumber"), "unitNumber is required"))
}
case constants.TenantOpSetConnectWhiteList:
if r.Spec.ConnectWhiteList == "" {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("connectWhiteList"), "connectWhiteList is required"))
}
case constants.TenantOpSetCharset:
if r.Spec.Charset == "" {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("charset"), "charset is required"))
}
case constants.TenantOpAddResourcePools:
if len(r.Spec.AddResourcePools) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("addResourcePools"), "addResourcePools is required"))
break
}
obcluster := &OBCluster{}
err := clt.Get(context.Background(), types.NamespacedName{Name: obtenant.Spec.ClusterName, Namespace: r.Namespace}, obcluster)
if err != nil {
if !apierrors.IsNotFound(err) {
allErrs = append(allErrs, field.InternalError(field.NewPath("spec").Child("targetTenant"), err))
} else {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("targetTenant"), r.Spec.TargetTenant, "The target tenant's cluster "+obtenant.Spec.ClusterName+" does not exist"))
}
}
if obcluster.Spec.Topology == nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("targetTenant"), r.Spec.TargetTenant, "The target tenant's cluster "+obtenant.Spec.ClusterName+" does not have a topology"))
}
pools := make(map[string]any)
for _, pool := range obtenant.Spec.Pools {
pools[pool.Zone] = struct{}{}
}
for _, pool := range r.Spec.AddResourcePools {
if _, ok := pools[pool.Zone]; ok {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("addResourcePools"), r.Spec.AddResourcePools, "The resource pool already exists"))
}
}
zonesInOBCluster := make(map[string]any, len(obcluster.Spec.Topology))
for _, zone := range obcluster.Spec.Topology {
zonesInOBCluster[zone.Zone] = struct{}{}
}
for _, pool := range r.Spec.AddResourcePools {
if _, ok := zonesInOBCluster[pool.Zone]; !ok {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("addResourcePools"), r.Spec.AddResourcePools, "The target zone "+pool.Zone+" does not exist in the cluster"))
}
}
case constants.TenantOpModifyResourcePools:
if len(r.Spec.ModifyResourcePools) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("modifyResourcePools"), "modifyResourcePools is required"))
break
}
pools := make(map[string]any)
for _, pool := range obtenant.Spec.Pools {
pools[pool.Zone] = struct{}{}
}
for _, pool := range r.Spec.ModifyResourcePools {
if _, ok := pools[pool.Zone]; !ok {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("modifyResourcePools"), r.Spec.ModifyResourcePools, "The target resource pool in zone "+pool.Zone+" does not exist"))
}
}
case constants.TenantOpDeleteResourcePools:
if len(r.Spec.DeleteResourcePools) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("deleteResourcePools"), "deleteResourcePools is required"))
}
pools := make(map[string]any)
for _, pool := range obtenant.Spec.Pools {
pools[pool.Zone] = struct{}{}
}
for _, pool := range r.Spec.DeleteResourcePools {
if _, ok := pools[pool]; !ok {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("deleteResourcePools"), r.Spec.DeleteResourcePools, "The target resource pool in zone "+pool+" does not exist"))
}
}
default:
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("type"), string(r.Spec.Type)+" type of operation is not supported"))
}
return allErrs.ToAggregate()
}
Expand Down
2 changes: 1 addition & 1 deletion api/v1alpha1/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func newTenantOperation(tenantName string) *OBTenantOperation {
ChangePwd: &OBTenantOpChangePwdSpec{},
ReplayUntil: &RestoreUntilConfig{},
TargetTenant: &tenantName,
AuxillaryTenant: &tenantName,
AuxiliaryTenant: &tenantName,
},
}
}
26 changes: 23 additions & 3 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

151 changes: 150 additions & 1 deletion config/crd/bases/oceanbase.oceanbase.com_obtenantoperations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,75 @@ spec:
spec:
description: OBTenantOperationSpec defines the desired state of OBTenantOperation
properties:
auxillaryTenant:
addResourcePools:
items:
properties:
priority:
default: 1
type: integer
resource:
description: TODO Split UnitConfig struct to SpecUnitConfig
and StatusUnitConfig
properties:
iopsWeight:
type: integer
logDiskSize:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
maxCPU:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
maxIops:
type: integer
memorySize:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
minCPU:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
minIops:
type: integer
required:
- maxCPU
- memorySize
type: object
type:
description: TODO Split LocalityType struct to SpecLocalityType
and StatusLocalityType
properties:
isActive:
description: TODO move isActive to ResourcePoolSpec And
ResourcePoolStatus
type: boolean
name:
type: string
replica:
type: integer
required:
- isActive
- name
- replica
type: object
zone:
type: string
required:
- resource
- zone
type: object
type: array
auxiliaryTenant:
type: string
changePwd:
properties:
Expand All @@ -71,13 +139,92 @@ spec:
- secretRef
- tenant
type: object
charset:
type: string
connectWhiteList:
type: string
deleteResourcePools:
items:
type: string
type: array
failover:
properties:
standbyTenant:
type: string
required:
- standbyTenant
type: object
force:
description: Auxiliary
type: boolean
modifyResourcePools:
items:
properties:
priority:
default: 1
type: integer
resource:
description: TODO Split UnitConfig struct to SpecUnitConfig
and StatusUnitConfig
properties:
iopsWeight:
type: integer
logDiskSize:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
maxCPU:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
maxIops:
type: integer
memorySize:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
minCPU:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
minIops:
type: integer
required:
- maxCPU
- memorySize
type: object
type:
description: TODO Split LocalityType struct to SpecLocalityType
and StatusLocalityType
properties:
isActive:
description: TODO move isActive to ResourcePoolSpec And
ResourcePoolStatus
type: boolean
name:
type: string
replica:
type: integer
required:
- isActive
- name
- replica
type: object
zone:
type: string
required:
- resource
- zone
type: object
type: array
replayUntil:
properties:
scn:
Expand All @@ -101,6 +248,8 @@ spec:
type: string
type:
type: string
unitNumber:
type: integer
required:
- type
type: object
Expand Down
Loading

0 comments on commit 6001e7c

Please sign in to comment.