-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
U-1159 On-call calendar data source (#84)
- Loading branch information
Showing
5 changed files
with
438 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "betteruptime_on_call_calendar Data Source - terraform-provider-better-uptime" | ||
subcategory: "" | ||
description: |- | ||
On-call calendar lookup. | ||
--- | ||
|
||
# betteruptime_on_call_calendar (Data Source) | ||
|
||
On-call calendar lookup. | ||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Optional | ||
|
||
- **name** (String) Name of the on-call calendar. | ||
|
||
### Read-Only | ||
|
||
- **default_calendar** (Boolean) Whether the on-call calendar is the default on-call calendar. | ||
- **id** (String) The ID of the on-call calendar. | ||
- **on_call_users** (List of Object) Array of on-call persons. (see [below for nested schema](#nestedatt--on_call_users)) | ||
|
||
<a id="nestedatt--on_call_users"></a> | ||
### Nested Schema for `on_call_users` | ||
|
||
Read-Only: | ||
|
||
- **email** (String) | ||
- **first_name** (String) | ||
- **id** (String) | ||
- **last_name** (String) | ||
- **phone_numbers** (List of String) | ||
|
||
|
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,148 @@ | ||
package provider | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func newOnCallCalendarDataSource() *schema.Resource { | ||
s := make(map[string]*schema.Schema) | ||
for k, v := range onCallCalendarSchema { | ||
cp := *v | ||
switch k { | ||
case "name": | ||
cp.Required = false | ||
cp.Optional = true | ||
cp.Computed = false | ||
default: | ||
cp.Computed = true | ||
cp.Optional = false | ||
cp.Required = false | ||
cp.ValidateDiagFunc = nil | ||
cp.Default = nil | ||
cp.DefaultFunc = nil | ||
cp.DiffSuppressFunc = nil | ||
} | ||
s[k] = &cp | ||
} | ||
return &schema.Resource{ | ||
ReadContext: onCallCalendarDefaultOrLookup, | ||
Description: "On-call calendar lookup.", | ||
Schema: s, | ||
} | ||
} | ||
|
||
func onCallCalendarDefaultOrLookup(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
if name, ok := d.Get("name").(string); ok && name != "" { | ||
return onCallCalendarLookup(ctx, d, meta) | ||
} | ||
return onCallDefaultCalendar(ctx, d, meta) | ||
} | ||
|
||
type onCallDefaultCalendarHTTPResponse struct { | ||
Data struct { | ||
ID string `json:"id"` | ||
Attributes onCallCalendar `json:"attributes"` | ||
Relationships onCallRelationships `json:"relationships"` | ||
} `json:"data"` | ||
Included []onCallIncluded `json:"included"` | ||
} | ||
|
||
func onCallDefaultCalendar(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
fetch := func() (*onCallDefaultCalendarHTTPResponse, error) { | ||
res, err := meta.(*client).Get(ctx, "/api/v2/on-calls/default") | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer func() { | ||
// Keep-Alive. | ||
_, _ = io.Copy(io.Discard, res.Body) | ||
_ = res.Body.Close() | ||
}() | ||
body, err := io.ReadAll(res.Body) | ||
if res.StatusCode != http.StatusOK { | ||
return nil, fmt.Errorf("GET %s returned %d: %s", res.Request.URL.String(), res.StatusCode, string(body)) | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
var tr onCallDefaultCalendarHTTPResponse | ||
return &tr, json.Unmarshal(body, &tr) | ||
} | ||
res, err := fetch() | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
d.SetId(res.Data.ID) | ||
if derr := onCallCalendarCopyAttrs(d, &res.Data.Attributes, res.Data.Relationships, res.Included); derr != nil { | ||
return derr | ||
} | ||
return nil | ||
} | ||
|
||
type onCallCalendarsPageHTTPResponse struct { | ||
Data []struct { | ||
ID string `json:"id"` | ||
Attributes onCallCalendar `json:"attributes"` | ||
Relationships onCallRelationships `json:"relationships"` | ||
} `json:"data"` | ||
Included []onCallIncluded `json:"included"` | ||
Pagination struct { | ||
First string `json:"first"` | ||
Last string `json:"last"` | ||
Prev string `json:"prev"` | ||
Next string `json:"next"` | ||
} `json:"pagination"` | ||
} | ||
|
||
func onCallCalendarLookup(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
fetch := func(page int) (*onCallCalendarsPageHTTPResponse, error) { | ||
res, err := meta.(*client).Get(ctx, fmt.Sprintf("/api/v2/on-calls?page=%d", page)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer func() { | ||
// Keep-Alive. | ||
_, _ = io.Copy(io.Discard, res.Body) | ||
_ = res.Body.Close() | ||
}() | ||
body, err := io.ReadAll(res.Body) | ||
if res.StatusCode != http.StatusOK { | ||
return nil, fmt.Errorf("GET %s returned %d: %s", res.Request.URL.String(), res.StatusCode, string(body)) | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
var tr onCallCalendarsPageHTTPResponse | ||
return &tr, json.Unmarshal(body, &tr) | ||
} | ||
calendarName := d.Get("name").(string) | ||
page := 1 | ||
for { | ||
res, err := fetch(page) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
for _, e := range res.Data { | ||
if *e.Attributes.Name == calendarName { | ||
if d.Id() != "" { | ||
return diag.Errorf("There are multiple on-call calendars with the same name: %s", calendarName) | ||
} | ||
d.SetId(e.ID) | ||
if derr := onCallCalendarCopyAttrs(d, &e.Attributes, e.Relationships, res.Included); derr != nil { | ||
return derr | ||
} | ||
} | ||
} | ||
page++ | ||
if res.Pagination.Next == "" { | ||
return 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,115 @@ | ||
package provider | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func TestOnCallCalendarData(t *testing.T) { | ||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
t.Log("Received " + r.Method + " " + r.RequestURI) | ||
|
||
if r.Header.Get("Authorization") != "Bearer foo" { | ||
t.Fatal("Not authorized: " + r.Header.Get("Authorization")) | ||
} | ||
|
||
prefix := "/api/v2/on-calls" | ||
|
||
switch { | ||
case r.Method == http.MethodGet && r.RequestURI == prefix+"?page=1": | ||
_, _ = w.Write([]byte(`{"data":[{"id":"123","attributes":{"name":"Primary","default_calendar":true},"relationships":{"on_call_users":{"data":[{"id":"123456","type":"user"}]}}}],"included":[{"id":"123456","type":"user","attributes":{"first_name":"John","last_name":"Smith","email":"[email protected]","phone_numbers":[]}}],"pagination":{"next":"..."}}`)) | ||
case r.Method == http.MethodGet && r.RequestURI == prefix+"?page=2": | ||
_, _ = w.Write([]byte(`{"data":[{"id":"456","attributes":{"name":"Secondary","default_calendar":false},"relationships":{"on_call_users":{"data":[{"id":"456789","type":"user"}]}}}],"included":[{"id":"456789","type":"user","attributes":{"first_name":"Jane","last_name":"Doe","email":"[email protected]","phone_numbers":["+44 808 157 0192"]}}],"pagination":{"next":null}}`)) | ||
default: | ||
t.Fatal("Unexpected " + r.Method + " " + r.RequestURI) | ||
} | ||
})) | ||
defer server.Close() | ||
|
||
var calendarName = "Secondary" | ||
|
||
resource.Test(t, resource.TestCase{ | ||
IsUnitTest: true, | ||
ProviderFactories: map[string]func() (*schema.Provider, error){ | ||
"betteruptime": func() (*schema.Provider, error) { | ||
return New(WithURL(server.URL)), nil | ||
}, | ||
}, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: fmt.Sprintf(` | ||
provider "betteruptime" { | ||
api_token = "foo" | ||
} | ||
data "betteruptime_on_call_calendar" "this" { | ||
name = "%s" | ||
} | ||
`, calendarName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrSet("data.betteruptime_on_call_calendar.this", "id"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "name", calendarName), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "default_calendar", "false"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.id", "456789"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.first_name", "Jane"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.last_name", "Doe"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.email", "[email protected]"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.phone_numbers.0", "+44 808 157 0192"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestDefaultOnCallCalendarData(t *testing.T) { | ||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
t.Log("Received " + r.Method + " " + r.RequestURI) | ||
|
||
if r.Header.Get("Authorization") != "Bearer foo" { | ||
t.Fatal("Not authorized: " + r.Header.Get("Authorization")) | ||
} | ||
|
||
switch { | ||
case r.Method == http.MethodGet && r.RequestURI == "/api/v2/on-calls/default": | ||
_, _ = w.Write([]byte(`{"data":{"id":"123","attributes":{"name":"Primary","default_calendar":true},"relationships":{"on_call_users":{"data":[{"id":"123456","type":"user"}]}}},"included":[{"id":"123456","type":"user","attributes":{"first_name":"John","last_name":"Smith","email":"[email protected]","phone_numbers":[]}}]}`)) | ||
default: | ||
t.Fatal("Unexpected " + r.Method + " " + r.RequestURI) | ||
} | ||
})) | ||
defer server.Close() | ||
|
||
resource.Test(t, resource.TestCase{ | ||
IsUnitTest: true, | ||
ProviderFactories: map[string]func() (*schema.Provider, error){ | ||
"betteruptime": func() (*schema.Provider, error) { | ||
return New(WithURL(server.URL)), nil | ||
}, | ||
}, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: ` | ||
provider "betteruptime" { | ||
api_token = "foo" | ||
} | ||
data "betteruptime_on_call_calendar" "this" { | ||
} | ||
`, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrSet("data.betteruptime_on_call_calendar.this", "id"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "name", "Primary"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "default_calendar", "true"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.id", "123456"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.first_name", "John"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.last_name", "Smith"), | ||
resource.TestCheckResourceAttr("data.betteruptime_on_call_calendar.this", "on_call_users.0.email", "[email protected]"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} |
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
Oops, something went wrong.