Skip to content

Commit a468414

Browse files
authored
Feature: standby tenant (#81)
Support: Change root's password of specific tenant Create a standby tenant from backup restore Create an empty standby tenant and follow a primary tenant's log stream Check whether the log of a tenant is of integrity Failover by activating standby tenant Switchover two tenants and over back
1 parent 5548768 commit a468414

File tree

68 files changed

+3107
-305
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3107
-305
lines changed

Makefile

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,9 @@ commit-hook: $(GOLANGCI_LINT) ## Install commit hook.
210210
.PHONY: connect
211211
connect:
212212
ifdef TENANT
213-
mysql -h$(shell kubectl get pods -o jsonpath='{.items[0].status.podIP}') -P2881 -A -uroot@${TENANT}
213+
$(eval nodeHost = $(shell kubectl get pods -o jsonpath='{.items[1].status.podIP}'))
214+
$(eval pwd = $(shell kubectl get secret $(shell kubectl get obtenant ${TENANT} -o jsonpath='{.status.credentials.root}') -o jsonpath='{.data.password}' | base64 -d))
215+
$(if $(strip $(pwd)), mysql -h$(nodeHost) -P2881 -A -uroot@${TENANT} -p$(pwd) -Doceanbase, mysql -h$(nodeHost) -P2881 -A -uroot@${TENANT} -Doceanbase)
214216
else
215-
mysql -h$(shell kubectl get pods -o jsonpath='{.items[0].status.podIP}') -P2881 -A -uroot -p
216-
endif
217-
218-
.PHONY: connectob
219-
connectob:
220-
ifdef TENANT
221-
mysql -h$(shell kubectl get pods -o jsonpath='{.items[0].status.podIP}') -P2881 -A -uroot@${TENANT} -Doceanbase
222-
else
223-
mysql -h$(shell kubectl get pods -o jsonpath='{.items[0].status.podIP}') -P2881 -A -uroot -p -Doceanbase
217+
mysql -h$(shell kubectl get pods -o jsonpath='{.items[1].status.podIP}') -P2881 -A -uroot -p -Doceanbase
224218
endif

PROJECT

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,8 @@ resources:
136136
kind: OBTenantOperation
137137
path: github.com/oceanbase/ob-operator/api/v1alpha1
138138
version: v1alpha1
139+
webhooks:
140+
defaulting: true
141+
validation: true
142+
webhookVersion: v1
139143
version: "3"

api/constants/backup.go

Lines changed: 26 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,62 +12,47 @@ See the Mulan PSL v2 for more details.
1212

1313
package constants
1414

15-
type BackupJobType string
15+
import "github.com/oceanbase/ob-operator/api/types"
1616

1717
const (
18-
BackupJobTypeFull BackupJobType = "FULL"
19-
BackupJobTypeIncr BackupJobType = "INC"
20-
BackupJobTypeClean BackupJobType = "CLEAN"
21-
BackupJobTypeArchive BackupJobType = "ARCHIVE"
18+
BackupJobTypeFull types.BackupJobType = "FULL"
19+
BackupJobTypeIncr types.BackupJobType = "INC"
20+
BackupJobTypeClean types.BackupJobType = "CLEAN"
21+
BackupJobTypeArchive types.BackupJobType = "ARCHIVE"
2222
)
2323

24-
type BackupJobStatus string
25-
2624
const (
27-
BackupJobStatusRunning BackupJobStatus = "RUNNING"
28-
BackupJobStatusInitializing BackupJobStatus = "INITIALIZING"
29-
BackupJobStatusSuccessful BackupJobStatus = "SUCCESSFUL"
30-
BackupJobStatusFailed BackupJobStatus = "FAILED"
31-
BackupJobStatusCanceled BackupJobStatus = "CANCELED"
32-
BackupJobStatusStopped BackupJobStatus = "STOPPED"
33-
BackupJobStatusSuspend BackupJobStatus = "SUSPEND"
25+
BackupJobStatusRunning types.BackupJobStatus = "RUNNING"
26+
BackupJobStatusInitializing types.BackupJobStatus = "INITIALIZING"
27+
BackupJobStatusSuccessful types.BackupJobStatus = "SUCCESSFUL"
28+
BackupJobStatusFailed types.BackupJobStatus = "FAILED"
29+
BackupJobStatusCanceled types.BackupJobStatus = "CANCELED"
30+
BackupJobStatusStopped types.BackupJobStatus = "STOPPED"
31+
BackupJobStatusSuspend types.BackupJobStatus = "SUSPEND"
3432
)
3533

36-
type BackupPolicyStatusType string
37-
3834
const (
39-
BackupPolicyStatusPreparing BackupPolicyStatusType = "PREPARING"
40-
BackupPolicyStatusPrepared BackupPolicyStatusType = "PREPARED"
41-
BackupPolicyStatusRunning BackupPolicyStatusType = "RUNNING"
42-
BackupPolicyStatusFailed BackupPolicyStatusType = "FAILED"
43-
BackupPolicyStatusPausing BackupPolicyStatusType = "PAUSING"
44-
BackupPolicyStatusPaused BackupPolicyStatusType = "PAUSED"
45-
BackupPolicyStatusStopped BackupPolicyStatusType = "STOPPED"
46-
BackupPolicyStatusResuming BackupPolicyStatusType = "RESUMING"
35+
BackupPolicyStatusPreparing types.BackupPolicyStatusType = "PREPARING"
36+
BackupPolicyStatusPrepared types.BackupPolicyStatusType = "PREPARED"
37+
BackupPolicyStatusRunning types.BackupPolicyStatusType = "RUNNING"
38+
BackupPolicyStatusFailed types.BackupPolicyStatusType = "FAILED"
39+
BackupPolicyStatusPausing types.BackupPolicyStatusType = "PAUSING"
40+
BackupPolicyStatusPaused types.BackupPolicyStatusType = "PAUSED"
41+
BackupPolicyStatusStopped types.BackupPolicyStatusType = "STOPPED"
42+
BackupPolicyStatusResuming types.BackupPolicyStatusType = "RESUMING"
4743
)
4844

49-
type BackupDestination struct {
50-
Type BackupDestType `json:"type,omitempty"`
51-
Path string `json:"path,omitempty"`
52-
}
53-
54-
type BackupDestType string
55-
5645
const (
57-
BackupDestTypeOSS BackupDestType = "OSS"
58-
BackupDestTypeNFS BackupDestType = "NFS"
46+
BackupDestTypeOSS types.BackupDestType = "OSS"
47+
BackupDestTypeNFS types.BackupDestType = "NFS"
5948
)
6049

61-
type LogArchiveDestState string
62-
6350
const (
64-
LogArchiveDestStateEnable LogArchiveDestState = "ENABLE"
65-
LogArchiveDestStateDefer LogArchiveDestState = "DEFER"
51+
LogArchiveDestStateEnable types.LogArchiveDestState = "ENABLE"
52+
LogArchiveDestStateDefer types.LogArchiveDestState = "DEFER"
6653
)
6754

68-
type ArchiveBinding string
69-
7055
const (
71-
ArchiveBindingOptional = "Optional"
72-
ArchiveBindingMandatory = "Mandatory"
56+
ArchiveBindingOptional types.ArchiveBinding = "Optional"
57+
ArchiveBindingMandatory types.ArchiveBinding = "Mandatory"
7358
)

api/constants/restore.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ See the Mulan PSL v2 for more details.
1212

1313
package constants
1414

15-
type RestoreJobStatus string
15+
import "github.com/oceanbase/ob-operator/api/types"
1616

1717
const (
18-
RestoreJobStarting RestoreJobStatus = "STARTING"
19-
RestoreJobRunning RestoreJobStatus = "RUNNING"
20-
RestoreJobFailed RestoreJobStatus = "FAILED"
21-
RestoreJobSuccessful RestoreJobStatus = "SUCCESSFUL"
22-
RestoreJobCanceled RestoreJobStatus = "CANCELED"
18+
RestoreJobStarting types.RestoreJobStatus = "STARTING"
19+
RestoreJobRunning types.RestoreJobStatus = "RUNNING"
20+
RestoreJobFailed types.RestoreJobStatus = "FAILED"
21+
RestoreJobSuccessful types.RestoreJobStatus = "SUCCESSFUL"
22+
RestoreJobCanceled types.RestoreJobStatus = "CANCELED"
2323

24-
RestoreJobStatusActivating RestoreJobStatus = "ACTIVATING"
25-
RestoreJobStatusReplaying RestoreJobStatus = "REPLAYING"
24+
RestoreJobStatusActivating types.RestoreJobStatus = "ACTIVATING"
25+
RestoreJobStatusReplaying types.RestoreJobStatus = "REPLAYING"
2626
)

api/constants/tenant.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,23 @@ See the Mulan PSL v2 for more details.
1212

1313
package constants
1414

15-
type TenantRole string
15+
import "github.com/oceanbase/ob-operator/api/types"
1616

1717
const (
18-
TenantRolePrimary TenantRole = "PRIMARY"
19-
TenantRoleStandby TenantRole = "STANDBY"
18+
TenantRolePrimary types.TenantRole = "PRIMARY"
19+
TenantRoleStandby types.TenantRole = "STANDBY"
2020
)
2121

22-
type TenantOperationType string
23-
2422
const (
25-
TenantOpSwitchover TenantOperationType = "SWITCHOVER"
26-
TenantOpFailover TenantOperationType = "FAILOVER"
27-
TenantOpChangePwd TenantOperationType = "CHANGE_PASSWORD"
23+
TenantOpSwitchover types.TenantOperationType = "SWITCHOVER"
24+
TenantOpFailover types.TenantOperationType = "FAILOVER"
25+
TenantOpChangePwd types.TenantOperationType = "CHANGE_PASSWORD"
2826
)
2927

30-
type TenantOperationStatus string
31-
3228
const (
33-
TenantOpStarting TenantOperationStatus = "STARTING"
34-
TenantOpRunning TenantOperationStatus = "RUNNING"
35-
TenantOpSuccessful TenantOperationStatus = "SUCCESSFUL"
36-
TenantOpFailed TenantOperationStatus = "FAILED"
29+
TenantOpStarting types.TenantOperationStatus = "STARTING"
30+
TenantOpRunning types.TenantOperationStatus = "RUNNING"
31+
TenantOpSuccessful types.TenantOperationStatus = "SUCCESSFUL"
32+
TenantOpFailed types.TenantOperationStatus = "FAILED"
33+
TenantOpReverting types.TenantOperationStatus = "REVERTING"
3734
)

api/types/types.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Copyright (c) 2023 OceanBase
3+
ob-operator is licensed under Mulan PSL v2.
4+
You can use this software according to the terms and conditions of the Mulan PSL v2.
5+
You may obtain a copy of Mulan PSL v2 at:
6+
http://license.coscl.org.cn/MulanPSL2
7+
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8+
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9+
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10+
See the Mulan PSL v2 for more details.
11+
*/
12+
13+
package types
14+
15+
type BackupJobType string
16+
type BackupJobStatus string
17+
type BackupPolicyStatusType string
18+
type BackupDestType string
19+
type LogArchiveDestState string
20+
type ArchiveBinding string
21+
type BackupDestination struct {
22+
Type BackupDestType `json:"type,omitempty"`
23+
Path string `json:"path,omitempty"`
24+
}
25+
26+
type RestoreJobStatus string
27+
28+
type TenantRole string
29+
type TenantOperationStatus string
30+
type TenantOperationType string

api/v1alpha1/obcluster_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ type OBClusterStatus struct {
5151

5252
//+kubebuilder:object:root=true
5353
//+kubebuilder:subresource:status
54+
//+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.status"
55+
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
5456

5557
// OBCluster is the Schema for the obclusters API
5658
type OBCluster struct {

api/v1alpha1/observer_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ type OBServerStatus struct {
5656

5757
//+kubebuilder:object:root=true
5858
//+kubebuilder:subresource:status
59+
//+kubebuilder:printcolumn:name="PodIP",type="string",JSONPath=".status.podIp"
60+
//+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.status"
61+
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
62+
//+kubebuilder:printcolumn:name="OBStatus",type="string",JSONPath=".status.obStatus"
5963

6064
// OBServer is the Schema for the observers API
6165
type OBServer struct {

api/v1alpha1/obtenant_types.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"k8s.io/apimachinery/pkg/api/resource"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222

23-
"github.com/oceanbase/ob-operator/api/constants"
23+
apitypes "github.com/oceanbase/ob-operator/api/types"
2424
)
2525

2626
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
@@ -46,9 +46,9 @@ type OBTenantSpec struct {
4646
Pools []ResourcePoolSpec `json:"pools"`
4747

4848
//+kubebuilder:default=PRIMARY
49-
TenantRole constants.TenantRole `json:"tenantRole,omitempty"`
50-
Source *TenantSourceSpec `json:"source,omitempty"`
51-
Credentials TenantCredentials `json:"credentials,omitempty"`
49+
TenantRole apitypes.TenantRole `json:"tenantRole,omitempty"`
50+
Source *TenantSourceSpec `json:"source,omitempty"`
51+
Credentials TenantCredentials `json:"credentials,omitempty"`
5252
}
5353

5454
type TenantCredentials struct {
@@ -113,8 +113,9 @@ type OBTenantStatus struct {
113113
OperationContext *OperationContext `json:"operationContext,omitempty"`
114114
TenantRecordInfo TenantRecordInfo `json:"tenantRecordInfo,omitempty"`
115115

116-
TenantRole constants.TenantRole `json:"tenantRole,omitempty"`
117-
Source *TenantSourceStatus `json:"source,omitempty"`
116+
TenantRole apitypes.TenantRole `json:"tenantRole,omitempty"`
117+
Source *TenantSourceStatus `json:"source,omitempty"`
118+
Credentials TenantCredentials `json:"credentials,omitempty"`
118119
}
119120

120121
type TenantSourceStatus struct {
@@ -196,6 +197,7 @@ type TenantRecordInfo struct {
196197
//+kubebuilder:subresource:status
197198
//+kubebuilder:printcolumn:name="status",type="string",JSONPath=".status.status"
198199
//+kubebuilder:printcolumn:name="tenantName",type="string",JSONPath=".spec.tenantName"
200+
//+kubebuilder:printcolumn:name="tenantRole",type="string",JSONPath=".status.tenantRole"
199201
//+kubebuilder:printcolumn:name="clusterName",type="string",JSONPath=".spec.obcluster"
200202
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
201203
//+kubebuilder:printcolumn:name="locality",type="string",JSONPath=".status.tenantRecordInfo.locality",priority=1

api/v1alpha1/obtenant_webhook.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"context"
21+
2022
apierrors "k8s.io/apimachinery/pkg/api/errors"
23+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2124
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/types"
2226
"k8s.io/apimachinery/pkg/util/validation/field"
2327
ctrl "sigs.k8s.io/controller-runtime"
28+
"sigs.k8s.io/controller-runtime/pkg/client"
2429
logf "sigs.k8s.io/controller-runtime/pkg/log"
2530
"sigs.k8s.io/controller-runtime/pkg/webhook"
2631
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -29,9 +34,11 @@ import (
2934
)
3035

3136
// log is for logging in this package.
32-
var _ = logf.Log.WithName("obtenant-resource")
37+
var tenantlog = logf.Log.WithName("obtenant-resource")
38+
var tenantClt client.Client
3339

3440
func (r *OBTenant) SetupWebhookWithManager(mgr ctrl.Manager) error {
41+
tenantClt = mgr.GetClient()
3542
return ctrl.NewWebhookManagedBy(mgr).
3643
For(r).
3744
Complete()
@@ -43,6 +50,23 @@ var _ webhook.Defaulter = &OBTenant{}
4350

4451
// Default implements webhook.Defaulter so a webhook will be registered for the type
4552
func (r *OBTenant) Default() {
53+
cluster := &OBCluster{}
54+
err := tenantClt.Get(context.Background(), types.NamespacedName{
55+
Namespace: r.GetNamespace(),
56+
Name: r.Spec.ClusterName,
57+
}, cluster)
58+
if err != nil {
59+
tenantlog.Error(err, "Failed to get cluster")
60+
} else {
61+
tenantlog.Info("Get cluster", "cluster", cluster)
62+
r.SetOwnerReferences([]metav1.OwnerReference{{
63+
APIVersion: cluster.APIVersion,
64+
Kind: cluster.Kind,
65+
Name: cluster.GetObjectMeta().GetName(),
66+
UID: cluster.GetObjectMeta().GetUID(),
67+
}})
68+
}
69+
4670
if r.Spec.TenantRole == "" {
4771
r.Spec.TenantRole = constants.TenantRolePrimary
4872
}
@@ -69,6 +93,13 @@ func (r *OBTenant) ValidateUpdate(old runtime.Object) (admission.Warnings, error
6993
func (r *OBTenant) validateMutation() error {
7094
var allErrs field.ErrorList
7195

96+
if r.Spec.Credentials.Root == "" {
97+
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("credentials").Child("root"), r.Spec.Credentials.Root, "Root password user secretref must be set"))
98+
}
99+
if r.Spec.Credentials.StandbyRO == "" {
100+
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("credentials").Child("standbyRo"), r.Spec.Credentials.StandbyRO, "Standby read-only user password secretref must be set"))
101+
}
102+
72103
// 1. Standby tenant must have a source
73104
if r.Spec.TenantRole == constants.TenantRoleStandby {
74105
if r.Spec.Source == nil {
@@ -77,6 +108,7 @@ func (r *OBTenant) validateMutation() error {
77108
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("tenantRole"), r.Spec.TenantRole, "Standby must have a source option, but both restore and tenantRef are nil now"))
78109
}
79110
}
111+
80112
// 2. Restore until with some limit must have a limit key
81113
if r.Spec.Source != nil && r.Spec.Source.Restore != nil {
82114
untilSpec := r.Spec.Source.Restore.Until

0 commit comments

Comments
 (0)