feat: add organization resource
This commit is contained in:
1 parent
cace004114
commit
dfec34e669
2 files changed
+281
No files matched your search
@@ -0,0 +1,167 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
organizationDescriptionKey = "description"
|
||||
organizationNameKey = "name"
|
||||
)
|
||||
|
||||
func resourceOrganization() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOrganizationCreate,
|
||||
Read: resourceOrganizationRead,
|
||||
Update: resourceOrganizationUpdate,
|
||||
Delete: resourceOrganizationDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
organizationNameKey: {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
organizationDescriptionKey: {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// convertOrganizationToResourceData populates the provided ResourceData with the appropriate values from the provided Project.
|
||||
// The organization passed into thie function should be one read from the boundary API with all fields populated.
|
||||
func convertOrganizationToResourceData(o *scopes.Scope, d *schema.ResourceData) error {
|
||||
if o.Name != "" {
|
||||
if err := d.Set(organizationNameKey, o.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if o.Description != "" {
|
||||
if err := d.Set(organizationDescriptionKey, o.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(o.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertResourceDataToOrganization returns a localy built Project using the values provided in the ResourceData.
|
||||
func convertResourceDataToOrganization(d *schema.ResourceData) (*scopes.Scope, error) {
|
||||
o := &scopes.Scope{Scope: &scopes.ScopeInfo{}}
|
||||
|
||||
if descVal, ok := d.GetOk(organizationDescriptionKey); ok {
|
||||
o.Description = descVal.(string)
|
||||
}
|
||||
|
||||
if nameVal, ok := d.GetOk(organizationNameKey); ok {
|
||||
o.Name = nameVal.(string)
|
||||
}
|
||||
|
||||
if d.Id() != "" {
|
||||
o.Id = d.Id()
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func resourceOrganizationCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
md := meta.(*metaData)
|
||||
client := md.client
|
||||
ctx := md.ctx
|
||||
|
||||
scp := scopes.NewScopesClient(client)
|
||||
o, err := convertResourceDataToOrganization(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o, _, err = scp.Create(
|
||||
ctx,
|
||||
client.ScopeId(),
|
||||
scopes.WithName(o.Name),
|
||||
scopes.WithDescription(o.Description))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetId(o.Id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOrganizationRead(d *schema.ResourceData, meta interface{}) error {
|
||||
md := meta.(*metaData)
|
||||
client := md.client
|
||||
ctx := md.ctx
|
||||
|
||||
scp := scopes.NewScopesClient(client)
|
||||
|
||||
o, _, err := scp.Read(ctx, d.Id())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return convertOrganizationToResourceData(o, d)
|
||||
}
|
||||
|
||||
func resourceOrganizationUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
md := meta.(*metaData)
|
||||
client := md.client
|
||||
ctx := md.ctx
|
||||
|
||||
projClient := client.Clone()
|
||||
projClient.SetScopeId(d.Id())
|
||||
scp := scopes.NewScopesClient(projClient)
|
||||
o, err := convertResourceDataToOrganization(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.HasChange(organizationDescriptionKey) {
|
||||
desc := d.Get(organizationDescriptionKey).(string)
|
||||
o.Description = desc
|
||||
}
|
||||
|
||||
if d.HasChange(organizationNameKey) {
|
||||
name := d.Get(organizationNameKey).(string)
|
||||
o.Name = name
|
||||
}
|
||||
|
||||
o, _, err = scp.Update(
|
||||
ctx,
|
||||
d.Id(),
|
||||
0,
|
||||
scopes.WithAutomaticVersioning(),
|
||||
scopes.WithDescription(o.Description),
|
||||
scopes.WithName(o.Name),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return convertOrganizationToResourceData(o, d)
|
||||
}
|
||||
|
||||
func resourceOrganizationDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
md := meta.(*metaData)
|
||||
client := md.client
|
||||
ctx := md.ctx
|
||||
|
||||
projClient := client.Clone()
|
||||
projClient.SetScopeId(d.Id())
|
||||
scp := scopes.NewScopesClient(projClient)
|
||||
o, err := convertResourceDataToOrganization(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _, err = scp.Delete(ctx, o.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed deleting organization: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"github.com/hashicorp/boundary/testing/controller"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||
)
|
||||
|
||||
const (
|
||||
orgFooName = "foo"
|
||||
orgFooDescription = "foo description"
|
||||
orgFooDescriptionUpdate = "foo bar description"
|
||||
)
|
||||
|
||||
var (
|
||||
fooOrg = `
|
||||
resource "boundary_organization" "foo" {}`
|
||||
|
||||
orgFoo = fmt.Sprintf(`
|
||||
resource "boundary_organization" "foo" {
|
||||
name = "%s"
|
||||
description = "%s"
|
||||
}`, orgFooName, orgFooDescription)
|
||||
|
||||
orgFooUpdate = fmt.Sprintf(`
|
||||
resource "boundary_organization" "foo" {
|
||||
name = "%s"
|
||||
description = "%s"
|
||||
}`, orgFooName, orgFooDescriptionUpdate)
|
||||
)
|
||||
|
||||
func TestAccOrganizationCreation(t *testing.T) {
|
||||
tc := controller.NewTestController(t, tcConfig...)
|
||||
defer tc.Shutdown()
|
||||
url := tc.ApiAddrs()[0]
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
Providers: testProviders,
|
||||
CheckDestroy: testAccCheckOrganizationResourceDestroy(t),
|
||||
Steps: []resource.TestStep{
|
||||
// test create
|
||||
{
|
||||
Config: testConfig(url, orgFoo),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckOrganizationResourceExists("boundary_organization.foo"),
|
||||
resource.TestCheckResourceAttr("boundary_organization.foo", organizationNameKey, orgFooName),
|
||||
resource.TestCheckResourceAttr("boundary_organization.foo", organizationDescriptionKey, orgFooDescription),
|
||||
),
|
||||
},
|
||||
// test update
|
||||
{
|
||||
Config: testConfig(url, orgFooUpdate),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckOrganizationResourceExists("boundary_organization.foo"),
|
||||
resource.TestCheckResourceAttr("boundary_organization.foo", organizationNameKey, orgFooName),
|
||||
resource.TestCheckResourceAttr("boundary_organization.foo", organizationDescriptionKey, orgFooDescriptionUpdate),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckOrganizationResourceExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
id := rs.Primary.ID
|
||||
if id == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(id, "o_") {
|
||||
return fmt.Errorf("ID not formatted as expected, expected prefix 'o_', got %s", id)
|
||||
}
|
||||
|
||||
md := testProvider.Meta().(*metaData)
|
||||
scp := scopes.NewScopesClient(md.client)
|
||||
|
||||
if _, _, err := scp.Read(md.ctx, id); err != nil {
|
||||
return fmt.Errorf("Got an error when reading organization %q: %v", id, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckOrganizationResourceDestroy(t *testing.T) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
// retrieve the connection established in Provider configuration
|
||||
md := testProvider.Meta().(*metaData)
|
||||
scp := scopes.NewScopesClient(md.client)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
id := rs.Primary.ID
|
||||
switch rs.Type {
|
||||
case "boundary_organization":
|
||||
if _, apiErr, _ := scp.Read(md.ctx, id); apiErr == nil || apiErr.Status != http.StatusNotFound && apiErr.Status != http.StatusForbidden {
|
||||
return fmt.Errorf("Didn't get a 404 or 403 when reading destroyed organization %q: %v", id, apiErr)
|
||||
}
|
||||
default:
|
||||
t.Logf("Got unknown resource type %q", rs.Type)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user