-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
slack: add data source for Slack channel (#147)
- Loading branch information
1 parent
f5591ed
commit 00adf5c
Showing
9 changed files
with
311 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
page_title: "FireHydrant Data Source: firehydrant_slack_channel" | ||
--- | ||
|
||
# firehydrant_slack_channel Data Source | ||
|
||
Use this data source to pass Slack channel information to other resources. | ||
|
||
## Example Usage | ||
|
||
Basic usage: | ||
```hcl | ||
data "firehydrant_slack_channel" "team_rocket" { | ||
slack_channel_id = "C1234567890" | ||
} | ||
resource "firehydrant_escalation_policy" "team_rocket" { | ||
# ... | ||
step { | ||
timeout = "PT5M" | ||
targets { | ||
type = "SlackChannel" | ||
id = data.firehydrant_slack_channel.team_rocket.id | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `slack_channel_id` - (Required) Slack's channel ID. | ||
|
||
## Attributes Reference | ||
|
||
In addition to all arguments above, the following attributes are exported: | ||
|
||
* `id` - The FireHydrant ID for the given Slack channel. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package firehydrant | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/dghubble/sling" | ||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
) | ||
|
||
// SlackChannelsClient is an interface for interacting with Slack channels | ||
type SlackChannelsClient interface { | ||
Get(ctx context.Context, slackID string) (*SlackChannelResponse, error) | ||
} | ||
|
||
// RESTSlackChannelsClient implements the SlackChannelClient interface | ||
type RESTSlackChannelsClient struct { | ||
client *APIClient | ||
} | ||
|
||
var _ SlackChannelsClient = &RESTSlackChannelsClient{} | ||
|
||
func (c *RESTSlackChannelsClient) restClient() *sling.Sling { | ||
return c.client.client() | ||
} | ||
|
||
// Get retrieves a Slack channel from FireHydrant using Slack ID. This is useful for looking up | ||
// a Slack channel's internal ID. | ||
func (c *RESTSlackChannelsClient) Get(ctx context.Context, slackID string) (*SlackChannelResponse, error) { | ||
channels := &SlackChannelsResponse{} | ||
apiError := &APIError{} | ||
response, err := c.restClient().Get("integrations/slack/channels?slack_channel_id="+slackID).Receive(channels, apiError) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not get slack channel: %w", err) | ||
} | ||
|
||
err = checkResponseStatusCode(response, apiError) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if channels.Channels == nil || len(channels.Channels) == 0 { | ||
return nil, fmt.Errorf("no slack channel found with id '%s'", slackID) | ||
} | ||
if channelCount := len(channels.Channels); channelCount > 1 { | ||
// "at least" because it may paginate. | ||
tflog.Error(ctx, "found more than one Slack channel", map[string]interface{}{ | ||
"id": slackID, | ||
"found": channelCount, | ||
}) | ||
for _, channel := range channels.Channels { | ||
tflog.Error(ctx, "found Slack channel", map[string]interface{}{ | ||
"id": channel.ID, | ||
"slack_channel_id": channel.SlackChannelID, | ||
"name": channel.Name, | ||
}) | ||
} | ||
return nil, fmt.Errorf("more than one Slack channel found: see Terraform logs for more information.") | ||
} | ||
|
||
tflog.Info(ctx, "found Slack channel", map[string]interface{}{ | ||
"id": channels.Channels[0].ID, | ||
"slack_channel_id": channels.Channels[0].SlackChannelID, | ||
"name": channels.Channels[0].Name, | ||
}) | ||
|
||
return channels.Channels[0], nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package firehydrant | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"net/http" | ||
"net/http/httptest" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func expectedSlackChannelResponse() *SlackChannelResponse { | ||
return &SlackChannelResponse{ | ||
ID: "00000000-0000-4000-8000-000000000000", | ||
Name: "#team-rocket", | ||
SlackChannelID: "C01010101Z", | ||
} | ||
} | ||
|
||
func expectedSlackChannelsResponseJSON() string { | ||
return `{ | ||
"data": [{"id":"00000000-0000-4000-8000-000000000000","name":"#team-rocket","slack_channel_id":"C01010101Z"}], | ||
"pagination": {"count":1,"page":1,"items":1,"pages":1,"last":1,"prev":null,"next":null} | ||
}` | ||
} | ||
|
||
func slackChannelMockServer(path, query *string) *httptest.Server { | ||
h := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | ||
*path = req.URL.Path | ||
*query = req.URL.Query().Get("slack_channel_id") | ||
|
||
if *query == "C01010101Z" { | ||
w.Write([]byte(expectedSlackChannelsResponseJSON())) | ||
} else { | ||
w.WriteHeader(http.StatusNotFound) | ||
} | ||
}) | ||
|
||
ts := httptest.NewServer(h) | ||
return ts | ||
} | ||
|
||
func TestSlackChannelGet(t *testing.T) { | ||
var requestPath, requestQuery string | ||
ts := slackChannelMockServer(&requestPath, &requestQuery) | ||
defer ts.Close() | ||
|
||
c, err := NewRestClient("test-token-very-authorized", WithBaseURL(ts.URL)) | ||
if err != nil { | ||
t.Fatalf("Received error initializing API client: %s", err.Error()) | ||
return | ||
} | ||
res, err := c.SlackChannels().Get(context.Background(), "C01010101Z") | ||
if err != nil { | ||
t.Fatalf("error retrieving slack channel: %s", err.Error()) | ||
} | ||
|
||
if expected := "/integrations/slack/channels"; expected != requestPath { | ||
t.Fatalf("request path mismatch: expected '%s', got: '%s'", expected, requestPath) | ||
} | ||
if expected := "C01010101Z"; expected != requestQuery { | ||
t.Fatalf("request query params mismatch: expected '%s', got: '%s'", expected, requestQuery) | ||
} | ||
|
||
expectedResponse := expectedSlackChannelResponse() | ||
if !reflect.DeepEqual(expectedResponse, res) { | ||
t.Fatalf("response mismatch: expected '%+v', got: '%+v'", expectedResponse, res) | ||
} | ||
} | ||
|
||
func TestSlackChannelGetNotFound(t *testing.T) { | ||
var requestPath, requestQuery string | ||
ts := slackChannelMockServer(&requestPath, &requestQuery) | ||
defer ts.Close() | ||
|
||
c, err := NewRestClient("test-token-very-authorized", WithBaseURL(ts.URL)) | ||
if err != nil { | ||
t.Fatalf("Received error initializing API client: %s", err.Error()) | ||
return | ||
} | ||
_, err = c.SlackChannels().Get(context.Background(), "C111111111") | ||
if err == nil { | ||
t.Fatalf("expected ErrorNotFound in retrieving slack channel, got nil") | ||
} | ||
if !errors.Is(err, ErrorNotFound) { | ||
t.Fatalf("expected ErrorNotFound in retrieving slack channel, got: %s", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package provider | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/firehydrant/terraform-provider-firehydrant/firehydrant" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func dataSourceSlackChannel() *schema.Resource { | ||
return &schema.Resource{ | ||
Description: "The `firehydrant_slack_channel` data source allows access to the details of a Slack channel.", | ||
ReadContext: dataFireHydrantSlackChannelRead, | ||
Schema: map[string]*schema.Schema{ | ||
"slack_channel_id": { | ||
Description: "ID of the channel, provided by Slack.", | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"id": { | ||
Description: "FireHydrant internal ID for the Slack channel.", | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataFireHydrantSlackChannelRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
// Get the API client | ||
firehydrantAPIClient := m.(firehydrant.Client) | ||
|
||
// Get the Slack channel | ||
channelID := d.Get("slack_channel_id").(string) | ||
slackChannel, err := firehydrantAPIClient.SlackChannels().Get(ctx, channelID) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
// Set the ID | ||
d.SetId(slackChannel.ID) | ||
|
||
return diag.Diagnostics{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package provider | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/firehydrant/terraform-provider-firehydrant/firehydrant" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func offlineSlackChannelsMockServer() *httptest.Server { | ||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | ||
w.Write([]byte(`{ | ||
"data": [{"id":"00000000-0000-4000-8000-000000000000","name":"#team-rocket","slack_channel_id":"C01010101Z"}], | ||
"pagination": {"count":1,"page":1,"items":1,"pages":1,"last":1,"prev":null,"next":null} | ||
}`)) | ||
})) | ||
} | ||
|
||
func TestOfflineSlackChannelsReadMemberID(t *testing.T) { | ||
ts := offlineSlackChannelsMockServer() | ||
defer ts.Close() | ||
|
||
c, err := firehydrant.NewRestClient("test-token-very-authorized", firehydrant.WithBaseURL(ts.URL)) | ||
if err != nil { | ||
t.Fatalf("Received error initializing API client: %s", err.Error()) | ||
return | ||
} | ||
r := schema.TestResourceDataRaw(t, dataSourceSlackChannel().Schema, map[string]interface{}{ | ||
"slack_channel_id": "C01010101Z", | ||
}) | ||
|
||
d := dataFireHydrantSlackChannelRead(context.Background(), r, c) | ||
if d.HasError() { | ||
t.Fatalf("error reading on-call schedule: %v", d) | ||
} | ||
if id := r.Id(); id != "00000000-0000-4000-8000-000000000000" { | ||
t.Fatalf("expected ID to be 00000000-0000-4000-8000-000000000000, got %s", id) | ||
} | ||
} |