-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new resource
consul_namespace_role_attachment
Discussion: #247
- Loading branch information
1 parent
bc4fb54
commit e3f2d45
Showing
6 changed files
with
362 additions
and
13 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package consul | ||
|
||
import ( | ||
"fmt" | ||
|
||
consulapi "github.com/hashicorp/consul/api" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
) | ||
|
||
func resourceConsulNamespaceRoleAttachment() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceConsulNamespaceRoleAttachmentCreate, | ||
Read: resourceConsulNamespaceRoleAttachmentRead, | ||
Delete: resourceConsulNamespaceRoleAttachmentDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"namespace": { | ||
Type: schema.TypeString, | ||
ForceNew: true, | ||
Required: true, | ||
Description: "The namespace to attach the role to.", | ||
}, | ||
"role": { | ||
Type: schema.TypeString, | ||
ForceNew: true, | ||
Required: true, | ||
Description: "The role name.", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceConsulNamespaceRoleAttachmentCreate(d *schema.ResourceData, meta interface{}) error { | ||
client, qOpts, wOpts := getClient(d, meta) | ||
|
||
name := d.Get("namespace").(string) | ||
role := d.Get("role").(string) | ||
|
||
namespace, err := findNamespace(client, qOpts, name) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, r := range namespace.ACLs.RoleDefaults { | ||
if r.Name == role { | ||
return fmt.Errorf("Role %q already attached to the namespace", role) | ||
} | ||
} | ||
|
||
namespace.ACLs.RoleDefaults = append(namespace.ACLs.RoleDefaults, consulapi.ACLLink{ | ||
Name: role, | ||
}) | ||
|
||
_, _, err = client.Namespaces().Update(namespace, wOpts) | ||
if err != nil { | ||
return fmt.Errorf("Failed to update namespace %q to attach role %q: %s", name, role, err) | ||
} | ||
|
||
d.SetId(fmt.Sprintf("%s:%s", name, role)) | ||
|
||
return resourceConsulNamespaceRoleAttachmentRead(d, meta) | ||
} | ||
|
||
func resourceConsulNamespaceRoleAttachmentRead(d *schema.ResourceData, meta interface{}) error { | ||
client, qOpts, _ := getClient(d, meta) | ||
|
||
name, role, err := parseTwoPartID(d.Id(), "namespace", "role") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
namespace, _, err := client.Namespaces().Read(name, qOpts) | ||
if err != nil { | ||
return fmt.Errorf("Failed to read namespace %q: %s", name, err) | ||
} | ||
if namespace == nil { | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
var found bool | ||
for _, l := range namespace.ACLs.RoleDefaults { | ||
if l.Name == role { | ||
found = true | ||
break | ||
} | ||
} | ||
|
||
if !found { | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
if err = d.Set("namespace", name); err != nil { | ||
return fmt.Errorf("Failed to set 'namespace': %s", err) | ||
} | ||
if err = d.Set("role", role); err != nil { | ||
return fmt.Errorf("Failed to set 'role': %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceConsulNamespaceRoleAttachmentDelete(d *schema.ResourceData, meta interface{}) error { | ||
client, qOpts, wOpts := getClient(d, meta) | ||
name, role, err := parseTwoPartID(d.Id(), "namespace", "role") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
namespace, err := findNamespace(client, qOpts, name) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for i, p := range namespace.ACLs.RoleDefaults { | ||
if p.Name == role { | ||
namespace.ACLs.RoleDefaults = append( | ||
namespace.ACLs.RoleDefaults[:i], | ||
namespace.ACLs.RoleDefaults[i+1:]..., | ||
) | ||
break | ||
} | ||
} | ||
|
||
_, _, err = client.Namespaces().Update(namespace, wOpts) | ||
if err != nil { | ||
return fmt.Errorf("Failed to remove role %q from namespace %q", role, name) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func findNamespace(client *consulapi.Client, qOpts *consulapi.QueryOptions, name string) (*consulapi.Namespace, error) { | ||
namespace, _, err := client.Namespaces().Read(name, qOpts) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to read namespace %q: %s", name, err) | ||
} | ||
|
||
if namespace == nil { | ||
return nil, fmt.Errorf("Namespace %q not found", name) | ||
} | ||
|
||
return namespace, nil | ||
} |
108 changes: 108 additions & 0 deletions
108
consul/resource_consul_namespace_role_attachment_test.go
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,108 @@ | ||
package consul | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/terraform" | ||
) | ||
|
||
func TestAccConsulNamespaceRoleAttachment(t *testing.T) { | ||
testRole := func(name string) func(*terraform.State) error { | ||
return func(s *terraform.State) error { | ||
client := getTestClient(testAccProvider.Meta()) | ||
namespace, _, err := client.Namespaces().Read("testroleattachment", nil) | ||
if err != nil { | ||
return fmt.Errorf("failed to read namespace testroleattachment: %s", err) | ||
} | ||
if namespace == nil { | ||
return fmt.Errorf("namespace testroleattachment not found") | ||
} | ||
if len(namespace.ACLs.RoleDefaults) != 1 { | ||
return fmt.Errorf("wrong number of roles: %d", len(namespace.ACLs.RoleDefaults)) | ||
} | ||
if namespace.ACLs.RoleDefaults[0].Name != name { | ||
return fmt.Errorf("wrong role, expected %q, found %q", name, namespace.ACLs.RoleDefaults[0].Name) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
resource.Test(t, resource.TestCase{ | ||
Providers: testAccProviders, | ||
PreCheck: func() { skipTestOnConsulCommunityEdition(t) }, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testResourceNamespaceRoleConfig, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("consul_namespace_role_attachment.test", "namespace", "testroleattachment"), | ||
resource.TestCheckResourceAttr("consul_namespace_role_attachment.test", "role", "role"), | ||
testRole("role"), | ||
), | ||
}, | ||
{ | ||
Config: testResourceNamespaceRoleConfigUpdate, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("consul_namespace_role_attachment.test", "namespace", "testroleattachment"), | ||
resource.TestCheckResourceAttr("consul_namespace_role_attachment.test", "role", "role2"), | ||
testRole("role2"), | ||
), | ||
}, | ||
{ | ||
Config: testResourceNamespaceRoleConfigUpdate, | ||
}, | ||
{ | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
ResourceName: "consul_namespace_role_attachment.test", | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
const testResourceNamespaceRoleConfig = ` | ||
resource "consul_namespace" "test" { | ||
name = "testroleattachment" | ||
lifecycle { | ||
ignore_changes = [role_defaults] | ||
} | ||
} | ||
resource "consul_acl_role" "test" { | ||
name = "role" | ||
service_identities { | ||
service_name = "foo" | ||
} | ||
} | ||
resource "consul_namespace_role_attachment" "test" { | ||
namespace = consul_namespace.test.name | ||
role = consul_acl_role.test.name | ||
} | ||
` | ||
|
||
const testResourceNamespaceRoleConfigUpdate = ` | ||
resource "consul_namespace" "test" { | ||
name = "testroleattachment" | ||
lifecycle { | ||
ignore_changes = [role_defaults] | ||
} | ||
} | ||
resource "consul_acl_role" "test2" { | ||
name = "role2" | ||
service_identities { | ||
service_name = "foo" | ||
} | ||
} | ||
resource "consul_namespace_role_attachment" "test" { | ||
namespace = consul_namespace.test.name | ||
role = consul_acl_role.test2.name | ||
} | ||
` |
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
Oops, something went wrong.