Skip to content

Commit d533fd6

Browse files
authored
Merge pull request #82 from SumoLogic/mfatyga-fields-provider
Add provider for custom fields API
2 parents ee4d445 + 5c4e944 commit d533fd6

File tree

6 files changed

+404
-1
lines changed

6 files changed

+404
-1
lines changed

sumologic/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func Provider() terraform.ResourceProvider {
6464
"sumologic_monitor": resourceSumologicMonitorsLibraryMonitor(),
6565
"sumologic_monitor_folder": resourceSumologicMonitorsLibraryFolder(),
6666
"sumologic_ingest_budget_v2": resourceSumologicIngestBudgetV2(),
67+
"sumologic_field": resourceSumologicField(),
6768
},
6869
DataSourcesMap: map[string]*schema.Resource{
6970
"sumologic_caller_identity": dataSourceSumologicCallerIdentity(),
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
7+
)
8+
9+
func resourceSumologicField() *schema.Resource {
10+
return &schema.Resource{
11+
Create: resourceSumologicFieldCreate,
12+
Read: resourceSumologicFieldRead,
13+
Delete: resourceSumologicFieldDelete,
14+
Importer: &schema.ResourceImporter{
15+
State: resourceSumologicFieldImport,
16+
},
17+
18+
Schema: map[string]*schema.Schema{
19+
20+
"field_name": {
21+
Type: schema.TypeString,
22+
Required: true,
23+
ForceNew: true,
24+
},
25+
26+
"field_id": {
27+
Type: schema.TypeString,
28+
Computed: true,
29+
ForceNew: false,
30+
},
31+
32+
"data_type": {
33+
Type: schema.TypeString,
34+
Optional: true,
35+
ForceNew: true,
36+
},
37+
38+
"state": {
39+
Type: schema.TypeString,
40+
Optional: true,
41+
ForceNew: true,
42+
},
43+
},
44+
}
45+
}
46+
47+
func resourceSumologicFieldRead(d *schema.ResourceData, meta interface{}) error {
48+
c := meta.(*Client)
49+
50+
id := d.Get("field_id").(string)
51+
name := d.Get("field_name").(string)
52+
if id == "" {
53+
newId, err := c.FindFieldId(name)
54+
if err != nil {
55+
return err
56+
}
57+
id = newId
58+
}
59+
60+
field, err := c.GetField(id)
61+
if err != nil {
62+
return err
63+
}
64+
65+
if field == nil {
66+
fmt.Printf("[WARN] Field not found, removing from state: %v - %v\n", id, err)
67+
d.SetId("")
68+
return nil
69+
}
70+
71+
d.Set("field_name", field.FieldName)
72+
d.Set("field_id", field.FieldId)
73+
d.Set("data_type", field.DataType)
74+
d.Set("state", field.State)
75+
76+
return nil
77+
}
78+
79+
func resourceSumologicFieldDelete(d *schema.ResourceData, meta interface{}) error {
80+
c := meta.(*Client)
81+
82+
id := d.Get("field_id").(string)
83+
name := d.Get("field_name").(string)
84+
if id == "" {
85+
newId, err := c.FindFieldId(name)
86+
if err != nil {
87+
return err
88+
}
89+
id = newId
90+
}
91+
92+
return c.DeleteField(id)
93+
}
94+
95+
func resourceSumologicFieldCreate(d *schema.ResourceData, meta interface{}) error {
96+
c := meta.(*Client)
97+
98+
if d.Id() == "" {
99+
field := resourceToField(d)
100+
id, err := c.CreateField(field)
101+
if err != nil {
102+
return err
103+
}
104+
105+
d.SetId(id)
106+
}
107+
108+
return resourceSumologicFieldRead(d, meta)
109+
}
110+
111+
func resourceSumologicFieldImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
112+
if d.Get("field_id").(string) == "" {
113+
d.Set("field_id", d.Id())
114+
}
115+
116+
return []*schema.ResourceData{d}, nil
117+
}
118+
119+
func resourceToField(d *schema.ResourceData) Field {
120+
return Field{
121+
DataType: d.Get("data_type").(string),
122+
FieldId: d.Get("field_id").(string),
123+
State: d.Get("state").(string),
124+
FieldName: d.Get("field_name").(string),
125+
}
126+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"strings"
7+
"testing"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
11+
)
12+
13+
func TestAccSumologicField_basic(t *testing.T) {
14+
var field Field
15+
testFieldName := "fields_provider_test"
16+
testDataType := "String"
17+
testState := "Enabled"
18+
resource.Test(t, resource.TestCase{
19+
PreCheck: func() { testAccPreCheck(t) },
20+
Providers: testAccProviders,
21+
CheckDestroy: testAccCheckFieldDestroy(field),
22+
Steps: []resource.TestStep{
23+
{
24+
Config: testAccCheckSumologicFieldConfigImported(testFieldName, testDataType, testState),
25+
},
26+
{
27+
ResourceName: "sumologic_field.foo",
28+
ImportState: true,
29+
ImportStateVerify: true,
30+
},
31+
},
32+
})
33+
}
34+
35+
func TestAccField_create(t *testing.T) {
36+
var field Field
37+
testFieldName := "fields_provider_test"
38+
testDataType := "String"
39+
testState := "Enabled"
40+
resource.Test(t, resource.TestCase{
41+
PreCheck: func() { testAccPreCheck(t) },
42+
Providers: testAccProviders,
43+
CheckDestroy: testAccCheckFieldDestroy(field),
44+
Steps: []resource.TestStep{
45+
{
46+
Config: testAccSumologicField(testFieldName, testDataType, testState),
47+
Check: resource.ComposeTestCheckFunc(
48+
testAccCheckFieldExists("sumologic_field.test", &field, t),
49+
testAccCheckFieldAttributes("sumologic_field.test"),
50+
resource.TestCheckResourceAttr("sumologic_field.test", "field_name", testFieldName),
51+
resource.TestCheckResourceAttr("sumologic_field.test", "data_type", testDataType),
52+
resource.TestCheckResourceAttr("sumologic_field.test", "state", testState),
53+
),
54+
},
55+
},
56+
})
57+
}
58+
59+
func testAccCheckFieldDestroy(field Field) resource.TestCheckFunc {
60+
return func(s *terraform.State) error {
61+
client := testAccProvider.Meta().(*Client)
62+
for _, r := range s.RootModule().Resources {
63+
id := r.Primary.ID
64+
u, err := client.GetField(id)
65+
if err != nil {
66+
return fmt.Errorf("Encountered an error: " + err.Error())
67+
}
68+
if u != nil {
69+
return fmt.Errorf("Field %s still exists", id)
70+
}
71+
}
72+
return nil
73+
}
74+
}
75+
76+
func testAccCheckFieldExists(name string, field *Field, t *testing.T) resource.TestCheckFunc {
77+
return func(s *terraform.State) error {
78+
rs, ok := s.RootModule().Resources[name]
79+
if !ok {
80+
//need this so that we don't get an unused import error for strconv in some cases
81+
return fmt.Errorf("Error = %s. Field not found: %s", strconv.FormatBool(ok), name)
82+
}
83+
84+
//need this so that we don't get an unused import error for strings in some cases
85+
if strings.EqualFold(rs.Primary.ID, "") {
86+
return fmt.Errorf("Field ID is not set")
87+
}
88+
89+
id := rs.Primary.ID
90+
client := testAccProvider.Meta().(*Client)
91+
newField, err := client.GetField(id)
92+
if err != nil {
93+
return fmt.Errorf("Field %s not found", id)
94+
}
95+
field = newField
96+
return nil
97+
}
98+
}
99+
func testAccCheckSumologicFieldConfigImported(fieldName string, dataType string, state string) string {
100+
return fmt.Sprintf(`
101+
resource "sumologic_field" "foo" {
102+
field_name = "%s"
103+
data_type = "%s"
104+
state = "%s"
105+
}
106+
`, fieldName, dataType, state)
107+
}
108+
109+
func testAccSumologicField(fieldName string, dataType string, state string) string {
110+
return fmt.Sprintf(`
111+
resource "sumologic_field" "test" {
112+
field_name = "%s"
113+
data_type = "%s"
114+
state = "%s"
115+
}
116+
`, fieldName, dataType, state)
117+
}
118+
119+
func testAccCheckFieldAttributes(name string) resource.TestCheckFunc {
120+
return func(s *terraform.State) error {
121+
f := resource.ComposeTestCheckFunc(
122+
resource.TestCheckResourceAttrSet(name, "field_name"),
123+
resource.TestCheckResourceAttrSet(name, "field_id"),
124+
resource.TestCheckResourceAttrSet(name, "data_type"),
125+
resource.TestCheckResourceAttrSet(name, "state"),
126+
)
127+
return f(s)
128+
}
129+
}

sumologic/sumologic_field.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package sumologic
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
)
8+
9+
func (s *Client) GetField(id string) (*Field, error) {
10+
urlWithoutParams := "v1/fields/%s"
11+
paramString := ""
12+
sprintfArgs := []interface{}{}
13+
sprintfArgs = append(sprintfArgs, id)
14+
15+
urlWithParams := fmt.Sprintf(urlWithoutParams+paramString, sprintfArgs...)
16+
17+
data, _, err := s.Get(urlWithParams)
18+
if err != nil {
19+
return nil, err
20+
}
21+
if data == nil {
22+
return nil, nil
23+
}
24+
25+
var field Field
26+
27+
err = json.Unmarshal(data, &field)
28+
if err != nil {
29+
return nil, err
30+
}
31+
32+
return &field, nil
33+
34+
}
35+
36+
func (s *Client) DeleteField(id string) error {
37+
urlWithoutParams := "v1/fields/%s"
38+
paramString := ""
39+
sprintfArgs := []interface{}{}
40+
sprintfArgs = append(sprintfArgs, id)
41+
42+
urlWithParams := fmt.Sprintf(urlWithoutParams+paramString, sprintfArgs...)
43+
44+
_, err := s.Delete(urlWithParams)
45+
46+
return err
47+
}
48+
49+
func (s *Client) CreateField(field Field) (string, error) {
50+
urlWithoutParams := "v1/fields"
51+
52+
data, err := s.Post(urlWithoutParams, field)
53+
if err != nil {
54+
return "", err
55+
}
56+
57+
var createdField Field
58+
59+
err = json.Unmarshal(data, &createdField)
60+
if err != nil {
61+
return "", err
62+
}
63+
64+
return createdField.FieldId, nil
65+
}
66+
67+
func (s *Client) FindFieldId(name string) (string, error) {
68+
urlWithoutParams := "v1/fields"
69+
70+
body, _, err := s.Get(urlWithoutParams)
71+
if err != nil {
72+
return "", err
73+
}
74+
75+
var prettyJSON bytes.Buffer
76+
error := json.Indent(&prettyJSON, body, "", "\t")
77+
if error != nil {
78+
return "", error
79+
}
80+
81+
var fields FieldsResponse
82+
83+
err = json.Unmarshal(body, &fields)
84+
if err != nil {
85+
return "", err
86+
}
87+
88+
for _, f := range fields.Data {
89+
if f.FieldName == name {
90+
return f.FieldId, nil
91+
}
92+
}
93+
94+
return "", fmt.Errorf("Field \"%s\" not found", name)
95+
}
96+
97+
type Field struct {
98+
FieldId string `json:"fieldId"`
99+
DataType string `json:"dataType"`
100+
State string `json:"state"`
101+
FieldName string `json:"fieldName"`
102+
}
103+
104+
type FieldsResponse struct {
105+
Data []Field `json:"data"`
106+
}

0 commit comments

Comments
 (0)