From c0147fcf451ba0e938ba240aa535d26c5499ebd0 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Mon, 16 Oct 2023 13:55:14 -0400 Subject: [PATCH 01/12] First commit to create PR --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 09c9135a..3152569d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ testbin/* !vendor/**/zz_generated.* -# editor and IDE paraphernalia +# editor and IDE paraphernalia .idea *.swp *.swo From 8f178ce35b48d3048c54099f2ea962d1f41aa337 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Wed, 15 Nov 2023 11:58:53 -0500 Subject: [PATCH 02/12] Created AppendRequest for Postgres HA --- common/constants.go | 8 ++++--- ndb_api/clone_helpers.go | 34 +++++++++++++++++++++++++++- ndb_api/common_helpers.go | 8 +++++-- ndb_api/db_helpers.go | 46 +++++++++++++++++++++++++++++++++++++- ndb_api/db_helpers_test.go | 26 ++++++++++----------- ndb_api/interfaces.go | 3 +++ 6 files changed, 105 insertions(+), 20 deletions(-) diff --git a/common/constants.go b/common/constants.go index 02339721..d6156f11 100644 --- a/common/constants.go +++ b/common/constants.go @@ -56,9 +56,11 @@ const ( NDB_CR_STATUS_ERROR = "Error" NDB_CR_STATUS_OK = "Ok" - NDB_PARAM_PASSWORD = "password" - NDB_PARAM_SSH_PUBLIC_KEY = "ssh_public_key" - NDB_PARAM_USERNAME = "username" + NDB_PARAM_PASSWORD = "password" + NDB_PARAM_SSH_PUBLIC_KEY = "ssh_public_key" + NDB_PARAM_USERNAME = "username" + NDB_PARAM_CLUSTER_NAME = "cluster_name" + NDB_PARAM_PATRONI_CLUSTER_NAME = "patroni_cluster_name" NDB_RECONCILE_DATABASE_COUNTER = 4 NDB_RECONCILE_INTERVAL_SECONDS = 15 diff --git a/ndb_api/clone_helpers.go b/ndb_api/clone_helpers.go index aa0f787e..6ae74b7c 100644 --- a/ndb_api/clone_helpers.go +++ b/ndb_api/clone_helpers.go @@ -90,8 +90,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 @@ -204,6 +208,34 @@ func (a *PostgresRequestAppender) appendCloningRequest(req *DatabaseCloneRequest return req, nil } +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) + + // 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) diff --git a/ndb_api/common_helpers.go b/ndb_api/common_helpers.go index 58514ead..b0cbc2af 100644 --- a/ndb_api/common_helpers.go +++ b/ndb_api/common_helpers.go @@ -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: diff --git a/ndb_api/db_helpers.go b/ndb_api/db_helpers.go index 0af5412a..c462a201 100644 --- a/ndb_api/db_helpers.go +++ b/ndb_api/db_helpers.go @@ -108,8 +108,11 @@ func GenerateProvisioningRequest(ctx context.Context, ndb_client *ndb_client.NDB }, } + // boolean for high availability + isHighAvailability := false + // Appending request body based on database type - appender, err := GetRequestAppender(database.GetInstanceType()) + appender, err := GetRequestAppender(database.GetInstanceType(), isHighAvailability) if err != nil { log.Error(err, "Error while appending provisioning request") return @@ -304,6 +307,47 @@ func (a *PostgresRequestAppender) appendProvisioningRequest(req *DatabaseProvisi return req, nil } +func (a *PostgresHARequestAppender) appendProvisioningRequest(req *DatabaseProvisionRequest, database DatabaseInterface, reqData map[string]interface{}) (*DatabaseProvisionRequest, error) { + dbPassword := reqData[common.NDB_PARAM_PASSWORD].(string) + databaseNames := database.GetInstanceDatabaseNames() + clusterName := reqData[common.NDB_PARAM_CLUSTER_NAME].(string) + patroniClusterName := reqData[common.NDB_PARAM_PATRONI_CLUSTER_NAME].(string) + req.SSHPublicKey = reqData[common.NDB_PARAM_SSH_PUBLIC_KEY].(string) + + // Default action arguments + actionArguments := map[string]string{ + /* Non-Configurable from additionalArguments*/ + "proxy_read_port": "5001", + "listener_port": "5432", + "proxy_write_port": "5000", + "enable_synchronous_mode": "true", + "auto_tune_staging_drive": "true", + "backup_policy": "primary_only", + "db_password": dbPassword, + "database_names": databaseNames, + "provision_virtual_ip": "true", + "deploy_haproxy": "true", + "failover_mode": "Automatic", + "node_type": "database", + "allocate_pg_hugepage": "false", + "cluster_database": "false", + "archive_wal_expire_days": "-1", + "enable_peer_auth": "false", + "cluster_name": clusterName, + "patroni_cluster_name": patroniClusterName, + } + + // 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)...) + + return req, nil +} + func (a *MySqlRequestAppender) appendProvisioningRequest(req *DatabaseProvisionRequest, database DatabaseInterface, reqData map[string]interface{}) (*DatabaseProvisionRequest, error) { dbPassword := reqData[common.NDB_PARAM_PASSWORD].(string) databaseNames := database.GetInstanceDatabaseNames() diff --git a/ndb_api/db_helpers_test.go b/ndb_api/db_helpers_test.go index f39af280..f82c4173 100644 --- a/ndb_api/db_helpers_test.go +++ b/ndb_api/db_helpers_test.go @@ -106,7 +106,7 @@ func TestGetRequestAppenderByType(t *testing.T) { } for _, tc := range tests { - got, _ := GetRequestAppender(tc.databaseType) + got, _ := GetRequestAppender(tc.databaseType, false) if !reflect.DeepEqual(tc.expected, got) { t.Fatalf("expected: %v, got: %v", tc.expected, got) } @@ -166,7 +166,7 @@ func TestPostgresProvisionRequestAppender_withoutAdditionalArguments_positiveWor } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -248,7 +248,7 @@ func TestPostgresProvisionRequestAppender_withAdditionalArguments_positiveWorkfl } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -294,7 +294,7 @@ func TestPostgresProvisionRequestAppender_withAdditionalArguments_negativeWorkfl }) mockDatabase.On("IsClone").Return(false) // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -400,7 +400,7 @@ func TestMSSQLProvisionRequestAppender_withoutAdditionalArguments_positiveWorklo } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MSSQL) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MSSQL, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -531,7 +531,7 @@ func TestMSSQLProvisionRequestAppender_withAdditionalArguments_positiveWorkflow( } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MSSQL) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MSSQL, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -593,7 +593,7 @@ func TestMSSQLProvisionRequestAppender_withAdditionalArguments_negativeWorkflow( }) mockDatabase.On("IsClone").Return(false) // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MSSQL) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MSSQL, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -669,7 +669,7 @@ func TestMongoDbProvisionRequestAppender_withoutAdditionalArguments_positiveWork } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MONGODB) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MONGODB, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -756,7 +756,7 @@ func TestMongoDbProvisionRequestAppender_withAdditionalArguments_positiveWorkflo } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MONGODB) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MONGODB, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -802,7 +802,7 @@ func TestMongoDbProvisionRequestAppender_withAdditionalArguments_negativeWorkflo }) mockDatabase.On("IsClone").Return(false) // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MONGODB) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MONGODB, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -857,7 +857,7 @@ func TestMySqlProvisionRequestAppender_withoutAdditionalArguments_positiveWorkfl } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MYSQL) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MYSQL, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -922,7 +922,7 @@ func TestMySqlProvisionRequestAppender_withAdditionalArguments_positiveWorkflow( } // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MYSQL) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MYSQL, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) @@ -968,7 +968,7 @@ func TestMySqlProvisionRequestAppender_withAdditionalArguments_negativeWorkflow( }) mockDatabase.On("IsClone").Return(false) // Get specific implementation of RequestAppender - requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MYSQL) + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_MYSQL, false) // Call function being tested resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) diff --git a/ndb_api/interfaces.go b/ndb_api/interfaces.go index f0c3dedd..640427c0 100644 --- a/ndb_api/interfaces.go +++ b/ndb_api/interfaces.go @@ -72,3 +72,6 @@ type PostgresRequestAppender struct{} // Implements RequestAppender type MySqlRequestAppender struct{} + +// Implements RequestAppender +type PostgresHARequestAppender struct{} From 7a6caeabf760a7f25df1afb8b3f1d0862ec95084 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Fri, 24 Nov 2023 01:07:11 -0500 Subject: [PATCH 03/12] Added tests for Postgres HA --- ndb_api/db_helpers_test.go | 321 +++++++++++++++++++++++++++++++++++-- 1 file changed, 306 insertions(+), 15 deletions(-) diff --git a/ndb_api/db_helpers_test.go b/ndb_api/db_helpers_test.go index f82c4173..df748f4d 100644 --- a/ndb_api/db_helpers_test.go +++ b/ndb_api/db_helpers_test.go @@ -13,13 +13,15 @@ import ( // Test constants const ( - TEST_PASSWORD = "testPassword" - TEST_SSHKEY = "testSSHKey" - TEST_DB_NAMES = "testDB" - TEST_INSTANCE_TYPE = "testInstance" - TEST_TIMEZONE = "test-timezone" - TEST_CLUSTER_ID = "test-cluster-id" - TEST_INSTANCE_SIZE = 100 + TEST_PASSWORD = "testPassword" + TEST_SSHKEY = "testSSHKey" + TEST_DB_NAMES = "testDB" + TEST_INSTANCE_TYPE = "testInstance" + TEST_TIMEZONE = "test-timezone" + TEST_CLUSTER_ID = "test-cluster-id" + TEST_INSTANCE_SIZE = 100 + TEST_CLUSTER_NAME = "test-cluster-name" + TEST_PATRONI_CLUSTER_NAME = "test-patroni-cluster-name" ) // Tests the validateReqData() function with different values of password and sshkey @@ -85,28 +87,38 @@ func TestGetRequestAppenderByType(t *testing.T) { // test data map tests := []struct { - databaseType string - expected interface{} + databaseType string + isHighAvailability bool + expected interface{} }{ {databaseType: common.DATABASE_TYPE_POSTGRES, - expected: &PostgresRequestAppender{}, + isHighAvailability: false, + expected: &PostgresRequestAppender{}, + }, + {databaseType: common.DATABASE_TYPE_POSTGRES, + isHighAvailability: true, + expected: &PostgresHARequestAppender{}, }, {databaseType: common.DATABASE_TYPE_MYSQL, - expected: &MySqlRequestAppender{}, + isHighAvailability: false, + expected: &MySqlRequestAppender{}, }, {databaseType: common.DATABASE_TYPE_MSSQL, - expected: &MSSQLRequestAppender{}, + isHighAvailability: false, + expected: &MSSQLRequestAppender{}, }, {databaseType: common.DATABASE_TYPE_MONGODB, - expected: &MongoDbRequestAppender{}, + isHighAvailability: false, + expected: &MongoDbRequestAppender{}, }, {databaseType: "test", - expected: nil, + isHighAvailability: false, + expected: nil, }, } for _, tc := range tests { - got, _ := GetRequestAppender(tc.databaseType, false) + got, _ := GetRequestAppender(tc.databaseType, tc.isHighAvailability) if !reflect.DeepEqual(tc.expected, got) { t.Fatalf("expected: %v, got: %v", tc.expected, got) } @@ -312,6 +324,285 @@ func TestPostgresProvisionRequestAppender_withAdditionalArguments_negativeWorkfl mockDatabase.AssertCalled(t, "GetInstanceDatabaseNames") } +// Tests PostgresHAProvisionRequestAppender(), without additional arguments, positive workflow +func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_positiveWorkflow(t *testing.T) { + + baseRequest := &DatabaseProvisionRequest{} + // Create a mock implementation of DatabaseInterface + mockDatabase := &MockDatabaseInterface{} + + reqData := map[string]interface{}{ + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + } + + // Mock required Mock Database Interface methods + mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) + mockDatabase.On("GetInstanceType").Return(common.DATABASE_TYPE_POSTGRES) + mockDatabase.On("GetAdditionalArguments").Return(map[string]string{}) + mockDatabase.On("IsClone").Return(false) + expectedActionArgs := []ActionArgument{ + { + Name: "proxy_read_port", + Value: "5001", + }, + { + Name: "listener_port", + Value: "5432", + }, + { + Name: "proxy_write_port", + Value: "5000", + }, + { + Name: "enable_synchronous_mode", + Value: "true", + }, + { + Name: "auto_tune_staging_drive", + Value: "true", + }, + { + Name: "backup_policy", + Value: "primary_only", + }, + { + Name: "db_password", + Value: TEST_PASSWORD, + }, + { + Name: "database_names", + Value: TEST_DB_NAMES, + }, + { + Name: "provision_virtual_ip", + Value: "true", + }, + { + Name: "deploy_haproxy", + Value: "true", + }, + { + Name: "failover_mode", + Value: "Automatic", + }, + { + Name: "node_type", + Value: "database", + }, + { + Name: "allocate_pg_hugepage", + Value: "false", + }, + { + Name: "cluster_database", + Value: "false", + }, + { + Name: "archive_wal_expire_days", + Value: "-1", + }, + { + Name: "enable_peer_auth", + Value: "false", + }, + { + Name: "cluster_name", + Value: TEST_CLUSTER_NAME, + }, + { + Name: "patroni_cluster_name", + Value: TEST_PATRONI_CLUSTER_NAME, + }, + } + + // Get specific implementation of RequestAppender + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, true) + + // Call function being tested + resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) + // Assert expected results + if resultRequest.SSHPublicKey != reqData[common.NDB_PARAM_SSH_PUBLIC_KEY] { + t.Errorf("Unexpected SSHPublicKey value. Expected: %s, Got: %s", reqData[common.NDB_PARAM_SSH_PUBLIC_KEY], resultRequest.SSHPublicKey) + } + + // Checks if expected and retrieved action arguments are equal + sortWantAndGotActionArgsByName(expectedActionArgs, resultRequest.ActionArguments) + + // Checks if no error was returned + if err != nil { + t.Errorf("Unexpected error. Expected: %v, Got: %v", nil, err) + } + + // Checks requestAppender.appendProvisioningRequest return type has no error and resultRequest.ActionArguments correctly configured + if !reflect.DeepEqual(expectedActionArgs, resultRequest.ActionArguments) { + t.Errorf("Unexpected ActionArguments. Expected: %v, Got: %v", expectedActionArgs, resultRequest.ActionArguments) + } + + // Verify that the mock method was called with the expected arguments + mockDatabase.AssertCalled(t, "GetInstanceDatabaseNames") +} + +// Test PostgresHAProvisionRequestAppender(), with additional arguments, positive workflow +func TestPostgresHAProvisionRequestAppender_withAdditionalArguments_positiveWorkflow(t *testing.T) { + + baseRequest := &DatabaseProvisionRequest{} + // Create a mock implementation of DatabaseInterface + mockDatabase := &MockDatabaseInterface{} + + reqData := map[string]interface{}{ + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + } + + // Mock required Mock Database Interface methods + mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) + mockDatabase.On("GetInstanceType").Return(common.DATABASE_TYPE_POSTGRES) + mockDatabase.On("GetAdditionalArguments").Return(map[string]string{ + "listener_port": "0000", + }) + mockDatabase.On("IsClone").Return(false) + + expectedActionArgs := []ActionArgument{ + { + Name: "listener_port", + Value: "0000", + }, + { + Name: "proxy_read_port", + Value: "5001", + }, + { + Name: "proxy_write_port", + Value: "5000", + }, + { + Name: "enable_synchronous_mode", + Value: "true", + }, + { + Name: "auto_tune_staging_drive", + Value: "true", + }, + { + Name: "backup_policy", + Value: "primary_only", + }, + { + Name: "db_password", + Value: TEST_PASSWORD, + }, + { + Name: "database_names", + Value: TEST_DB_NAMES, + }, + { + Name: "provision_virtual_ip", + Value: "true", + }, + { + Name: "deploy_haproxy", + Value: "true", + }, + { + Name: "failover_mode", + Value: "Automatic", + }, + { + Name: "node_type", + Value: "database", + }, + { + Name: "allocate_pg_hugepage", + Value: "false", + }, + { + Name: "cluster_database", + Value: "false", + }, + { + Name: "archive_wal_expire_days", + Value: "-1", + }, + { + Name: "enable_peer_auth", + Value: "false", + }, + { + Name: "cluster_name", + Value: TEST_CLUSTER_NAME, + }, + { + Name: "patroni_cluster_name", + Value: TEST_PATRONI_CLUSTER_NAME, + }, + } + + // Get specific implementation of RequestAppender + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, true) + + // Call function being tested + resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) + + // Assert expected results + if resultRequest.SSHPublicKey != reqData[common.NDB_PARAM_SSH_PUBLIC_KEY] { + t.Errorf("Unexpected SSHPublicKey value. Expected: %s, Got: %s", reqData[common.NDB_PARAM_SSH_PUBLIC_KEY], resultRequest.SSHPublicKey) + } + + // Sort expected and retrieved action arguments + sortWantAndGotActionArgsByName(expectedActionArgs, resultRequest.ActionArguments) + + // Checks if no error was returned + if err != nil { + t.Errorf("Unexpected error. Expected: %v, Got: %v", nil, err) + } + // Check if the lengths of expected and retrieved action arguments are equal + if !reflect.DeepEqual(expectedActionArgs, resultRequest.ActionArguments) { + t.Errorf("Unexpected ActionArguments. Expected: %v, Got: %v", expectedActionArgs, resultRequest.ActionArguments) + } + + // Verify that the mock method was called with the expected arguments + mockDatabase.AssertCalled(t, "GetInstanceDatabaseNames") +} + +// Test PostgresHAProvisionRequestAppender(), with additional arguments, negative workflow +func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_negativeWorkflow(t *testing.T) { + + baseRequest := &DatabaseProvisionRequest{} + // Create a mock implementation of DatabaseInterface + mockDatabase := &MockDatabaseInterface{} + + reqData := map[string]interface{}{ + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + } + + // Mock required Mock Database Interface methods + mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) + mockDatabase.On("GetInstanceType").Return(common.DATABASE_TYPE_POSTGRES) + mockDatabase.On("GetAdditionalArguments").Return(map[string]string{ + "invalid-key": "invalid-value", + }) + mockDatabase.On("IsClone").Return(false) + // Get specific implementation of RequestAppender + requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, true) + + // Call function being tested + resultRequest, err := requestAppender.appendProvisioningRequest(baseRequest, mockDatabase, reqData) + + // Checks if error was returned + if err == nil { + t.Errorf("Should have errored. Expected: Setting configured action arguments failed! invalid-key is not an allowed additional argument, Got: %v", err) + } + // Checks if resultRequestIsNil + if resultRequest != nil { + t.Errorf("Should have errored. Expected: resultRequest to be nil, Got: %v", resultRequest) + } + + // Verify that the mock method was called with the expected arguments + mockDatabase.AssertCalled(t, "GetInstanceDatabaseNames") +} + // Tests MSSQLProvisionRequestAppender(), without additional arguments, positive workflow func TestMSSQLProvisionRequestAppender_withoutAdditionalArguments_positiveWorklow(t *testing.T) { From 192982f05e65d02be90fef26aa348304ff68c4b8 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Mon, 27 Nov 2023 23:20:45 -0500 Subject: [PATCH 04/12] Tests added for Postgres HA Append Request. Test cases passing --- ndb_api/db_helpers_test.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ndb_api/db_helpers_test.go b/ndb_api/db_helpers_test.go index df748f4d..e5b51a7e 100644 --- a/ndb_api/db_helpers_test.go +++ b/ndb_api/db_helpers_test.go @@ -332,8 +332,10 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_positiveW mockDatabase := &MockDatabaseInterface{} reqData := map[string]interface{}{ - common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, - common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + common.NDB_PARAM_CLUSTER_NAME: TEST_CLUSTER_NAME, + common.NDB_PARAM_PATRONI_CLUSTER_NAME: TEST_PATRONI_CLUSTER_NAME, } // Mock required Mock Database Interface methods @@ -451,8 +453,10 @@ func TestPostgresHAProvisionRequestAppender_withAdditionalArguments_positiveWork mockDatabase := &MockDatabaseInterface{} reqData := map[string]interface{}{ - common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, - common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + common.NDB_PARAM_CLUSTER_NAME: TEST_CLUSTER_NAME, + common.NDB_PARAM_PATRONI_CLUSTER_NAME: TEST_PATRONI_CLUSTER_NAME, } // Mock required Mock Database Interface methods @@ -573,8 +577,10 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_negativeW mockDatabase := &MockDatabaseInterface{} reqData := map[string]interface{}{ - common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, - common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, + common.NDB_PARAM_CLUSTER_NAME: TEST_CLUSTER_NAME, + common.NDB_PARAM_PATRONI_CLUSTER_NAME: TEST_PATRONI_CLUSTER_NAME, } // Mock required Mock Database Interface methods From a7a3a6bf203126159b127b24eec3ec402b0cbc0e Mon Sep 17 00:00:00 2001 From: Rushil Patel Date: Thu, 30 Nov 2023 18:18:13 -0500 Subject: [PATCH 05/12] Made changes in API for High Avaibility of PostGres DB --- api/v1alpha1/database_types.go | 4 ++++ api/v1alpha1/webhook_helpers.go | 9 +++++++++ api/v1alpha1/webhook_suite_test.go | 3 +++ api/v1alpha1/zz_generated.deepcopy.go | 3 +++ config/samples/ndb_v1aplha1_secrets.yaml | 21 +++++++++++++++++++++ controller_adapters/database.go | 4 ++++ controller_adapters/database_test.go | 24 ++++++++++++++++++++++++ ndb_api/interfaces.go | 1 + 8 files changed, 69 insertions(+) create mode 100644 config/samples/ndb_v1aplha1_secrets.yaml diff --git a/api/v1alpha1/database_types.go b/api/v1alpha1/database_types.go index 06247563..afc28121 100644 --- a/api/v1alpha1/database_types.go +++ b/api/v1alpha1/database_types.go @@ -107,6 +107,8 @@ type Instance struct { // +optional // Additional database engine specific arguments AdditionalArguments map[string]string `json:"additionalArguments"` + // +optional + IsHighAvailibility bool `json:"isHighAvailibility"` } type Clone struct { @@ -133,6 +135,8 @@ type Clone struct { // +optional // Additional database engine specific arguments AdditionalArguments map[string]string `json:"additionalArguments"` + + IsHighAvailibility bool `json:"isHighAvailibility"` } // Time Machine details diff --git a/api/v1alpha1/webhook_helpers.go b/api/v1alpha1/webhook_helpers.go index 45559d8f..560df228 100644 --- a/api/v1alpha1/webhook_helpers.go +++ b/api/v1alpha1/webhook_helpers.go @@ -261,6 +261,11 @@ func initializeObjects(spec *DatabaseSpec) { databaselog.Info("Initializing Instance AdditionalArguments") spec.Instance.AdditionalArguments = map[string]string{} } + // ask mazin + // if spec.Instance.IsHighAvailibility == false { + // databaselog.Info("Initializing Instance IsHighAvailibility") + // spec.Instance.IsHighAvailibility = false + // } // Initialize Clone properties if spec.Clone == nil { @@ -275,6 +280,10 @@ func initializeObjects(spec *DatabaseSpec) { databaselog.Info("Initializing Clone AdditionalArguments") spec.Clone.AdditionalArguments = map[string]string{} } + //if spec.Clone.IsHighAvailibility == false { + // databaselog.Info("Initializing Clone IsHighAvailibility") + // spec.Clone.IsHighAvailibility = false + //} databaselog.Info("Exiting initializeObjects logic!") } diff --git a/api/v1alpha1/webhook_suite_test.go b/api/v1alpha1/webhook_suite_test.go index 2173c2db..ae19de6a 100644 --- a/api/v1alpha1/webhook_suite_test.go +++ b/api/v1alpha1/webhook_suite_test.go @@ -60,6 +60,7 @@ const ( CREDENTIAL_SECRET = "database-secret" TIMEZONE = "UTC" SIZE = 10 + HA = false ) func TestAPIs(t *testing.T) { @@ -615,6 +616,7 @@ func createDefaultDatabase(metadataName string) *Database { Type: common.DATABASE_TYPE_POSTGRES, Profiles: &(Profiles{}), AdditionalArguments: map[string]string{}, + IsHighAvailibility: HA, }, }, } @@ -639,6 +641,7 @@ func createDefaultClone(metadataName string) *Database { SnapshotId: DEFAULT_UUID, Profiles: &(Profiles{}), AdditionalArguments: map[string]string{}, + IsHighAvailibility: HA, }, }, } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 96e391a9..5f3d9350 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -18,6 +18,8 @@ limitations under the License. */ // Code generated by controller-gen. DO NOT EDIT. +// make generate manifest + package v1alpha1 @@ -191,6 +193,7 @@ func (in *Instance) DeepCopyInto(out *Instance) { (*out)[key] = val } } + } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance. diff --git a/config/samples/ndb_v1aplha1_secrets.yaml b/config/samples/ndb_v1aplha1_secrets.yaml new file mode 100644 index 00000000..85a3da90 --- /dev/null +++ b/config/samples/ndb_v1aplha1_secrets.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Secret +metadata: + name: ndb-secret-name +type: Opaque +stringData: + username: testNdbServer + password: testNdbPassword + ca_certificate: | + -----BEGIN CERTIFICATE----- + CA CERTIFICATE (ca_certificate is optional) + -----END CERTIFICATE----- +--- +apiVersion: v1 +kind: Secret +metadata: + name: db-instance-secret-name +type: Opaque +stringData: + password: test123 + ssh_public_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5c1Kfw2w6gTcv/GYH6tr+RtVS2dITV7hirQrlrUFTXbvOS4lRgpRwxY2BjVh7TjgKQ6ZiS+09rIABCIDeV1GP6n2651XYJ161J9qfGSjZphIh48qiQGdkDlPa2fh1aQkUxdjIzh42/hDFrlZWXKBS0V2jiCiqa8R8kgEGLiYsbJb/Pa+4G39/F85kg3JdNeeSFl7w9Cxrfn225/2ISQeaD6S+gOrvvfrcDLDU+q3jxbkB3vU4mqt+4tC4G24tjPZr93vdFkroXr3HpjmAHSABWL2tkKc3encAaIEH0+OI2HKeXIYdOYQsprv8/6/0OyNwEmTdSN4qn9Q8PPtRnqbj diff --git a/controller_adapters/database.go b/controller_adapters/database.go index c2bc4506..031f8581 100644 --- a/controller_adapters/database.go +++ b/controller_adapters/database.go @@ -145,6 +145,10 @@ func (d *Database) GetInstanceSize() int { return d.Spec.Instance.Size } +func (d *Database) GetInstanceIsHighAvailibility() bool { + return d.Spec.Instance.IsHighAvailibility +} + // Returns basic details about the Time Machine if provided in the // underlying database, else returns defaults like: // TM Name: _TM diff --git a/controller_adapters/database_test.go b/controller_adapters/database_test.go index 60a91bde..79cc358d 100644 --- a/controller_adapters/database_test.go +++ b/controller_adapters/database_test.go @@ -231,6 +231,30 @@ func TestDatabase_GetInstanceSize(t *testing.T) { }) } +// Tests the GetInstanceIsHighAvailibility() function retrieves Size correctly: +func TestDatabase_GetInstanceIsHighAvailibility(t *testing.T) { + + name := "Contains IsHighAvailibility" + database := Database{ + Database: v1alpha1.Database{ + Spec: v1alpha1.DatabaseSpec{ + Instance: &v1alpha1.Instance{ + IsHighAvailibility: true, + }, + }, + }, + } + wantIsHighAvailibility := true + + t.Run(name, func(t *testing.T) { + + gotIsHighAvailibility := database.GetInstanceIsHighAvailibility() + if gotIsHighAvailibility != wantIsHighAvailibility { + t.Errorf("Database.GetInstanceIsHighAvailibility() gotIsHighAvailibility= %v, want %v", gotIsHighAvailibility, wantIsHighAvailibility) + } + }) +} + // Tests the GetClusterId() function retrieves ClusterId correctly: func TestDatabase_GetClusterId(t *testing.T) { diff --git a/ndb_api/interfaces.go b/ndb_api/interfaces.go index f0c3dedd..809c34e0 100644 --- a/ndb_api/interfaces.go +++ b/ndb_api/interfaces.go @@ -49,6 +49,7 @@ type DatabaseInterface interface { GetCloneSourceDBId() string GetCloneSnapshotId() string GetAdditionalArguments() map[string]string + GetInstanceIsHighAvailibility() bool } // Internal Interfaces From 9ac4d6d8c8dd83f8b069fb38d65b6952dd31a09b Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Thu, 30 Nov 2023 23:48:54 -0500 Subject: [PATCH 06/12] High Availability getter corrected --- controller_adapters/database.go | 2 +- controller_adapters/database_test.go | 2 +- ndb_api/interface_mock_test.go | 6 ++++++ ndb_api/interfaces.go | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/controller_adapters/database.go b/controller_adapters/database.go index 031f8581..1304f1a3 100644 --- a/controller_adapters/database.go +++ b/controller_adapters/database.go @@ -145,7 +145,7 @@ func (d *Database) GetInstanceSize() int { return d.Spec.Instance.Size } -func (d *Database) GetInstanceIsHighAvailibility() bool { +func (d *Database) GetInstanceIsHighAvailability() bool { return d.Spec.Instance.IsHighAvailibility } diff --git a/controller_adapters/database_test.go b/controller_adapters/database_test.go index 79cc358d..d8dfeb99 100644 --- a/controller_adapters/database_test.go +++ b/controller_adapters/database_test.go @@ -248,7 +248,7 @@ func TestDatabase_GetInstanceIsHighAvailibility(t *testing.T) { t.Run(name, func(t *testing.T) { - gotIsHighAvailibility := database.GetInstanceIsHighAvailibility() + gotIsHighAvailibility := database.GetInstanceIsHighAvailability() if gotIsHighAvailibility != wantIsHighAvailibility { t.Errorf("Database.GetInstanceIsHighAvailibility() gotIsHighAvailibility= %v, want %v", gotIsHighAvailibility, wantIsHighAvailibility) } diff --git a/ndb_api/interface_mock_test.go b/ndb_api/interface_mock_test.go index 4190debc..8ec1c253 100644 --- a/ndb_api/interface_mock_test.go +++ b/ndb_api/interface_mock_test.go @@ -136,3 +136,9 @@ func (m *MockDatabaseInterface) GetAdditionalArguments() map[string]string { // If the type assertion fails, return default return map[string]string{} } + +// GetInstanceIsHighAvailability is a mock implementation of the GetInstanceIsHighAvailability method in the Database interface +func (m *MockDatabaseInterface) GetInstanceIsHighAvailability() bool { + args := m.Called() + return args.Bool(0) +} diff --git a/ndb_api/interfaces.go b/ndb_api/interfaces.go index 809c34e0..60af6d8e 100644 --- a/ndb_api/interfaces.go +++ b/ndb_api/interfaces.go @@ -49,7 +49,7 @@ type DatabaseInterface interface { GetCloneSourceDBId() string GetCloneSnapshotId() string GetAdditionalArguments() map[string]string - GetInstanceIsHighAvailibility() bool + GetInstanceIsHighAvailability() bool } // Internal Interfaces From b44a6fa7768fec590f28553d50f2526722645d2f Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Thu, 30 Nov 2023 23:51:37 -0500 Subject: [PATCH 07/12] Ran make generate manifest --- api/v1alpha1/zz_generated.deepcopy.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 5f3d9350..96e391a9 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -18,8 +18,6 @@ limitations under the License. */ // Code generated by controller-gen. DO NOT EDIT. -// make generate manifest - package v1alpha1 @@ -193,7 +191,6 @@ func (in *Instance) DeepCopyInto(out *Instance) { (*out)[key] = val } } - } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance. From f12924c9bcf39ca2b5d69d5d339373cae2bb37e8 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Sat, 2 Dec 2023 23:30:18 -0500 Subject: [PATCH 08/12] SetNodesParameters added --- .gitignore | 2 +- api/v1alpha1/database_types.go | 2 +- api/v1alpha1/webhook_helpers.go | 9 --- .../crd/bases/ndb.nutanix.com_databases.yaml | 4 ++ config/samples/ndb_v1aplha1_secrets.yaml | 21 ------ ndb_api/clone_helpers.go | 66 ++++++++++++++++++- ndb_api/common_types.go | 12 ++-- ndb_api/db_helpers.go | 62 +++++++++++++++-- ndb_api/db_helpers_test.go | 7 ++ 9 files changed, 141 insertions(+), 44 deletions(-) delete mode 100644 config/samples/ndb_v1aplha1_secrets.yaml diff --git a/.gitignore b/.gitignore index c0867775..2ef2395e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ testbin/* sandbox -config/samples/ndb.yaml +config/samples/* .DS_Store test/__debug_bin diff --git a/api/v1alpha1/database_types.go b/api/v1alpha1/database_types.go index afc28121..344322db 100644 --- a/api/v1alpha1/database_types.go +++ b/api/v1alpha1/database_types.go @@ -135,7 +135,7 @@ type Clone struct { // +optional // Additional database engine specific arguments AdditionalArguments map[string]string `json:"additionalArguments"` - + // +optional IsHighAvailibility bool `json:"isHighAvailibility"` } diff --git a/api/v1alpha1/webhook_helpers.go b/api/v1alpha1/webhook_helpers.go index 560df228..45559d8f 100644 --- a/api/v1alpha1/webhook_helpers.go +++ b/api/v1alpha1/webhook_helpers.go @@ -261,11 +261,6 @@ func initializeObjects(spec *DatabaseSpec) { databaselog.Info("Initializing Instance AdditionalArguments") spec.Instance.AdditionalArguments = map[string]string{} } - // ask mazin - // if spec.Instance.IsHighAvailibility == false { - // databaselog.Info("Initializing Instance IsHighAvailibility") - // spec.Instance.IsHighAvailibility = false - // } // Initialize Clone properties if spec.Clone == nil { @@ -280,10 +275,6 @@ func initializeObjects(spec *DatabaseSpec) { databaselog.Info("Initializing Clone AdditionalArguments") spec.Clone.AdditionalArguments = map[string]string{} } - //if spec.Clone.IsHighAvailibility == false { - // databaselog.Info("Initializing Clone IsHighAvailibility") - // spec.Clone.IsHighAvailibility = false - //} databaselog.Info("Exiting initializeObjects logic!") } diff --git a/config/crd/bases/ndb.nutanix.com_databases.yaml b/config/crd/bases/ndb.nutanix.com_databases.yaml index c9c2438d..f69c4778 100644 --- a/config/crd/bases/ndb.nutanix.com_databases.yaml +++ b/config/crd/bases/ndb.nutanix.com_databases.yaml @@ -65,6 +65,8 @@ spec: description: description: Description of the clone instance type: string + isHighAvailibility: + type: boolean name: description: Name of the clone instance type: string @@ -151,6 +153,8 @@ spec: description: description: Description of the database instance type: string + isHighAvailibility: + type: boolean name: description: Name of the database instance type: string diff --git a/config/samples/ndb_v1aplha1_secrets.yaml b/config/samples/ndb_v1aplha1_secrets.yaml deleted file mode 100644 index 85a3da90..00000000 --- a/config/samples/ndb_v1aplha1_secrets.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: ndb-secret-name -type: Opaque -stringData: - username: testNdbServer - password: testNdbPassword - ca_certificate: | - -----BEGIN CERTIFICATE----- - CA CERTIFICATE (ca_certificate is optional) - -----END CERTIFICATE----- ---- -apiVersion: v1 -kind: Secret -metadata: - name: db-instance-secret-name -type: Opaque -stringData: - password: test123 - ssh_public_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5c1Kfw2w6gTcv/GYH6tr+RtVS2dITV7hirQrlrUFTXbvOS4lRgpRwxY2BjVh7TjgKQ6ZiS+09rIABCIDeV1GP6n2651XYJ161J9qfGSjZphIh48qiQGdkDlPa2fh1aQkUxdjIzh42/hDFrlZWXKBS0V2jiCiqa8R8kgEGLiYsbJb/Pa+4G39/F85kg3JdNeeSFl7w9Cxrfn225/2ISQeaD6S+gOrvvfrcDLDU+q3jxbkB3vU4mqt+4tC4G24tjPZr93vdFkroXr3HpjmAHSABWL2tkKc3encAaIEH0+OI2HKeXIYdOYQsprv8/6/0OyNwEmTdSN4qn9Q8PPtRnqbj diff --git a/ndb_api/clone_helpers.go b/ndb_api/clone_helpers.go index 6ae74b7c..c2b99a7b 100644 --- a/ndb_api/clone_helpers.go +++ b/ndb_api/clone_helpers.go @@ -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" @@ -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 @@ -208,10 +209,73 @@ 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*/ diff --git a/ndb_api/common_types.go b/ndb_api/common_types.go index 26c57a91..1dae7ed0 100644 --- a/ndb_api/common_types.go +++ b/ndb_api/common_types.go @@ -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 { diff --git a/ndb_api/db_helpers.go b/ndb_api/db_helpers.go index c462a201..c19bf64a 100644 --- a/ndb_api/db_helpers.go +++ b/ndb_api/db_helpers.go @@ -92,7 +92,7 @@ func GenerateProvisioningRequest(ctx context.Context, ndb_client *ndb_client.NDB }, Nodes: []Node{ { - Properties: make([]string, 0), + Properties: make([]map[string]string, 0), VmName: database.GetName() + "_VM", }, }, @@ -108,11 +108,8 @@ func GenerateProvisioningRequest(ctx context.Context, ndb_client *ndb_client.NDB }, } - // boolean for high availability - isHighAvailability := false - // Appending request body based on database type - appender, err := GetRequestAppender(database.GetInstanceType(), isHighAvailability) + appender, err := GetRequestAppender(database.GetInstanceType(), database.GetInstanceIsHighAvailability()) if err != nil { log.Error(err, "Error while appending provisioning request") return @@ -307,6 +304,57 @@ func (a *PostgresRequestAppender) appendProvisioningRequest(req *DatabaseProvisi return req, nil } +func setNodesParameters(req *DatabaseProvisionRequest, database DatabaseInterface) { + // 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{ + Properties: props, + VmName: database.GetName() + "-" + strconv.Itoa(i), + NxClusterId: database.GetClusterId(), + }) + } +} + func (a *PostgresHARequestAppender) appendProvisioningRequest(req *DatabaseProvisionRequest, database DatabaseInterface, reqData map[string]interface{}) (*DatabaseProvisionRequest, error) { dbPassword := reqData[common.NDB_PARAM_PASSWORD].(string) databaseNames := database.GetInstanceDatabaseNames() @@ -314,6 +362,10 @@ func (a *PostgresHARequestAppender) appendProvisioningRequest(req *DatabaseProvi patroniClusterName := reqData[common.NDB_PARAM_PATRONI_CLUSTER_NAME].(string) req.SSHPublicKey = reqData[common.NDB_PARAM_SSH_PUBLIC_KEY].(string) + // Set the number of nodes to 5, 3 Postgres nodes + 2 HA Proxy nodes + req.NodeCount = 5 + setNodesParameters(req, database) + // Default action arguments actionArguments := map[string]string{ /* Non-Configurable from additionalArguments*/ diff --git a/ndb_api/db_helpers_test.go b/ndb_api/db_helpers_test.go index e5b51a7e..278318ec 100644 --- a/ndb_api/db_helpers_test.go +++ b/ndb_api/db_helpers_test.go @@ -340,8 +340,10 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_positiveW // Mock required Mock Database Interface methods mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) + mockDatabase.On("GetName").Return("TestPostgresHADB") mockDatabase.On("GetInstanceType").Return(common.DATABASE_TYPE_POSTGRES) mockDatabase.On("GetAdditionalArguments").Return(map[string]string{}) + mockDatabase.On("GetClusterId").Return(TEST_CLUSTER_ID) mockDatabase.On("IsClone").Return(false) expectedActionArgs := []ActionArgument{ { @@ -461,10 +463,12 @@ func TestPostgresHAProvisionRequestAppender_withAdditionalArguments_positiveWork // Mock required Mock Database Interface methods mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) + mockDatabase.On("GetName").Return("TestPostgresHADB") mockDatabase.On("GetInstanceType").Return(common.DATABASE_TYPE_POSTGRES) mockDatabase.On("GetAdditionalArguments").Return(map[string]string{ "listener_port": "0000", }) + mockDatabase.On("GetClusterId").Return(TEST_CLUSTER_ID) mockDatabase.On("IsClone").Return(false) expectedActionArgs := []ActionArgument{ @@ -585,10 +589,12 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_negativeW // Mock required Mock Database Interface methods mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) + mockDatabase.On("GetName").Return("TestPostgresHADB") mockDatabase.On("GetInstanceType").Return(common.DATABASE_TYPE_POSTGRES) mockDatabase.On("GetAdditionalArguments").Return(map[string]string{ "invalid-key": "invalid-value", }) + mockDatabase.On("GetClusterId").Return(TEST_CLUSTER_ID) mockDatabase.On("IsClone").Return(false) // Get specific implementation of RequestAppender requestAppender, _ := GetRequestAppender(common.DATABASE_TYPE_POSTGRES, true) @@ -1585,6 +1591,7 @@ func TestGenerateProvisioningRequest_AgainstDifferentReqData(t *testing.T) { mockDatabase.On("GetInstanceSize").Return(TEST_INSTANCE_SIZE) mockDatabase.On("GetInstanceDatabaseNames").Return(TEST_DB_NAMES) mockDatabase.On("GetAdditionalArguments").Return(map[string]string{}) + mockDatabase.On("GetInstanceIsHighAvailability").Return(false) mockDatabase.On("IsClone").Return(false) // Test From 132fd8e4171a239fc0b2e984b03e18b3cfbe67e8 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Mon, 4 Dec 2023 00:34:51 -0500 Subject: [PATCH 09/12] HA Provisioning tested on NDB. Fixes in the Application Flow --- api/v1alpha1/database_types.go | 4 +- api/v1alpha1/webhook_suite_test.go | 4 +- common/constants.go | 8 ++-- .../crd/bases/ndb.nutanix.com_databases.yaml | 4 +- controller_adapters/database.go | 2 +- controller_adapters/database_test.go | 16 +++---- ndb_api/db_helpers.go | 19 +++++---- ndb_api/db_helpers_test.go | 42 ++++++++----------- ndb_client/ndb_client.go | 3 ++ 9 files changed, 49 insertions(+), 53 deletions(-) diff --git a/api/v1alpha1/database_types.go b/api/v1alpha1/database_types.go index 344322db..81e03a4a 100644 --- a/api/v1alpha1/database_types.go +++ b/api/v1alpha1/database_types.go @@ -108,7 +108,7 @@ type Instance struct { // Additional database engine specific arguments AdditionalArguments map[string]string `json:"additionalArguments"` // +optional - IsHighAvailibility bool `json:"isHighAvailibility"` + IsHighAvailability bool `json:"isHighAvailability"` } type Clone struct { @@ -136,7 +136,7 @@ type Clone struct { // Additional database engine specific arguments AdditionalArguments map[string]string `json:"additionalArguments"` // +optional - IsHighAvailibility bool `json:"isHighAvailibility"` + IsHighAvailability bool `json:"isHighAvailability"` } // Time Machine details diff --git a/api/v1alpha1/webhook_suite_test.go b/api/v1alpha1/webhook_suite_test.go index ae19de6a..89219420 100644 --- a/api/v1alpha1/webhook_suite_test.go +++ b/api/v1alpha1/webhook_suite_test.go @@ -616,7 +616,7 @@ func createDefaultDatabase(metadataName string) *Database { Type: common.DATABASE_TYPE_POSTGRES, Profiles: &(Profiles{}), AdditionalArguments: map[string]string{}, - IsHighAvailibility: HA, + IsHighAvailability: HA, }, }, } @@ -641,7 +641,7 @@ func createDefaultClone(metadataName string) *Database { SnapshotId: DEFAULT_UUID, Profiles: &(Profiles{}), AdditionalArguments: map[string]string{}, - IsHighAvailibility: HA, + IsHighAvailability: HA, }, }, } diff --git a/common/constants.go b/common/constants.go index d6156f11..02339721 100644 --- a/common/constants.go +++ b/common/constants.go @@ -56,11 +56,9 @@ const ( NDB_CR_STATUS_ERROR = "Error" NDB_CR_STATUS_OK = "Ok" - NDB_PARAM_PASSWORD = "password" - NDB_PARAM_SSH_PUBLIC_KEY = "ssh_public_key" - NDB_PARAM_USERNAME = "username" - NDB_PARAM_CLUSTER_NAME = "cluster_name" - NDB_PARAM_PATRONI_CLUSTER_NAME = "patroni_cluster_name" + NDB_PARAM_PASSWORD = "password" + NDB_PARAM_SSH_PUBLIC_KEY = "ssh_public_key" + NDB_PARAM_USERNAME = "username" NDB_RECONCILE_DATABASE_COUNTER = 4 NDB_RECONCILE_INTERVAL_SECONDS = 15 diff --git a/config/crd/bases/ndb.nutanix.com_databases.yaml b/config/crd/bases/ndb.nutanix.com_databases.yaml index f69c4778..8110df33 100644 --- a/config/crd/bases/ndb.nutanix.com_databases.yaml +++ b/config/crd/bases/ndb.nutanix.com_databases.yaml @@ -65,7 +65,7 @@ spec: description: description: Description of the clone instance type: string - isHighAvailibility: + isHighAvailability: type: boolean name: description: Name of the clone instance @@ -153,7 +153,7 @@ spec: description: description: Description of the database instance type: string - isHighAvailibility: + isHighAvailability: type: boolean name: description: Name of the database instance diff --git a/controller_adapters/database.go b/controller_adapters/database.go index 1304f1a3..3757ae23 100644 --- a/controller_adapters/database.go +++ b/controller_adapters/database.go @@ -146,7 +146,7 @@ func (d *Database) GetInstanceSize() int { } func (d *Database) GetInstanceIsHighAvailability() bool { - return d.Spec.Instance.IsHighAvailibility + return d.Spec.Instance.IsHighAvailability } // Returns basic details about the Time Machine if provided in the diff --git a/controller_adapters/database_test.go b/controller_adapters/database_test.go index d8dfeb99..a0de35a0 100644 --- a/controller_adapters/database_test.go +++ b/controller_adapters/database_test.go @@ -231,26 +231,26 @@ func TestDatabase_GetInstanceSize(t *testing.T) { }) } -// Tests the GetInstanceIsHighAvailibility() function retrieves Size correctly: -func TestDatabase_GetInstanceIsHighAvailibility(t *testing.T) { +// Tests the GetInstanceIsHighAvailability() function retrieves Size correctly: +func TestDatabase_GetInstanceIsHighAvailability(t *testing.T) { - name := "Contains IsHighAvailibility" + name := "Contains IsHighAvailability" database := Database{ Database: v1alpha1.Database{ Spec: v1alpha1.DatabaseSpec{ Instance: &v1alpha1.Instance{ - IsHighAvailibility: true, + IsHighAvailability: true, }, }, }, } - wantIsHighAvailibility := true + wantIsHighAvailability := true t.Run(name, func(t *testing.T) { - gotIsHighAvailibility := database.GetInstanceIsHighAvailability() - if gotIsHighAvailibility != wantIsHighAvailibility { - t.Errorf("Database.GetInstanceIsHighAvailibility() gotIsHighAvailibility= %v, want %v", gotIsHighAvailibility, wantIsHighAvailibility) + gotIsHighAvailability := database.GetInstanceIsHighAvailability() + if gotIsHighAvailability != wantIsHighAvailability { + t.Errorf("Database.GetInstanceIsHighAvailability() gotIsHighAvailability= %v, want %v", gotIsHighAvailability, wantIsHighAvailability) } }) } diff --git a/ndb_api/db_helpers.go b/ndb_api/db_helpers.go index c19bf64a..74775787 100644 --- a/ndb_api/db_helpers.go +++ b/ndb_api/db_helpers.go @@ -318,7 +318,7 @@ func setNodesParameters(req *DatabaseProvisionRequest, database DatabaseInterfac } req.Nodes = append(req.Nodes, Node{ Properties: props, - VmName: database.GetName() + "_haproxy" + strconv.Itoa(i), + VmName: database.GetName() + "_haproxy" + strconv.Itoa(i+1), NxClusterId: database.GetClusterId(), }) } @@ -348,9 +348,11 @@ func setNodesParameters(req *DatabaseProvisionRequest, database DatabaseInterfac "value": "", } req.Nodes = append(req.Nodes, Node{ - Properties: props, - VmName: database.GetName() + "-" + strconv.Itoa(i), - NxClusterId: database.GetClusterId(), + Properties: props, + VmName: database.GetName() + "-" + strconv.Itoa(i+1), + NetworkProfileId: req.NetworkProfileId, + ComputeProfileId: req.ComputeProfileId, + NxClusterId: database.GetClusterId(), }) } } @@ -358,14 +360,15 @@ func setNodesParameters(req *DatabaseProvisionRequest, database DatabaseInterfac func (a *PostgresHARequestAppender) appendProvisioningRequest(req *DatabaseProvisionRequest, database DatabaseInterface, reqData map[string]interface{}) (*DatabaseProvisionRequest, error) { dbPassword := reqData[common.NDB_PARAM_PASSWORD].(string) databaseNames := database.GetInstanceDatabaseNames() - clusterName := reqData[common.NDB_PARAM_CLUSTER_NAME].(string) - patroniClusterName := reqData[common.NDB_PARAM_PATRONI_CLUSTER_NAME].(string) req.SSHPublicKey = reqData[common.NDB_PARAM_SSH_PUBLIC_KEY].(string) // Set the number of nodes to 5, 3 Postgres nodes + 2 HA Proxy nodes req.NodeCount = 5 setNodesParameters(req, database) + // Set clustered to true + req.Clustered = true + // Default action arguments actionArguments := map[string]string{ /* Non-Configurable from additionalArguments*/ @@ -385,8 +388,8 @@ func (a *PostgresHARequestAppender) appendProvisioningRequest(req *DatabaseProvi "cluster_database": "false", "archive_wal_expire_days": "-1", "enable_peer_auth": "false", - "cluster_name": clusterName, - "patroni_cluster_name": patroniClusterName, + "cluster_name": "psqlcluster", + "patroni_cluster_name": "patroni", } // Appending/overwriting database actionArguments to actionArguments diff --git a/ndb_api/db_helpers_test.go b/ndb_api/db_helpers_test.go index 278318ec..a36522a0 100644 --- a/ndb_api/db_helpers_test.go +++ b/ndb_api/db_helpers_test.go @@ -13,15 +13,13 @@ import ( // Test constants const ( - TEST_PASSWORD = "testPassword" - TEST_SSHKEY = "testSSHKey" - TEST_DB_NAMES = "testDB" - TEST_INSTANCE_TYPE = "testInstance" - TEST_TIMEZONE = "test-timezone" - TEST_CLUSTER_ID = "test-cluster-id" - TEST_INSTANCE_SIZE = 100 - TEST_CLUSTER_NAME = "test-cluster-name" - TEST_PATRONI_CLUSTER_NAME = "test-patroni-cluster-name" + TEST_PASSWORD = "testPassword" + TEST_SSHKEY = "testSSHKey" + TEST_DB_NAMES = "testDB" + TEST_INSTANCE_TYPE = "testInstance" + TEST_TIMEZONE = "test-timezone" + TEST_CLUSTER_ID = "test-cluster-id" + TEST_INSTANCE_SIZE = 100 ) // Tests the validateReqData() function with different values of password and sshkey @@ -332,10 +330,8 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_positiveW mockDatabase := &MockDatabaseInterface{} reqData := map[string]interface{}{ - common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, - common.NDB_PARAM_PASSWORD: TEST_PASSWORD, - common.NDB_PARAM_CLUSTER_NAME: TEST_CLUSTER_NAME, - common.NDB_PARAM_PATRONI_CLUSTER_NAME: TEST_PATRONI_CLUSTER_NAME, + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, } // Mock required Mock Database Interface methods @@ -412,11 +408,11 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_positiveW }, { Name: "cluster_name", - Value: TEST_CLUSTER_NAME, + Value: "psqlcluster", }, { Name: "patroni_cluster_name", - Value: TEST_PATRONI_CLUSTER_NAME, + Value: "patroni", }, } @@ -455,10 +451,8 @@ func TestPostgresHAProvisionRequestAppender_withAdditionalArguments_positiveWork mockDatabase := &MockDatabaseInterface{} reqData := map[string]interface{}{ - common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, - common.NDB_PARAM_PASSWORD: TEST_PASSWORD, - common.NDB_PARAM_CLUSTER_NAME: TEST_CLUSTER_NAME, - common.NDB_PARAM_PATRONI_CLUSTER_NAME: TEST_PATRONI_CLUSTER_NAME, + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, } // Mock required Mock Database Interface methods @@ -538,11 +532,11 @@ func TestPostgresHAProvisionRequestAppender_withAdditionalArguments_positiveWork }, { Name: "cluster_name", - Value: TEST_CLUSTER_NAME, + Value: "psqlcluster", }, { Name: "patroni_cluster_name", - Value: TEST_PATRONI_CLUSTER_NAME, + Value: "patroni", }, } @@ -581,10 +575,8 @@ func TestPostgresHAProvisionRequestAppender_withoutAdditionalArguments_negativeW mockDatabase := &MockDatabaseInterface{} reqData := map[string]interface{}{ - common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, - common.NDB_PARAM_PASSWORD: TEST_PASSWORD, - common.NDB_PARAM_CLUSTER_NAME: TEST_CLUSTER_NAME, - common.NDB_PARAM_PATRONI_CLUSTER_NAME: TEST_PATRONI_CLUSTER_NAME, + common.NDB_PARAM_SSH_PUBLIC_KEY: TEST_SSHKEY, + common.NDB_PARAM_PASSWORD: TEST_PASSWORD, } // Mock required Mock Database Interface methods diff --git a/ndb_client/ndb_client.go b/ndb_client/ndb_client.go index 379384a0..eb82f769 100644 --- a/ndb_client/ndb_client.go +++ b/ndb_client/ndb_client.go @@ -47,6 +47,7 @@ func NewNDBClient(username, password, url, caCert string, skipVerify bool) *NDBC func (ndbClient *NDBClient) Get(path string) (*http.Response, error) { url := ndbClient.url + "/" + path req, err := http.NewRequest(http.MethodGet, url, nil) + req.Header.Add("Cookie", "eraAuth=eyJhbGciOiJSUzUxMiJ9") if err != nil { // fmt.Println(err) return nil, err @@ -59,6 +60,7 @@ func (ndbClient *NDBClient) Post(path string, body interface{}) (*http.Response, url := ndbClient.url + "/" + path payload, _ := json.Marshal(body) req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payload)) + req.Header.Add("Cookie", "eraAuth=eyJhbGciOiJSUzUxMiJ9") if err != nil { // fmt.Println(err) return nil, err @@ -72,6 +74,7 @@ func (ndbClient *NDBClient) Delete(path string, body interface{}) (*http.Respons url := ndbClient.url + "/" + path payload, _ := json.Marshal(body) req, err := http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(payload)) + req.Header.Add("Cookie", "eraAuth=eyJhbGciOiJSUzUxMiJ9") if err != nil { // fmt.Println(err) return nil, err From 2109ea845008d75d269ea800232dc4e9183ebce8 Mon Sep 17 00:00:00 2001 From: Sai Rithvik Ayithapu Date: Mon, 4 Dec 2023 00:36:52 -0500 Subject: [PATCH 10/12] Cookie removed --- ndb_client/ndb_client.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/ndb_client/ndb_client.go b/ndb_client/ndb_client.go index eb82f769..379384a0 100644 --- a/ndb_client/ndb_client.go +++ b/ndb_client/ndb_client.go @@ -47,7 +47,6 @@ func NewNDBClient(username, password, url, caCert string, skipVerify bool) *NDBC func (ndbClient *NDBClient) Get(path string) (*http.Response, error) { url := ndbClient.url + "/" + path req, err := http.NewRequest(http.MethodGet, url, nil) - req.Header.Add("Cookie", "eraAuth=eyJhbGciOiJSUzUxMiJ9") if err != nil { // fmt.Println(err) return nil, err @@ -60,7 +59,6 @@ func (ndbClient *NDBClient) Post(path string, body interface{}) (*http.Response, url := ndbClient.url + "/" + path payload, _ := json.Marshal(body) req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payload)) - req.Header.Add("Cookie", "eraAuth=eyJhbGciOiJSUzUxMiJ9") if err != nil { // fmt.Println(err) return nil, err @@ -74,7 +72,6 @@ func (ndbClient *NDBClient) Delete(path string, body interface{}) (*http.Respons url := ndbClient.url + "/" + path payload, _ := json.Marshal(body) req, err := http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(payload)) - req.Header.Add("Cookie", "eraAuth=eyJhbGciOiJSUzUxMiJ9") if err != nil { // fmt.Println(err) return nil, err From 3368c3758f3d0bd57519fdedccfdd10f8062d4bb Mon Sep 17 00:00:00 2001 From: Ayithapu Sai Rithvik <58836321+rithvik2607@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:35:02 -0500 Subject: [PATCH 11/12] Updated README.md Added isHighAvailability key-value pair to sample YAML files --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 958e4e2c..fc431728 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,8 @@ spec: size: 10 timezone: "UTC" type: postgres + # Optional parameter. In case nothing is specified, isHighAvailability 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 @@ -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" + # Optional parameter. In case nothing is specified, isHighAvailability 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 From f7d8fe9e73b3b09c652498ea0fbc08081e6b4c1f Mon Sep 17 00:00:00 2001 From: Ayithapu Sai Rithvik <58836321+rithvik2607@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:36:40 -0500 Subject: [PATCH 12/12] Update README.md Corrections to the sample YAML files --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc431728..140f0b44 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ spec: size: 10 timezone: "UTC" type: postgres - # Optional parameter. In case nothing is specified, isHighAvailability is set to false + # 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 @@ -216,7 +216,7 @@ 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" - # Optional parameter. In case nothing is specified, isHighAvailability is set to false + # 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