Skip to content

Commit

Permalink
Add support for Snapshot Management
Browse files Browse the repository at this point in the history
Signed-off-by: Philip Dubois <[email protected]>
  • Loading branch information
duboisph committed Nov 13, 2023
1 parent d85be66 commit 666e288
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 80 deletions.
6 changes: 3 additions & 3 deletions docs/resources/sm_policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Provides an OpenSearch Snapshot Management (SM) policy. Please refer to the Open
```terraform
# Create an SM policy
resource "opensearch_sm_policy" "snapshot_to_s3" {
policy_id = "snapshot_to_s3"
body = file("${path.module}/policies/snapshot_to_s3.json")
policy_name = "snapshot_to_s3"
body = file("${path.module}/policies/snapshot_to_s3.json")
}
```

Expand All @@ -26,7 +26,7 @@ resource "opensearch_sm_policy" "snapshot_to_s3" {
### Required

- `body` (String) The policy document.
- `policy_id` (String) The id of the SM policy.
- `policy_name` (String) The name of the SM policy.

### Optional

Expand Down
4 changes: 2 additions & 2 deletions examples/resources/opensearch_sm_policy/resource.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Create an SM policy
resource "opensearch_sm_policy" "snapshot_to_s3" {
policy_id = "snapshot_to_s3"
body = file("${path.module}/policies/snapshot_to_s3.json")
policy_name = "snapshot_to_s3"
body = file("${path.module}/policies/snapshot_to_s3.json")
}
2 changes: 1 addition & 1 deletion provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func Provider() *schema.Provider {
"opensearch_snapshot_repository": resourceOpensearchSnapshotRepository(),
"opensearch_channel_configuration": resourceOpenSearchChannelConfiguration(),
"opensearch_anomaly_detection": resourceOpenSearchAnomalyDetection(),
"opensearch_sm_policy": resourceOpenSearchSMPolicy(),
"opensearch_sm_policy": resourceOpenSearchSMPolicy(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
81 changes: 62 additions & 19 deletions provider/resource_opensearch_sm_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"net/http"
"net/url"
"reflect"
"strconv"
"time"

Expand All @@ -19,8 +20,8 @@ import (
)

var openSearchSMPolicySchema = map[string]*schema.Schema{
"policy_id": {
Description: "The id of the SM policy.",
"policy_name": {
Description: "The name of the SM policy.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
Expand All @@ -29,7 +30,7 @@ var openSearchSMPolicySchema = map[string]*schema.Schema{
Description: "The policy document.",
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: diffSuppressPolicy,
DiffSuppressFunc: smDiffSuppressPolicy,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
Expand Down Expand Up @@ -58,28 +59,33 @@ func resourceOpenSearchSMPolicy() *schema.Resource {
Delete: resourceOpensearchSMPolicyDelete,
Schema: openSearchSMPolicySchema,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
d.Set("policy_name", d.Id())

Check failure on line 63 in provider/resource_opensearch_sm_policy.go

View workflow job for this annotation

GitHub Actions / Runs go linters

Error return value of `d.Set` is not checked (errcheck)
d.SetId(fmt.Sprintf("%s-sm-policy", d.Id()))
return []*schema.ResourceData{d}, nil
},
},
}
}

func resourceOpensearchSMPolicyCreate(d *schema.ResourceData, m interface{}) error {
if _, err := resourceOpensearchPostPutSMPolicy(d, m, "POST"); err != nil {
policyResponse, err := resourceOpensearchPostPutSMPolicy(d, m, "POST")

if err != nil {
log.Printf("[INFO] Failed to create OpensearchPolicy: %+v", err)
return err
}

policyID := d.Get("policy_id").(string)
d.SetId(policyID)
d.SetId(policyResponse.PolicyID)
return resourceOpensearchSMPolicyRead(d, m)
}

func resourceOpensearchSMPolicyRead(d *schema.ResourceData, m interface{}) error {
policyResponse, err := resourceOpensearchGetSMPolicy(d.Id(), m)
policyResponse, err := resourceOpensearchGetSMPolicy(d.Get("policy_name").(string), m)

if err != nil {
if elastic6.IsNotFound(err) || elastic7.IsNotFound(err) {
log.Printf("[WARN] Opensearch Policy (%s) not found, removing from state", d.Id())
log.Printf("[WARN] Opensearch Policy (%s) not found, removing from state", d.Get("policy_name").(string))
d.SetId("")
return nil
}
Expand All @@ -91,10 +97,12 @@ func resourceOpensearchSMPolicyRead(d *schema.ResourceData, m interface{}) error
return err
}

if err := d.Set("policy_id", policyResponse.PolicyID); err != nil {
return fmt.Errorf("error setting policy_id: %s", err)
bodyStringNormalized, _ := structure.NormalizeJsonString(string(bodyString))

if err := d.Set("policy_name", policyResponse.Policy["name"]); err != nil {
return fmt.Errorf("error setting policy_name: %s", err)
}
if err := d.Set("body", bodyString); err != nil {
if err := d.Set("body", bodyStringNormalized); err != nil {
return fmt.Errorf("error setting body: %s", err)
}
if err := d.Set("primary_term", policyResponse.PrimaryTerm); err != nil {
Expand All @@ -116,8 +124,8 @@ func resourceOpensearchSMPolicyUpdate(d *schema.ResourceData, m interface{}) err
}

func resourceOpensearchSMPolicyDelete(d *schema.ResourceData, m interface{}) error {
path, err := uritemplates.Expand("/_plugins/_sm/policies/{policy_id}", map[string]string{
"policy_id": d.Id(),
path, err := uritemplates.Expand("/_plugins/_sm/policies/{policy_name}", map[string]string{
"policy_name": d.Get("policy_name").(string),
})
if err != nil {
return fmt.Errorf("error building URL path for policy: %+v", err)
Expand All @@ -143,12 +151,12 @@ func resourceOpensearchSMPolicyDelete(d *schema.ResourceData, m interface{}) err
return err
}

func resourceOpensearchGetSMPolicy(policyID string, m interface{}) (SMPolicyResponse, error) {
func resourceOpensearchGetSMPolicy(policyName string, m interface{}) (SMPolicyResponse, error) {
var err error
response := new(SMPolicyResponse)

path, err := uritemplates.Expand("/_plugins/_sm/policies/{policy_id}", map[string]string{
"policy_id": policyID,
path, err := uritemplates.Expand("/_plugins/_sm/policies/{policy_name}", map[string]string{
"policy_name": policyName,
})

if err != nil {
Expand Down Expand Up @@ -196,8 +204,8 @@ func resourceOpensearchPostPutSMPolicy(d *schema.ResourceData, m interface{}, me
params.Set("if_primary_term", strconv.Itoa(primTerm))
}

path, err := uritemplates.Expand("/_plugins/_sm/policies/{policy_id}", map[string]string{
"policy_id": d.Get("policy_id").(string),
path, err := uritemplates.Expand("/_plugins/_sm/policies/{policy_name}", map[string]string{
"policy_name": d.Get("policy_name").(string),
})
if err != nil {
return response, fmt.Errorf("error building URL path for policy: %+v", err)
Expand Down Expand Up @@ -242,3 +250,38 @@ type SMPolicyResponse struct {
SeqNo int `json:"_seq_no"`
Policy map[string]interface{} `json:"sm_policy"`
}

func smDiffSuppressPolicy(k, old, new string, d *schema.ResourceData) bool {
var oo, no interface{}
if err := json.Unmarshal([]byte(old), &oo); err != nil {
return false
}
if err := json.Unmarshal([]byte(new), &no); err != nil {
return false
}

om, ok := oo.(map[string]interface{})
if ok {
normalizePolicy(om)
}

nm, ok := no.(map[string]interface{})
if ok {
normalizePolicy(nm)
}

// Suppress diff of autogenerated fields by copying them to the old object
if name, ok := om["name"]; ok {
nm["name"] = name
}

if enabled_time, ok := om["enabled_time"]; ok {
nm["enabled_time"] = enabled_time
}

if schedule, ok := om["schedule"]; ok {
nm["schedule"] = schedule
}

return reflect.DeepEqual(oo, no)
}
99 changes: 44 additions & 55 deletions provider/resource_opensearch_sm_policy_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// TODO!

package provider

import (
Expand All @@ -17,15 +15,16 @@ func TestAccOpensearchSMPolicy(t *testing.T) {
if diags.HasError() {
t.Skipf("err: %#v", diags)
}
var allowed bool
var allowed bool = true

config := testAccOpensearchSMPolicyV7

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)

if !allowed {
t.Skip("OpenSearch SMPolicies only supported on ES 6.")
t.Skip("OpenSearch Snapshot Management only supported on Opensearch >= 2.1")
}
},
Providers: testAccOpendistroProviders,
Expand All @@ -37,7 +36,7 @@ func TestAccOpensearchSMPolicy(t *testing.T) {
testCheckOpensearchSMPolicyExists("opensearch_sm_policy.test_policy"),
resource.TestCheckResourceAttr(
"opensearch_sm_policy.test_policy",
"policy_id",
"policy_name",
"test_policy",
),
),
Expand All @@ -59,7 +58,7 @@ func testCheckOpensearchSMPolicyExists(name string) resource.TestCheckFunc {
meta := testAccOpendistroProvider.Meta()

var err error
_, err = resourceOpensearchGetSMPolicy(rs.Primary.ID, meta.(*ProviderConf))
_, err = resourceOpensearchGetSMPolicy(rs.Primary.Attributes["policy_name"], meta.(*ProviderConf))

if err != nil {
return err
Expand All @@ -81,7 +80,7 @@ func testCheckOpensearchSMPolicyDestroy(s *terraform.State) error {
if err != nil {
return err
}
_, err = resourceOpensearchGetSMPolicy(rs.Primary.ID, meta.(*ProviderConf))
_, err = resourceOpensearchGetSMPolicy(rs.Primary.Attributes["policy_name"], meta.(*ProviderConf))

if err != nil {
return nil // should be not found error
Expand All @@ -94,58 +93,48 @@ func testCheckOpensearchSMPolicyDestroy(s *terraform.State) error {
}

var testAccOpensearchSMPolicyV7 = `
resource "opensearch_snapshot_repository" "test" {
name = "terraform-test"
type = "fs"
settings = {
location = "/tmp/opensearch"
}
}
resource "opensearch_sm_policy" "test_policy" {
policy_id = "test_policy"
policy_name = "test_policy"
body = <<EOF
{
"policy": {
"description": "ingesting logs",
"default_state": "ingest",
"ism_template": [{
"index_patterns": ["foo-*"],
"priority": 0
}],
"error_notification": {
"destination": {
"slack": {
"url": "https://webhook.slack.example.com"
}
},
"message_template": {
"lang": "mustache",
"source": "The index *{{ctx.index}}* failed to rollover."
}
},
"states": [
{
"name": "ingest",
"actions": [{
"rollover": {
"min_doc_count": 5
}
}],
"transitions": [{
"state_name": "search"
}]
},
{
"name": "search",
"actions": [],
"transitions": [{
"state_name": "delete",
"conditions": {
"min_index_age": "5m"
}
}]
},
{
"name": "delete",
"actions": [{
"delete": {}
}],
"transitions": []
"enabled": true,
"description": "Test policy",
"creation": {
"schedule": {
"cron": {
"expression": "0 0 * * *",
"timezone": "UTC"
}
]
},
"time_limit": "1h"
},
"deletion": {
"schedule": {
"cron": {
"expression": "0 1 * * *",
"timezone": "UTC"
}
},
"condition": {
"max_age": "14d",
"max_count": 400,
"min_count": 1
},
"time_limit": "1h"
},
"snapshot_config": {
"timezone": "UTC",
"indices": "*",
"repository": "${opensearch_snapshot_repository.test.name}"
}
}
EOF
Expand Down

0 comments on commit 666e288

Please sign in to comment.