-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: environment management support
- Loading branch information
Showing
24 changed files
with
917 additions
and
101 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
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,143 @@ | ||
package v2 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/hashicorp/jsonapi" | ||
|
||
hnyclient "github.com/honeycombio/terraform-provider-honeycombio/client" | ||
) | ||
|
||
// Compile-time proof of interface implementation. | ||
var _ Environments = (*environments)(nil) | ||
|
||
type Environments interface { | ||
Create(ctx context.Context, env *Environment) (*Environment, error) | ||
Get(ctx context.Context, id string) (*Environment, error) | ||
Update(ctx context.Context, env *Environment) (*Environment, error) | ||
Delete(ctx context.Context, id string) error | ||
List(ctx context.Context, opts ...ListOption) (*Pager[Environment], error) | ||
} | ||
|
||
type environments struct { | ||
client *Client | ||
authinfo *AuthMetadata | ||
} | ||
|
||
const ( | ||
environmentsPath = "/2/teams/%s/environments" | ||
environmentsByIDPath = "/2/teams/%s/environments/%s" | ||
) | ||
|
||
const ( | ||
EnvironmentColorBlue = "blue" | ||
EnvironmentColorGreen = "green" | ||
EnvironmentColorGold = "gold" | ||
EnvironmentColorRed = "red" | ||
EnvironmentColorPurple = "purple" | ||
EnvironmentColorLightBlue = "lightBlue" | ||
EnvironmentColorLightGreen = "lightGreen" | ||
EnvironmentColorLightGold = "lightGold" | ||
EnvironmentColorLightRed = "lightRed" | ||
EnvironmentColorLightPurple = "lightPurple" | ||
) | ||
|
||
func EnvironmentColorTypes() []string { | ||
return []string{ | ||
EnvironmentColorBlue, | ||
EnvironmentColorGreen, | ||
EnvironmentColorGold, | ||
EnvironmentColorRed, | ||
EnvironmentColorPurple, | ||
EnvironmentColorLightBlue, | ||
EnvironmentColorLightGreen, | ||
EnvironmentColorLightGold, | ||
EnvironmentColorLightRed, | ||
EnvironmentColorLightPurple, | ||
} | ||
} | ||
|
||
func (e *environments) Create(ctx context.Context, env *Environment) (*Environment, error) { | ||
r, err := e.client.Do(ctx, | ||
http.MethodPost, | ||
fmt.Sprintf(environmentsPath, e.authinfo.Team.Slug), | ||
env, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if r.StatusCode != http.StatusCreated { | ||
return nil, hnyclient.ErrorFromResponse(r) | ||
} | ||
|
||
envrion := new(Environment) | ||
if err := jsonapi.UnmarshalPayload(r.Body, envrion); err != nil { | ||
return nil, err | ||
} | ||
return envrion, nil | ||
} | ||
|
||
func (e *environments) Get(ctx context.Context, id string) (*Environment, error) { | ||
r, err := e.client.Do(ctx, | ||
http.MethodGet, | ||
fmt.Sprintf(environmentsByIDPath, e.authinfo.Team.Slug, id), | ||
nil, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if r.StatusCode != http.StatusOK { | ||
return nil, hnyclient.ErrorFromResponse(r) | ||
} | ||
|
||
envrion := new(Environment) | ||
if err := jsonapi.UnmarshalPayload(r.Body, envrion); err != nil { | ||
return nil, err | ||
} | ||
return envrion, nil | ||
} | ||
|
||
func (e *environments) Update(ctx context.Context, env *Environment) (*Environment, error) { | ||
r, err := e.client.Do(ctx, | ||
http.MethodPatch, | ||
fmt.Sprintf(environmentsByIDPath, e.authinfo.Team.Slug, env.ID), | ||
env, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if r.StatusCode != http.StatusOK { | ||
return nil, hnyclient.ErrorFromResponse(r) | ||
} | ||
|
||
envrion := new(Environment) | ||
if err := jsonapi.UnmarshalPayload(r.Body, envrion); err != nil { | ||
return nil, err | ||
} | ||
return envrion, nil | ||
} | ||
|
||
func (e *environments) Delete(ctx context.Context, id string) error { | ||
r, err := e.client.Do(ctx, | ||
http.MethodDelete, | ||
fmt.Sprintf(environmentsByIDPath, e.authinfo.Team.Slug, id), | ||
nil, | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
if r.StatusCode != http.StatusNoContent { | ||
return hnyclient.ErrorFromResponse(r) | ||
} | ||
return nil | ||
} | ||
|
||
func (e *environments) List(ctx context.Context, os ...ListOption) (*Pager[Environment], error) { | ||
return NewPager[Environment]( | ||
e.client, | ||
fmt.Sprintf(environmentsPath, e.authinfo.Team.Slug), | ||
os..., | ||
) | ||
} |
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,141 @@ | ||
package v2 | ||
|
||
import ( | ||
"context" | ||
"math" | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
hnyclient "github.com/honeycombio/terraform-provider-honeycombio/client" | ||
"github.com/honeycombio/terraform-provider-honeycombio/internal/helper" | ||
"github.com/honeycombio/terraform-provider-honeycombio/internal/helper/test" | ||
) | ||
|
||
func TestClient_Environments(t *testing.T) { | ||
ctx := context.Background() | ||
c := newTestClient(t) | ||
|
||
t.Run("happy path", func(t *testing.T) { | ||
// create a new Environment | ||
newEnv := &Environment{ | ||
Name: test.RandomStringWithPrefix("test.", 20), | ||
Description: helper.ToPtr(test.RandomString(50)), | ||
Color: helper.ToPtr(EnvironmentColorBlue), | ||
} | ||
e, err := c.Environments.Create(ctx, newEnv) | ||
require.NoError(t, err) | ||
assert.NotEmpty(t, e.ID) | ||
assert.Equal(t, newEnv.Name, e.Name) | ||
assert.NotEmpty(t, e.Slug) | ||
assert.Equal(t, newEnv.Description, e.Description) | ||
assert.Equal(t, newEnv.Color, e.Color) | ||
if assert.NotNil(t, e.Settings) { | ||
assert.True(t, *e.Settings.DeleteProtected) | ||
} | ||
|
||
// read the Environment back and compare | ||
env, err := c.Environments.Get(ctx, e.ID) | ||
require.NoError(t, err) | ||
assert.Equal(t, e.ID, env.ID) | ||
assert.Equal(t, e.Name, env.Name) | ||
assert.Equal(t, e.Slug, env.Slug) | ||
assert.Equal(t, e.Description, env.Description) | ||
assert.Equal(t, e.Color, env.Color) | ||
if assert.NotNil(t, env.Settings) { | ||
assert.True(t, *env.Settings.DeleteProtected) | ||
} | ||
|
||
// update the Environment's description and color | ||
newDescription := helper.ToPtr(test.RandomString(50)) | ||
env.Description = newDescription | ||
env.Color = helper.ToPtr(EnvironmentColorGreen) | ||
env, err = c.Environments.Update(ctx, env) | ||
require.NoError(t, err) | ||
assert.Equal(t, e.ID, env.ID) | ||
assert.Equal(t, newDescription, env.Description) | ||
assert.Equal(t, EnvironmentColorGreen, *env.Color) | ||
|
||
// try to delete the environment with delete protection enabled | ||
var de hnyclient.DetailedError | ||
err = c.Environments.Delete(ctx, env.ID) | ||
require.ErrorAs(t, err, &de) | ||
assert.Equal(t, http.StatusConflict, de.Status) | ||
|
||
// disable deletion protection and delete the Environment | ||
_, err = c.Environments.Update(ctx, &Environment{ | ||
ID: env.ID, | ||
Settings: &EnvironmentSettings{ | ||
DeleteProtected: helper.ToPtr(false), | ||
}, | ||
}) | ||
require.NoError(t, err) | ||
err = c.Environments.Delete(ctx, env.ID) | ||
require.NoError(t, err) | ||
|
||
// verify the Environment was deleted | ||
_, err = c.Environments.Get(ctx, env.ID) | ||
require.ErrorAs(t, err, &de) | ||
assert.True(t, de.IsNotFound()) | ||
}) | ||
} | ||
|
||
func TestClient_Environments_Pagination(t *testing.T) { | ||
ctx := context.Background() | ||
c := newTestClient(t) | ||
|
||
// create a bunch of environments | ||
numEnvs := int(math.Floor(1.5 * float64(defaultPageSize))) | ||
testEnvs := make([]*Environment, numEnvs) | ||
for i := 0; i < numEnvs; i++ { | ||
e, err := c.Environments.Create(ctx, &Environment{ | ||
Name: test.RandomStringWithPrefix("test.", 20), | ||
}) | ||
require.NoError(t, err) | ||
testEnvs[i] = e | ||
} | ||
t.Cleanup(func() { | ||
for _, e := range testEnvs { | ||
c.Environments.Update(ctx, &Environment{ | ||
ID: e.ID, | ||
Settings: &EnvironmentSettings{ | ||
DeleteProtected: helper.ToPtr(false), | ||
}, | ||
}) | ||
c.Environments.Delete(ctx, e.ID) | ||
} | ||
}) | ||
|
||
t.Run("happy path", func(t *testing.T) { | ||
envs := make([]*Environment, 0) | ||
pager, err := c.Environments.List(ctx) | ||
require.NoError(t, err) | ||
|
||
items, err := pager.Next(ctx) | ||
require.NoError(t, err) | ||
assert.Len(t, items, defaultPageSize, "incorrect number of items") | ||
assert.True(t, pager.HasNext(), "should have more pages") | ||
envs = append(envs, items...) | ||
|
||
for pager.HasNext() { | ||
items, err = pager.Next(ctx) | ||
require.NoError(t, err) | ||
envs = append(envs, items...) | ||
} | ||
// we can't guarantee that there are exactly numEnvs environments | ||
assert.GreaterOrEqual(t, len(envs), numEnvs, "should have at least %d environments", numEnvs) | ||
}) | ||
|
||
t.Run("works with custom page size", func(t *testing.T) { | ||
pageSize := 5 | ||
pager, err := c.Environments.List(ctx, PageSize(pageSize)) | ||
require.NoError(t, err) | ||
|
||
items, err := pager.Next(ctx) | ||
require.NoError(t, err) | ||
assert.Len(t, items, pageSize, "incorrect number of items") | ||
assert.True(t, pager.HasNext(), "should have more pages") | ||
}) | ||
} |
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,35 @@ | ||
# Data Source: honeycombio_environment | ||
|
||
The `honeycombio_environment` data source retrieves the details of a single Environment. | ||
|
||
-> **NOTE** This data source requires the provider be configured with a Management Key with `environments:read` in the configured scopes. | ||
|
||
-> **Note** Terraform will fail unless a single Environment is returned by the search. | ||
Ensure that your search is specific enough to return an Environment. | ||
If you want to match multiple Environments, use the `honeycombio_environments` data source instead. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
# Retrieve the details of a Environment | ||
data "honeycombio_environment" "prod" { | ||
id = "hcaen_01j1d7t02zf7wgw7q89z3t60vf" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `id` - (Required) The ID of the Environment | ||
|
||
## Attribute Reference | ||
|
||
In addition to all arguments above, the following attributes are exported: | ||
|
||
* `name` - the Environment's name. | ||
* `slug` - the Environment's slug. | ||
* `description` - the Environment's description. | ||
* `color` - the Environment's color. | ||
* `delete_protected` - the current state of the Environment's deletion protection status. | ||
|
Oops, something went wrong.