Skip to content

Commit 284af82

Browse files
JHeilCoveophillbaker
authored andcommitted
Add odfe_user resource
1 parent 3cf0c58 commit 284af82

3 files changed

+450
-0
lines changed

es/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ func Provider() terraform.ResourceProvider {
150150
"elasticsearch_opendistro_monitor": resourceElasticsearchOpenDistroMonitor(),
151151
"elasticsearch_opendistro_roles_mapping": resourceElasticsearchOpenDistroRolesMapping(),
152152
"elasticsearch_opendistro_role": resourceElasticsearchOpenDistroRole(),
153+
"elasticsearch_opendistro_user": resourceElasticsearchOpenDistroUser(),
153154
"elasticsearch_xpack_role": resourceElasticsearchXpackRole(),
154155
"elasticsearch_xpack_role_mapping": resourceElasticsearchXpackRoleMapping(),
155156
"elasticsearch_xpack_snapshot_lifecycle_policy": resourceElasticsearchXpackSnapshotLifecyclePolicy(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
package es
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
"log"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
11+
"github.com/olivere/elastic/uritemplates"
12+
13+
elastic7 "github.com/olivere/elastic/v7"
14+
)
15+
16+
func resourceElasticsearchOpenDistroUser() *schema.Resource {
17+
return &schema.Resource{
18+
Create: resourceElasticsearchOpenDistroUserCreate,
19+
Read: resourceElasticsearchOpenDistroUserRead,
20+
Update: resourceElasticsearchOpenDistroUserUpdate,
21+
Delete: resourceElasticsearchOpenDistroUserDelete,
22+
Schema: map[string]*schema.Schema{
23+
"username": {
24+
Type: schema.TypeString,
25+
Required: true,
26+
},
27+
"password": {
28+
Type: schema.TypeString,
29+
Required: true,
30+
Sensitive: true,
31+
},
32+
"backend_roles": {
33+
Type: schema.TypeSet,
34+
Optional: true,
35+
Elem: &schema.Schema{Type: schema.TypeString},
36+
},
37+
"attributes": {
38+
Type: schema.TypeMap,
39+
Optional: true,
40+
Elem: &schema.Schema{Type: schema.TypeString},
41+
},
42+
"description": {
43+
Type: schema.TypeString,
44+
Optional: true,
45+
},
46+
},
47+
Importer: &schema.ResourceImporter{
48+
State: schema.ImportStatePassthrough,
49+
},
50+
}
51+
}
52+
53+
func resourceElasticsearchOpenDistroUserCreate(d *schema.ResourceData, m interface{}) error {
54+
_, err := resourceElasticsearchPutOpenDistroUser(d, m)
55+
56+
if err != nil {
57+
return err
58+
}
59+
60+
name := d.Get("username").(string)
61+
d.SetId(name)
62+
return resourceElasticsearchOpenDistroUserRead(d, m)
63+
}
64+
65+
func resourceElasticsearchOpenDistroUserRead(d *schema.ResourceData, m interface{}) error {
66+
res, err := resourceElasticsearchGetOpenDistroUser(d.Id(), m)
67+
68+
if err != nil {
69+
if elastic7.IsNotFound(err) {
70+
log.Printf("[WARN] OdfeUser (%s) not found, removing from state", d.Id())
71+
d.SetId("")
72+
return nil
73+
}
74+
return err
75+
}
76+
77+
ds := &resourceDataSetter{d: d}
78+
ds.set("backend_roles", res.BackendRoles)
79+
ds.set("attributes", res.Attributes)
80+
ds.set("description", res.Description)
81+
return ds.err
82+
}
83+
84+
func resourceElasticsearchOpenDistroUserUpdate(d *schema.ResourceData, m interface{}) error {
85+
if _, err := resourceElasticsearchPutOpenDistroUser(d, m); err != nil {
86+
return err
87+
}
88+
89+
return resourceElasticsearchOpenDistroUserRead(d, m)
90+
}
91+
92+
func resourceElasticsearchOpenDistroUserDelete(d *schema.ResourceData, m interface{}) error {
93+
var err error
94+
95+
path, err := uritemplates.Expand("/_opendistro/_security/api/internalusers/{name}", map[string]string{
96+
"name": d.Get("username").(string),
97+
})
98+
if err != nil {
99+
return fmt.Errorf("Error building URL path for user: %+v", err)
100+
}
101+
102+
switch client := m.(type) {
103+
case *elastic7.Client:
104+
_, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
105+
Method: "DELETE",
106+
Path: path,
107+
})
108+
default:
109+
err = errors.New("Role resource not implemented prior to Elastic v7")
110+
}
111+
112+
return err
113+
}
114+
115+
func resourceElasticsearchGetOpenDistroUser(userID string, m interface{}) (UserBody, error) {
116+
var err error
117+
user := new(UserBody)
118+
119+
path, err := uritemplates.Expand("/_opendistro/_security/api/internalusers/{name}", map[string]string{
120+
"name": userID,
121+
})
122+
123+
if err != nil {
124+
return *user, fmt.Errorf("Error building URL path for user: %+v", err)
125+
}
126+
127+
var body json.RawMessage
128+
switch client := m.(type) {
129+
case *elastic7.Client:
130+
var res *elastic7.Response
131+
res, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
132+
Method: "GET",
133+
Path: path,
134+
})
135+
body = res.Body
136+
default:
137+
err = errors.New("Role resource not implemented prior to Elastic v7")
138+
}
139+
140+
if err != nil {
141+
return *user, err
142+
}
143+
var userDefinition map[string]UserBody
144+
145+
if err := json.Unmarshal(body, &userDefinition); err != nil {
146+
return *user, fmt.Errorf("Error unmarshalling user body: %+v: %+v", err, body)
147+
}
148+
149+
*user = userDefinition[userID]
150+
151+
return *user, err
152+
}
153+
154+
func resourceElasticsearchPutOpenDistroUser(d *schema.ResourceData, m interface{}) (*UserResponse, error) {
155+
response := new(UserResponse)
156+
157+
userDefinition := UserBody{
158+
BackendRoles: d.Get("backend_roles").(*schema.Set).List(),
159+
Description: d.Get("description").(string),
160+
Attributes: d.Get("attributes").(map[string]interface{}),
161+
Password: d.Get("password").(string),
162+
}
163+
164+
userJSON, err := json.Marshal(userDefinition)
165+
if err != nil {
166+
return response, fmt.Errorf("Body Error : %s", userJSON)
167+
}
168+
169+
path, err := uritemplates.Expand("/_opendistro/_security/api/internalusers/{name}", map[string]string{
170+
"name": d.Get("username").(string),
171+
})
172+
if err != nil {
173+
return response, fmt.Errorf("Error building URL path for user: %+v", err)
174+
}
175+
176+
var body json.RawMessage
177+
switch client := m.(type) {
178+
case *elastic7.Client:
179+
var res *elastic7.Response
180+
res, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
181+
Method: "PUT",
182+
Path: path,
183+
Body: string(userJSON),
184+
})
185+
body = res.Body
186+
default:
187+
err = errors.New("User resource not implemented prior to Elastic v7")
188+
}
189+
190+
if err != nil {
191+
return response, fmt.Errorf("Error creating user mapping: %+v: %+v: %+v", err, body, string(userJSON))
192+
}
193+
194+
if err := json.Unmarshal(body, response); err != nil {
195+
return response, fmt.Errorf("Error unmarshalling user body: %+v: %+v", err, body)
196+
}
197+
198+
return response, nil
199+
}
200+
201+
// UserBody used by the odfe's API
202+
type UserBody struct {
203+
BackendRoles []interface{} `json:"backend_roles"`
204+
Attributes map[string]interface{} `json:"attributes"`
205+
Description string `json:"description"`
206+
Password string `json:"password"`
207+
}
208+
209+
// UserResponse sent by the odfe's API
210+
type UserResponse struct {
211+
Message string `json:"message"`
212+
Status string `json:"status"`
213+
}

0 commit comments

Comments
 (0)