Skip to content
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

Feat: cli: tenant management #575

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 77 additions & 58 deletions internal/cli/cluster/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ See the Mulan PSL v2 for more details.
package cluster

import (
"errors"
"fmt"

apitypes "github.com/oceanbase/ob-operator/api/types"
Expand All @@ -28,13 +29,14 @@ import (
apiresource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/oceanbase/ob-operator/internal/cli/generic"
utils "github.com/oceanbase/ob-operator/internal/cli/utils"
modelcommon "github.com/oceanbase/ob-operator/internal/dashboard/model/common"
param "github.com/oceanbase/ob-operator/internal/dashboard/model/param"
)

type CreateOptions struct {
ResourceOptions
generic.ResourceOptions
ClusterName string `json:"clusterName"`
ClusterId int64 `json:"clusterId"`
RootPassword string `json:"rootPassword"`
Expand All @@ -44,6 +46,7 @@ type CreateOptions struct {
Parameters []modelcommon.KVPair `json:"parameters"`
BackupVolume *param.NFSVolumeSpec `json:"backupVolume"`
Zones map[string]string `json:"zones"`
KvParameters map[string]string `json:"kvParameters"`
Mode string `json:"mode"`
}

Expand All @@ -59,6 +62,9 @@ func NewCreateOptions() *CreateOptions {
}

func (o *CreateOptions) Validate() error {
if o.Namespace == "" {
return errors.New("namespace not specified")
}
if !utils.CheckPassword(o.RootPassword) {
return fmt.Errorf("Password is not secure, must contain at least 2 uppercase and lowercase letters, numbers and special characters")
}
Expand All @@ -73,6 +79,11 @@ func (o *CreateOptions) Parse(_ *cobra.Command, args []string) error {
if err != nil {
return err
}
parameters, err := utils.MapParameters(o.KvParameters)
if err != nil {
return err
}
o.Parameters = parameters
o.Topology = topology
o.Name = args[0]
return nil
Expand All @@ -81,7 +92,7 @@ func (o *CreateOptions) Parse(_ *cobra.Command, args []string) error {
func (o *CreateOptions) Complete() error {
// if not specific id, using timestamp
if o.ClusterId == 0 {
o.ClusterId = utils.GenerateClusterId()
o.ClusterId = utils.GenerateClusterID()
}
// if not specific password, using random password, range [8,32]
if o.RootPassword == "" {
Expand All @@ -93,62 +104,6 @@ func (o *CreateOptions) Complete() error {
return nil
}

func (o *CreateOptions) AddFlags(cmd *cobra.Command) {
// Add base and specific feature flags, Only support observer and zone config
o.AddBaseFlags(cmd)
o.AddObserverFlags(cmd)
o.AddZoneFlags(cmd)
}

// AddZoneFlags adds the zone-related flags to the command.
func (o *CreateOptions) AddZoneFlags(cmd *cobra.Command) {
zoneFlags := pflag.NewFlagSet("zone", pflag.ContinueOnError)
zoneFlags.StringToStringVarP(&o.Zones, "zones", "z", map[string]string{"z1": "1"}, "The zones of the cluster in the format 'zone=value', multiple values can be provided separated by commas")
cmd.Flags().AddFlagSet(zoneFlags)
}

// AddBaseFlags adds the base flags to the command.
func (o *CreateOptions) AddBaseFlags(cmd *cobra.Command) {
baseFlags := cmd.Flags()
baseFlags.StringVar(&o.Name, "name", "", "The name in k8s, if not specified, use cluster name")
baseFlags.StringVar(&o.Namespace, "namespace", "default", "The namespace of the cluster")
baseFlags.Int64Var(&o.ClusterId, "id", 0, "The id of the cluster")
baseFlags.StringVar(&o.RootPassword, "root-password", "", "The root password of the cluster")
baseFlags.StringVar(&o.Mode, "mode", "", "The mode of the cluster")
}

// AddObserverFlags adds the observer-related flags to the command.
func (o *CreateOptions) AddObserverFlags(cmd *cobra.Command) {
observerFlags := pflag.NewFlagSet("observer", pflag.ContinueOnError)
observerFlags.StringVar(&o.OBServer.Image, "image", "oceanbase/oceanbase-cloud-native:4.2.1.6-106000012024042515", "The image of the observer")
observerFlags.Int64Var(&o.OBServer.Resource.Cpu, "cpu", 2, "The cpu of the observer")
observerFlags.Int64Var(&o.OBServer.Resource.MemoryGB, "memory", 10, "The memory of the observer")
observerFlags.StringVar(&o.OBServer.Storage.Data.StorageClass, "data-storage-class", "local-path", "The storage class of the data storage")
observerFlags.StringVar(&o.OBServer.Storage.RedoLog.StorageClass, "redo-log-storage-class", "local-path", "The storage class of the redo log storage")
observerFlags.StringVar(&o.OBServer.Storage.Log.StorageClass, "log-storage-class", "local-path", "The storage class of the log storage")
observerFlags.Int64Var(&o.OBServer.Storage.Data.SizeGB, "data-storage-size", 50, "The size of the data storage")
observerFlags.Int64Var(&o.OBServer.Storage.RedoLog.SizeGB, "redo-log-storage-size", 50, "The size of the redo log storage")
observerFlags.Int64Var(&o.OBServer.Storage.Log.SizeGB, "log-storage-size", 20, "The size of the log storage")
cmd.Flags().AddFlagSet(observerFlags)
}

// AddMonitorFlags adds the monitor-related flags to the command.
func (o *CreateOptions) AddMonitorFlags(cmd *cobra.Command) {
monitorFlags := pflag.NewFlagSet("monitor", pflag.ContinueOnError)
monitorFlags.StringVar(&o.Monitor.Image, "monitor-image", "oceanbase/obagent:4.2.1-100000092023101717", "The image of the monitor")
monitorFlags.Int64Var(&o.Monitor.Resource.Cpu, "monitor-cpu", 1, "The cpu of the monitor")
monitorFlags.Int64Var(&o.Monitor.Resource.MemoryGB, "monitor-memory", 1, "The memory of the monitor")
cmd.Flags().AddFlagSet(monitorFlags)
}

// AddBackupVolumeFlags adds the backup-volume-related flags to the command.
func (o *CreateOptions) AddBackupVolumeFlags(cmd *cobra.Command) {
backupVolumeFlags := pflag.NewFlagSet("backup-volume", pflag.ContinueOnError)
backupVolumeFlags.StringVar(&o.BackupVolume.Address, "backup-storage-class", "local-path", "The storage class of the backup storage")
backupVolumeFlags.StringVar(&o.BackupVolume.Path, "backup-storage-size", "/opt/nfs", "The size of the backup storage")
cmd.Flags().AddFlagSet(backupVolumeFlags)
}

func buildOBServerTemplate(observerSpec *param.OBServerSpec) *apitypes.OBServerTemplate {
if observerSpec == nil {
return nil
Expand Down Expand Up @@ -334,3 +289,67 @@ func CreateOBClusterInstance(param *CreateOptions) *v1alpha1.OBCluster {
}
return obcluster
}

// AddFlags adds base and specific feature flags, Only support observer and zone config
func (o *CreateOptions) AddFlags(cmd *cobra.Command) {
o.AddBaseFlags(cmd)
o.AddObserverFlags(cmd)
o.AddZoneFlags(cmd)
o.AddParameterFlags(cmd)
}

// AddZoneFlags adds the zone-related flags to the command.
func (o *CreateOptions) AddZoneFlags(cmd *cobra.Command) {
zoneFlags := pflag.NewFlagSet("zone", pflag.ContinueOnError)
zoneFlags.StringToStringVarP(&o.Zones, "zones", "z", map[string]string{"z1": "1"}, "The zones of the cluster in the format 'Zone=Replica', multiple values can be provided separated by commas")
cmd.Flags().AddFlagSet(zoneFlags)
}

// AddBaseFlags adds the base flags to the command.
func (o *CreateOptions) AddBaseFlags(cmd *cobra.Command) {
baseFlags := cmd.Flags()
baseFlags.StringVarP(&o.ClusterName, "cluster-name", "n", "", "Cluster name, if not specified, use resource name in k8s instead")
baseFlags.StringVar(&o.Namespace, "namespace", "default", "The namespace of the cluster")
baseFlags.Int64Var(&o.ClusterId, "id", 0, "The id of the cluster")
baseFlags.StringVarP(&o.RootPassword, "root-password", "p", "", "The root password of the cluster")
baseFlags.StringVar(&o.Mode, "mode", "", "The mode of the cluster")
}

// AddObserverFlags adds the observer-related flags to the command.
func (o *CreateOptions) AddObserverFlags(cmd *cobra.Command) {
observerFlags := pflag.NewFlagSet("observer", pflag.ContinueOnError)
observerFlags.StringVar(&o.OBServer.Image, "image", "oceanbase/oceanbase-cloud-native:4.2.1.6-106000012024042515", "The image of the observer")
observerFlags.Int64Var(&o.OBServer.Resource.Cpu, "cpu", 2, "The cpu of the observer")
observerFlags.Int64Var(&o.OBServer.Resource.MemoryGB, "memory", 10, "The memory of the observer")
observerFlags.StringVar(&o.OBServer.Storage.Data.StorageClass, "data-storage-class", "local-path", "The storage class of the data storage")
observerFlags.StringVar(&o.OBServer.Storage.RedoLog.StorageClass, "redo-log-storage-class", "local-path", "The storage class of the redo log storage")
observerFlags.StringVar(&o.OBServer.Storage.Log.StorageClass, "log-storage-class", "local-path", "The storage class of the log storage")
observerFlags.Int64Var(&o.OBServer.Storage.Data.SizeGB, "data-storage-size", 50, "The size of the data storage")
observerFlags.Int64Var(&o.OBServer.Storage.RedoLog.SizeGB, "redo-log-storage-size", 50, "The size of the redo log storage")
observerFlags.Int64Var(&o.OBServer.Storage.Log.SizeGB, "log-storage-size", 20, "The size of the log storage")
cmd.Flags().AddFlagSet(observerFlags)
}

// AddMonitorFlags adds the monitor-related flags to the command.
func (o *CreateOptions) AddMonitorFlags(cmd *cobra.Command) {
monitorFlags := pflag.NewFlagSet("monitor", pflag.ContinueOnError)
monitorFlags.StringVar(&o.Monitor.Image, "monitor-image", "oceanbase/obagent:4.2.1-100000092023101717", "The image of the monitor")
monitorFlags.Int64Var(&o.Monitor.Resource.Cpu, "monitor-cpu", 1, "The cpu of the monitor")
monitorFlags.Int64Var(&o.Monitor.Resource.MemoryGB, "monitor-memory", 1, "The memory of the monitor")
cmd.Flags().AddFlagSet(monitorFlags)
}

// AddBackupVolumeFlags adds the backup-volume-related flags to the command.
func (o *CreateOptions) AddBackupVolumeFlags(cmd *cobra.Command) {
backupVolumeFlags := pflag.NewFlagSet("backup-volume", pflag.ContinueOnError)
backupVolumeFlags.StringVar(&o.BackupVolume.Address, "backup-storage-class", "local-path", "The storage class of the backup storage")
backupVolumeFlags.StringVar(&o.BackupVolume.Path, "backup-storage-size", "/opt/nfs", "The size of the backup storage")
cmd.Flags().AddFlagSet(backupVolumeFlags)
}

// AddParameterFlags adds the parameter-related flags, e.g. __min_full_resource_pool_memory, to the command
func (o *CreateOptions) AddParameterFlags(cmd *cobra.Command) {
parameterFlags := pflag.NewFlagSet("parameters", pflag.ContinueOnError)
parameterFlags.StringToStringVar(&o.KvParameters, "parameters", map[string]string{"__min_full_resource_pool_memory": "2147483648", "system_memory": "1G"}, "Other parameter settings in obcluster, e.g., __min_full_resource_pool_memory")
cmd.Flags().AddFlagSet(parameterFlags)
}
13 changes: 12 additions & 1 deletion internal/cli/cluster/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,21 @@ See the Mulan PSL v2 for more details.
*/
package cluster

import (
"github.com/spf13/cobra"

"github.com/oceanbase/ob-operator/internal/cli/generic"
)

type DeleteOptions struct {
ResourceOptions
generic.ResourceOptions
}

func NewDeleteOptions() *DeleteOptions {
return &DeleteOptions{}
}

// AddFlags add basic flags for cluster management
func (o *DeleteOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.Namespace, "namespace", "default", "namespace of ob cluster")
}
7 changes: 4 additions & 3 deletions internal/cli/cluster/scale.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ import (
apiconst "github.com/oceanbase/ob-operator/api/constants"
apitypes "github.com/oceanbase/ob-operator/api/types"
"github.com/oceanbase/ob-operator/api/v1alpha1"
"github.com/oceanbase/ob-operator/internal/cli/generic"
utils "github.com/oceanbase/ob-operator/internal/cli/utils"
oceanbaseconst "github.com/oceanbase/ob-operator/internal/const/oceanbase"
param "github.com/oceanbase/ob-operator/internal/dashboard/model/param"
)

type ScaleOptions struct {
ResourceOptions
generic.ResourceOptions
Zones map[string]string `json:"zones"`
Topology []param.ZoneTopology `json:"topology"`
OldTopology []apitypes.OBZoneTopology `json:"oldTopology"`
Expand Down Expand Up @@ -138,7 +139,7 @@ func (o *ScaleOptions) Validate() error {
if !found {
typeAdd = true
}
if typeDelete && zoneNum-deleteNum < maxDeleteNum {
if typeDelete && deleteNum > maxDeleteNum {
return fmt.Errorf("Obcluster has %d Zones, can only delete %d zones", zoneNum, maxDeleteNum)
}
}
Expand All @@ -156,7 +157,7 @@ func (o *ScaleOptions) Validate() error {
o.ScaleType = "addZones"
}
if trueCount > 1 {
return fmt.Errorf("Only one type of scale is allower at a time")
return fmt.Errorf("Only one type of scale is allowed at a time")
}
if trueCount == 0 {
return fmt.Errorf("No scale type specified")
Expand Down
13 changes: 12 additions & 1 deletion internal/cli/cluster/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,21 @@ See the Mulan PSL v2 for more details.
*/
package cluster

import (
"github.com/spf13/cobra"

"github.com/oceanbase/ob-operator/internal/cli/generic"
)

type ShowOptions struct {
ResourceOptions
generic.ResourceOptions
}

func NewShowOptions() *ShowOptions {
return &ShowOptions{}
}

// AddFlags add basic flags for cluster management
func (o *ShowOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.Namespace, "namespace", "default", "namespace of ob cluster")
}
7 changes: 4 additions & 3 deletions internal/cli/cluster/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ import (
apiconst "github.com/oceanbase/ob-operator/api/constants"
"github.com/oceanbase/ob-operator/api/types"
"github.com/oceanbase/ob-operator/api/v1alpha1"
"github.com/oceanbase/ob-operator/internal/cli/generic"
oceanbaseconst "github.com/oceanbase/ob-operator/internal/const/oceanbase"
"github.com/oceanbase/ob-operator/internal/dashboard/business/constant"
"github.com/oceanbase/ob-operator/internal/dashboard/model/common"
param "github.com/oceanbase/ob-operator/internal/dashboard/model/param"
)

type UpdateOptions struct {
ResourceOptions
generic.ResourceOptions
Resource common.ResourceSpec `json:"resource"`
Storage *param.OBServerStorageSpec `json:"storage"`
UpdateType string `json:"updateType"`
Expand All @@ -44,8 +45,8 @@ func NewUpdateOptions() *UpdateOptions {
}
}

// GetUpdateOperations creates update opertaions
func GetUpdateOperations(o *UpdateOptions) *v1alpha1.OBClusterOperation {
// GetUpdateOperation creates update opertaions
func GetUpdateOperation(o *UpdateOptions) *v1alpha1.OBClusterOperation {
updateOp := &v1alpha1.OBClusterOperation{
ObjectMeta: v1.ObjectMeta{
Name: o.Name + "-update-" + rand.String(6),
Expand Down
7 changes: 4 additions & 3 deletions internal/cli/cluster/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@ import (

apiconst "github.com/oceanbase/ob-operator/api/constants"
"github.com/oceanbase/ob-operator/api/v1alpha1"
"github.com/oceanbase/ob-operator/internal/cli/generic"
oceanbaseconst "github.com/oceanbase/ob-operator/internal/const/oceanbase"
)

type UpgradeOptions struct {
ResourceOptions
generic.ResourceOptions
Image string `json:"image"`
}

func NewUpgradeOptions() *UpgradeOptions {
return &UpgradeOptions{}
}

// GetUpgradeOperations creates upgrade opertaions
func GetUpgradeOperations(o *UpgradeOptions) *v1alpha1.OBClusterOperation {
// GetUpgradeOperation creates upgrade opertaions
func GetUpgradeOperation(o *UpgradeOptions) *v1alpha1.OBClusterOperation {
upgradeOp := &v1alpha1.OBClusterOperation{
ObjectMeta: v1.ObjectMeta{
Name: o.Name + "-upgrade-" + rand.String(6),
Expand Down
7 changes: 4 additions & 3 deletions internal/cli/cmd/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import (
// NewCmd is command for cluster management
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "cluster <subcommand>",
Short: "Command for cluster management",
Long: `Command for cluster management, such as Create, UpGrade, Delete, Scale, Show.`,
Use: "cluster <subcommand>",
Aliases: []string{"c"},
Short: "Command for cluster management",
Long: `Command for cluster management, such as Create, UpGrade, Delete, Scale, Show.`,
}
cmd.AddCommand(NewCreateCmd())
cmd.AddCommand(NewDeleteCmd())
Expand Down
3 changes: 1 addition & 2 deletions internal/cli/cmd/cluster/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
cluster "github.com/oceanbase/ob-operator/internal/cli/cluster"
cmdUtil "github.com/oceanbase/ob-operator/internal/cli/cmd/util"
"github.com/oceanbase/ob-operator/internal/clients"
oberr "github.com/oceanbase/ob-operator/pkg/errors"
)

// NewCreateCmd create an ob cluster
Expand All @@ -46,7 +45,7 @@ func NewCreateCmd() *cobra.Command {
}
_, err := clients.CreateOBCluster(cmd.Context(), obcluster)
if err != nil {
logger.Fatalln(oberr.NewInternal(err.Error()))
logger.Fatalln(err)
}
logger.Printf("Create obcluster instance: %s", o.ClusterName)
logger.Printf("Run `echo $(kubectl get secret %s -o jsonpath='{.data.password}'|base64 --decode)` to get the secrets", obcluster.Spec.UserSecrets.Root)
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cmd/cluster/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/oceanbase/ob-operator/internal/clients"
)

// NewDeleteCmd delete ob clusters
// NewDeleteCmd delete ob cluster
func NewDeleteCmd() *cobra.Command {
o := cluster.NewDeleteOptions()
logger := cmdUtil.GetDefaultLoggerInstance()
Expand Down
4 changes: 2 additions & 2 deletions internal/cli/cmd/cluster/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ func NewListCmd() *cobra.Command {
return obclusterList.Items[i].Name < obclusterList.Items[j].Name
})
if len(obclusterList.Items) == 0 {
logger.Println("No clusters found")
logger.Println("No OBClusters found")
return
}
tbLog.Println("Namespace \t Name \t Create Time \t Status")
tbLog.Println("NAMESPACE \t NAME \t CREATE TIME \t STATUS")
for _, cluster := range obclusterList.Items {
tbLog.Printf("%s \t %s \t %s \t %s\n", cluster.Namespace, cluster.Name, cluster.CreationTimestamp, cluster.Status.Status)
}
Expand Down
Loading
Loading