Skip to content
Open
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
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ testbin/*

!vendor/**/zz_generated.*

# editor and IDE paraphernalia
# editor and IDE paraphernalia
.idea
*.swp
*.swo
Expand All @@ -27,7 +27,7 @@ testbin/*


sandbox
config/samples/ndb.yaml
config/samples/*
.DS_Store

test/__debug_bin
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ spec:
size: 10
timezone: "UTC"
type: postgres
# isHighAvailability is an optional parameter. In case nothing is specified, it is set to false
isHighAvailability: false

# You can specify any (or none) of these types of profiles: compute, software, network, dbParam
# If not specified, the corresponding Out-of-Box (OOB) profile will be used wherever applicable
Expand Down Expand Up @@ -214,6 +216,8 @@ spec:
# Cluster id of the cluster where the Database has to be provisioned
# Can be fetched from the GET /clusters endpoint
clusterId: "Nutanix Cluster Id"
# isHighAvailability is an optional parameter. In case nothing is specified, it is set to false
isHighAvailability: false
# You can specify any (or none) of these types of profiles: compute, software, network, dbParam
# If not specified, the corresponding Out-of-Box (OOB) profile will be used wherever applicable
# Name is case-sensitive. ID is the UUID of the profile. Profile should be in the "READY" state
Expand Down
4 changes: 4 additions & 0 deletions api/v1alpha1/database_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ type Instance struct {
// +optional
// Additional database engine specific arguments
AdditionalArguments map[string]string `json:"additionalArguments"`
// +optional
IsHighAvailability bool `json:"isHighAvailability"`
}

type Clone struct {
Expand All @@ -133,6 +135,8 @@ type Clone struct {
// +optional
// Additional database engine specific arguments
AdditionalArguments map[string]string `json:"additionalArguments"`
// +optional
IsHighAvailability bool `json:"isHighAvailability"`
}

// Time Machine details
Expand Down
3 changes: 3 additions & 0 deletions api/v1alpha1/webhook_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const (
CREDENTIAL_SECRET = "database-secret"
TIMEZONE = "UTC"
SIZE = 10
HA = false
)

func TestAPIs(t *testing.T) {
Expand Down Expand Up @@ -615,6 +616,7 @@ func createDefaultDatabase(metadataName string) *Database {
Type: common.DATABASE_TYPE_POSTGRES,
Profiles: &(Profiles{}),
AdditionalArguments: map[string]string{},
IsHighAvailability: HA,
},
},
}
Expand All @@ -639,6 +641,7 @@ func createDefaultClone(metadataName string) *Database {
SnapshotId: DEFAULT_UUID,
Profiles: &(Profiles{}),
AdditionalArguments: map[string]string{},
IsHighAvailability: HA,
},
},
}
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/ndb.nutanix.com_databases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ spec:
description:
description: Description of the clone instance
type: string
isHighAvailability:
type: boolean
name:
description: Name of the clone instance
type: string
Expand Down Expand Up @@ -151,6 +153,8 @@ spec:
description:
description: Description of the database instance
type: string
isHighAvailability:
type: boolean
name:
description: Name of the database instance
type: string
Expand Down
4 changes: 4 additions & 0 deletions controller_adapters/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ func (d *Database) GetInstanceSize() int {
return d.Spec.Instance.Size
}

func (d *Database) GetInstanceIsHighAvailability() bool {
return d.Spec.Instance.IsHighAvailability
}

// Returns basic details about the Time Machine if provided in the
// underlying database, else returns defaults like:
// TM Name: <db_instance_name>_TM
Expand Down
24 changes: 24 additions & 0 deletions controller_adapters/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,30 @@ func TestDatabase_GetInstanceSize(t *testing.T) {
})
}

// Tests the GetInstanceIsHighAvailability() function retrieves Size correctly:
func TestDatabase_GetInstanceIsHighAvailability(t *testing.T) {

name := "Contains IsHighAvailability"
database := Database{
Database: v1alpha1.Database{
Spec: v1alpha1.DatabaseSpec{
Instance: &v1alpha1.Instance{
IsHighAvailability: true,
},
},
},
}
wantIsHighAvailability := true

t.Run(name, func(t *testing.T) {

gotIsHighAvailability := database.GetInstanceIsHighAvailability()
if gotIsHighAvailability != wantIsHighAvailability {
t.Errorf("Database.GetInstanceIsHighAvailability() gotIsHighAvailability= %v, want %v", gotIsHighAvailability, wantIsHighAvailability)
}
})
}

// Tests the GetClusterId() function retrieves ClusterId correctly:
func TestDatabase_GetClusterId(t *testing.T) {

Expand Down
100 changes: 98 additions & 2 deletions ndb_api/clone_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ndb_api
import (
"context"
"fmt"
"strconv"

"github.com/nutanix-cloud-native/ndb-operator/common"
"github.com/nutanix-cloud-native/ndb-operator/ndb_client"
Expand Down Expand Up @@ -79,7 +80,7 @@ func GenerateCloningRequest(ctx context.Context, ndb_client *ndb_client.NDBClien
NetworkProfileId: profilesMap[common.PROFILE_TYPE_NETWORK].Id,
NewDbServerTimeZone: "",
NxClusterId: database.GetClusterId(),
Properties: make([]string, 0),
Properties: make([]map[string]string, 0),
},
},
// Added by request appenders as per the engine
Expand All @@ -90,8 +91,12 @@ func GenerateCloningRequest(ctx context.Context, ndb_client *ndb_client.NDBClien
NetworkProfileId: profilesMap[common.PROFILE_TYPE_NETWORK].Id,
DatabaseParameterProfileId: profilesMap[common.PROFILE_TYPE_DATABASE_PARAMETER].Id,
}

// boolean for high availability
isHighAvailability := false

// Appending request body based on database type
appender, err := GetRequestAppender(databaseType)
appender, err := GetRequestAppender(databaseType, isHighAvailability)
if err != nil {
log.Error(err, "Error while getting a request appender")
return
Expand Down Expand Up @@ -204,6 +209,97 @@ func (a *PostgresRequestAppender) appendCloningRequest(req *DatabaseCloneRequest
return req, nil
}

func setCloneNodesParameters(req *DatabaseCloneRequest, database DatabaseInterface) {
// Extract values of ComputeProfileId and NetworkProfileId
computeProfileId := req.Nodes[0].ComputeProfileId
networkProfileId := req.Nodes[0].NetworkProfileId
serverTimeZone := req.Nodes[0].NewDbServerTimeZone

// Clear the original req.Nodes array
req.Nodes = []Node{}

// Create node object for HA Proxy
for i := 0; i < 2; i++ {
// Hard coding the HA Proxy properties
props := make([]map[string]string, 1)
props[0] = map[string]string{
"name": "node_type",
"value": "haproxy",
}
req.Nodes = append(req.Nodes, Node{
Properties: props,
VmName: database.GetName() + "_haproxy" + strconv.Itoa(i),
NxClusterId: database.GetClusterId(),
})
}

// Create node object for Database Instances
for i := 0; i < 3; i++ {
// Hard coding the DB properties
props := make([]map[string]string, 4)
props[0] = map[string]string{
"name": "role",
"value": "Secondary",
}
// 1st node will be the primary node
if i == 0 {
props[0]["value"] = "Primary"
}
props[1] = map[string]string{
"name": "failover_mode",
"value": "Automatic",
}
props[2] = map[string]string{
"name": "node_type",
"value": "database",
}
props[3] = map[string]string{
"name": "remote_archive_destination",
"value": "",
}
req.Nodes = append(req.Nodes, Node{
ComputeProfileId: computeProfileId,
NetworkProfileId: networkProfileId,
NewDbServerTimeZone: serverTimeZone,
Properties: props,
VmName: database.GetName() + "-" + strconv.Itoa(i),
NxClusterId: database.GetClusterId(),
})
}
}

func (a *PostgresHARequestAppender) appendCloningRequest(req *DatabaseCloneRequest, database DatabaseInterface, reqData map[string]interface{}) (*DatabaseCloneRequest, error) {
req.SSHPublicKey = reqData[common.NDB_PARAM_SSH_PUBLIC_KEY].(string)
dbPassword := reqData[common.NDB_PARAM_PASSWORD].(string)

// Set the number of nodes to 5, 3 Postgres nodes + 2 HA Proxy nodes
req.NodeCount = 5
setCloneNodesParameters(req, database)

// Default action arguments
actionArguments := map[string]string{
/* Non-Configurable from additionalArguments*/
"vm_name": database.GetName(),
"dbserver_description": "DB Server VM for " + database.GetName(),
"db_password": dbPassword,
}

// Appending/overwriting database actionArguments to actionArguments
if err := setConfiguredActionArguments(database, actionArguments); err != nil {
return nil, err
}

// Converting action arguments map to list and appending to req.ActionArguments
req.ActionArguments = append(req.ActionArguments, convertMapToActionArguments(actionArguments)...)

// Appending LCMConfig Details if specified
if err := appendLCMConfigDetailsToRequest(req, database.GetAdditionalArguments()); err != nil {
return nil, err
}

return req, nil
}

func (a *MySqlRequestAppender) appendCloningRequest(req *DatabaseCloneRequest, database DatabaseInterface, reqData map[string]interface{}) (*DatabaseCloneRequest, error) {
req.SSHPublicKey = reqData[common.NDB_PARAM_SSH_PUBLIC_KEY].(string)
dbPassword := reqData[common.NDB_PARAM_PASSWORD].(string)
Expand Down
8 changes: 6 additions & 2 deletions ndb_api/common_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,16 @@ func GetDatabasePortByType(dbType string) int32 {
}

// Get specific implementation of the DBProvisionRequestAppender interface based on the provided databaseType
func GetRequestAppender(databaseType string) (requestAppender RequestAppender, err error) {
func GetRequestAppender(databaseType string, isHighAvailability bool) (requestAppender RequestAppender, err error) {
switch databaseType {
case common.DATABASE_TYPE_MYSQL:
requestAppender = &MySqlRequestAppender{}
case common.DATABASE_TYPE_POSTGRES:
requestAppender = &PostgresRequestAppender{}
if isHighAvailability {
requestAppender = &PostgresHARequestAppender{}
} else {
requestAppender = &PostgresRequestAppender{}
}
case common.DATABASE_TYPE_MONGODB:
requestAppender = &MongoDbRequestAppender{}
case common.DATABASE_TYPE_MSSQL:
Expand Down
12 changes: 6 additions & 6 deletions ndb_api/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ type ActionArgument struct {
}

type Node struct {
VmName string `json:"vmName"`
ComputeProfileId string `json:"computeProfileId,omitempty"`
NetworkProfileId string `json:"networkProfileId,omitempty"`
NewDbServerTimeZone string `json:"newDbServerTimeZone,omitempty"`
NxClusterId string `json:"nxClusterId,omitempty"`
Properties []string `json:"properties"`
VmName string `json:"vmName"`
ComputeProfileId string `json:"computeProfileId,omitempty"`
NetworkProfileId string `json:"networkProfileId,omitempty"`
NewDbServerTimeZone string `json:"newDbServerTimeZone,omitempty"`
NxClusterId string `json:"nxClusterId,omitempty"`
Properties []map[string]string `json:"properties"`
}

type Property struct {
Expand Down
Loading