From 2b891e612838e3ff41aff34aa6bab93fc1db8c3f Mon Sep 17 00:00:00 2001 From: Shaun McCormick Date: Thu, 20 Apr 2023 16:48:00 -0500 Subject: [PATCH] Add firehydrant_teams and firehydrant_team data source --- CHANGELOG.md | 2 + docs/data-sources/team.md | 35 ++++++++++ docs/data-sources/teams.md | 44 ++++++++++++ examples/teams.tf | 11 +++ firehydrant/client.go | 75 ++------------------ firehydrant/teams.go | 121 ++++++++++++++++++++++++++++++++ firehydrant/teams_test.go | 98 ++++++++++++++++++++++++++ firehydrant/types.go | 22 ++++++ go.sum | 56 +++++++++++++++ provider/team_data.go | 102 +++++++++++++++++++++++++++ provider/team_data_test.go | 124 +++++++++++++++++++++++++++++++++ provider/team_resource.go | 8 +-- provider/team_resource_test.go | 6 +- provider/teams_data.go | 83 ++++++++++++++++++++++ provider/teams_data_test.go | 69 ++++++++++++++++++ 15 files changed, 778 insertions(+), 78 deletions(-) create mode 100644 docs/data-sources/team.md create mode 100644 docs/data-sources/teams.md create mode 100644 firehydrant/teams.go create mode 100644 firehydrant/teams_test.go create mode 100644 provider/team_data.go create mode 100644 provider/team_data_test.go create mode 100644 provider/teams_data.go create mode 100644 provider/teams_data_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index cb38ba3d..0478ac4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ENHANCEMENTS: * Bump golang from 1.16 to 1.18 +* **New Data Source:** `firehydrant_team` ([#121](https://github.com/firehydrant/terraform-provider-firehydrant/pull/121)) +* **New Data Source:** `firehydrant_teams` ([#121](https://github.com/firehydrant/terraform-provider-firehydrant/pull/121)) * resource/service: Added `auto_add_responding_team` attribute to service ([#117](https://github.com/firehydrant/terraform-provider-firehydrant/pull/117)) * data_source/service: Added `auto_add_responding_team` attribute to service ([#117](https://github.com/firehydrant/terraform-provider-firehydrant/pull/117)) * data_source/services: Added `auto_add_responding_team` attribute to service ([#117](https://github.com/firehydrant/terraform-provider-firehydrant/pull/117)) diff --git a/docs/data-sources/team.md b/docs/data-sources/team.md new file mode 100644 index 00000000..fdb55712 --- /dev/null +++ b/docs/data-sources/team.md @@ -0,0 +1,35 @@ +--- +page_title: "FireHydrant Data Source: firehydrant_team" +subcategory: "" +--- + +# firehydrant_team Data Source + +Use this data source to get information on a team matching the given criteria. + +## Example Usage + +Basic usage: + +```hcl +data "firehydrant_team" "test-team" { + id = "157a83c4-17d1-4362-a4e8-a45412d19af2" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `id` - (Required) The ID of the team to retrieve. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the team. +* `name` - The name of the team. +* `description` - A description of the team. +* `slug` - The slug for the team. +* `service_ids` - A set of IDs of the services associated with this team +* `owned_service_ids` - A set of IDs of the services owned by this team diff --git a/docs/data-sources/teams.md b/docs/data-sources/teams.md new file mode 100644 index 00000000..8ab6cc22 --- /dev/null +++ b/docs/data-sources/teams.md @@ -0,0 +1,44 @@ +--- +page_title: "FireHydrant Data Source: firehydrant_teams" +subcategory: "" +--- + +# firehydrant_teams Data Source + +Use this data source to get information on all teams matching the given criteria. + +## Example Usage + +Basic usage: +```hcl +data "firehydrant_teams" "all-teams" { +} +``` + +Getting all teams with `database` in the name: +```hcl +data "firehydrant_teams" "database-named-teams" { + query = "database" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `query` - (Optional) A query to search for teams by their name. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `teams` - All the teams matching the criteria specified by `query`. + +The `teams` block contains: + +* `id` - The ID of the team. +* `name` - The name of the team. +* `description` - A description of the team. +* `slug` - The slug for the team. +* `service_ids` - A set of IDs of the services associated with this team +* `owned_service_ids` - A set of IDs of the services owned by this team diff --git a/examples/teams.tf b/examples/teams.tf index ca109477..3a1c2a4c 100644 --- a/examples/teams.tf +++ b/examples/teams.tf @@ -1,3 +1,14 @@ resource "firehydrant_team" "firefighters" { name = "Firefighters" } + +data "firehydrant_team" "firefighters" { + id = "857a83c4-17d1-4362-a4e8-42d1a3d19ed1" +} + +data "firehydrant_teams" "all_teams" { +} + +data "firehydrant_teams" "test_teams" { + query = "Test" +} diff --git a/firehydrant/client.go b/firehydrant/client.go index 67868d81..81bd7258 100644 --- a/firehydrant/client.go +++ b/firehydrant/client.go @@ -69,12 +69,7 @@ type Client interface { Services() ServicesClient Severities() SeveritiesClient TaskLists() TaskListsClient - - // Teams - GetTeam(ctx context.Context, id string) (*TeamResponse, error) - CreateTeam(ctx context.Context, req CreateTeamRequest) (*TeamResponse, error) - UpdateTeam(ctx context.Context, id string, req UpdateTeamRequest) (*TeamResponse, error) - DeleteTeam(ctx context.Context, id string) error + Teams() TeamsClient // Users GetUsers(ctx context.Context, params GetUserParams) (*UserResponse, error) @@ -195,21 +190,9 @@ func (c *APIClient) TaskLists() TaskListsClient { return &RESTTaskListsClient{client: c} } -// GetTeam retrieves a team from FireHydrant -func (c *APIClient) GetTeam(ctx context.Context, id string) (*TeamResponse, error) { - teamResponse := &TeamResponse{} - apiError := &APIError{} - response, err := c.client().Get("teams/"+id).Receive(teamResponse, apiError) - if err != nil { - return nil, errors.Wrap(err, "could not get team") - } - - err = checkResponseStatusCode(response, apiError) - if err != nil { - return nil, err - } - - return teamResponse, nil +// Teams returns a TeamsClient interface for interacting with teams in FireHydrant +func (c *APIClient) Teams() TeamsClient { + return &RESTTeamsClient{client: c} } // GetUsers gets matching users in FireHydrant @@ -245,53 +228,3 @@ func (c *APIClient) GetSchedules(ctx context.Context, params GetScheduleParams) return scheduleResponse, nil } - -// CreateTeam creates a team in FireHydrant -func (c *APIClient) CreateTeam(ctx context.Context, req CreateTeamRequest) (*TeamResponse, error) { - teamResponse := &TeamResponse{} - apiError := &APIError{} - response, err := c.client().Post("teams").BodyJSON(&req).Receive(teamResponse, apiError) - if err != nil { - return nil, errors.Wrap(err, "could not create team") - } - - err = checkResponseStatusCode(response, apiError) - if err != nil { - return nil, err - } - - return teamResponse, nil -} - -// UpdateTeam updates a team in FireHydrant -func (c *APIClient) UpdateTeam(ctx context.Context, id string, req UpdateTeamRequest) (*TeamResponse, error) { - teamResponse := &TeamResponse{} - apiError := &APIError{} - response, err := c.client().Patch("teams/"+id).BodyJSON(&req).Receive(teamResponse, apiError) - if err != nil { - return nil, errors.Wrap(err, "could not update team") - } - - err = checkResponseStatusCode(response, apiError) - if err != nil { - return nil, err - } - - return teamResponse, nil -} - -// DeleteTeam deletes a team from FireHydrant -func (c *APIClient) DeleteTeam(ctx context.Context, id string) error { - apiError := &APIError{} - response, err := c.client().Delete("teams/"+id).Receive(nil, apiError) - if err != nil { - return errors.Wrap(err, "could not delete team") - } - - err = checkResponseStatusCode(response, apiError) - if err != nil { - return err - } - - return nil -} diff --git a/firehydrant/teams.go b/firehydrant/teams.go new file mode 100644 index 00000000..a4402532 --- /dev/null +++ b/firehydrant/teams.go @@ -0,0 +1,121 @@ +package firehydrant + +import ( + "context" + "github.com/dghubble/sling" + "github.com/pkg/errors" +) + +// TeamsClient is an interface for interacting with teams on FireHydrant +type TeamsClient interface { + Get(ctx context.Context, slug string) (*TeamResponse, error) + List(ctx context.Context, req *TeamQuery) (*TeamsResponse, error) + Create(ctx context.Context, createReq CreateTeamRequest) (*TeamResponse, error) + Update(ctx context.Context, slug string, updateReq UpdateTeamRequest) (*TeamResponse, error) + Archive(ctx context.Context, slug string) error +} + +// RESTTeamsClient implements the TeamsClient interface +type RESTTeamsClient struct { + client *APIClient +} + +var _ TeamsClient = &RESTTeamsClient{} + +func (c *RESTTeamsClient) restClient() *sling.Sling { + return c.client.client() +} + +// Get retrieves a team from FireHydrant +func (c *RESTTeamsClient) Get(ctx context.Context, id string) (*TeamResponse, error) { + teamResponse := &TeamResponse{} + apiError := &APIError{} + response, err := c.restClient().Get("teams/"+id).Receive(teamResponse, apiError) + if err != nil { + return nil, errors.Wrap(err, "could not get team") + } + + err = checkResponseStatusCode(response, apiError) + if err != nil { + return nil, err + } + + return teamResponse, nil +} + +// List retrieves a list of teams based on a team query +func (c *RESTTeamsClient) List(ctx context.Context, req *TeamQuery) (*TeamsResponse, error) { + teamsResponse := &TeamsResponse{} + apiError := &APIError{} + curPage := 1 + + for { + req.Page = curPage + response, err := c.restClient().Get("teams").QueryStruct(req).Receive(teamsResponse, apiError) + if err != nil { + return nil, errors.Wrap(err, "could not get teams") + } + + err = checkResponseStatusCode(response, apiError) + if err != nil { + return nil, err + } + + if teamsResponse.Pagination == nil || teamsResponse.Pagination.Last == curPage { + break + } + curPage += 1 + } + + return teamsResponse, nil +} + +// Create creates a team +func (c *RESTTeamsClient) Create(ctx context.Context, createReq CreateTeamRequest) (*TeamResponse, error) { + teamResponse := &TeamResponse{} + apiError := &APIError{} + response, err := c.restClient().Post("teams").BodyJSON(&createReq).Receive(teamResponse, apiError) + if err != nil { + return nil, errors.Wrap(err, "could not create team") + } + + err = checkResponseStatusCode(response, apiError) + if err != nil { + return nil, err + } + + return teamResponse, nil +} + +// Update updates a team in FireHydrant +func (c *RESTTeamsClient) Update(ctx context.Context, slug string, updateReq UpdateTeamRequest) (*TeamResponse, error) { + teamResponse := &TeamResponse{} + apiError := &APIError{} + response, err := c.restClient().Patch("teams/"+slug).BodyJSON(&updateReq).Receive(teamResponse, apiError) + if err != nil { + return nil, errors.Wrap(err, "could not update team") + } + + err = checkResponseStatusCode(response, apiError) + if err != nil { + return nil, err + } + + return teamResponse, nil +} + +// Archive archives a team in FireHydrant +func (c *RESTTeamsClient) Archive(ctx context.Context, slug string) error { + apiError := &APIError{} + response, err := c.restClient().Delete("teams/"+slug).Receive(nil, apiError) + if err != nil { + return errors.Wrap(err, "could not archive team") + } + + err = checkResponseStatusCode(response, apiError) + if err != nil { + return err + } + + return nil +} diff --git a/firehydrant/teams_test.go b/firehydrant/teams_test.go new file mode 100644 index 00000000..b31754bf --- /dev/null +++ b/firehydrant/teams_test.go @@ -0,0 +1,98 @@ +package firehydrant + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/google/go-querystring/query" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetTeam(t *testing.T) { + resp := &TeamResponse{} + testTeamID := "test-team-id" + c, teardown, err := setupClient("/teams/"+testTeamID, resp) + require.NoError(t, err) + defer teardown() + + res, err := c.Teams().Get(context.TODO(), testTeamID) + require.NoError(t, err, "error retrieving a team") + assert.Equal(t, resp.ID, res.ID, "returned team did not match") + assert.Equal(t, resp.Name, res.Name, "returned team did not match") +} + +func TestCreateTeam(t *testing.T) { + resp := &TeamResponse{} + c, teardown, err := setupClient("/teams", resp, + AssertRequestJSONBody(t, CreateTeamRequest{Name: "fake-team", Description: "fake description"}), + AssertRequestMethod(t, "POST"), + ) + + require.NoError(t, err) + defer teardown() + + _, err = c.Teams().Create(context.TODO(), CreateTeamRequest{Name: "fake-team", Description: "fake description"}) + require.NoError(t, err, "error creating a team") +} + +func TestGetTeams(t *testing.T) { + var requestPathRcvd string + response := TeamsResponse{ + Teams: []TeamResponse{ + { + ID: "test-team", + }, + }, + Pagination: &Pagination{ + Count: 1, + Page: 1, + Items: 1, + Pages: 1, + Last: 1, + Next: 1, + }, + } + + h := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + requestPathRcvd = req.URL.Path + "?" + req.URL.RawQuery + + if err := json.NewEncoder(w).Encode(&response); err != nil { + panic(err) + } + }) + ts := httptest.NewServer(h) + + defer ts.Close() + + testToken := "testing-123" + c, err := NewRestClient(testToken, WithBaseURL(ts.URL)) + + if err != nil { + t.Fatalf("Received error initializing API client: %s", err.Error()) + return + } + + qry := &TeamQuery{ + Query: "test-team", + } + + vs, err := query.Values(qry) + if err != nil { + t.Fatalf(err.Error()) + } + + t.Log(vs) + + _, err = c.Teams().List(context.TODO(), qry) + if err != nil { + t.Fatalf("Received error hitting ping endpoint: %s", err.Error()) + } + + if expected := "/teams?page=1&query=test-team"; expected != requestPathRcvd { + t.Fatalf("Expected %s, Got: %s for request path", expected, requestPathRcvd) + } +} diff --git a/firehydrant/types.go b/firehydrant/types.go index c112db07..8487c7ce 100644 --- a/firehydrant/types.go +++ b/firehydrant/types.go @@ -200,6 +200,12 @@ type TeamResponse struct { UpdatedAt time.Time `json:"updated_at"` } +// TeamsResponse is the payload for retrieving a list of teams +type TeamsResponse struct { + Teams []TeamResponse `json:"data"` + Pagination *Pagination `json:"pagination,omitempty"` +} + // MembershipResponse represents the response coming back from teams // for membership type MembershipResponse struct { @@ -216,6 +222,12 @@ type Membership struct { UserId string `json:"user_id,omitempty"` } +// TeamQuery is the query used to search for teams +type TeamQuery struct { + Query string `url:"query,omitempty"` + Page int `url:"page,omitempty"` +} + // CreateTeamRequest is the payload for creating a service // URL: POST https://api.firehydrant.io/v1/services type CreateTeamRequest struct { @@ -236,3 +248,13 @@ type UpdateTeamRequest struct { Description string `json:"description"` Memberships []Membership `json:"memberships,omitempty"` } + +type Pagination struct { + Count int `json:"count"` + Page int `json:"page"` + Items int `json:"items"` + Pages int `json:"pages"` + Last int `json:"last"` + Prev int `json:"prev,omitempty"` + Next int `json:"next,omitempty"` +} diff --git a/go.sum b/go.sum index f80fc7dc..d045af13 100644 --- a/go.sum +++ b/go.sum @@ -9,13 +9,17 @@ github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C6 github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= @@ -25,10 +29,15 @@ github.com/bxcodec/faker/v3 v3.5.0 h1:Rahy6dwbd6up0wbwbV7dFyQb+jmdC51kpATuUdnzfM github.com/bxcodec/faker/v3 v3.5.0/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -42,7 +51,9 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -57,6 +68,7 @@ github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6 github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -83,6 +95,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -101,6 +114,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw= github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -134,6 +148,8 @@ github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b57 github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI= github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -142,6 +158,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -154,10 +171,14 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -165,8 +186,11 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -175,6 +199,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -187,10 +213,13 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46 h1:Dz0HrI1AtNSGCE8LXLLqoZU4iuOJXPWndenCsZfstA8= github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46/go.mod h1:is8FVkzSi7PYLWEXT5MgWhglFsyyiW8ffxAoJqfuFZo= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -209,15 +238,18 @@ github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37w github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY= github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -228,6 +260,8 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -236,13 +270,17 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -252,20 +290,26 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -279,6 +323,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -286,28 +331,38 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211222154725-9823f7ba7562 h1:sZWkpp+mMCIr/XzilKM5CjCxqe2o7SyJ+kz097OkcNM= google.golang.org/genproto v0.0.0-20211222154725-9823f7ba7562/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -316,6 +371,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/provider/team_data.go b/provider/team_data.go new file mode 100644 index 00000000..0ce08519 --- /dev/null +++ b/provider/team_data.go @@ -0,0 +1,102 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/firehydrant/terraform-provider-firehydrant/firehydrant" + + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceTeam() *schema.Resource { + return &schema.Resource{ + ReadContext: dataFireHydrantTeam, + Schema: map[string]*schema.Schema{ + // Required + "id": { + Type: schema.TypeString, + Required: true, + }, + + // Computed + "name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "slug": { + Type: schema.TypeString, + Computed: true, + }, + "service_ids": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "owned_service_ids": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataFireHydrantTeam(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + // Get the API client + firehydrantAPIClient := m.(firehydrant.Client) + + // Get the team + id := d.Get("id").(string) + tflog.Debug(ctx, fmt.Sprintf("Read team: %s", id), map[string]interface{}{ + "id": id, + }) + teamResponse, err := firehydrantAPIClient.Teams().Get(ctx, id) + if err != nil { + return diag.Errorf("Error reading team %s: %v", id, err) + } + + // Gather values from API response + attributes := map[string]interface{}{ + "id": teamResponse.ID, + "name": teamResponse.Name, + "description": teamResponse.Description, + "slug": teamResponse.Slug, + } + + // Collect mapped service IDs + serviceIDs := make([]string, 0) + for _, service := range teamResponse.Services { + serviceIDs = append(serviceIDs, service.ID) + } + attributes["service_ids"] = serviceIDs + + // Collect mapped owned service IDs + ownedServiceIDs := make([]string, 0) + for _, service := range teamResponse.OwnedServices { + ownedServiceIDs = append(ownedServiceIDs, service.ID) + } + attributes["owned_service_ids"] = ownedServiceIDs + + // Set the data source attributes to the values we got from the API + for key, value := range attributes { + if err := d.Set(key, value); err != nil { + return diag.Errorf("Error setting %s for team %s: %v", key, id, err) + } + } + + // Set the team's ID in state + d.SetId(teamResponse.ID) + + return diag.Diagnostics{} +} diff --git a/provider/team_data_test.go b/provider/team_data_test.go new file mode 100644 index 00000000..61114d3f --- /dev/null +++ b/provider/team_data_test.go @@ -0,0 +1,124 @@ +package provider + +import ( + "fmt" + "net/http" + "net/http/httptest" + "os" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testTeamDataSourceConfig_basic() string { + return fmt.Sprintln(` +data "firehydrant_team" "test_team" { + name = "Test Team" +}`) +} + +func TestTeamDataSource_OneMatch(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + if r.URL.Path != "/ping" && r.URL.Path != "/teams" { + t.Errorf("Expected to request '/ping' or '/teams', got: %s", r.URL.Path) + } + if r.URL.Path == "/teams" && r.URL.Query().Get("query") != "Test Team" { + t.Errorf("Expected query param 'query' to be 'Test Team', got: %s", r.URL.Query().Get("query")) + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"data":[{"id": "123", "name": "Test Team", "slug":"test-team"}]}`)) + })) + + defer server.Close() + + orig := os.Getenv("FIREHYDRANT_BASE_URL") + os.Setenv("FIREHYDRANT_BASE_URL", server.URL) + t.Cleanup(func() { os.Setenv("FIREHYDRANT_BASE_URL", orig) }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testFireHydrantIsSetup(t) }, + ProviderFactories: defaultProviderFactories(), + Steps: []resource.TestStep{ + { + Config: testTeamDataSourceConfig_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.firehydrant_team.test_team", "id"), + resource.TestCheckResourceAttr( + "data.firehydrant_team.test_team", "id", "123"), + resource.TestCheckResourceAttr( + "data.firehydrant_team.test_team", "name", "Test Team"), + resource.TestCheckResourceAttr( + "data.firehydrant_team.test_team", "slug", "test-team"), + ), + }, + }, + }) +} + +func TestTeamDataSource_MultipleMatches(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + if r.URL.Path != "/ping" && r.URL.Path != "/teams" { + t.Errorf("Expected to request '/ping' or '/teams', got: %s", r.URL.Path) + } + if r.URL.Path == "/teams" && r.URL.Query().Get("query") != "Test Team" { + t.Errorf("Expected query param 'query' to be 'Test Team', got: %s", r.URL.Query().Get("query")) + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"data":[{"id": "123", "name": "Test Team", "slug": "test-team"}]}`)) + w.Write([]byte(`{"data":[{"id": "123", "name": "Test Team", "slug": "test-team"},{"id": "456", "name": "Test Team 2", "slug": "test-team-2"}]}`)) + })) + + defer server.Close() + + orig := os.Getenv("FIREHYDRANT_BASE_URL") + os.Setenv("FIREHYDRANT_BASE_URL", server.URL) + t.Cleanup(func() { os.Setenv("FIREHYDRANT_BASE_URL", orig) }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testFireHydrantIsSetup(t) }, + ProviderFactories: defaultProviderFactories(), + Steps: []resource.TestStep{ + { + Config: testTeamDataSourceConfig_basic(), + ExpectError: regexp.MustCompile(`Found multiple matching teams for 'Test Team'`), + }, + }, + }) +} + +func TestTeamDataSource_NoMatches(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + if r.URL.Path != "/ping" && r.URL.Path != "/teams" { + t.Errorf("Expected to request '/ping' or '/teams', got: %s", r.URL.Path) + } + if r.URL.Path == "/teams" && r.URL.Query().Get("query") != "Test Team" { + t.Errorf("Expected query param 'query' to be 'Test Team', got: %s", r.URL.Query().Get("query")) + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"data":[]}`)) + })) + + defer server.Close() + + orig := os.Getenv("FIREHYDRANT_BASE_URL") + os.Setenv("FIREHYDRANT_BASE_URL", server.URL) + t.Cleanup(func() { os.Setenv("FIREHYDRANT_BASE_URL", orig) }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testFireHydrantIsSetup(t) }, + ProviderFactories: defaultProviderFactories(), + Steps: []resource.TestStep{ + { + Config: testTeamDataSourceConfig_basic(), + ExpectError: regexp.MustCompile(`Did not find team matching 'Test Team'`), + }, + }, + }) +} diff --git a/provider/team_resource.go b/provider/team_resource.go index 3974d036..9b969af3 100644 --- a/provider/team_resource.go +++ b/provider/team_resource.go @@ -66,7 +66,7 @@ func readResourceFireHydrantTeam(ctx context.Context, d *schema.ResourceData, m tflog.Debug(ctx, fmt.Sprintf("Read team: %s", teamID), map[string]interface{}{ "id": teamID, }) - teamResponse, err := firehydrantAPIClient.GetTeam(ctx, teamID) + teamResponse, err := firehydrantAPIClient.Teams().Get(ctx, teamID) if err != nil { if errors.Is(err, firehydrant.ErrorNotFound) { tflog.Debug(ctx, fmt.Sprintf("Team %s no longer exists", teamID), map[string]interface{}{ @@ -129,7 +129,7 @@ func createResourceFireHydrantTeam(ctx context.Context, d *schema.ResourceData, tflog.Debug(ctx, fmt.Sprintf("Create team: %s", createRequest.Name), map[string]interface{}{ "name": createRequest.Name, }) - teamResponse, err := firehydrantAPIClient.CreateTeam(ctx, createRequest) + teamResponse, err := firehydrantAPIClient.Teams().Create(ctx, createRequest) if err != nil { return diag.Errorf("Error creating team %s: %v", createRequest.Name, err) } @@ -166,7 +166,7 @@ func updateResourceFireHydrantTeam(ctx context.Context, d *schema.ResourceData, tflog.Debug(ctx, fmt.Sprintf("Update team: %s", d.Id()), map[string]interface{}{ "id": d.Id(), }) - _, err := firehydrantAPIClient.UpdateTeam(ctx, d.Id(), updateRequest) + _, err := firehydrantAPIClient.Teams().Update(ctx, d.Id(), updateRequest) if err != nil { return diag.Errorf("Error updating team %s: %v", d.Id(), err) } @@ -184,7 +184,7 @@ func deleteResourceFireHydrantTeam(ctx context.Context, d *schema.ResourceData, tflog.Debug(ctx, fmt.Sprintf("Delete team: %s", teamID), map[string]interface{}{ "id": teamID, }) - err := firehydrantAPIClient.DeleteTeam(ctx, teamID) + err := firehydrantAPIClient.Teams().Archive(ctx, teamID) if err != nil { if errors.Is(err, firehydrant.ErrorNotFound) { return nil diff --git a/provider/team_resource_test.go b/provider/team_resource_test.go index 8f500614..01dca9f1 100644 --- a/provider/team_resource_test.go +++ b/provider/team_resource_test.go @@ -140,7 +140,7 @@ func testAccCheckTeamResourceExistsWithAttributes_basic(resourceName string) res return err } - teamResponse, err := client.GetTeam(context.TODO(), teamResource.Primary.ID) + teamResponse, err := client.Teams().Get(context.TODO(), teamResource.Primary.ID) if err != nil { return err } @@ -173,7 +173,7 @@ func testAccCheckTeamResourceExistsWithAttributes_update(resourceName string) re return err } - teamResponse, err := client.GetTeam(context.TODO(), teamResource.Primary.ID) + teamResponse, err := client.Teams().Get(context.TODO(), teamResource.Primary.ID) if err != nil { return err } @@ -208,7 +208,7 @@ func testAccCheckTeamResourceDestroy() resource.TestCheckFunc { return fmt.Errorf("No instance ID is set") } - _, err := client.GetTeam(context.TODO(), teamResource.Primary.ID) + _, err := client.Teams().Get(context.TODO(), teamResource.Primary.ID) if err == nil { return fmt.Errorf("Team %s still exists", teamResource.Primary.ID) } diff --git a/provider/teams_data.go b/provider/teams_data.go new file mode 100644 index 00000000..234a0307 --- /dev/null +++ b/provider/teams_data.go @@ -0,0 +1,83 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/firehydrant/terraform-provider-firehydrant/firehydrant" + + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceTeams() *schema.Resource { + return &schema.Resource{ + ReadContext: dataFireHydrantTeams, + Schema: map[string]*schema.Schema{ + // Optional + "query": { + Type: schema.TypeString, + Optional: true, + }, + + // Computed + "teams": { + Type: schema.TypeList, + Computed: true, + Elem: dataSourceTeam(), + }, + }, + } +} + +func dataFireHydrantTeams(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + // Get the API client + firehydrantAPIClient := m.(firehydrant.Client) + + // Get the teams + query := d.Get("query").(string) + tflog.Debug(ctx, fmt.Sprintf("Read teams"), map[string]interface{}{ + "query": query, + }) + teamsResponse, err := firehydrantAPIClient.Teams().List(ctx, &firehydrant.TeamQuery{ + Query: query, + }) + if err != nil { + return diag.Errorf("Error reading teams: %v", err) + } + + // Set the data source attributes to the values we got from the API + teams := make([]interface{}, 0) + for _, team := range teamsResponse.Teams { + attributes := map[string]interface{}{ + "id": team.ID, + "name": team.Name, + "description": team.Description, + "slug": team.Slug, + } + + // Collect mapped service IDs + serviceIDs := make([]string, 0) + for _, service := range team.Services { + serviceIDs = append(serviceIDs, service.ID) + } + attributes["service_ids"] = serviceIDs + + // Collect mapped owned service IDs + ownedServiceIDs := make([]string, 0) + for _, ownedService := range team.OwnedServices { + ownedServiceIDs = append(ownedServiceIDs, ownedService.ID) + } + attributes["owned_service_ids"] = ownedServiceIDs + + teams = append(teams, attributes) + } + if err := d.Set("teams", teams); err != nil { + return diag.Errorf("Error setting teams: %v", err) + } + + d.SetId("does-not-matter") + + return diag.Diagnostics{} +} diff --git a/provider/teams_data_test.go b/provider/teams_data_test.go new file mode 100644 index 00000000..7ed4ac03 --- /dev/null +++ b/provider/teams_data_test.go @@ -0,0 +1,69 @@ +package provider + +import ( + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccTeamsDataSource_basic(t *testing.T) { + rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testFireHydrantIsSetup(t) }, + ProviderFactories: defaultProviderFactories(), + Steps: []resource.TestStep{ + { + Config: testAccTeamsDataSourceConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.firehydrant_teams.all_teams", "teams.#"), + testAccCheckTeamsSet("data.firehydrant_teams.all_teams"), + ), + }, + }, + }) +} + +func testAccCheckTeamsSet(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + teamsResource, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Can't find teams resource in state: %s", name) + } + + if teamsResource.Primary.ID == "" { + return fmt.Errorf("Teams resource ID not set") + } + + attributes := teamsResource.Primary.Attributes + teams, teamsOk := attributes["teams.#"] + if !teamsOk { + return fmt.Errorf("Teams list is missing") + } + + teamsCount, err := strconv.Atoi(teams) + if err != nil { + return err + } + + if teamsCount <= 1 { + return fmt.Errorf("Incorrect number of teams - expected at least 1, got %d", teamsCount) + } + + return nil + } +} + +func testAccTeamsDataSourceConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "firehydrant_team" "test_team" { + name = "test-team-%s" +} + +data "firehydrant_teams" "all_teams" { +}`, rName) +}