Skip to content

Commit

Permalink
[CLOUDGA-18071] CLI support for asymmetric geo-partitioned cluster cr…
Browse files Browse the repository at this point in the history
…eation
  • Loading branch information
vmallepalli committed Feb 6, 2024
1 parent cbaf7b6 commit 745103c
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 77 deletions.
63 changes: 53 additions & 10 deletions cmd/cluster/create_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cluster
import (
"fmt"
"os"
"strconv"
"strings"

"github.com/sirupsen/logrus"
Expand All @@ -41,14 +42,38 @@ var createClusterCmd = &cobra.Command{
logrus.Fatalf(ybmAuthClient.GetApiErrorDetails(err))
}
authApi.GetInfo("", "")
asymmetricGeoEnabled := util.IsFeatureFlagEnabled(util.ASYMMETRIC_GEO)

clusterName, _ := cmd.Flags().GetString("cluster-name")
credentials, _ := cmd.Flags().GetStringToString("credentials")

username := credentials["username"]
password := credentials["password"]
regionInfoMapList := []map[string]string{}
if cmd.Flags().Changed("region-info") {
changedRegionInfo := cmd.Flags().Changed("region-info")
changedNodeInfo := cmd.Flags().Changed("node-config")

defaultNumCores := 0
defaultDiskSizeGb := 0
defaultDiskIops := 0
if changedNodeInfo {
nodeConfig, _ := cmd.Flags().GetStringToInt("node-config")
numCores, ok := nodeConfig["num-cores"]
if !asymmetricGeoEnabled && !ok {
logrus.Fatalln("Number of cores not specified in node config")
}
if asymmetricGeoEnabled && ok {
defaultNumCores = numCores
}
if diskSizeGb, ok := nodeConfig["disk-size-gb"]; ok {
defaultDiskSizeGb = diskSizeGb
}
if diskIops, ok := nodeConfig["disk-iops"]; ok {
defaultDiskIops = diskIops
}
}

if changedRegionInfo {
regionInfoList, _ := cmd.Flags().GetStringArray("region-info")
for _, regionInfoString := range regionInfoList {
regionInfoMap := map[string]string{}
Expand All @@ -72,6 +97,18 @@ var createClusterCmd = &cobra.Command{
if len(strings.TrimSpace(val)) != 0 {
regionInfoMap["vpc"] = val
}
case "num-cores":
if asymmetricGeoEnabled && len(strings.TrimSpace(val)) != 0 {
regionInfoMap["num-cores"] = val
}
case "disk-size-gb":
if asymmetricGeoEnabled && len(strings.TrimSpace(val)) != 0 {
regionInfoMap["disk-size-gb"] = val
}
case "disk-iops":
if asymmetricGeoEnabled && len(strings.TrimSpace(val)) != 0 {
regionInfoMap["disk-iops"] = val
}
}
}

Expand All @@ -81,18 +118,20 @@ var createClusterCmd = &cobra.Command{
if _, ok := regionInfoMap["num-nodes"]; !ok {
logrus.Fatalln("Number of nodes not specified in region info")
}
if _, ok := regionInfoMap["num-cores"]; asymmetricGeoEnabled && !ok && defaultNumCores > 0 {
regionInfoMap["num-cores"] = strconv.Itoa(defaultNumCores)
}
if _, ok := regionInfoMap["disk-size-gb"]; asymmetricGeoEnabled && !ok && defaultDiskSizeGb > 0 {
regionInfoMap["disk-size-gb"] = strconv.Itoa(defaultDiskSizeGb)
}
if _, ok := regionInfoMap["disk-iops"]; asymmetricGeoEnabled && !ok && defaultDiskIops > 0 {
regionInfoMap["disk-iops"] = strconv.Itoa(defaultDiskIops)
}

regionInfoMapList = append(regionInfoMapList, regionInfoMap)
}
}

if cmd.Flags().Changed("node-config") {
nodeConfig, _ := cmd.Flags().GetStringToInt("node-config")
if _, ok := nodeConfig["num-cores"]; !ok {
logrus.Fatalln("Number of cores not specified in node config")
}
}

cmkSpec, err := encryption.GetCmkSpecFromCommand(cmd)
if err != nil {
logrus.Fatalf("Error while getting CMK spec: %s", err)
Expand Down Expand Up @@ -176,7 +215,6 @@ func init() {
createClusterCmd.Flags().String("database-version", "", "[OPTIONAL] The database version of the cluster. Production, Innovation or Preview. Default depends on cluster tier, Sandbox is Preview, Dedicated is Production.")
if util.IsFeatureFlagEnabled(util.ENTERPRISE_SECURITY) {
createClusterCmd.Flags().Bool("enterprise-security", false, "[OPTIONAL] The security level of cluster. Advanced security will have security checks for cluster. Default false.")

}
createClusterCmd.Flags().String("encryption-spec", "", `[OPTIONAL] The customer managed key spec for the cluster.
Please provide key value pairs as follows:
Expand All @@ -191,7 +229,12 @@ func init() {
createClusterCmd.Flags().String("fault-tolerance", "", "[OPTIONAL] The fault tolerance domain of the cluster. The possible values are NONE, NODE, ZONE and REGION. Default NONE.")
createClusterCmd.Flags().Int32("num-faults-to-tolerate", 0, "[OPTIONAL] The number of domain faults to tolerate for the level specified. The possible values are 0 for NONE, 1 for ZONE and [1-3] for anything else. Defaults to 0 for NONE, 1 otherwise.")
createClusterCmd.Flags().StringToInt("node-config", nil, "[OPTIONAL] Configuration of the cluster nodes. Please provide key value pairs num-cores=<num-cores>,disk-size-gb=<disk-size-gb>,disk-iops=<disk-iops> as the value. If specified, num-cores is mandatory, while disk-size-gb and disk-iops are optional.")
createClusterCmd.Flags().StringArray("region-info", []string{}, `[OPTIONAL] Region information for the cluster. Please provide key value pairs region=<region-name>,num-nodes=<number-of-nodes>,vpc=<vpc-name> as the value. If specified, region and num-nodes are mandatory, vpc is optional. Information about multiple regions can be specified by using multiple --region-info arguments. Default if not specified is us-west-2 AWS region.`)
if util.IsFeatureFlagEnabled(util.ASYMMETRIC_GEO) {
createClusterCmd.Flags().MarkDeprecated("node-config", "please use --region-info to specify num-cores, disk-size-gb, and disk-iops")
createClusterCmd.Flags().StringArray("region-info", []string{}, `[OPTIONAL] Region information for the cluster. Please provide key value pairs region=<region-name>,num-nodes=<number-of-nodes>,vpc=<vpc-name>,num-cores=<num-cores>,disk-size-gb=<disk-size-gb>,disk-iops=<disk-iops> as the value. If specified, region and num-nodes are mandatory, while num-cores, disk-size-gb, disk-iops, and vpc are optional. Information about multiple regions can be specified by using multiple --region-info arguments. Default if not specified is us-west-2 AWS region.`)
} else {
createClusterCmd.Flags().StringArray("region-info", []string{}, `[OPTIONAL] Region information for the cluster. Please provide key value pairs region=<region-name>,num-nodes=<number-of-nodes>,vpc=<vpc-name> as the value. If specified, region and num-nodes are mandatory, vpc is optional. Information about multiple regions can be specified by using multiple --region-info arguments. Default if not specified is us-west-2 AWS region.`)
}
createClusterCmd.Flags().String("preferred-region", "", "[OPTIONAL] The preferred region in a multi region cluster. A preferred region is where all the reads and writes are handled.")
createClusterCmd.Flags().String("default-region", "", "[OPTIONAL] The default region in a geo partitioned cluster. A default region is where all the tables not created within a tablespace reside.")

Expand Down
100 changes: 78 additions & 22 deletions cmd/cluster/update_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/yugabyte/ybm-cli/cmd/util"
ybmAuthClient "github.com/yugabyte/ybm-cli/internal/client"
"github.com/yugabyte/ybm-cli/internal/formatter"
ybmclient "github.com/yugabyte/yugabytedb-managed-go-client-internal"
Expand All @@ -36,6 +37,7 @@ var updateClusterCmd = &cobra.Command{
Long: "Update a cluster",
Run: func(cmd *cobra.Command, args []string) {

asymmetricGeoEnabled := util.IsFeatureFlagEnabled(util.ASYMMETRIC_GEO)
clusterName, _ := cmd.Flags().GetString("cluster-name")
authApi, err := ybmAuthClient.NewAuthApiClient()
if err != nil {
Expand All @@ -62,9 +64,31 @@ var updateClusterCmd = &cobra.Command{
populateFlags(cmd, originalSpec, trackName, authApi)

regionInfoMapList := []map[string]string{}
if cmd.Flags().Changed("region-info") {
changedRegionInfo := cmd.Flags().Changed("region-info")
changedNodeInfo := cmd.Flags().Changed("node-config")

defaultNumCores := 0
defaultDiskSizeGb := 0
defaultDiskIops := 0
if changedNodeInfo {
nodeConfig, _ := cmd.Flags().GetStringToInt("node-config")
numCores, ok := nodeConfig["num-cores"]
if !asymmetricGeoEnabled && !ok {
logrus.Fatalln("Number of cores not specified in node config")
}
if asymmetricGeoEnabled && ok {
defaultNumCores = numCores
}
if diskSizeGb, ok := nodeConfig["disk-size-gb"]; ok {
defaultDiskSizeGb = diskSizeGb
}
if diskIops, ok := nodeConfig["disk-iops"]; ok {
defaultDiskIops = diskIops
}
}

if changedRegionInfo {
regionInfoList, _ := cmd.Flags().GetStringArray("region-info")
regionInfoList = strings.Split(regionInfoList[0], "|")
for _, regionInfoString := range regionInfoList {
regionInfoMap := map[string]string{}
for _, regionInfo := range strings.Split(regionInfoString, ",") {
Expand All @@ -87,6 +111,18 @@ var updateClusterCmd = &cobra.Command{
if len(strings.TrimSpace(val)) != 0 {
regionInfoMap["vpc"] = val
}
case "num-cores":
if asymmetricGeoEnabled && len(strings.TrimSpace(val)) != 0 {
regionInfoMap["num-cores"] = val
}
case "disk-size-gb":
if asymmetricGeoEnabled && len(strings.TrimSpace(val)) != 0 {
regionInfoMap["disk-size-gb"] = val
}
case "disk-iops":
if asymmetricGeoEnabled && len(strings.TrimSpace(val)) != 0 {
regionInfoMap["disk-iops"] = val
}
}
}

Expand All @@ -96,18 +132,20 @@ var updateClusterCmd = &cobra.Command{
if _, ok := regionInfoMap["num-nodes"]; !ok {
logrus.Fatalln("Number of nodes not specified in region info")
}
if _, ok := regionInfoMap["num-cores"]; asymmetricGeoEnabled && !ok && defaultNumCores > 0 {
regionInfoMap["num-cores"] = strconv.Itoa(defaultNumCores)
}
if _, ok := regionInfoMap["disk-size-gb"]; asymmetricGeoEnabled && !ok && defaultDiskSizeGb > 0 {
regionInfoMap["disk-size-gb"] = strconv.Itoa(defaultDiskSizeGb)
}
if _, ok := regionInfoMap["disk-iops"]; asymmetricGeoEnabled && !ok && defaultDiskIops > 0 {
regionInfoMap["disk-iops"] = strconv.Itoa(defaultDiskIops)
}

regionInfoMapList = append(regionInfoMapList, regionInfoMap)
}
}

if cmd.Flags().Changed("node-config") {
nodeConfig, _ := cmd.Flags().GetStringToInt("node-config")
if _, ok := nodeConfig["num-cores"]; !ok {
logrus.Fatal("Number of cores not specified in node config\n")
}
}

clusterSpec, err := authApi.CreateClusterSpec(cmd, regionInfoMapList)
if err != nil {
logrus.Fatalf("Error while creating cluster spec: %v", err)
Expand Down Expand Up @@ -172,7 +210,12 @@ func init() {
updateClusterCmd.Flags().String("cloud-provider", "", "[OPTIONAL] The cloud provider where database needs to be deployed. AWS, AZURE or GCP.")
updateClusterCmd.Flags().String("cluster-type", "", "[OPTIONAL] Cluster replication type. SYNCHRONOUS or GEO_PARTITIONED.")
updateClusterCmd.Flags().StringToInt("node-config", nil, "[OPTIONAL] Configuration of the cluster nodes. Please provide key value pairs num-cores=<num-cores>,disk-size-gb=<disk-size-gb>,disk-iops=<disk-iops> as the value. If provided, num-cores is mandatory, while disk-size-gb and disk-iops are optional.")
updateClusterCmd.Flags().StringArray("region-info", []string{}, `[OPTIONAL] Region information for the cluster. Please provide key value pairs, region=<region-name>,num-nodes=<number-of-nodes>,vpc=<vpc-name> as the value. If provided, region and num-nodes are mandatory, vpc is optional.`)
if util.IsFeatureFlagEnabled(util.ASYMMETRIC_GEO) {
updateClusterCmd.Flags().MarkDeprecated("node-config", "please use --region-info to specify num-cores, disk-size-gb, and disk-iops")
updateClusterCmd.Flags().StringArray("region-info", []string{}, `[OPTIONAL] Region information for the cluster. Please provide key value pairs, region=<region-name>,num-nodes=<number-of-nodes>,vpc=<vpc-name>,num-cores=<num-cores>,disk-size-gb=<disk-size-gb>,disk-iops=<disk-iops> as the value. If specified, region and num-nodes are mandatory, while num-cores, disk-size-gb, disk-iops, and vpc are optional.`)
} else {
updateClusterCmd.Flags().StringArray("region-info", []string{}, `[OPTIONAL] Region information for the cluster. Please provide key value pairs, region=<region-name>,num-nodes=<number-of-nodes>,vpc=<vpc-name> as the value. If provided, region and num-nodes are mandatory, vpc is optional.`)
}
updateClusterCmd.Flags().String("cluster-tier", "", "[OPTIONAL] The tier of the cluster. Sandbox or Dedicated.")
updateClusterCmd.Flags().String("fault-tolerance", "", "[OPTIONAL] The fault tolerance domain of the cluster. The possible values are NONE, NODE, ZONE and REGION.")
updateClusterCmd.Flags().String("database-version", "", "[OPTIONAL] The database version of the cluster. Production or Innovation or Preview.")
Expand Down Expand Up @@ -216,27 +259,29 @@ func populateFlags(cmd *cobra.Command, originalSpec ybmclient.ClusterSpec, track
if diskSizeGb, ok := originalSpec.ClusterInfo.NodeInfo.GetDiskSizeGbOk(); ok {
nodeConfig += "disk-size-gb=" + strconv.Itoa(int(*diskSizeGb))
}
if diskIops, ok := originalSpec.ClusterInfo.NodeInfo.GetDiskIopsOk(); ok {
if diskIops != nil {
nodeConfig += "disk-iops=" + strconv.Itoa(int(*diskIops))
if diskIops, ok := originalSpec.ClusterInfo.NodeInfo.GetDiskIopsOk(); ok && diskIops != nil {
if nodeConfig != "" {
nodeConfig += ","
}
nodeConfig += "disk-iops=" + strconv.Itoa(int(*diskIops))
}
if numCores, ok := originalSpec.ClusterInfo.NodeInfo.GetNumCoresOk(); ok {
nodeConfig += ",num-cores=" + strconv.Itoa(int(*numCores))
if nodeConfig != "" {
nodeConfig += ","
}
nodeConfig += "num-cores=" + strconv.Itoa(int(*numCores))
}
cmd.Flag("node-config").Value.Set(nodeConfig)
cmd.Flag("node-config").Changed = true

}
regionInfoList := ""
numRegions := len(originalSpec.ClusterRegionInfo)
regionInfoList := []string{}
if !cmd.Flags().Changed("region-info") {
for index, clusterRegionInfo := range originalSpec.ClusterRegionInfo {
for _, clusterRegionInfo := range originalSpec.ClusterRegionInfo {
regionInfo := ""
if region, ok := clusterRegionInfo.PlacementInfo.CloudInfo.GetRegionOk(); ok && region != nil {
regionInfo += "region=" + *region
}
//logrus.Errorln(clusterRegionInfo.PlacementInfo.GetNumNodes())
if numNodes, ok := clusterRegionInfo.PlacementInfo.GetNumNodesOk(); ok && numNodes != nil {
regionInfo += ",num-nodes=" + strconv.Itoa(int(*numNodes))
}
Expand All @@ -249,12 +294,23 @@ func populateFlags(cmd *cobra.Command, originalSpec ybmclient.ClusterSpec, track
}
regionInfo += ",vpc=" + vpcName
}
regionInfoList += regionInfo
if index < numRegions-1 {
regionInfoList += "|"

if util.IsFeatureFlagEnabled(util.ASYMMETRIC_GEO) {
if nodeInfo, ok := clusterRegionInfo.GetNodeInfoOk(); ok {
if numCores, ok_ := nodeInfo.GetNumCoresOk(); ok_ {
regionInfo += ",num-cores=" + strconv.Itoa(int(*numCores))
}
if diskSizeGb, ok_ := nodeInfo.GetDiskSizeGbOk(); ok_ {
regionInfo += ",disk-size-gb=" + strconv.Itoa(int(*diskSizeGb))
}
if diskIops, ok_ := nodeInfo.GetDiskIopsOk(); ok_ && diskIops != nil {
regionInfo += ",disk-iops=" + strconv.Itoa(int(*diskIops))
}
}
}
regionInfoList = append(regionInfoList, regionInfo)
}
cmd.Flag("region-info").Value.Set(regionInfoList)
cmd.Flags().Set("region-info", strings.Join(regionInfoList, " "))
cmd.Flag("region-info").Changed = true

}
Expand Down
1 change: 1 addition & 0 deletions cmd/util/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
AZURE_CIDR_ALLOWED FeatureFlag = "AZURE_CIDR_ALLOWED"
ENTERPRISE_SECURITY FeatureFlag = "ENTERPRISE_SECURITY"
INCREMENTAL_BACKUP FeatureFlag = "INCREMENTAL_BACKUP"
ASYMMETRIC_GEO FeatureFlag = "ASYMMETRIC_GEO"
)

func (f FeatureFlag) String() string {
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.17.0
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
<<<<<<< HEAD
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240123191212-6c0c5862cc02
=======
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240131113907-1ba9d5e67a7a
>>>>>>> ac6bb7f (Update cluster and describe cluster work)
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/mod v0.14.0
golang.org/x/term v0.15.0
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,13 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk=
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA=
<<<<<<< HEAD
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240123191212-6c0c5862cc02 h1:nE2LaAIy3Tsv9QRVqxwShsqQ2rIkXMGU8tsUHf52fAY=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240123191212-6c0c5862cc02/go.mod h1:5vW0xIzIZw+1djkiWKx0qqNmqbRBSf4mjc4qw8lIMik=
=======
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240131113907-1ba9d5e67a7a h1:Lj0hIO1LuXJ4jO0dEe8dIBX9X06CSvo6xNfdV8spJKs=
github.com/yugabyte/yugabytedb-managed-go-client-internal v0.0.0-20240131113907-1ba9d5e67a7a/go.mod h1:5vW0xIzIZw+1djkiWKx0qqNmqbRBSf4mjc4qw8lIMik=
>>>>>>> ac6bb7f (Update cluster and describe cluster work)
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
Loading

0 comments on commit 745103c

Please sign in to comment.