Skip to content

Commit 962e94f

Browse files
authored
Add some features that ob-operator supports to dashboard (#659)
1 parent e176679 commit 962e94f

File tree

16 files changed

+486
-32
lines changed

16 files changed

+486
-32
lines changed

internal/cli/utils/parser.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ func MapZonesToTopology(zones map[string]string) ([]param.ZoneTopology, error) {
4343
Zone: zoneName,
4444
Replicas: replica,
4545
NodeSelector: make([]common.KVPair, 0),
46-
Tolerations: make([]common.KVPair, 0),
4746
Affinities: make([]common.AffinitySpec, 0),
4847
})
4948
}

internal/dashboard/business/oceanbase/obcluster.go

Lines changed: 192 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ import (
2020

2121
"github.com/google/uuid"
2222
"github.com/pkg/errors"
23+
"github.com/sirupsen/logrus"
2324
logger "github.com/sirupsen/logrus"
2425
corev1 "k8s.io/api/core/v1"
2526
apiresource "k8s.io/apimachinery/pkg/api/resource"
2627
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2728

29+
"github.com/oceanbase/ob-operator/api/constants"
2830
apitypes "github.com/oceanbase/ob-operator/api/types"
2931
"github.com/oceanbase/ob-operator/api/v1alpha1"
3032
"github.com/oceanbase/ob-operator/internal/clients"
@@ -35,7 +37,9 @@ import (
3537
modelcommon "github.com/oceanbase/ob-operator/internal/dashboard/model/common"
3638
"github.com/oceanbase/ob-operator/internal/dashboard/model/param"
3739
"github.com/oceanbase/ob-operator/internal/dashboard/model/response"
40+
"github.com/oceanbase/ob-operator/internal/dashboard/utils"
3841
oberr "github.com/oceanbase/ob-operator/pkg/errors"
42+
models "github.com/oceanbase/ob-operator/pkg/oceanbase-sdk/model"
3943
)
4044

4145
const (
@@ -115,11 +119,16 @@ func buildOBClusterResponse(ctx context.Context, obcluster *v1alpha1.OBCluster)
115119
// TODO: add metrics
116120
Metrics: nil,
117121
}
118-
var parameters []modelcommon.KVPair
122+
var parameters []response.ParameterSpec
123+
statusParameterMap := make(map[string]string, 0)
124+
for _, param := range obcluster.Status.Parameters {
125+
statusParameterMap[param.Name] = param.Value
126+
}
119127
for _, param := range obcluster.Spec.Parameters {
120-
parameters = append(parameters, modelcommon.KVPair{
121-
Key: param.Name,
122-
Value: param.Value,
128+
parameters = append(parameters, response.ParameterSpec{
129+
Name: param.Name,
130+
SpecValue: param.Value,
131+
Value: statusParameterMap[param.Name],
123132
})
124133
}
125134
respCluster.Parameters = parameters
@@ -537,6 +546,7 @@ func generateOBClusterInstance(param *param.CreateOBClusterParam) *v1alpha1.OBCl
537546
Parameters: parameters,
538547
Topology: topology,
539548
UserSecrets: generateUserSecrets(param.Name, param.ClusterId),
549+
Scenario: param.Scenario,
540550
},
541551
}
542552
switch param.Mode {
@@ -546,6 +556,12 @@ func generateOBClusterInstance(param *param.CreateOBClusterParam) *v1alpha1.OBCl
546556
obcluster.Annotations[oceanbaseconst.AnnotationsMode] = oceanbaseconst.ModeService
547557
default:
548558
}
559+
if param.DeletionProtection {
560+
obcluster.Annotations[oceanbaseconst.AnnotationsIgnoreDeletion] = "true"
561+
}
562+
if param.PvcIndependent {
563+
obcluster.Annotations[oceanbaseconst.AnnotationsIndependentPVCLifecycle] = "true"
564+
}
549565
return obcluster
550566
}
551567

@@ -723,3 +739,175 @@ func GetOBClusterStatistic(ctx context.Context) ([]response.OBClusterStatistic,
723739
})
724740
return statisticResult, nil
725741
}
742+
743+
func PatchOBCluster(ctx context.Context, nn *param.K8sObjectIdentity, param *param.PatchOBClusterParam) (*response.OBCluster, error) {
744+
obcluster, err := clients.GetOBCluster(ctx, nn.Namespace, nn.Name)
745+
if err != nil {
746+
return nil, errors.Wrapf(err, "Get obcluster %s %s", nn.Namespace, nn.Name)
747+
}
748+
if obcluster.Status.Status != clusterstatus.Running {
749+
return nil, errors.Errorf("OBCluster status is invalid %s", obcluster.Status.Status)
750+
}
751+
alreadyIgnoredDeletion := obcluster.Annotations[oceanbaseconst.AnnotationsIgnoreDeletion] == "true"
752+
753+
if obcluster.Spec.OBServerTemplate != nil {
754+
// Update resource if specified
755+
obcluster.Spec.OBServerTemplate.Resource = &apitypes.ResourceSpec{
756+
Cpu: *apiresource.NewQuantity(param.Resource.Cpu, apiresource.DecimalSI),
757+
Memory: *apiresource.NewQuantity(param.Resource.MemoryGB*constant.GB, apiresource.BinarySI),
758+
}
759+
} else if param.Storage != nil && obcluster.Spec.OBServerTemplate != nil {
760+
// Update storage if specified
761+
obcluster.Spec.OBServerTemplate.Storage = &apitypes.OceanbaseStorageSpec{
762+
DataStorage: &apitypes.StorageSpec{
763+
StorageClass: param.Storage.Data.StorageClass,
764+
Size: *apiresource.NewQuantity(param.Storage.Data.SizeGB*constant.GB, apiresource.BinarySI),
765+
},
766+
RedoLogStorage: &apitypes.StorageSpec{
767+
StorageClass: param.Storage.RedoLog.StorageClass,
768+
Size: *apiresource.NewQuantity(param.Storage.RedoLog.SizeGB*constant.GB, apiresource.BinarySI),
769+
},
770+
LogStorage: &apitypes.StorageSpec{
771+
StorageClass: param.Storage.Log.StorageClass,
772+
Size: *apiresource.NewQuantity(param.Storage.Log.SizeGB*constant.GB, apiresource.BinarySI),
773+
},
774+
}
775+
} else if param.Monitor != nil && obcluster.Spec.MonitorTemplate == nil {
776+
// Update monitor if specified
777+
obcluster.Spec.MonitorTemplate = &apitypes.MonitorTemplate{
778+
Image: param.Monitor.Image,
779+
Resource: &apitypes.ResourceSpec{
780+
Cpu: *apiresource.NewQuantity(param.Monitor.Resource.Cpu, apiresource.DecimalSI),
781+
Memory: *apiresource.NewQuantity(param.Monitor.Resource.MemoryGB*constant.GB, apiresource.BinarySI),
782+
},
783+
}
784+
} else if param.RemoveMonitor {
785+
// Remove monitor if specified
786+
obcluster.Spec.MonitorTemplate = nil
787+
} else if param.BackupVolume != nil && obcluster.Spec.BackupVolume == nil {
788+
// Update backup volume if specified
789+
obcluster.Spec.BackupVolume = &apitypes.BackupVolumeSpec{
790+
Volume: &corev1.Volume{
791+
Name: "ob-backup",
792+
VolumeSource: corev1.VolumeSource{
793+
NFS: &corev1.NFSVolumeSource{
794+
Server: param.BackupVolume.Address,
795+
Path: param.BackupVolume.Path,
796+
ReadOnly: false,
797+
},
798+
},
799+
},
800+
}
801+
} else if param.RemoveBackupVolume {
802+
// Remove backup volume if specified
803+
obcluster.Spec.BackupVolume = nil
804+
} else if len(param.Parameters) > 0 {
805+
// Update parameters if specified
806+
obcluster.Spec.Parameters = buildOBClusterParameters(param.Parameters)
807+
}
808+
809+
if param.AddDeletionProtection && !alreadyIgnoredDeletion {
810+
// Update deletion protection if specified
811+
obcluster.Annotations[oceanbaseconst.AnnotationsIgnoreDeletion] = "true"
812+
} else if param.RemoveDeletionProtection && alreadyIgnoredDeletion {
813+
delete(obcluster.Annotations, oceanbaseconst.AnnotationsIgnoreDeletion)
814+
}
815+
816+
cluster, err := clients.UpdateOBCluster(ctx, obcluster)
817+
if err != nil {
818+
return nil, oberr.NewInternal(err.Error())
819+
}
820+
return buildOBClusterResponse(ctx, cluster)
821+
}
822+
823+
func RestartOBServers(ctx context.Context, nn *param.K8sObjectIdentity, param *param.RestartOBServersParam) (*response.OBCluster, error) {
824+
obcluster, err := clients.GetOBCluster(ctx, nn.Namespace, nn.Name)
825+
if err != nil {
826+
return nil, errors.Wrapf(err, "Get obcluster %s %s", nn.Namespace, nn.Name)
827+
}
828+
if obcluster.Status.Status != clusterstatus.Running {
829+
return nil, errors.Errorf("OBCluster status is invalid %s", obcluster.Status.Status)
830+
}
831+
832+
// Create OBClusterOperation for restarting observers
833+
operation := &v1alpha1.OBClusterOperation{
834+
ObjectMeta: metav1.ObjectMeta{
835+
GenerateName: "restart-observers-",
836+
Namespace: nn.Namespace,
837+
},
838+
Spec: v1alpha1.OBClusterOperationSpec{
839+
Type: constants.ClusterOpTypeRestartOBServers,
840+
OBCluster: nn.Name,
841+
RestartOBServers: &v1alpha1.RestartOBServersConfig{
842+
OBServers: param.OBServers,
843+
OBZones: param.OBZones,
844+
All: param.All,
845+
},
846+
},
847+
}
848+
849+
_, err = clients.CreateOBClusterOperation(ctx, operation)
850+
if err != nil {
851+
return nil, oberr.NewInternal(err.Error())
852+
}
853+
854+
return buildOBClusterResponse(ctx, obcluster)
855+
}
856+
857+
func DeleteOBServers(ctx context.Context, nn *param.K8sObjectIdentity, param *param.DeleteOBServersParam) (*response.OBCluster, error) {
858+
obcluster, err := clients.GetOBCluster(ctx, nn.Namespace, nn.Name)
859+
if err != nil {
860+
return nil, errors.Wrapf(err, "Get obcluster %s %s", nn.Namespace, nn.Name)
861+
}
862+
if obcluster.Status.Status != clusterstatus.Running {
863+
return nil, errors.Errorf("OBCluster status is invalid %s", obcluster.Status.Status)
864+
}
865+
866+
// Create OBClusterOperation for deleting observers
867+
operation := &v1alpha1.OBClusterOperation{
868+
ObjectMeta: metav1.ObjectMeta{
869+
GenerateName: "delete-observers-",
870+
Namespace: nn.Namespace,
871+
},
872+
Spec: v1alpha1.OBClusterOperationSpec{
873+
Type: constants.ClusterOpTypeDeleteOBServers,
874+
OBCluster: nn.Name,
875+
DeleteOBServers: &v1alpha1.DeleteOBServersConfig{
876+
OBServers: param.OBServers,
877+
},
878+
},
879+
}
880+
881+
_, err = clients.CreateOBClusterOperation(ctx, operation)
882+
if err != nil {
883+
return nil, oberr.NewInternal(err.Error())
884+
}
885+
886+
return buildOBClusterResponse(ctx, obcluster)
887+
}
888+
889+
func ListOBClusterParameters(ctx context.Context, nn *param.K8sObjectIdentity) ([]*models.Parameter, error) {
890+
obcluster, err := clients.GetOBCluster(ctx, nn.Namespace, nn.Name)
891+
if err != nil {
892+
return nil, errors.Wrapf(err, "Get obcluster %s %s", nn.Namespace, nn.Name)
893+
}
894+
observerList := v1alpha1.OBServerList{}
895+
err = clients.ServerClient.List(ctx, nn.Namespace, &observerList, metav1.ListOptions{
896+
LabelSelector: fmt.Sprintf("%s=%s", oceanbaseconst.LabelRefOBCluster, nn.Name),
897+
})
898+
if err != nil {
899+
logrus.WithError(err).Error("Failed to list observers")
900+
return nil, errors.Wrap(err, "List observers")
901+
}
902+
conn, err := utils.GetOBConnection(ctx, obcluster, "root", "sys", obcluster.Spec.UserSecrets.Root)
903+
if err != nil {
904+
logrus.Info("Failed to get OceanBase database connection")
905+
return nil, errors.Wrap(err, "Get OceanBase database connection")
906+
}
907+
parameters, err := conn.ListParametersWithTenantID(ctx, 1)
908+
if err != nil {
909+
logrus.WithError(err).Error("Failed to query parameters")
910+
return nil, errors.Wrap(err, "Query parameters")
911+
}
912+
return parameters, nil
913+
}

internal/dashboard/business/oceanbase/obcluster_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ func getMockedCreateClusterParam() *param.CreateOBClusterParam {
4141
Key: "test-node-selector",
4242
Value: "test-node-selector-value",
4343
}},
44-
Tolerations: []common.KVPair{{
45-
Key: "test-toleration",
46-
Value: "test-toleration-value",
44+
Tolerations: []common.TolerationSpec{{
45+
KVPair: common.KVPair{
46+
Key: "test-toleration",
47+
Value: "test-toleration-value",
48+
},
4749
}},
4850
Affinities: []common.AffinitySpec{{
4951
SelectorExpression: common.SelectorExpression{

internal/dashboard/business/oceanbase/obtenant.go

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/oceanbase/ob-operator/api/v1alpha1"
3232
"github.com/oceanbase/ob-operator/internal/clients"
3333
"github.com/oceanbase/ob-operator/internal/clients/schema"
34+
oceanbaseconst "github.com/oceanbase/ob-operator/internal/const/oceanbase"
3435
"github.com/oceanbase/ob-operator/internal/const/status/tenantstatus"
3536
"github.com/oceanbase/ob-operator/internal/dashboard/model/param"
3637
"github.com/oceanbase/ob-operator/internal/dashboard/model/response"
@@ -41,8 +42,10 @@ import (
4142
func buildOBTenantApiType(nn types.NamespacedName, p *param.CreateOBTenantParam) (*v1alpha1.OBTenant, error) {
4243
t := &v1alpha1.OBTenant{
4344
ObjectMeta: v1.ObjectMeta{
44-
Name: nn.Name,
45-
Namespace: nn.Namespace,
45+
Name: nn.Name,
46+
Namespace: nn.Namespace,
47+
Annotations: make(map[string]string),
48+
Labels: make(map[string]string),
4649
},
4750
TypeMeta: v1.TypeMeta{
4851
Kind: schema.OBTenantKind,
@@ -58,6 +61,8 @@ func buildOBTenantApiType(nn types.NamespacedName, p *param.CreateOBTenantParam)
5861

5962
// guard non-nil
6063
Pools: []v1alpha1.ResourcePoolSpec{},
64+
65+
Scenario: p.Scenario,
6166
},
6267
}
6368

@@ -141,6 +146,27 @@ func buildOBTenantApiType(nn types.NamespacedName, p *param.CreateOBTenantParam)
141146
}
142147
}
143148
}
149+
if len(p.Variables) > 0 {
150+
t.Spec.Variables = make([]apitypes.Variable, 0, len(p.Variables))
151+
for i := range p.Variables {
152+
t.Spec.Variables = append(t.Spec.Variables, apitypes.Variable{
153+
Name: p.Variables[i].Key,
154+
Value: p.Variables[i].Value,
155+
})
156+
}
157+
}
158+
if len(p.Parameters) > 0 {
159+
t.Spec.Parameters = make([]apitypes.Parameter, 0, len(p.Parameters))
160+
for i := range p.Parameters {
161+
t.Spec.Parameters = append(t.Spec.Parameters, apitypes.Parameter{
162+
Name: p.Parameters[i].Key,
163+
Value: p.Parameters[i].Value,
164+
})
165+
}
166+
}
167+
if p.DeletionProtection {
168+
t.Annotations[oceanbaseconst.AnnotationsIgnoreDeletion] = "true"
169+
}
144170
return t, nil
145171
}
146172

@@ -351,7 +377,7 @@ func CreateOBTenant(ctx context.Context, nn types.NamespacedName, p *param.Creat
351377
}
352378

353379
if p.Source.Restore.OSSAccessID != "" && p.Source.Restore.OSSAccessKey != "" {
354-
ossSecretName := p.Name + "-oss-access-" + rand.String(6)
380+
ossSecretName := nn.Name + "-backup-" + strings.ToLower(strings.ReplaceAll(string(p.Source.Restore.Type), "_", "-")) + "-secret-" + rand.String(6)
355381
t.Spec.Source.Restore.ArchiveSource.OSSAccessSecret = ossSecretName
356382
t.Spec.Source.Restore.BakDataSource.OSSAccessSecret = ossSecretName
357383
_, err = k8sclient.ClientSet.CoreV1().Secrets(nn.Namespace).Create(ctx, &corev1.Secret{
@@ -362,6 +388,8 @@ func CreateOBTenant(ctx context.Context, nn types.NamespacedName, p *param.Creat
362388
StringData: map[string]string{
363389
"accessId": p.Source.Restore.OSSAccessID,
364390
"accessKey": p.Source.Restore.OSSAccessKey,
391+
"appId": p.Source.Restore.AppID,
392+
"s3Region": p.Source.Restore.Region,
365393
},
366394
}, v1.CreateOptions{})
367395
if err != nil {
@@ -548,6 +576,7 @@ func PatchTenant(ctx context.Context, nn types.NamespacedName, p *param.PatchTen
548576
if err != nil {
549577
return nil, err
550578
}
579+
alreadyIgnoreDeletion := tenant.Annotations[oceanbaseconst.AnnotationsIgnoreDeletion] == "true"
551580
if p.UnitNumber != nil {
552581
tenant.Spec.UnitNumber = *p.UnitNumber
553582
}
@@ -595,6 +624,31 @@ func PatchTenant(ctx context.Context, nn types.NamespacedName, p *param.PatchTen
595624
}
596625
}
597626
}
627+
if alreadyIgnoreDeletion && p.RemoveDeletionProtection {
628+
delete(tenant.Annotations, oceanbaseconst.AnnotationsIgnoreDeletion)
629+
} else if !alreadyIgnoreDeletion && p.AddDeletionProtection {
630+
tenant.Annotations[oceanbaseconst.AnnotationsIgnoreDeletion] = "true"
631+
}
632+
if len(p.Variables) > 0 {
633+
newVars := make([]apitypes.Variable, 0, len(p.Variables))
634+
for i := range p.Variables {
635+
newVars = append(newVars, apitypes.Variable{
636+
Name: p.Variables[i].Key,
637+
Value: p.Variables[i].Value,
638+
})
639+
}
640+
tenant.Spec.Variables = newVars
641+
}
642+
if len(p.Parameters) > 0 {
643+
newParameters := make([]apitypes.Parameter, 0, len(p.Parameters))
644+
for i := range p.Parameters {
645+
newParameters = append(newParameters, apitypes.Parameter{
646+
Name: p.Parameters[i].Key,
647+
Value: p.Parameters[i].Value,
648+
})
649+
}
650+
tenant.Spec.Parameters = newParameters
651+
}
598652
tenant, err = clients.UpdateOBTenant(ctx, tenant)
599653
if err != nil {
600654
return nil, err

0 commit comments

Comments
 (0)