Skip to content

Commit b7973e1

Browse files
afedorchabhilash-av
authored andcommitted
support Glob inclusion and exclusion patterns in Object Lifecycle Management rules
1 parent 233aae4 commit b7973e1

16 files changed

+283
-49
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Support for cloning of Autonomous Databases
1515
- Support for node metadata in container engine node pool
1616
- Support for Data Guard Associations for databases
17+
- Support glob inclusion and exclusion patterns for object names allowed in Object Storage Lifecycle Policies rules
1718

1819
## 3.18.0 (March 13, 2019)
1920

oci/object_storage_object_lifecycle_policy_data_source.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ func ObjectStorageObjectLifecyclePolicyDataSource() *schema.Resource {
6868
// Required
6969

7070
// Optional
71+
"exclusion_patterns": {
72+
Type: schema.TypeList,
73+
Optional: true,
74+
Computed: true,
75+
Elem: &schema.Schema{
76+
Type: schema.TypeString,
77+
},
78+
},
79+
"inclusion_patterns": {
80+
Type: schema.TypeList,
81+
Optional: true,
82+
Computed: true,
83+
Elem: &schema.Schema{
84+
Type: schema.TypeString,
85+
},
86+
},
7187
"inclusion_prefixes": {
7288
Type: schema.TypeList,
7389
Optional: true,
@@ -165,5 +181,11 @@ func fixupObjectNameFilterInclusionPrefixesAsList(objectLifecycleRuleMap map[str
165181
objectNameFilterMap := firstElement.(map[string]interface{})
166182
inclusionPrefixesSet := objectNameFilterMap["inclusion_prefixes"].(*schema.Set)
167183
objectNameFilterMap["inclusion_prefixes"] = inclusionPrefixesSet.List()
184+
185+
inclusionPatternsSet := objectNameFilterMap["inclusion_patterns"].(*schema.Set)
186+
objectNameFilterMap["inclusion_patterns"] = inclusionPatternsSet.List()
187+
188+
exclusionPatternsSet := objectNameFilterMap["exclusion_patterns"].(*schema.Set)
189+
objectNameFilterMap["exclusion_patterns"] = exclusionPatternsSet.List()
168190
}
169191
}

oci/object_storage_object_lifecycle_policy_resource.go

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,24 @@ func ObjectStorageObjectLifecyclePolicyResource() *schema.Resource {
9090
// Required
9191

9292
// Optional
93+
"exclusion_patterns": {
94+
Type: schema.TypeSet,
95+
Optional: true,
96+
Computed: true,
97+
Set: literalTypeHashCodeForSets,
98+
Elem: &schema.Schema{
99+
Type: schema.TypeString,
100+
},
101+
},
102+
"inclusion_patterns": {
103+
Type: schema.TypeSet,
104+
Optional: true,
105+
Computed: true,
106+
Set: literalTypeHashCodeForSets,
107+
Elem: &schema.Schema{
108+
Type: schema.TypeString,
109+
},
110+
},
93111
"inclusion_prefixes": {
94112
Type: schema.TypeSet,
95113
Optional: true,
@@ -415,6 +433,32 @@ func ObjectLifecycleRuleToMap(obj oci_object_storage.ObjectLifecycleRule) map[st
415433
func (s *ObjectStorageObjectLifecyclePolicyResourceCrud) mapToObjectNameFilter(fieldKeyFormat string) (oci_object_storage.ObjectNameFilter, error) {
416434
result := oci_object_storage.ObjectNameFilter{}
417435

436+
result.ExclusionPatterns = []string{}
437+
if exclusionPatterns, ok := s.D.GetOkExists(fmt.Sprintf(fieldKeyFormat, "exclusion_patterns")); ok {
438+
set := exclusionPatterns.(*schema.Set)
439+
interfaces := set.List()
440+
tmp := make([]string, len(interfaces))
441+
for i := range interfaces {
442+
if interfaces[i] != nil {
443+
tmp[i] = interfaces[i].(string)
444+
}
445+
}
446+
result.ExclusionPatterns = tmp
447+
}
448+
449+
result.InclusionPatterns = []string{}
450+
if inclusionPatterns, ok := s.D.GetOkExists(fmt.Sprintf(fieldKeyFormat, "inclusion_patterns")); ok {
451+
set := inclusionPatterns.(*schema.Set)
452+
interfaces := set.List()
453+
tmp := make([]string, len(interfaces))
454+
for i := range interfaces {
455+
if interfaces[i] != nil {
456+
tmp[i] = interfaces[i].(string)
457+
}
458+
}
459+
result.InclusionPatterns = tmp
460+
}
461+
418462
result.InclusionPrefixes = []string{}
419463
if inclusionPrefixes, ok := s.D.GetOkExists(fmt.Sprintf(fieldKeyFormat, "inclusion_prefixes")); ok {
420464
set := inclusionPrefixes.(*schema.Set)
@@ -427,7 +471,6 @@ func (s *ObjectStorageObjectLifecyclePolicyResourceCrud) mapToObjectNameFilter(f
427471
}
428472
result.InclusionPrefixes = tmp
429473
}
430-
431474
return result, nil
432475
}
433476

@@ -440,6 +483,18 @@ func ObjectNameFilterToMap(obj *oci_object_storage.ObjectNameFilter) map[string]
440483
}
441484
result["inclusion_prefixes"] = schema.NewSet(literalTypeHashCodeForSets, inclusionPrefixes)
442485

486+
exclusionPatterns := []interface{}{}
487+
for _, item := range obj.ExclusionPatterns {
488+
exclusionPatterns = append(exclusionPatterns, item)
489+
}
490+
result["exclusion_patterns"] = schema.NewSet(literalTypeHashCodeForSets, exclusionPatterns)
491+
492+
inclusionPatterns := []interface{}{}
493+
for _, item := range obj.InclusionPatterns {
494+
inclusionPatterns = append(inclusionPatterns, item)
495+
}
496+
result["inclusion_patterns"] = schema.NewSet(literalTypeHashCodeForSets, inclusionPatterns)
497+
443498
return result
444499
}
445500

@@ -459,13 +514,30 @@ func rulesHashCodeForSets(v interface{}) int {
459514
if tmpList := objectNameFilter.([]interface{}); len(tmpList) > 0 {
460515
buf.WriteString("object_name_filter-")
461516
objectNameFilterRaw := tmpList[0].(map[string]interface{})
462-
if inclusionPrefixes, ok := objectNameFilterRaw["inclusion_prefixes"]; ok {
517+
if inclusionPrefixes, ok := objectNameFilterRaw["inclusion_prefixes"]; ok && inclusionPrefixes != "" {
518+
buf.WriteString(fmt.Sprintf("inclusionPrefix-"))
463519
set := inclusionPrefixes.(*schema.Set)
464520
inclusionPrefixesArr := set.List()
465-
for inclusionPrefix := range inclusionPrefixesArr {
521+
for _, inclusionPrefix := range inclusionPrefixesArr {
466522
buf.WriteString(fmt.Sprintf("%v-", inclusionPrefix))
467523
}
468524
}
525+
if exclusionPatterns, ok := objectNameFilterRaw["exclusion_patterns"]; ok && exclusionPatterns != "" {
526+
buf.WriteString(fmt.Sprintf("exclusion_patterns-"))
527+
set := exclusionPatterns.(*schema.Set)
528+
exclusionPatternsArr := set.List()
529+
for _, exclusionPattern := range exclusionPatternsArr {
530+
buf.WriteString(fmt.Sprintf("%v-", exclusionPattern))
531+
}
532+
}
533+
if inclusionPatterns, ok := objectNameFilterRaw["inclusion_patterns"]; ok && inclusionPatterns != "" {
534+
buf.WriteString(fmt.Sprintf("inclusion_patterns-"))
535+
set := inclusionPatterns.(*schema.Set)
536+
inclusionPatternsArr := set.List()
537+
for _, inclusionPattern := range inclusionPatternsArr {
538+
buf.WriteString(fmt.Sprintf("%v-", inclusionPattern))
539+
}
540+
}
469541
}
470542
}
471543
if timeAmount, ok := m["time_amount"]; ok {

oci/object_storage_object_lifecycle_policy_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ var (
4343
"object_name_filter": RepresentationGroup{Optional, objectLifecyclePolicyRulesObjectNameFilterRepresentation},
4444
}
4545
objectLifecyclePolicyRulesObjectNameFilterRepresentation = map[string]interface{}{
46+
"exclusion_patterns": Representation{repType: Optional, create: []string{`exclusionPattern1`, `exclusionPattern2`}, update: []string{`exclusionPattern1`, `exclusionPattern2`, `exclusionPattern3`}},
47+
"inclusion_patterns": Representation{repType: Optional, create: []string{`inclusionPattern1`, `inclusionPattern2`}, update: []string{`inclusionPattern1`, `inclusionPattern2`, `inclusionPattern3`}},
4648
"inclusion_prefixes": Representation{repType: Optional, create: []string{bucketName, bucketName2}, update: []string{bucketName, bucketName2, bucketName3}},
4749
}
4850

@@ -105,6 +107,8 @@ func TestObjectStorageObjectLifecyclePolicyResource_basic(t *testing.T) {
105107
"name": "sampleRule",
106108
"object_name_filter.#": "1",
107109
"object_name_filter.0.inclusion_prefixes.#": "2",
110+
"object_name_filter.0.exclusion_patterns.#": "2",
111+
"object_name_filter.0.inclusion_patterns.#": "2",
108112
"time_amount": "10",
109113
"time_unit": "DAYS",
110114
},
@@ -131,6 +135,8 @@ func TestObjectStorageObjectLifecyclePolicyResource_basic(t *testing.T) {
131135
"name": "name2",
132136
"object_name_filter.#": "1",
133137
"object_name_filter.0.inclusion_prefixes.#": "3",
138+
"object_name_filter.0.exclusion_patterns.#": "3",
139+
"object_name_filter.0.inclusion_patterns.#": "3",
134140
"time_amount": "11",
135141
"time_unit": "YEARS",
136142
},
@@ -164,6 +170,8 @@ func TestObjectStorageObjectLifecyclePolicyResource_basic(t *testing.T) {
164170
"name": "name2",
165171
"object_name_filter.#": "1",
166172
"object_name_filter.0.inclusion_prefixes.#": "3",
173+
"object_name_filter.0.exclusion_patterns.#": "3",
174+
"object_name_filter.0.inclusion_patterns.#": "3",
167175
"time_amount": "11",
168176
"time_unit": "YEARS",
169177
},
@@ -196,6 +204,20 @@ func TestObjectStorageObjectLifecyclePolicyResource_validations(t *testing.T) {
196204

197205
resourceName := "oci_objectstorage_object_lifecycle_policy.test_object_lifecycle_policy"
198206

207+
objectLifecyclePolicyRulesObjectNameFilterDifferentOrderRepresentation := map[string]interface{}{
208+
"inclusion_prefixes": Representation{repType: Optional, create: []string{bucketName, bucketName2}, update: []string{bucketName, bucketName2, bucketName3}},
209+
"inclusion_patterns": Representation{repType: Optional, create: []string{`inclusionPattern1`, `inclusionPattern2`}, update: []string{`inclusionPattern1`, `inclusionPattern2`, `inclusionPattern3`}},
210+
"exclusion_patterns": Representation{repType: Optional, create: []string{`exclusionPattern1`, `exclusionPattern2`}, update: []string{`exclusionPattern1`, `exclusionPattern2`, `exclusionPattern3`}},
211+
}
212+
213+
objectLifecyclePolicyRulesObjectNameFilterOneValueIncludeRepresentation := map[string]interface{}{
214+
"inclusion_patterns": Representation{repType: Optional, create: []string{`inclusionPattern1`}},
215+
}
216+
217+
objectLifecyclePolicyRulesObjectNameFilterOneValueExcludeRepresentation := map[string]interface{}{
218+
"exclusion_patterns": Representation{repType: Optional, create: []string{`inclusionPattern1`}},
219+
}
220+
199221
resource.Test(t, resource.TestCase{
200222
PreCheck: func() { testAccPreCheck(t) },
201223
Providers: map[string]terraform.ResourceProvider{
@@ -234,6 +256,79 @@ func TestObjectStorageObjectLifecyclePolicyResource_validations(t *testing.T) {
234256
PlanOnly: true,
235257
ExpectNonEmptyPlan: true,
236258
},
259+
// Change the value for the inclusion prefixes to see plan has changed
260+
{
261+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
262+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
263+
getUpdatedRepresentationCopy("rules.object_name_filter.inclusion_prefixes", Representation{repType: Optional, create: []string{bucketName, bucketName2 + "_test"}}, objectLifecyclePolicyRepresentation)),
264+
PlanOnly: true,
265+
ExpectNonEmptyPlan: true,
266+
},
267+
// change order of inclusion patterns
268+
{
269+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
270+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
271+
getUpdatedRepresentationCopy("rules.object_name_filter.inclusion_patterns", Representation{repType: Optional, create: []string{`inclusionPattern2`, `inclusionPattern1`}}, objectLifecyclePolicyRepresentation)),
272+
PlanOnly: true,
273+
ExpectNonEmptyPlan: false,
274+
},
275+
// Remove inclusion patterns to see plan has changed
276+
{
277+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
278+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
279+
getUpdatedRepresentationCopy("rules.object_name_filter.inclusion_patterns", Representation{repType: Optional, create: []string{}}, objectLifecyclePolicyRepresentation)),
280+
PlanOnly: true,
281+
ExpectNonEmptyPlan: true,
282+
},
283+
// change order of exclusion patterns
284+
{
285+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
286+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
287+
getUpdatedRepresentationCopy("rules.object_name_filter.exclusion_patterns", Representation{repType: Optional, create: []string{`exclusionPattern2`, `exclusionPattern1`}}, objectLifecyclePolicyRepresentation)),
288+
PlanOnly: true,
289+
ExpectNonEmptyPlan: false,
290+
},
291+
// Remove exclusion patterns to see plan has changed
292+
{
293+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
294+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
295+
getUpdatedRepresentationCopy("rules.object_name_filter.exclusion_patterns", Representation{repType: Optional, create: []string{}}, objectLifecyclePolicyRepresentation)),
296+
PlanOnly: true,
297+
ExpectNonEmptyPlan: true,
298+
},
299+
// change order of object_name_filter
300+
{
301+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
302+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
303+
getUpdatedRepresentationCopy("rules.object_name_filter", RepresentationGroup{Optional, objectLifecyclePolicyRulesObjectNameFilterDifferentOrderRepresentation}, objectLifecyclePolicyRepresentation)),
304+
PlanOnly: true,
305+
ExpectNonEmptyPlan: false,
306+
},
307+
308+
// update the object_name_filter properties with the only one inclusion_patterns value
309+
{
310+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
311+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
312+
getUpdatedRepresentationCopy("rules.object_name_filter", RepresentationGroup{Optional, objectLifecyclePolicyRulesObjectNameFilterOneValueIncludeRepresentation}, objectLifecyclePolicyRepresentation)),
313+
Check: resource.ComposeAggregateTestCheckFunc(
314+
resource.TestCheckResourceAttr(resourceName, "bucket", bucketName),
315+
resource.TestCheckResourceAttr(resourceName, "rules.#", "1"),
316+
resource.TestCheckResourceAttrSet(resourceName, "namespace"),
317+
318+
func(s *terraform.State) (err error) {
319+
_, err = fromInstanceState(s, resourceName, "id")
320+
return err
321+
},
322+
),
323+
},
324+
// change to the same value for the exclusion_patterns
325+
{
326+
Config: config + compartmentIdVariableStr + ObjectLifecyclePolicyResourceDependencies +
327+
generateResourceFromRepresentationMap("oci_objectstorage_object_lifecycle_policy", "test_object_lifecycle_policy", Optional, Create,
328+
getUpdatedRepresentationCopy("rules.object_name_filter", RepresentationGroup{Optional, objectLifecyclePolicyRulesObjectNameFilterOneValueExcludeRepresentation}, objectLifecyclePolicyRepresentation)),
329+
PlanOnly: true,
330+
ExpectNonEmptyPlan: true,
331+
},
237332
},
238333
})
239334
}

website/docs/d/object_storage_bucket.html.markdown

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: |-
99
# Data Source: oci_objectstorage_bucket
1010
This data source provides details about a specific Bucket resource in Oracle Cloud Infrastructure Object Storage service.
1111

12-
Gets the current representation of the given bucket in the given namespace.
12+
Gets the current representation of the given bucket in the given Object Storage namespace.
1313

1414

1515
## Example Usage
@@ -27,7 +27,7 @@ data "oci_objectstorage_bucket" "test_bucket" {
2727
The following arguments are supported:
2828

2929
* `name` - (Required) The name of the bucket. Avoid entering confidential information. Example: `my-new-bucket1`
30-
* `namespace` - (Required) The top-level namespace used for the request.
30+
* `namespace` - (Required) The Object Storage namespace used for the request.
3131

3232

3333
## Attributes Reference
@@ -40,13 +40,13 @@ The following attributes are exported:
4040
* `compartment_id` - The compartment ID in which the bucket is authorized.
4141
* `created_by` - The OCID of the user who created the bucket.
4242
* `defined_tags` - Defined tags for this resource. Each key is predefined and scoped to a namespace. For more information, see [Resource Tags](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). Example: `{"Operations.CostCenter": "42"}`
43-
* `etag` - The entity tag for the bucket.
43+
* `etag` - The entity tag (ETag) for the bucket.
4444
* `freeform_tags` - Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. For more information, see [Resource Tags](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). Example: `{"Department": "Finance"}`
45-
* `kms_key_id` - The OCID of a KMS key id used to call KMS to generate data key, decrypt the encrypted data key
45+
* `kms_key_id` - The OCID of a KMS key id used to call KMS to generate data key or decrypt the encrypted data key.
4646
* `metadata` - Arbitrary string keys and values for user-defined metadata.
4747
* `name` - The name of the bucket. Avoid entering confidential information. Example: my-new-bucket1
48-
* `namespace` - The namespace in which the bucket lives.
49-
* `object_lifecycle_policy_etag` - The entity tag for the live object lifecycle policy on the bucket.
50-
* `storage_tier` - The type of storage tier of this bucket. A bucket is set to 'Standard' tier by default, which means the bucket will be put in the standard storage tier. When 'Archive' tier type is set explicitly, the bucket is put in the archive storage tier. The 'storageTier' property is immutable after bucket is created.
48+
* `namespace` - The Object Storage namespace in which the bucket lives.
49+
* `object_lifecycle_policy_etag` - The entity tag (ETag) for the live object lifecycle policy on the bucket.
50+
* `storage_tier` - The storage tier type assigned to the bucket. A bucket is set to 'Standard' tier by default, which means objects uploaded or copied to the bucket will be in the standard storage tier. When the 'Archive' tier type is set explicitly for a bucket, objects uploaded or copied to the bucket will be stored in archive storage. The 'storageTier' property is immutable after bucket is created.
5151
* `time_created` - The date and time the bucket was created, as described in [RFC 2616](https://tools.ietf.org/rfc/rfc2616), section 14.29.
5252

0 commit comments

Comments
 (0)