Skip to content

Commit

Permalink
Merge branch 'opensearch-project:main' into opensearch_serverless_sup…
Browse files Browse the repository at this point in the history
…port
  • Loading branch information
vasyaxparfenov authored Oct 24, 2023
2 parents 63a3b59 + b33b9cb commit 0278ef7
Show file tree
Hide file tree
Showing 7 changed files with 673 additions and 0 deletions.
82 changes: 82 additions & 0 deletions docs/resources/anomaly_detection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "opensearch_anomaly_detection Resource - terraform-provider-opensearch"
subcategory: ""
description: |-
Provides an OpenSearch anonaly detection. Please refer to the OpenSearch anomaly detection documentation for details.
---

# opensearch_anomaly_detection (Resource)

Provides an OpenSearch anonaly detection. Please refer to the OpenSearch anomaly detection documentation for details.

## Example Usage

```terraform
resource "opensearch_anomaly_detection" "foo" {
body = <<EOF
{
"name": "foo",
"description": "Test detector",
"time_field": "@timestamp",
"indices": [
"security-auditlog*"
],
"feature_attributes": [
{
"feature_name": "test",
"feature_enabled": true,
"aggregation_query": {
"test": {
"value_count": {
"field": "audit_category.keyword"
}
}
}
}
],
"filter_query": {
"bool": {
"filter": [
{
"range": {
"value": {
"gt": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"detection_interval": {
"period": {
"interval": 1,
"unit": "Minutes"
}
},
"window_delay": {
"period": {
"interval": 1,
"unit": "Minutes"
}
},
"result_index" : "opensearch-ad-plugin-result-test"
}
EOF
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `body` (String) The anomaly detection document

### Read-Only

- `id` (String) The ID of this resource.


53 changes: 53 additions & 0 deletions examples/resources/opensearch_anomaly_detection/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
resource "opensearch_anomaly_detection" "foo" {
body = <<EOF
{
"name": "foo",
"description": "Test detector",
"time_field": "@timestamp",
"indices": [
"security-auditlog*"
],
"feature_attributes": [
{
"feature_name": "test",
"feature_enabled": true,
"aggregation_query": {
"test": {
"value_count": {
"field": "audit_category.keyword"
}
}
}
}
],
"filter_query": {
"bool": {
"filter": [
{
"range": {
"value": {
"gt": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"detection_interval": {
"period": {
"interval": 1,
"unit": "Minutes"
}
},
"window_delay": {
"period": {
"interval": 1,
"unit": "Minutes"
}
},
"result_index" : "opensearch-ad-plugin-result-test"
}
EOF
}
20 changes: 20 additions & 0 deletions provider/diff_suppress_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,23 @@ func diffSuppressPolicy(k, old, new string, d *schema.ResourceData) bool {

return reflect.DeepEqual(oo, no)
}

func diffSuppressAnomalyDetection(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
}

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

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

return reflect.DeepEqual(oo, no)
}
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ func Provider() *schema.Provider {
"opensearch_script": resourceOpensearchScript(),
"opensearch_snapshot_repository": resourceOpensearchSnapshotRepository(),
"opensearch_channel_configuration": resourceOpenSearchChannelConfiguration(),
"opensearch_anomaly_detection": resourceOpenSearchAnomalyDetection(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
224 changes: 224 additions & 0 deletions provider/resource_opensearch_anomaly_detection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package provider

import (
"context"
"encoding/json"
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/olivere/elastic/uritemplates"
elastic7 "github.com/olivere/elastic/v7"
)

var anomalyDetectionSchema = map[string]*schema.Schema{
"body": {
Description: "The anomaly detection document",
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: diffSuppressAnomalyDetection,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
ValidateFunc: validation.StringIsJSON,
},
}

func resourceOpenSearchAnomalyDetection() *schema.Resource {
return &schema.Resource{
Description: "Provides an OpenSearch anonaly detection. Please refer to the OpenSearch anomaly detection documentation for details.",
Create: resourceOpensearchAnomalyDetectionCreate,
Read: resourceOpensearchAnomalyDetectionRead,
Update: resourceOpensearchAnomalyDetectionUpdate,
Delete: resourceOpensearchAnomalyDetectionDelete,
Schema: anomalyDetectionSchema,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
}
}

func resourceOpensearchAnomalyDetectionCreate(d *schema.ResourceData, m interface{}) error {
res, err := resourceOpensearchPostAnomalyDetection(d, m)

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

d.SetId(res.ID)
log.Printf("[INFO] Object ID: %s", d.Id())

return resourceOpensearchAnomalyDetectionRead(d, m)
}

func resourceOpensearchAnomalyDetectionRead(d *schema.ResourceData, m interface{}) error {
res, err := resourceOpensearchAnomalyDetectionGet(d.Id(), m)

if elastic7.IsNotFound(err) {
log.Printf("[WARN] Anomaly Detector (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return err
}

d.SetId(res.ID)

anomalyDetectionJSON, err := json.Marshal(res.AnomalyDetector)
if err != nil {
return err
}
anomalyDetectionJsonNormalized, err := structure.NormalizeJsonString(string(anomalyDetectionJSON))
if err != nil {
return err
}
err = d.Set("body", anomalyDetectionJsonNormalized)
return err
}

func resourceOpensearchAnomalyDetectionUpdate(d *schema.ResourceData, m interface{}) error {
_, err := resourceOpensearchPutAnomalyDetection(d, m)

if err != nil {
return err
}

return resourceOpensearchAnomalyDetectionRead(d, m)
}

func resourceOpensearchAnomalyDetectionGet(anomalyDetectionID string, m interface{}) (*anomalyDetectionResponse, error) {
var err error
response := new(anomalyDetectionResponse)

path, err := uritemplates.Expand("/_plugins/_anomaly_detection/detectors/{id}", map[string]string{
"id": anomalyDetectionID,
})
if err != nil {
return response, fmt.Errorf("error building URL path for anomaly detector: %+v", err)
}

var body json.RawMessage
osClient, err := getClient(m.(*ProviderConf))
if err != nil {
return nil, err
}
var res *elastic7.Response
res, err = osClient.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
Method: "GET",
Path: path,
})
if err != nil {
return response, err
}
body = res.Body

if err := json.Unmarshal(body, response); err != nil {
return response, fmt.Errorf("error unmarshalling anomaly detector body: %+v: %+v", err, body)
}
log.Printf("[INFO] Response: %+v", response)
normalizeAnomalyDetection(response.AnomalyDetector)
log.Printf("[INFO] Response: %+v", response)
log.Printf("The version %v", response.Version)
return response, err
}

func resourceOpensearchPostAnomalyDetection(d *schema.ResourceData, m interface{}) (*anomalyDetectionResponse, error) {
anomalyDetectionJSON := d.Get("body").(string)

var err error
response := new(anomalyDetectionResponse)

path := "/_plugins/_anomaly_detection/detectors/"

var body json.RawMessage
osClient, err := getClient(m.(*ProviderConf))
if err != nil {
return nil, err
}
var res *elastic7.Response
res, err = osClient.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
Method: "POST",
Path: path,
Body: anomalyDetectionJSON,
})
if err != nil {
return response, err
}
body = res.Body

if err := json.Unmarshal(body, response); err != nil {
return response, fmt.Errorf("error unmarshalling anomaly detector body: %+v: %+v", err, body)
}
normalizeAnomalyDetection(response.AnomalyDetector)
return response, nil
}

func resourceOpensearchPutAnomalyDetection(d *schema.ResourceData, m interface{}) (*anomalyDetectionResponse, error) {
anomalyDetectionJSON := d.Get("body").(string)

var err error
response := new(anomalyDetectionResponse)

path, err := uritemplates.Expand("/_plugins/_anomaly_detection/detectors/{id}", map[string]string{
"id": d.Id(),
})
if err != nil {
return response, fmt.Errorf("error building URL path for anomaly detector: %+v", err)
}

var body json.RawMessage
osClient, err := getClient(m.(*ProviderConf))
if err != nil {
return nil, err
}
var res *elastic7.Response
res, err = osClient.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
Method: "PUT",
Path: path,
Body: anomalyDetectionJSON,
})
if err != nil {
return response, err
}
body = res.Body

if err := json.Unmarshal(body, response); err != nil {
return response, fmt.Errorf("error unmarshalling anomaly detector body: %+v: %+v", err, body)
}

return response, nil
}

func resourceOpensearchAnomalyDetectionDelete(d *schema.ResourceData, m interface{}) error {
var err error

path, err := uritemplates.Expand("/_plugins/_anomaly_detection/detectors/{id}", map[string]string{
"id": d.Id(),
})
if err != nil {
return fmt.Errorf("error building URL path for anomaly detector: %+v", err)
}

osClient, err := getClient(m.(*ProviderConf))
if err != nil {
return err
}
_, err = osClient.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
Method: "DELETE",
Path: path,
})

return err
}

type anomalyDetectionResponse struct {
Version int `json:"_version"`
ID string `json:"_id"`
AnomalyDetector map[string]interface{} `json:"anomaly_detector"`
}
Loading

0 comments on commit 0278ef7

Please sign in to comment.