Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
a182070
Initial commit with work from previous semester
irion4686 Mar 23, 2024
b18fc0e
Fixed ReadMe formatting
irion4686 Mar 24, 2024
04b6e17
Added back optional tags on IsHighAvailability field
irion4686 Mar 25, 2024
917228a
Added node struct to allow setting of properties for individual nodes
irion4686 Apr 2, 2024
b937355
Added implementation for the getInstanceNodes method
irion4686 Apr 4, 2024
5ba62b8
Implemented dynamically setting of nodes and basic validation of node…
irion4686 Apr 8, 2024
0d43f84
Dynamically setting all arguments
kpatel0923 Apr 9, 2024
7ed55c9
Changed Node struct to have new NodeProperties struct
irion4686 Apr 11, 2024
77d9f67
Fixed unit tests and added default nodes settings
irion4686 Apr 12, 2024
6cc94b7
cleaning up
irion4686 Apr 16, 2024
d2d16a0
cleaning up
irion4686 Apr 16, 2024
af1bce2
Updated dynamic nodes format
irion4686 Apr 16, 2024
5134ca5
Merge pull request #4 from irion4686/dynamic-nodes
justinorringer Apr 16, 2024
c326980
Added omitempty to nodes to fix existing unit tests
irion4686 Apr 17, 2024
a1b6dd7
Merge pull request #5 from irion4686/dynamic-nodes
irion4686 Apr 18, 2024
ec0daa8
Moved default logic to map and new function
justinorringer Apr 18, 2024
83a0bce
Changed clone to dynamically build Nodes
justinorringer Apr 18, 2024
f3d3d62
Set NodeCount based on actual nodes
justinorringer Apr 18, 2024
16caf1a
Add changes for end-to-end high availability tests
ArcZz Apr 18, 2024
ddd0d6e
edit folder name
ArcZz Apr 18, 2024
ff1f6d9
Update automation/tests/provisioning/pg-ha_test_2/pg-ha_test.go
justinorringer Apr 18, 2024
383ad7b
Added default cluster_name when none given
irion4686 Apr 18, 2024
d4057bf
fixed unit test
irion4686 Apr 18, 2024
108572d
fixed unit test
irion4686 Apr 18, 2024
933a405
Separated postgres HA additional arguments and fixed isHighAvailabili…
irion4686 Apr 21, 2024
ce9e102
moved the appendProvisioningRequest for PostgresHA to be near others
irion4686 Apr 21, 2024
9238fcb
Merge branch 'dev' into ete_ha_test
justinorringer Apr 21, 2024
731a1de
Moving folder, cleanup
justinorringer Apr 21, 2024
ee127e5
Uncommit spacing change
justinorringer Apr 21, 2024
707cb29
Newline
justinorringer Apr 21, 2024
835a1ac
webhook test updates
kpatel0923 Apr 22, 2024
233de04
syntax errors
kpatel0923 Apr 22, 2024
667a9f2
more syntax errors
kpatel0923 Apr 22, 2024
ee2a1e1
Naming issue
kpatel0923 Apr 22, 2024
708b4cf
VmName
kpatel0923 Apr 22, 2024
5886293
properties name
kpatel0923 Apr 22, 2024
c81b5aa
properties
kpatel0923 Apr 22, 2024
95857e4
Node change
kpatel0923 Apr 22, 2024
9f24ced
testing a new change for creating nodes
kpatel0923 Apr 22, 2024
de3903b
Validation for clone and provision
justinorringer Apr 22, 2024
c71d1a0
Correct variable declaration
justinorringer Apr 22, 2024
5879c22
Type errors
justinorringer Apr 22, 2024
5032fbc
Default should run prior to Validate
justinorringer Apr 22, 2024
a087217
Validation for clone and provision
justinorringer Apr 22, 2024
6e753d0
Correct variable declaration
justinorringer Apr 22, 2024
6b108e6
Type errors
justinorringer Apr 22, 2024
666abfd
Default should run prior to Validate
justinorringer Apr 22, 2024
66c9069
Updated tests
irion4686 Apr 22, 2024
20a725d
Updated required nodes to 3 database nodes
irion4686 Apr 22, 2024
31b0234
Merge pull request #12 from irion4686/update-nodes
justinorringer Apr 22, 2024
760ddb2
Adding back the Make changes
justinorringer Apr 23, 2024
1da557a
Merge branch 'dev' into ete_ha_test
justinorringer Apr 23, 2024
4db5552
Merge pull request #8 from irion4686/ete_ha_test
ArcZz Apr 23, 2024
3dcbcd1
Revert "end to end test with custom test case"
justinorringer Apr 23, 2024
348e60c
Merge pull request #13 from irion4686/revert-8-ete_ha_test
justinorringer Apr 23, 2024
f541e13
Removing cloning functionality
justinorringer Apr 23, 2024
7bc5b15
Removed the wrong struct params
justinorringer Apr 23, 2024
cbfc971
Adding back the appendCloningRequest hook needed
justinorringer Apr 23, 2024
f4b05c3
GetInstanceIsHA on clone
justinorringer Apr 23, 2024
bf09f04
Fix test, no IsHighAvailability field on clone
justinorringer Apr 23, 2024
bf3dd2d
Reflect cloning removed in readme
justinorringer Apr 23, 2024
2002a96
Removed the clone tests and added db tests
kpatel0923 Apr 24, 2024
33e9ecd
Merge branch 'dev' into webhook-test-update
justinorringer Apr 24, 2024
497a918
Release v0.5.1 (#198)
mazin-s Apr 22, 2024
eb00f13
Fixed test case
kpatel0923 Apr 24, 2024
1babd0d
Merge branch 'webhook-test-update' of https://github.com/irion4686/nd…
kpatel0923 Apr 24, 2024
bbc9598
Added check to the end to end test to assert that more than 1 node wa…
irion4686 Apr 24, 2024
7188d25
Merge pull request #17 from irion4686/webhook-test-update
justinorringer Apr 24, 2024
6af152c
Merge branch 'dev' into ete_ha_test
justinorringer Apr 25, 2024
4fc1804
Merge pull request #8 from irion4686/ete_ha_test
ArcZz Apr 23, 2024
71688cc
Added check to the end to end test to assert that more than 1 node wa…
irion4686 Apr 24, 2024
02bb089
Merge pull request #18 from irion4686/ete_ha_test
ArcZz Apr 25, 2024
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
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ 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
# Name is case-sensitive. ID is the UUID of the profile. Profile should be in the "READY" state
Expand Down Expand Up @@ -214,6 +216,9 @@ 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
21 changes: 21 additions & 0 deletions api/v1alpha1/database_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,23 @@ type Instance struct {
// +optional
// Additional database engine specific arguments
AdditionalArguments map[string]string `json:"additionalArguments"`
// +optional
IsHighAvailability bool `json:"isHighAvailability"`
// +optional
Nodes []*Node `json:"nodes,omitempty"`
}
type Node struct {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember to validate this in web hooks. e.g validate vmNames being unique, properties correctly defined, etc.

// +optional
VmName string `json:"vmName"`
Properties NodeProperties `json:"properties"`
}

type NodeProperties struct {
Comment thread
justinorringer marked this conversation as resolved.
NodeType string `json:"node_type"`
// +optional
Role string `json:"role"`
// +optional
FailoverMode string `json:"failover_mode"`
}

type Clone struct {
Expand All @@ -133,6 +150,10 @@ type Clone struct {
// +optional
// Additional database engine specific arguments
AdditionalArguments map[string]string `json:"additionalArguments"`
// +optional
IsHighAvailability bool `json:"isHighAvailability"`
// +optional
Nodes []*Node `json:"nodes,omitempty"`
}

// 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) {
Comment thread
justinorringer marked this conversation as resolved.
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
19 changes: 18 additions & 1 deletion common/util/additionalArguments.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,24 @@ func GetAllowedAdditionalArgumentsForDatabase(dbType string) (map[string]bool, e
case common.DATABASE_TYPE_POSTGRES:
return map[string]bool{
/* Has a default */
"listener_port": true,
"listener_port": true,
Comment thread
justinorringer marked this conversation as resolved.
Outdated
"proxy_read_port": true,
"proxy_write_port": true,
"enable_synchronous_mode": true,
"auto_tune_staging_drive": true,
"backup_policy": true,
"db_password": true,
"database_names": true,
"provision_virtual_ip": true,
"deploy_haproxy": true,
"failover_mode": true,
"node_type": true,
"allocate_pg_hugepage": true,
"cluster_database": true,
"archive_wal_expire_days": true,
"enable_peer_auth": true,
"cluster_name": true,
"patroni_cluster_name": true,
}, nil
case common.DATABASE_TYPE_MYSQL:
return map[string]bool{
Expand Down
48 changes: 48 additions & 0 deletions config/crd/bases/ndb.nutanix.com_databases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,33 @@ spec:
description:
description: Description of the clone instance
type: string
isHighAvailability:
type: boolean
name:
description: Name of the clone instance
type: string
nodes:
items:
properties:
failoverMode:
type: string
nodeType:
type: string
nxClusterId:
type: string
nxClusterName:
type: string
remoteArchiveDestination:
type: string
role:
type: string
vmName:
type: string
required:
- nodeType
- vmName
type: object
type: array
profiles:
properties:
compute:
Expand Down Expand Up @@ -155,9 +179,33 @@ spec:
description:
description: Description of the database instance
type: string
isHighAvailability:
type: boolean
name:
description: Name of the database instance
type: string
nodes:
items:
properties:
failoverMode:
type: string
nodeType:
type: string
nxClusterId:
type: string
nxClusterName:
type: string
remoteArchiveDestination:
type: string
role:
type: string
vmName:
type: string
required:
- nodeType
- vmName
type: object
type: array
profiles:
properties:
compute:
Expand Down
8 changes: 8 additions & 0 deletions controller_adapters/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ func (d *Database) GetInstanceSize() int {
return d.Spec.Instance.Size
}

func (d *Database) GetInstanceIsHighAvailability() bool {
Comment thread
justinorringer marked this conversation as resolved.
return d.Spec.Instance.IsHighAvailability
}

func (d *Database) GetInstanceNodes() []*v1alpha1.Node {
Comment thread
justinorringer marked this conversation as resolved.
return d.Spec.Instance.Nodes
}

// 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 @@ -18,6 +18,7 @@ import (
"errors"
"fmt"

"github.com/nutanix-cloud-native/ndb-operator/api/v1alpha1"
"github.com/nutanix-cloud-native/ndb-operator/common"
"github.com/nutanix-cloud-native/ndb-operator/ndb_client"
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -85,7 +86,7 @@ func GenerateCloningRequest(ctx context.Context, ndb_client ndb_client.NDBClient
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 @@ -96,8 +97,11 @@ func GenerateCloningRequest(ctx context.Context, ndb_client ndb_client.NDBClient
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 @@ -210,6 +214,98 @@ func (a *PostgresRequestAppender) appendCloningRequest(req *DatabaseCloneRequest
return req, nil
}

func setCloneNodesParameters(req *DatabaseCloneRequest, database DatabaseInterface) {
Comment thread
justinorringer marked this conversation as resolved.
Outdated
// Extract values of ComputeProfileId and NetworkProfileId
computeProfileId := req.Nodes[0].ComputeProfileId
networkProfileId := req.Nodes[0].NetworkProfileId
serverTimeZone := req.Nodes[0].NewDbServerTimeZone

// Convert database.Instance.Nodes to the common type Nodes
req.Nodes = []Node{}
for _, node := range database.GetInstanceNodes() {
built := Node{}
if node.Properties.NodeType == "haproxy" {
built = buildHAProxyNode(req, node, database.GetClusterId())
} else {
built = buildDatabaseNode(req, node, computeProfileId, networkProfileId, serverTimeZone, database.GetClusterId())
}

req.Nodes = append(req.Nodes, built)
}
}

func buildHAProxyNode(req *DatabaseCloneRequest, node *v1alpha1.Node, clusterId string) Node {
props := make([]map[string]string, 1)
props[0] = map[string]string{
"name": "node_type",
"value": node.Properties.NodeType,
}
return Node{
Properties: props,
VmName: node.VmName,
NxClusterId: clusterId,
}
}

func buildDatabaseNode(req *DatabaseCloneRequest, node *v1alpha1.Node, computeProfileId, networkProfileId, serverTimeZone, clusterId string) Node {
props := make([]map[string]string, 4)
props[0] = map[string]string{
"name": "role",
"value": node.Properties.Role,
}
props[1] = map[string]string{
"name": "failover_mode",
"value": node.Properties.FailoverMode,
}
props[2] = map[string]string{
"name": "node_type",
"value": node.Properties.NodeType,
}
props[3] = map[string]string{
"name": "remote_archive_destination",
"value": "",
}
return Node{
ComputeProfileId: computeProfileId,
NetworkProfileId: networkProfileId,
NewDbServerTimeZone: serverTimeZone,
Properties: props,
VmName: node.VmName,
NxClusterId: clusterId,
}
}

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)

req.NodeCount = len(database.GetInstanceNodes())
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 @@ -134,12 +134,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) {
Comment thread
justinorringer marked this conversation as resolved.
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
2 changes: 1 addition & 1 deletion ndb_api/common_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func TestGetRequestAppender(t *testing.T) {
}

for _, tc := range testCases {
result, err := GetRequestAppender(tc.databaseType)
result, err := GetRequestAppender(tc.databaseType, false)
if tc.expectedResult {
assert.NotNil(t, result)
assert.NoError(t, err)
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