Skip to content

Commit

Permalink
feat: DDS Backup, Restore, Configuration support (#709)
Browse files Browse the repository at this point in the history
  • Loading branch information
anton-sidelnikov authored Aug 19, 2024
1 parent a05c248 commit db3e93b
Show file tree
Hide file tree
Showing 38 changed files with 1,038 additions and 69 deletions.
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

0 comments on commit db3e93b

Please sign in to comment.