Skip to content

Commit 09deafe

Browse files
afedorchdshelbyo
authored andcommitted
Block Storage: Cross-region backups
1 parent 1c56846 commit 09deafe

File tree

10 files changed

+608
-14
lines changed

10 files changed

+608
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### Added
44
- Support for the Instance Pools & Instance Configurations
5+
- Support for the Block Volume cross-region backups
56

67
## 3.8.0 (November 28, 2018)
78

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
variable "tenancy_ocid" {}
2+
3+
variable "compartment_ocid" {}
4+
variable "user_ocid" {}
5+
variable "fingerprint" {}
6+
variable "private_key_path" {}
7+
variable "region" {}
8+
variable "source_region" {}
9+
variable "source_volume_backup_id" {}
10+
11+
variable "availability_domain" {
12+
default = "3"
13+
}
14+
15+
variable "volume_backup_defined_tags_value" {
16+
default = "value"
17+
}
18+
19+
variable "volume_backup_display_name" {
20+
default = "displayName"
21+
}
22+
23+
variable "volume_backup_copy_display_name" {
24+
default = "displayNameCopy"
25+
}
26+
27+
variable "volume_backup_state" {
28+
default = "AVAILABLE"
29+
}
30+
31+
variable "volume_backup_freeform_tags" {
32+
type = "map"
33+
34+
default = {
35+
Department = "Finance"
36+
}
37+
}
38+
39+
variable "volume_backup_type" {
40+
default = "FULL"
41+
}
42+
43+
provider "oci" {
44+
tenancy_ocid = "${var.tenancy_ocid}"
45+
user_ocid = "${var.user_ocid}"
46+
fingerprint = "${var.fingerprint}"
47+
private_key_path = "${var.private_key_path}"
48+
region = "${var.region}"
49+
}
50+
51+
resource "oci_core_volume" "test_volume" {
52+
availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
53+
compartment_id = "${var.compartment_ocid}"
54+
display_name = "-tf-volume"
55+
}
56+
57+
resource "oci_core_volume_backup" "test_volume_backup" {
58+
#Required
59+
volume_id = "${oci_core_volume.test_volume.id}"
60+
61+
#Optional
62+
display_name = "${var.volume_backup_display_name}"
63+
freeform_tags = "${var.volume_backup_freeform_tags}"
64+
type = "${var.volume_backup_type}"
65+
}
66+
67+
resource "oci_core_volume_backup" "test_volume_backup_cross_region_sourced" {
68+
#Required
69+
source_details {
70+
region = "${var.source_region}"
71+
volume_backup_id = "${var.source_volume_backup_id}"
72+
}
73+
74+
#Optional
75+
display_name = "${var.volume_backup_copy_display_name}"
76+
}
77+
78+
data "oci_identity_availability_domains" "ADs" {
79+
compartment_id = "${var.tenancy_ocid}"
80+
}
81+
82+
data "oci_core_volume_backups" "test_volume_backup" {
83+
#Required
84+
compartment_id = "${var.compartment_ocid}"
85+
86+
#Optional
87+
display_name = "${var.volume_backup_display_name}"
88+
state = "${var.volume_backup_state}"
89+
volume_id = "${oci_core_volume.test_volume.id}"
90+
}
91+
92+
data "oci_core_volume_backups" "test_volume_backup_from_source" {
93+
#Required
94+
compartment_id = "${var.compartment_ocid}"
95+
96+
#Optional
97+
display_name = "${var.volume_backup_copy_display_name}"
98+
source_volume_backup_id = "${var.source_volume_backup_id}"
99+
}
100+
101+
output "volumeBackup" {
102+
value = "${data.oci_core_volume_backups.test_volume_backup.display_name}"
103+
}
104+
105+
output "volumeBackupIdFromSource" {
106+
value = "${data.oci_core_volume_backups.test_volume_backup_from_source.source_volume_backup_id}"
107+
}

oci/core_volume_backup_resource.go

Lines changed: 112 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package provider
44

55
import (
66
"context"
7+
"fmt"
78
"strconv"
89

910
"github.com/hashicorp/terraform/helper/schema"
@@ -22,37 +23,64 @@ func VolumeBackupResource() *schema.Resource {
2223
Update: updateVolumeBackup,
2324
Delete: deleteVolumeBackup,
2425
Schema: map[string]*schema.Schema{
25-
// Required
26+
// Optional
2627
"volume_id": {
27-
Type: schema.TypeString,
28-
Required: true,
29-
ForceNew: true,
28+
Type: schema.TypeString,
29+
Optional: true,
30+
ForceNew: true,
31+
Computed: true,
32+
ConflictsWith: []string{"source_details"},
33+
},
34+
"source_details": {
35+
Type: schema.TypeList,
36+
Optional: true,
37+
ForceNew: true,
38+
MaxItems: 1,
39+
MinItems: 1,
40+
ConflictsWith: []string{"volume_id"},
41+
Elem: &schema.Resource{
42+
Schema: map[string]*schema.Schema{
43+
// Required
44+
"region": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
ForceNew: true,
48+
},
49+
// Required
50+
"volume_backup_id": {
51+
Type: schema.TypeString,
52+
Required: true,
53+
ForceNew: true,
54+
},
55+
},
56+
},
3057
},
31-
32-
// Optional
3358
"defined_tags": {
3459
Type: schema.TypeMap,
3560
Optional: true,
3661
Computed: true,
3762
DiffSuppressFunc: definedTagsDiffSuppressFunction,
3863
Elem: schema.TypeString,
64+
ConflictsWith: []string{"source_details"},
3965
},
4066
"display_name": {
4167
Type: schema.TypeString,
4268
Optional: true,
4369
Computed: true,
4470
},
4571
"freeform_tags": {
46-
Type: schema.TypeMap,
47-
Optional: true,
48-
Computed: true,
49-
Elem: schema.TypeString,
72+
Type: schema.TypeMap,
73+
Optional: true,
74+
Computed: true,
75+
Elem: schema.TypeString,
76+
ConflictsWith: []string{"source_details"},
5077
},
5178
"type": {
52-
Type: schema.TypeString,
53-
Optional: true,
54-
Computed: true,
55-
ForceNew: true,
79+
Type: schema.TypeString,
80+
Optional: true,
81+
Computed: true,
82+
ForceNew: true,
83+
ConflictsWith: []string{"source_details"},
5684
},
5785

5886
// Computed
@@ -77,6 +105,10 @@ func VolumeBackupResource() *schema.Resource {
77105
Type: schema.TypeString,
78106
Computed: true,
79107
},
108+
"source_volume_backup_id": {
109+
Type: schema.TypeString,
110+
Computed: true,
111+
},
80112
"state": {
81113
Type: schema.TypeString,
82114
Computed: true,
@@ -138,6 +170,7 @@ func deleteVolumeBackup(d *schema.ResourceData, m interface{}) error {
138170
type VolumeBackupResourceCrud struct {
139171
BaseCrud
140172
Client *oci_core.BlockstorageClient
173+
SourceRegionClient *oci_core.BlockstorageClient
141174
Res *oci_core.VolumeBackup
142175
DisableNotFoundRetries bool
143176
}
@@ -174,6 +207,67 @@ func (s *VolumeBackupResourceCrud) DeletedTarget() []string {
174207
}
175208

176209
func (s *VolumeBackupResourceCrud) Create() error {
210+
if s.isCopyCreate() {
211+
return s.createVolumeBackupCopy()
212+
}
213+
214+
return s.CreateVolumeBackup()
215+
}
216+
217+
func (s *VolumeBackupResourceCrud) isCopyCreate() bool {
218+
if sourceDetails, ok := s.D.GetOkExists("source_details"); ok {
219+
if tmpList := sourceDetails.([]interface{}); len(tmpList) > 0 {
220+
return true
221+
}
222+
}
223+
return false
224+
}
225+
226+
func (s *VolumeBackupResourceCrud) createVolumeBackupCopy() error {
227+
copyVolumeBackupRequest := oci_core.CopyVolumeBackupRequest{}
228+
229+
configProvider := *s.Client.ConfigurationProvider()
230+
if configProvider == nil {
231+
return fmt.Errorf("cannot access ConfigurationProvider")
232+
}
233+
currentRegion, error := configProvider.Region()
234+
if error != nil {
235+
return fmt.Errorf("cannot access Region for the current ConfigurationProvider")
236+
}
237+
238+
if sourceDetails, ok := s.D.GetOkExists("source_details"); ok && sourceDetails != nil {
239+
fieldKeyFormat := fmt.Sprintf("%s.%d.%%s", "source_details", 0)
240+
241+
if region, ok := s.D.GetOkExists(fmt.Sprintf(fieldKeyFormat, "region")); ok {
242+
tmp := region.(string)
243+
err := s.createBlockStorageSourceRegionClient(tmp)
244+
if err != nil {
245+
return err
246+
}
247+
}
248+
copyVolumeBackupRequest.DestinationRegion = &currentRegion
249+
250+
if volumeBackupId, ok := s.D.GetOkExists(fmt.Sprintf(fieldKeyFormat, "volume_backup_id")); ok {
251+
tmp := volumeBackupId.(string)
252+
copyVolumeBackupRequest.VolumeBackupId = &tmp
253+
}
254+
}
255+
256+
if displayName, ok := s.D.GetOkExists("display_name"); ok {
257+
tmp := displayName.(string)
258+
copyVolumeBackupRequest.DisplayName = &tmp
259+
}
260+
261+
response, err := s.SourceRegionClient.CopyVolumeBackup(context.Background(), copyVolumeBackupRequest)
262+
if err != nil {
263+
return err
264+
}
265+
266+
s.Res = &response.VolumeBackup
267+
return nil
268+
}
269+
270+
func (s *VolumeBackupResourceCrud) CreateVolumeBackup() error {
177271
request := oci_core.CreateVolumeBackupRequest{}
178272

179273
if definedTags, ok := s.D.GetOkExists("defined_tags"); ok {
@@ -305,6 +399,10 @@ func (s *VolumeBackupResourceCrud) SetData() error {
305399

306400
s.D.Set("source_type", s.Res.SourceType)
307401

402+
if s.Res.SourceVolumeBackupId != nil {
403+
s.D.Set("source_volume_backup_id", *s.Res.SourceVolumeBackupId)
404+
}
405+
308406
s.D.Set("state", s.Res.LifecycleState)
309407

310408
if s.Res.TimeCreated != nil {

0 commit comments

Comments
 (0)