Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: DDS Backup, Restore, Configuration support #709

Merged
merged 3 commits into from
Aug 19, 2024
Merged
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
117 changes: 117 additions & 0 deletions acceptance/openstack/dds/v3/backups_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package v3

import (
"os"
"testing"

golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/common/pointerto"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/backups"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/instances"
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
)

func TestDdsBackupLifeCycle(t *testing.T) {
instanceId := os.Getenv("DDS_INSTANCE_ID")
if instanceId == "" {
t.Skip("`DDS_INSTANCE_ID` need to be defined")
}
client, err := clients.NewDdsV3Client()
th.AssertNoErr(t, err)

t.Logf("Attempting to create DDSv3 backup for instance: %s", instanceId)
backupOpts := backups.CreateOpts{
Backup: &backups.Backup{
InstanceId: instanceId,
Name: tools.RandomString("dmd-dds-backup-", 5),
Description: "this is backup for dds",
},
}
backup, err := backups.Create(client, backupOpts)
th.AssertNoErr(t, err)
err = waitForBackupAvailable(client, 600, backup.BackupId)
th.AssertNoErr(t, err)
t.Logf("DDSv3 backup successfully created")
th.AssertNoErr(t, err)

t.Cleanup(func() {
t.Logf("Attempting to delete DDSv3 backup: %s", backup.BackupId)
delJob, errDel := backups.Delete(client, backup.BackupId)
err = waitForJobCompleted(client, 600, delJob.JobId)
th.AssertNoErr(t, errDel)
t.Logf("Deleted DDSv3 backup: %s", backup.BackupId)
})

t.Logf("Attempting to list DDSv3 backups for instance: %s", instanceId)
backupList, err := backups.List(client, backups.ListBackupsOpts{
InstanceId: instanceId,
})
th.AssertNoErr(t, err)
th.AssertEquals(t, backupList.TotalCount, 2)

t.Logf("Attempting to get download links for DDSv3 backup: %s", backup.BackupId)
links, err := backups.ListBackupDownloadLinks(client, backups.BackupLinkOpts{
InstanceId: instanceId,
BackupId: backup.BackupId,
})
th.AssertNoErr(t, err)
th.AssertEquals(t, len(links.Files), 1)

t.Logf("Attempting to set backup policy for DDSv3 instance: %s", instanceId)
err = backups.SetBackupPolicy(client, backups.ModifyBackupPolicyOpts{
InstanceId: instanceId,
BackupPolicy: &instances.BackupStrategy{
StartTime: "01:00-02:00",
KeepDays: pointerto.Int(365),
Period: "1,2,3,5,6,7",
},
})
th.AssertNoErr(t, err)

t.Logf("Attempting to get backup policy for DDSv3 instance: %s", instanceId)
getPolicy, err := backups.GetBackupPolicy(client, instanceId)
th.AssertNoErr(t, err)
th.AssertEquals(t, "01:00-02:00", getPolicy.StartTime)
th.AssertEquals(t, 365, *getPolicy.KeepDays)
th.AssertEquals(t, "1,2,3,5,6,7", getPolicy.Period)

t.Logf("Attempting to modify backup policy for DDSv3 instance: %s", instanceId)
err = backups.SetBackupPolicy(client, backups.ModifyBackupPolicyOpts{
InstanceId: instanceId,
BackupPolicy: &instances.BackupStrategy{
StartTime: "03:00-04:00",
KeepDays: pointerto.Int(7),
Period: "1,2,3",
},
})
th.AssertNoErr(t, err)

t.Logf("Attempting to get again backup policy for DDSv3 instance: %s", instanceId)
getPolicyModified, err := backups.GetBackupPolicy(client, instanceId)
th.AssertNoErr(t, err)
th.AssertEquals(t, "03:00-04:00", getPolicyModified.StartTime)
th.AssertEquals(t, 7, *getPolicyModified.KeepDays)
th.AssertEquals(t, "1,2,3", getPolicyModified.Period)
}

func waitForBackupAvailable(client *golangsdk.ServiceClient, secs int, backupId string) error {
return golangsdk.WaitFor(secs, func() (bool, error) {
listOpts := backups.ListBackupsOpts{
BackupId: backupId,
}
backupList, err := backups.List(client, listOpts)
if err != nil {
return false, err
}
if backupList.TotalCount == 1 {
b := backupList.Backups
if len(b) == 1 && b[0].Status == "COMPLETED" {
return true, nil
}
return false, nil
}
return false, nil
})
}
41 changes: 41 additions & 0 deletions acceptance/openstack/dds/v3/configuration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package v3

import (
"os"
"testing"

"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/configurations"
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
)

func TestDdsConfigurationLifeCycle(t *testing.T) {
instanceId := os.Getenv("DDS_INSTANCE_ID")

if instanceId == "" {
t.Skip("`DDS_INSTANCE_ID` need to be defined")
}

client, err := clients.NewDdsV3Client()
th.AssertNoErr(t, err)

t.Logf("Attempting to get DDSv3 instance config")
config, err := configurations.GetInstanceConfig(client, instanceId, configurations.ConfigOpts{EntityId: instanceId})
th.AssertNoErr(t, err)
th.AssertEquals(t, "mongodb", config.DatastoreName)

t.Logf("Attempting to list DDSv3 template configurations")
configList, err := configurations.List(client, configurations.ListConfigOpts{})
th.AssertNoErr(t, err)
th.AssertEquals(t, 29, configList.TotalCount)

t.Logf("Attempting to get DDSv3 template configuration")
getConfig, err := configurations.Get(client, configList.Configurations[0].ID)
th.AssertNoErr(t, err)
th.AssertEquals(t, "Default-DDS-3.2-Shard", getConfig.Name)

t.Logf("Attempting to apply DDSv3 template configuration")
_, err = configurations.Apply(client, configList.Configurations[11].ID,
configurations.ApplyOpts{EntityIDs: []string{instanceId}})
th.AssertNoErr(t, err)
}
6 changes: 5 additions & 1 deletion acceptance/openstack/dds/v3/instances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/opentelekomcloud/gophertelekomcloud/openstack/common/tags"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/instances"
ddsjob "github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/job"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/networking/v1/subnets"
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
)

Expand Down Expand Up @@ -132,6 +133,9 @@ func updateDdsInstance(t *testing.T, client *golangsdk.ServiceClient, instance i
netClient, err := clients.NewNetworkV1Client()
th.AssertNoErr(t, err)

sn, err := subnets.Get(netClient, instance.SubnetId).Extract()
th.AssertNoErr(t, err)

elasticIP := networking.CreateEip(t, netClient, 100)
t.Cleanup(func() {
networking.DeleteEip(t, netClient, elasticIP.ID)
Expand Down Expand Up @@ -169,7 +173,7 @@ func updateDdsInstance(t *testing.T, client *golangsdk.ServiceClient, instance i
t.Log("Modify instance internal IP")
job, err = instances.ModifyInternalIp(client, instances.ModifyInternalIpOpts{
InstanceId: instance.Id,
NewIp: "192.168.1.42",
NewIp: tools.SetLastOctet(tools.ExtractNetworkAddress(sn.CIDR), 100),
NodeId: instance.Groups[0].Nodes[0].Id,
})
th.AssertNoErr(t, err)
Expand Down
59 changes: 59 additions & 0 deletions acceptance/openstack/dds/v3/restore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package v3

import (
"os"
"testing"

"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/backups"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/instances"
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
)

func TestDdsRestoreLifeCycle(t *testing.T) {
instanceId := os.Getenv("DDS_INSTANCE_ID")

if instanceId == "" {
t.Skip("`DDS_INSTANCE_ID` need to be defined")
}

client, err := clients.NewDdsV3Client()
th.AssertNoErr(t, err)

t.Logf("Attempting to create DDSv3 backup for instance: %s", instanceId)
backupOpts := backups.CreateOpts{
Backup: &backups.Backup{
InstanceId: instanceId,
Name: tools.RandomString("dmd-dds-backup-", 5),
Description: "this is backup for dds",
},
}
backup, err := backups.Create(client, backupOpts)
th.AssertNoErr(t, err)
err = waitForBackupAvailable(client, 600, backup.BackupId)
th.AssertNoErr(t, err)
t.Logf("DDSv3 backup successfully created")
th.AssertNoErr(t, err)

t.Cleanup(func() {
t.Logf("Attempting to delete DDSv3 backup: %s", backup.BackupId)
delJob, errDel := backups.Delete(client, backup.BackupId)
err = waitForJobCompleted(client, 600, delJob.JobId)
th.AssertNoErr(t, errDel)
t.Logf("Deleted DDSv3 backup: %s", backup.BackupId)
})

t.Logf("Attempting to restore DDSv3 instance to Original: %s", instanceId)
restoreJob, err := instances.RestoreToOriginal(client, instances.RestoreToOriginalOpts{
Source: instances.Source{
InstanceId: instanceId,
Type: "backup",
BackupId: backup.BackupId,
},
Target: instances.Target{InstanceId: instanceId},
})
th.AssertNoErr(t, err)
err = waitForJobCompleted(client, 600, *restoreJob)
th.AssertNoErr(t, err)
}
7 changes: 3 additions & 4 deletions acceptance/openstack/hss/v5/server_group_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package v2

import (
"os"
"testing"

"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
Expand Down Expand Up @@ -33,9 +32,9 @@ func TestServerList(t *testing.T) {
}

func TestServerLifecycle(t *testing.T) {
if os.Getenv("RUN_HSS_LIFECYCLE") == "" {
t.Skip("too slow to run in zuul")
}
// if os.Getenv("RUN_HSS_LIFECYCLE") == "" {
// t.Skip("too slow to run in zuul")
// }
client, err := clients.NewHssClient()
th.AssertNoErr(t, err)

Expand Down
26 changes: 26 additions & 0 deletions acceptance/tools/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"crypto/rand"
"encoding/json"
"errors"
"fmt"
mrand "math/rand"
"strings"
"testing"
"time"
)
Expand Down Expand Up @@ -71,3 +73,27 @@ func PrintResource(t *testing.T, resource interface{}) {
b, _ := json.MarshalIndent(resource, "", " ")
t.Logf(string(b))
}

// ExtractNetworkAddress removes the mask from the CIDR block
func ExtractNetworkAddress(cidr string) string {
parts := strings.Split(cidr, "/")
if len(parts) != 2 {
return ""
}
return parts[0]
}

// SetLastOctet changes the last octet of the IP address to the specified value
func SetLastOctet(ip string, newLastOctet int) string {
// Split IP into its components
parts := strings.Split(ip, ".")
if len(parts) != 4 {
return ip
}

// Replace the last octet with the new value
parts[3] = fmt.Sprintf("%d", newLastOctet)

// Reassemble the IP address
return strings.Join(parts, ".")
}
41 changes: 41 additions & 0 deletions openstack/dds/v3/backups/Create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package backups

import (
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/internal/build"
)

type CreateOpts struct {
Backup *Backup `json:"backup" required:"true"`
}

type Backup struct {
// Specifies the instance ID, which can be obtained by calling the API for querying instances.
// If you do not have an instance, you can call the API used for creating an instance.
InstanceId string `json:"instance_id" required:"true"`
// Specifies the manual backup name.
// The value must be 4 to 64 characters in length and start with a letter (from A to Z or from a to z).
// It is case-sensitive and can contain only letters, digits (from 0 to 9), hyphens (-), and underscores (_).
Name string `json:"name" required:"true"`
// Specifies the manual backup description.
// The description must consist of a maximum of 256 characters and cannot
// contain the following special characters: >!<"&'=
Description string `json:"description,omitempty"`
}

func Create(client *golangsdk.ServiceClient, opts CreateOpts) (*Job, error) {
b, err := build.RequestBody(opts, "")
if err != nil {
return nil, err
}

// POST https://{Endpoint}/v3/{project_id}/backups
raw, err := client.Post(client.ServiceURL("backups"), b, nil, &golangsdk.RequestOpts{
OkCodes: []int{200},
})
if err != nil {
return nil, err
}

return extractJob(err, raw)
}
11 changes: 11 additions & 0 deletions openstack/dds/v3/backups/Delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package backups

import golangsdk "github.com/opentelekomcloud/gophertelekomcloud"

func Delete(client *golangsdk.ServiceClient, backupId string) (*Job, error) {
// DELETE https://{Endpoint}/v3/{project_id}/backups/{backup_id}
raw, err := client.Delete(client.ServiceURL("backups", backupId), &golangsdk.RequestOpts{
OkCodes: []int{200},
})
return extractJob(err, raw)
}
19 changes: 19 additions & 0 deletions openstack/dds/v3/backups/GetBackupPolicy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package backups

import (
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/internal/extract"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/dds/v3/instances"
)

func GetBackupPolicy(client *golangsdk.ServiceClient, instanceId string) (*instances.BackupStrategy, error) {
// GET https://{Endpoint}/v3/{project_id}/instances/{instance_id}/backups/policy
raw, err := client.Get(client.ServiceURL("instances", instanceId, "backups", "policy"), nil, nil)
if err != nil {
return nil, err
}

var res instances.BackupStrategy
err = extract.IntoStructPtr(raw.Body, &res, "backup_policy")
return &res, err
}
Loading