Skip to content

Commit 07aa6c0

Browse files
committed
Support for cross region replication
1 parent deaf3be commit 07aa6c0

21 files changed

+1389
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Support for pod security policy in kubernetes
55
- Support for Oracle Big Data Service
66
- Support for application definition parameters update in dataflow application
7+
- Support for Cross Region Replication
78

89
## 3.68.0 (March 25, 2020)
910

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<body>
4+
<h1>Welcome</h1>
5+
</body>
6+
</html>
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
3+
/*
4+
* This example shows how to manage a bucket with a replication policy
5+
*/
6+
7+
variable "tenancy_ocid" {}
8+
9+
variable "user_ocid" {}
10+
variable "fingerprint" {}
11+
variable "private_key_path" {}
12+
variable "compartment_ocid" {}
13+
14+
variable "region" {
15+
default = "us-ashburn-1"
16+
}
17+
18+
//the object can be created from the object data in the other region
19+
locals {
20+
source_region = "${var.region}"
21+
}
22+
23+
provider "oci" {
24+
region = "${var.region}"
25+
tenancy_ocid = "${var.tenancy_ocid}"
26+
user_ocid = "${var.user_ocid}"
27+
fingerprint = "${var.fingerprint}"
28+
private_key_path = "${var.private_key_path}"
29+
}
30+
31+
resource "oci_objectstorage_bucket" "bucket1" {
32+
compartment_id = "${var.compartment_ocid}"
33+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
34+
name = "tf-example-source-bucket"
35+
access_type = "NoPublicAccess"
36+
}
37+
38+
resource "oci_objectstorage_bucket" "bucket2" {
39+
compartment_id = "${var.compartment_ocid}"
40+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
41+
name = "tf-example-destination-bucket"
42+
access_type = "NoPublicAccess"
43+
}
44+
45+
data "oci_objectstorage_bucket_summaries" "buckets" {
46+
compartment_id = "${var.compartment_ocid}"
47+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
48+
49+
filter {
50+
name = "name"
51+
values = ["${oci_objectstorage_bucket.bucket1.name}", "${oci_objectstorage_bucket.bucket2.name}"]
52+
}
53+
}
54+
55+
output buckets {
56+
value = "${data.oci_objectstorage_bucket_summaries.buckets.bucket_summaries}"
57+
}
58+
59+
/*
60+
* This example file shows how to read and output the object storage namespace and namespace_metadata.
61+
*/
62+
63+
data "oci_objectstorage_namespace" "ns" {
64+
#Optional
65+
compartment_id = "${var.compartment_ocid}"
66+
}
67+
68+
output namespace {
69+
value = "${data.oci_objectstorage_namespace.ns.namespace}"
70+
}
71+
72+
resource "oci_objectstorage_namespace_metadata" "namespace-metadata1" {
73+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
74+
default_s3compartment_id = "${var.compartment_ocid}"
75+
default_swift_compartment_id = "${var.compartment_ocid}"
76+
}
77+
78+
data oci_objectstorage_namespace_metadata namespace-metadata1 {
79+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
80+
}
81+
82+
output namespace-metadata {
83+
value = <<EOF
84+
85+
namespace = ${data.oci_objectstorage_namespace_metadata.namespace-metadata1.namespace}
86+
default_s3compartment_id = ${data.oci_objectstorage_namespace_metadata.namespace-metadata1.default_s3compartment_id}
87+
default_swift_compartment_id = ${data.oci_objectstorage_namespace_metadata.namespace-metadata1.default_swift_compartment_id}
88+
EOF
89+
}
90+
91+
resource "oci_objectstorage_object" "object1" {
92+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
93+
bucket = "${oci_objectstorage_bucket.bucket1.name}"
94+
object = "index.html"
95+
content_language = "en-US"
96+
content_type = "text/html"
97+
content = "${file("index.html")}"
98+
content_disposition = "attachment; filename=\"filename.html\""
99+
}
100+
101+
data "oci_objectstorage_objects" "objects1" {
102+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
103+
bucket = "${oci_objectstorage_bucket.bucket1.name}"
104+
}
105+
106+
data "oci_objectstorage_object" "object" {
107+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
108+
bucket = "${oci_objectstorage_bucket.bucket1.name}"
109+
object = "index.html"
110+
}
111+
112+
output objects {
113+
value = "${data.oci_objectstorage_objects.objects1.objects}"
114+
}
115+
116+
resource "oci_objectstorage_replication_policy" "bucket_rp" {
117+
namespace = "${data.oci_objectstorage_namespace.ns.namespace}"
118+
bucket = "${oci_objectstorage_bucket.bucket1.name}"
119+
name = "rpOnBucket"
120+
destination_region_name = "${var.region}"
121+
delete_object_in_destination_bucket = "ACCEPT"
122+
destination_bucket_name = "${oci_objectstorage_bucket.bucket2.name}"
123+
}

oci/crud_helpers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ const (
4848
SUCCEEDED = "SUCCEEDED"
4949
)
5050

51+
type deleteObjectInDestinationBucketStateEnum string
52+
53+
// Set of constants representing the allowable values for ListCustomProtectionRulesLifecycleStateEnum
54+
const (
55+
deleteObjectInDestinationBucketStateEnumAccept deleteObjectInDestinationBucketStateEnum = "ACCEPT"
56+
)
57+
5158
const (
5259
OpcNextPageHeader = "Opc-Next-Page"
5360
)

oci/objectstorage_bucket_data_source.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ func (s *ObjectStorageBucketDataSourceCrud) SetData() error {
105105

106106
s.D.Set("freeform_tags", s.Res.FreeformTags)
107107

108+
if s.Res.IsReadOnly != nil {
109+
s.D.Set("is_read_only", *s.Res.IsReadOnly)
110+
}
111+
108112
if s.Res.Id != nil {
109113
s.D.Set("bucket_id", *s.Res.Id)
110114
}
@@ -123,6 +127,10 @@ func (s *ObjectStorageBucketDataSourceCrud) SetData() error {
123127
s.D.Set("object_lifecycle_policy_etag", *s.Res.ObjectLifecyclePolicyEtag)
124128
}
125129

130+
if s.Res.ReplicationEnabled != nil {
131+
s.D.Set("replication_enabled", *s.Res.ReplicationEnabled)
132+
}
133+
126134
s.D.Set("storage_tier", s.Res.StorageTier)
127135

128136
if s.Res.TimeCreated != nil {

oci/objectstorage_bucket_resource.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,18 @@ func ObjectStorageBucketResource() *schema.Resource {
109109
Type: schema.TypeString,
110110
Computed: true,
111111
},
112+
"is_read_only": {
113+
Type: schema.TypeBool,
114+
Computed: true,
115+
},
112116
"object_lifecycle_policy_etag": {
113117
Type: schema.TypeString,
114118
Computed: true,
115119
},
120+
"replication_enabled": {
121+
Type: schema.TypeBool,
122+
Computed: true,
123+
},
116124
"time_created": {
117125
Type: schema.TypeString,
118126
Computed: true,
@@ -388,6 +396,10 @@ func (s *ObjectStorageBucketResourceCrud) SetData() error {
388396

389397
s.D.Set("freeform_tags", s.Res.FreeformTags)
390398

399+
if s.Res.IsReadOnly != nil {
400+
s.D.Set("is_read_only", *s.Res.IsReadOnly)
401+
}
402+
391403
if s.Res.KmsKeyId != nil {
392404
s.D.Set("kms_key_id", *s.Res.KmsKeyId)
393405
}
@@ -412,6 +424,10 @@ func (s *ObjectStorageBucketResourceCrud) SetData() error {
412424
s.D.Set("object_lifecycle_policy_etag", *s.Res.ObjectLifecyclePolicyEtag)
413425
}
414426

427+
if s.Res.ReplicationEnabled != nil {
428+
s.D.Set("replication_enabled", *s.Res.ReplicationEnabled)
429+
}
430+
415431
s.D.Set("storage_tier", s.Res.StorageTier)
416432

417433
if s.Res.TimeCreated != nil {

oci/objectstorage_bucket_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,16 @@ func TestObjectStorageBucketResource_basic(t *testing.T) {
250250
resource.TestCheckResourceAttrSet(singularDatasourceName, "etag"),
251251
resource.TestCheckResourceAttr(singularDatasourceName, "freeform_tags.%", "1"),
252252
resource.TestCheckResourceAttrSet(singularDatasourceName, "id"),
253+
resource.TestCheckResourceAttrSet(singularDatasourceName, "is_read_only"),
253254
resource.TestCheckResourceAttr(singularDatasourceName, "metadata.%", "1"),
254255
resource.TestCheckResourceAttr(singularDatasourceName, "name", testBucketName2),
255256
resource.TestCheckResourceAttrSet(singularDatasourceName, "namespace"),
256257
// This is difficult to test because TF is eager in creating the datasource and gives stale results.
257258
// If a depends_on is added, we get an error like "After applying this step and refreshing, the plan was not empty:"
258259
//resource.TestCheckResourceAttrSet(singularDatasourceName, "object_lifecycle_policy_etag"),
259260
resource.TestCheckResourceAttr(singularDatasourceName, "object_events_enabled", "true"),
261+
resource.TestCheckResourceAttrSet(singularDatasourceName, "object_lifecycle_policy_etag"),
262+
resource.TestCheckResourceAttrSet(singularDatasourceName, "replication_enabled"),
260263
resource.TestCheckResourceAttr(singularDatasourceName, "storage_tier", "Standard"),
261264
resource.TestCheckResourceAttrSet(singularDatasourceName, "time_created"),
262265
),
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
2+
3+
package oci
4+
5+
import (
6+
"context"
7+
8+
"github.com/hashicorp/terraform/helper/schema"
9+
oci_object_storage "github.com/oracle/oci-go-sdk/objectstorage"
10+
)
11+
12+
func init() {
13+
RegisterDatasource("oci_objectstorage_replication_policies", ObjectStorageReplicationPoliciesDataSource())
14+
}
15+
16+
func ObjectStorageReplicationPoliciesDataSource() *schema.Resource {
17+
return &schema.Resource{
18+
Read: readObjectStorageReplicationPolicies,
19+
Schema: map[string]*schema.Schema{
20+
"filter": dataSourceFiltersSchema(),
21+
"bucket": {
22+
Type: schema.TypeString,
23+
Required: true,
24+
},
25+
"namespace": {
26+
Type: schema.TypeString,
27+
Required: true,
28+
},
29+
"replication_policies": {
30+
Type: schema.TypeList,
31+
Computed: true,
32+
Elem: GetDataSourceItemSchema(ObjectStorageReplicationPolicyResource()),
33+
},
34+
},
35+
}
36+
}
37+
38+
func readObjectStorageReplicationPolicies(d *schema.ResourceData, m interface{}) error {
39+
sync := &ObjectStorageReplicationPoliciesDataSourceCrud{}
40+
sync.D = d
41+
sync.Client = m.(*OracleClients).objectStorageClient
42+
43+
return ReadResource(sync)
44+
}
45+
46+
type ObjectStorageReplicationPoliciesDataSourceCrud struct {
47+
D *schema.ResourceData
48+
Client *oci_object_storage.ObjectStorageClient
49+
Res *oci_object_storage.ListReplicationPoliciesResponse
50+
}
51+
52+
func (s *ObjectStorageReplicationPoliciesDataSourceCrud) VoidState() {
53+
s.D.SetId("")
54+
}
55+
56+
func (s *ObjectStorageReplicationPoliciesDataSourceCrud) Get() error {
57+
request := oci_object_storage.ListReplicationPoliciesRequest{}
58+
59+
if bucket, ok := s.D.GetOkExists("bucket"); ok {
60+
tmp := bucket.(string)
61+
request.BucketName = &tmp
62+
}
63+
64+
if namespace, ok := s.D.GetOkExists("namespace"); ok {
65+
tmp := namespace.(string)
66+
request.NamespaceName = &tmp
67+
}
68+
69+
request.RequestMetadata.RetryPolicy = getRetryPolicy(false, "object_storage")
70+
71+
response, err := s.Client.ListReplicationPolicies(context.Background(), request)
72+
if err != nil {
73+
return err
74+
}
75+
76+
s.Res = &response
77+
request.Page = s.Res.OpcNextPage
78+
79+
for request.Page != nil {
80+
listResponse, err := s.Client.ListReplicationPolicies(context.Background(), request)
81+
if err != nil {
82+
return err
83+
}
84+
85+
s.Res.Items = append(s.Res.Items, listResponse.Items...)
86+
request.Page = listResponse.OpcNextPage
87+
}
88+
89+
return nil
90+
}
91+
92+
func (s *ObjectStorageReplicationPoliciesDataSourceCrud) SetData() error {
93+
if s.Res == nil {
94+
return nil
95+
}
96+
97+
s.D.SetId(GenerateDataSourceID())
98+
resources := []map[string]interface{}{}
99+
100+
for _, r := range s.Res.Items {
101+
replicationPolicy := map[string]interface{}{}
102+
103+
if r.DestinationBucketName != nil {
104+
replicationPolicy["destination_bucket_name"] = *r.DestinationBucketName
105+
}
106+
107+
if r.DestinationRegionName != nil {
108+
replicationPolicy["destination_region_name"] = *r.DestinationRegionName
109+
}
110+
111+
if r.Id != nil {
112+
replicationPolicy["id"] = *r.Id
113+
}
114+
115+
if r.Name != nil {
116+
replicationPolicy["name"] = *r.Name
117+
}
118+
119+
replicationPolicy["status"] = r.Status
120+
121+
if r.StatusMessage != nil {
122+
replicationPolicy["status_message"] = *r.StatusMessage
123+
}
124+
125+
if r.TimeCreated != nil {
126+
replicationPolicy["time_created"] = r.TimeCreated.String()
127+
}
128+
129+
if r.TimeLastSync != nil {
130+
replicationPolicy["time_last_sync"] = r.TimeLastSync.String()
131+
}
132+
133+
resources = append(resources, replicationPolicy)
134+
}
135+
136+
if f, fOk := s.D.GetOkExists("filter"); fOk {
137+
resources = ApplyFilters(f.(*schema.Set), resources, ObjectStorageReplicationPoliciesDataSource().Schema["replication_policies"].Elem.(*schema.Resource).Schema)
138+
}
139+
140+
if err := s.D.Set("replication_policies", resources); err != nil {
141+
return err
142+
}
143+
144+
return nil
145+
}

0 commit comments

Comments
 (0)