Skip to content

Commit cb71889

Browse files
committed
[opendistro destination] Fix destination get in odfe>=1.11.0.
1 parent 4efcb82 commit cb71889

File tree

3 files changed

+96
-34
lines changed

3 files changed

+96
-34
lines changed

es/data_source_elasticsearch_opendistro_destination.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ func dataSourceElasticsearchOpenDistroDestination() *schema.Resource {
4747
func dataSourceElasticsearchOpenDistroDestinationRead(d *schema.ResourceData, m interface{}) error {
4848
destinationName := d.Get("name").(string)
4949

50-
response := new(destinationResponse)
51-
5250
// See https://github.com/opendistro-for-elasticsearch/alerting/issues/70, no tags or API endpoint for searching destination
5351
var id string
5452
var body *json.RawMessage
@@ -73,7 +71,8 @@ func dataSourceElasticsearchOpenDistroDestinationRead(d *schema.ResourceData, m
7371
return nil
7472
}
7573

76-
if err := json.Unmarshal(*body, response); err != nil {
74+
destination := make(map[string]interface{})
75+
if err := json.Unmarshal(*body, &destination); err != nil {
7776
return fmt.Errorf("error unmarshalling destination body: %+v: %+v", err, body)
7877
}
7978

@@ -82,7 +81,7 @@ func dataSourceElasticsearchOpenDistroDestinationRead(d *schema.ResourceData, m
8281
// we get a non-uniform map[string]interface{} back for the body, terraform
8382
// only accepts a mapping of string to primitive values
8483
simplifiedBody := map[string]string{}
85-
for key, value := range response.Destination.(map[string]interface{}) {
84+
for key, value := range destination["destination"].(map[string]interface{}) {
8685
if stringified, ok := value.(string); ok {
8786
simplifiedBody[key] = stringified
8887
} else {

es/resource_elasticsearch_opendistro_destination.go

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func resourceElasticsearchOpenDistroDestinationCreate(d *schema.ResourceData, m
7979
}
8080

8181
func resourceElasticsearchOpenDistroDestinationRead(d *schema.ResourceData, m interface{}) error {
82-
res, err := resourceElasticsearchOpenDistroGetDestination(d.Id(), m)
82+
destination, err := resourceElasticsearchOpenDistroQueryOrGetDestination(d.Id(), m)
8383

8484
if elastic6.IsNotFound(err) || elastic7.IsNotFound(err) {
8585
log.Printf("[WARN] Destination (%s) not found, removing from state", d.Id())
@@ -91,7 +91,12 @@ func resourceElasticsearchOpenDistroDestinationRead(d *schema.ResourceData, m in
9191
return err
9292
}
9393

94-
err = d.Set("body", res)
94+
body, err := json.Marshal(destination)
95+
if err != nil {
96+
return err
97+
}
98+
99+
err = d.Set("body", string(body))
95100
return err
96101
}
97102

@@ -137,39 +142,79 @@ func resourceElasticsearchOpenDistroDestinationDelete(d *schema.ResourceData, m
137142
return err
138143
}
139144

140-
func resourceElasticsearchOpenDistroGetDestination(destinationID string, m interface{}) (string, error) {
141-
var err error
142-
response := new(destinationResponse)
143-
144-
// See https://github.com/opendistro-for-elasticsearch/alerting/issues/56, no API endpoint for retrieving destination
145-
var body *json.RawMessage
146-
esClient, err := getClient(m.(*ProviderConf))
147-
if err != nil {
148-
return "", err
149-
}
145+
func resourceElasticsearchOpenDistroGetDestination(destinationID string, esClient interface{}) (Destination, error) {
150146
switch client := esClient.(type) {
151147
case *elastic7.Client:
152-
body, err = elastic7GetObject(client, DESTINATION_INDEX, destinationID)
153-
case *elastic6.Client:
154-
body, err = elastic6GetObject(client, DESTINATION_TYPE, DESTINATION_INDEX, destinationID)
148+
path, err := uritemplates.Expand("/_opendistro/_alerting/destinations/{id}", map[string]string{
149+
"id": destinationID,
150+
})
151+
if err != nil {
152+
return Destination{}, fmt.Errorf("error building URL path for destination: %+v", err)
153+
}
154+
155+
httpResponse, err := client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{
156+
Method: "GET",
157+
Path: path,
158+
})
159+
if err != nil {
160+
return Destination{}, err
161+
}
162+
163+
var drg destinationResponseGet
164+
if err := json.Unmarshal(httpResponse.Body, &drg); err != nil {
165+
return Destination{}, fmt.Errorf("error unmarshalling destination body: %+v", err)
166+
}
167+
// The response structure from the API is the same for the index and get
168+
// endpoints :|, and different from the other endpoints. Normalize the
169+
// response here.
170+
if len(drg.Destinations) > 0 {
171+
return drg.Destinations[0], nil
172+
} else {
173+
return Destination{}, fmt.Errorf("endpoint returned empty set of destinations: %+v", drg)
174+
}
155175
default:
156-
err = errors.New("destination resource not implemented prior to Elastic v6")
176+
return Destination{}, errors.New("destination get api not implemented prior to ODFE 1.11.0")
157177
}
178+
}
158179

180+
func resourceElasticsearchOpenDistroQueryOrGetDestination(destinationID string, m interface{}) (Destination, error) {
181+
esClient, err := getClient(m.(*ProviderConf))
159182
if err != nil {
160-
return "", err
161-
}
162-
163-
if err := json.Unmarshal(*body, response); err != nil {
164-
return "", fmt.Errorf("error unmarshalling destination body: %+v: %+v", err, body)
183+
return Destination{}, err
165184
}
166185

167-
tj, err := json.Marshal(response.Destination)
168-
if err != nil {
169-
return "", err
186+
var dr destinationResponse
187+
switch client := esClient.(type) {
188+
case *elastic7.Client:
189+
// See https://github.com/opendistro-for-elasticsearch/alerting/issues/56,
190+
// no API endpoint for retrieving destination prior to ODFE 1.11.0. So do
191+
// a request, if it 404s, fall back to trying to query the index.
192+
destination, err := resourceElasticsearchOpenDistroGetDestination(destinationID, client)
193+
if err == nil {
194+
return destination, err
195+
} else {
196+
body, err := elastic7GetObject(client, DESTINATION_INDEX, destinationID)
197+
198+
if err != nil {
199+
return Destination{}, err
200+
}
201+
if err := json.Unmarshal(*body, &dr); err != nil {
202+
return Destination{}, fmt.Errorf("error unmarshalling destination body: %+v: %+v", err, body)
203+
}
204+
return dr.Destination, nil
205+
}
206+
case *elastic6.Client:
207+
body, err := elastic6GetObject(client, DESTINATION_TYPE, DESTINATION_INDEX, destinationID)
208+
if err != nil {
209+
return Destination{}, err
210+
}
211+
if err := json.Unmarshal(*body, &dr); err != nil {
212+
return Destination{}, fmt.Errorf("error unmarshalling destination body: %+v: %+v", err, body)
213+
}
214+
return dr.Destination, nil
215+
default:
216+
return Destination{}, errors.New("destination resource not implemented prior to Elastic v6")
170217
}
171-
172-
return string(tj), err
173218
}
174219

175220
func resourceElasticsearchOpenDistroPostDestination(d *schema.ResourceData, m interface{}) (*destinationResponse, error) {
@@ -270,5 +315,23 @@ func resourceElasticsearchOpenDistroPutDestination(d *schema.ResourceData, m int
270315
type destinationResponse struct {
271316
Version int `json:"_version"`
272317
ID string `json:"_id"`
273-
Destination interface{} `json:"destination"`
318+
Destination Destination `json:"destination"`
319+
}
320+
321+
// When this api endpoint was introduced after the other endpoints, it has a
322+
// different response structure
323+
type destinationResponseGet struct {
324+
Total int `json:"totalDestinations"`
325+
Destinations []Destination `json:"destinations"`
326+
}
327+
328+
type Destination struct {
329+
ID string `json:"id"`
330+
Type string `json:"type"`
331+
Name string `json:"name"`
332+
Slack interface{} `json:"slack,omitempty"`
333+
CustomWebhook interface{} `json:"custom_webhook,omitempty"`
334+
Chime interface{} `json:"chime,omitempty"`
335+
SNS interface{} `json:"sns,omitempty"`
336+
Email interface{} `json:"email,omitempty"`
274337
}

es/resource_elasticsearch_opendistro_destination_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func testCheckElasticsearchOpenDistroDestinationExists(name string) resource.Tes
108108
meta := testAccOpendistroProvider.Meta()
109109

110110
var err error
111-
_, err = resourceElasticsearchOpenDistroGetDestination(rs.Primary.ID, meta.(*ProviderConf))
111+
_, err = resourceElasticsearchOpenDistroQueryOrGetDestination(rs.Primary.ID, meta.(*ProviderConf))
112112

113113
if err != nil {
114114
return err
@@ -133,9 +133,9 @@ func testCheckElasticsearchOpenDistroDestinationDestroy(s *terraform.State) erro
133133
}
134134
switch esClient.(type) {
135135
case *elastic7.Client:
136-
_, err = resourceElasticsearchOpenDistroGetDestination(rs.Primary.ID, meta.(*ProviderConf))
136+
_, err = resourceElasticsearchOpenDistroQueryOrGetDestination(rs.Primary.ID, meta.(*ProviderConf))
137137
case *elastic6.Client:
138-
_, err = resourceElasticsearchOpenDistroGetDestination(rs.Primary.ID, meta.(*ProviderConf))
138+
_, err = resourceElasticsearchOpenDistroQueryOrGetDestination(rs.Primary.ID, meta.(*ProviderConf))
139139
default:
140140
}
141141

0 commit comments

Comments
 (0)