diff --git a/consul/data_source_consul_acl_role.go b/consul/data_source_consul_acl_role.go index b8a4b625..7feee63d 100644 --- a/consul/data_source_consul_acl_role.go +++ b/consul/data_source_consul_acl_role.go @@ -16,16 +16,19 @@ func dataSourceConsulACLRole() *schema.Resource { Type: schema.TypeString, Required: true, }, + "namespace": { + Type: schema.TypeString, + Optional: true, + }, // Out parameters "description": { Type: schema.TypeString, - Optional: true, + Computed: true, }, - "policies": { Type: schema.TypeList, - Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { @@ -39,10 +42,9 @@ func dataSourceConsulACLRole() *schema.Resource { }, }, }, - "service_identities": { Type: schema.TypeList, - Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "service_name": { @@ -58,10 +60,21 @@ func dataSourceConsulACLRole() *schema.Resource { }, }, }, - - "namespace": { - Type: schema.TypeString, - Optional: true, + "node_identities": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node_name": { + Type: schema.TypeString, + Computed: true, + }, + "datacenter": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, }, }, } @@ -79,11 +92,6 @@ func datasourceConsulACLRoleRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Could not find role '%s'", name) } - d.SetId(role.ID) - if err = d.Set("description", role.Description); err != nil { - return fmt.Errorf("Failed to set 'description': %v", err) - } - policies := make([]map[string]interface{}, len(role.Policies)) for i, p := range role.Policies { policies[i] = map[string]interface{}{ @@ -91,9 +99,6 @@ func datasourceConsulACLRoleRead(d *schema.ResourceData, meta interface{}) error "id": p.ID, } } - if err = d.Set("policies", policies); err != nil { - return fmt.Errorf("Failed to set 'policies': %v", err) - } identities := make([]map[string]interface{}, len(role.ServiceIdentities)) for i, si := range role.ServiceIdentities { @@ -102,9 +107,22 @@ func datasourceConsulACLRoleRead(d *schema.ResourceData, meta interface{}) error "datacenters": si.Datacenters, } } - if err = d.Set("service_identities", identities); err != nil { - return fmt.Errorf("Failed to set 'service_identities': %v", err) + + nodeIdentities := make([]interface{}, len(role.NodeIdentities)) + for i, ni := range role.NodeIdentities { + nodeIdentities[i] = map[string]interface{}{ + "node_name": ni.NodeName, + "datacenter": ni.Datacenter, + } } - return nil + d.SetId(role.ID) + + sw := newStateWriter(d) + sw.set("description", role.Description) + sw.set("policies", policies) + sw.set("service_identities", identities) + sw.set("node_identities", nodeIdentities) + + return sw.error() } diff --git a/consul/data_source_consul_acl_role_test.go b/consul/data_source_consul_acl_role_test.go index 71637b61..7d607bd1 100644 --- a/consul/data_source_consul_acl_role_test.go +++ b/consul/data_source_consul_acl_role_test.go @@ -18,15 +18,19 @@ func TestAccDataACLRole_basic(t *testing.T) { }, { Config: testAccDataSourceACLRoleConfigBasic, - Check: resource.ComposeTestCheckFunc( - testAccCheckDataSourceValue("data.consul_acl_role.test", "name", "foo"), - testAccCheckDataSourceValue("data.consul_acl_role.test", "description", "bar"), - testAccCheckDataSourceValue("data.consul_acl_role.test", "policies.#", "1"), - testAccCheckDataSourceValue("data.consul_acl_role.test", "policies.0.id", ""), - testAccCheckDataSourceValue("data.consul_acl_role.test", "policies.0.name", "test"), - testAccCheckDataSourceValue("data.consul_acl_role.test", "service_identities.#", "1"), - testAccCheckDataSourceValue("data.consul_acl_role.test", "service_identities.0.service_name", "foo"), - testAccCheckDataSourceValue("data.consul_acl_role.test", "service_identities.0.datacenters.#", "0"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.consul_acl_role.test", "description", "bar"), + resource.TestCheckResourceAttrSet("data.consul_acl_role.test", "id"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "name", "foo"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "node_identities.#", "1"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "node_identities.0.datacenter", "world"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "node_identities.0.node_name", "hello"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "policies.#", "1"), + resource.TestCheckResourceAttrSet("data.consul_acl_role.test", "policies.0.id"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "policies.0.name", "test"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "service_identities.#", "1"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "service_identities.0.datacenters.#", "0"), + resource.TestCheckResourceAttr("data.consul_acl_role.test", "service_identities.0.service_name", "foo"), ), }, }, @@ -82,6 +86,11 @@ resource "consul_acl_role" "test" { service_identities { service_name = "foo" } + + node_identities { + node_name = "hello" + datacenter = "world" + } } data "consul_acl_role" "test" { diff --git a/consul/data_source_consul_acl_token.go b/consul/data_source_consul_acl_token.go index ef2b63e0..10c111e0 100644 --- a/consul/data_source_consul_acl_token.go +++ b/consul/data_source_consul_acl_token.go @@ -1,7 +1,7 @@ package consul import ( - "fmt" + "time" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -17,16 +17,19 @@ func dataSourceConsulACLToken() *schema.Resource { Required: true, Type: schema.TypeString, }, + "namespace": { + Type: schema.TypeString, + Optional: true, + }, // Out parameters "description": { Type: schema.TypeString, - Optional: true, + Computed: true, }, - "policies": { Type: schema.TypeList, - Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { @@ -40,15 +43,72 @@ func dataSourceConsulACLToken() *schema.Resource { }, }, }, - + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + Description: "List of roles.", + }, + "service_identities": { + Type: schema.TypeList, + Computed: true, + Description: "The list of service identities that should be applied to the token.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the service.", + }, + "datacenters": { + Type: schema.TypeList, + Computed: true, + Description: "Specifies the datacenters the effective policy is valid within.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "node_identities": { + Type: schema.TypeList, + Computed: true, + Description: "The list of node identities that should be applied to the token.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node_name": { + Type: schema.TypeString, + Computed: true, + Description: "The list of node identities that should be applied to the token.", + }, + "datacenter": { + Type: schema.TypeString, + Computed: true, + Description: "Specifies the node's datacenter.", + }, + }, + }, + }, "local": { Type: schema.TypeBool, - Optional: true, + Computed: true, }, - - "namespace": { - Type: schema.TypeString, - Optional: true, + "expiration_time": { + Type: schema.TypeString, + Computed: true, + Description: "If set this represents the point after which a token should be considered revoked and is eligible for destruction.", }, }, } @@ -71,16 +131,45 @@ func dataSourceConsulACLTokenRead(d *schema.ResourceData, meta interface{}) erro } } - d.SetId(accessorID) - if err = d.Set("description", aclToken.Description); err != nil { - return fmt.Errorf("Error while setting 'description': %s", err) + roles := make([]interface{}, len(aclToken.Roles)) + for i, r := range aclToken.Roles { + roles[i] = map[string]interface{}{ + "id": r.ID, + "name": r.Name, + } } - if err = d.Set("local", aclToken.Local); err != nil { - return fmt.Errorf("Error while setting 'local': %s", err) + + serviceIdentities := make([]map[string]interface{}, len(aclToken.ServiceIdentities)) + for i, si := range aclToken.ServiceIdentities { + serviceIdentities[i] = map[string]interface{}{ + "service_name": si.ServiceName, + "datacenters": si.Datacenters, + } } - if err = d.Set("policies", policies); err != nil { - return fmt.Errorf("Error while setting 'policies': %s", err) + + nodeIdentities := make([]map[string]interface{}, len(aclToken.NodeIdentities)) + for i, ni := range aclToken.NodeIdentities { + nodeIdentities[i] = map[string]interface{}{ + "node_name": ni.NodeName, + "datacenter": ni.Datacenter, + } + } + + var expirationTime string + if aclToken.ExpirationTime != nil { + expirationTime = aclToken.ExpirationTime.Format(time.RFC3339) } - return nil + d.SetId(accessorID) + + sw := newStateWriter(d) + sw.set("description", aclToken.Description) + sw.set("local", aclToken.Local) + sw.set("policies", policies) + sw.set("roles", roles) + sw.set("service_identities", serviceIdentities) + sw.set("node_identities", nodeIdentities) + sw.set("expiration_time", expirationTime) + + return sw.error() } diff --git a/consul/data_source_consul_acl_token_test.go b/consul/data_source_consul_acl_token_test.go index 6dd182ef..21286fd2 100644 --- a/consul/data_source_consul_acl_token_test.go +++ b/consul/data_source_consul_acl_token_test.go @@ -13,12 +13,23 @@ func TestAccDataACLToken_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccDataACLTokenConfig, - Check: resource.ComposeTestCheckFunc( - testAccCheckDataSourceValue("data.consul_acl_token.read", "description", "test"), - testAccCheckDataSourceValue("data.consul_acl_token.read", "policies.#", "1"), - testAccCheckDataSourceValue("data.consul_acl_token.read", "policies.0.name", "test"), - testAccCheckDataSourceValue("data.consul_acl_token.read", "policies.0.id", ""), - testAccCheckDataSourceValue("data.consul_acl_token.read", "local", "true"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.consul_acl_token.read", "accessor_id"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "description", "test"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "expiration_time", ""), + resource.TestCheckResourceAttrSet("data.consul_acl_token.read", "id"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "local", "false"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "node_identities.#", "1"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "node_identities.0.datacenter", "bar"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "node_identities.0.node_name", "foo"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "policies.#", "1"), + resource.TestCheckResourceAttrSet("data.consul_acl_token.read", "policies.0.id"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "policies.0.name", "test"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "roles.#", "0"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "service_identities.#", "1"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "service_identities.0.datacenters.#", "1"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "service_identities.0.datacenters.0", "world"), + resource.TestCheckResourceAttr("data.consul_acl_token.read", "service_identities.0.service_name", "hello"), ), }, }, @@ -60,7 +71,17 @@ resource "consul_acl_policy" "test" { resource "consul_acl_token" "test" { description = "test" policies = ["${consul_acl_policy.test.name}"] - local = true + local = false + + service_identities { + service_name = "hello" + datacenters = ["world"] + } + + node_identities { + node_name = "foo" + datacenter = "bar" + } } data "consul_acl_token" "read" { diff --git a/consul/resource_consul_acl_role.go b/consul/resource_consul_acl_role.go index 3cc9eb5f..93fff12b 100644 --- a/consul/resource_consul_acl_role.go +++ b/consul/resource_consul_acl_role.go @@ -23,13 +23,11 @@ func resourceConsulACLRole() *schema.Resource { Required: true, Description: "The name of the ACL role.", }, - "description": { Type: schema.TypeString, Optional: true, Description: "A free form human readable description of the role.", }, - "policies": { Type: schema.TypeSet, Optional: true, @@ -38,7 +36,6 @@ func resourceConsulACLRole() *schema.Resource { }, Description: "The list of policies that should be applied to the role.", }, - "service_identities": { Type: schema.TypeSet, Optional: true, @@ -60,7 +57,25 @@ func resourceConsulACLRole() *schema.Resource { }, Description: "The list of service identities that should be applied to the role.", }, - + "node_identities": { + Type: schema.TypeList, + Optional: true, + Description: "The list of node identities that should be applied to the role.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the node.", + }, + "datacenter": { + Type: schema.TypeString, + Required: true, + Description: "Specifies the node's datacenter.", + }, + }, + }, + }, "namespace": { Type: schema.TypeString, Optional: true, @@ -98,28 +113,10 @@ func resourceConsulACLRoleRead(d *schema.ResourceData, meta interface{}) error { return nil } - if err = d.Set("name", role.Name); err != nil { - return fmt.Errorf("Failed to set 'name': %s", err) - } - - if err = d.Set("description", role.Description); err != nil { - return fmt.Errorf("Failed to set 'description': %s", err) - } - // Consul Enterprise will change "" to "default" but Community Edition only - // understands the first one. - if d.Get("namespace").(string) != "" || role.Namespace != "default" { - if err = d.Set("namespace", role.Namespace); err != nil { - return fmt.Errorf("failed to set 'namespace': %v", err) - } - } - policies := make([]string, len(role.Policies)) for i, policy := range role.Policies { policies[i] = policy.ID } - if err = d.Set("policies", policies); err != nil { - return fmt.Errorf("Failed to set 'policies': %s", err) - } serviceIdentities := make([]map[string]interface{}, len(role.ServiceIdentities)) for i, serviceIdentity := range role.ServiceIdentities { @@ -128,11 +125,32 @@ func resourceConsulACLRoleRead(d *schema.ResourceData, meta interface{}) error { "datacenters": serviceIdentity.Datacenters, } } - if err = d.Set("service_identities", serviceIdentities); err != nil { - return fmt.Errorf("Failed to set 'service_identities': %s", err) + + nodeIdentities := make([]interface{}, len(role.NodeIdentities)) + for i, ni := range role.NodeIdentities { + nodeIdentities[i] = map[string]interface{}{ + "node_name": ni.NodeName, + "datacenter": ni.Datacenter, + } } - return nil + sw := newStateWriter(d) + + // Consul Enterprise will change "" to "default" but Community Edition only + // understands the first one. + if d.Get("namespace").(string) != "" || role.Namespace != "default" { + if err = d.Set("namespace", role.Namespace); err != nil { + return fmt.Errorf("failed to set 'namespace': %v", err) + } + } + + sw.set("name", role.Name) + sw.set("description", role.Description) + sw.set("policies", policies) + sw.set("service_identities", serviceIdentities) + sw.set("node_identities", nodeIdentities) + + return sw.error() } func resourceConsulACLRoleUpdate(d *schema.ResourceData, meta interface{}) error { @@ -179,7 +197,6 @@ func getRole(d *schema.ResourceData, meta interface{}) *consulapi.ACLRole { } role.Policies = policies - serviceIdentities := make([]*consulapi.ACLServiceIdentity, 0) for _, raw := range d.Get("service_identities").(*schema.Set).List() { s := raw.(map[string]interface{}) @@ -188,12 +205,19 @@ func getRole(d *schema.ResourceData, meta interface{}) *consulapi.ACLRole { datacenters[i] = d.(string) } - serviceIdentities = append(serviceIdentities, &consulapi.ACLServiceIdentity{ + role.ServiceIdentities = append(role.ServiceIdentities, &consulapi.ACLServiceIdentity{ ServiceName: s["service_name"].(string), Datacenters: datacenters, }) } - role.ServiceIdentities = serviceIdentities + + for _, ni := range d.Get("node_identities").([]interface{}) { + n := ni.(map[string]interface{}) + role.NodeIdentities = append(role.NodeIdentities, &consulapi.ACLNodeIdentity{ + NodeName: n["node_name"].(string), + Datacenter: n["datacenter"].(string), + }) + } return role } diff --git a/consul/resource_consul_acl_role_test.go b/consul/resource_consul_acl_role_test.go index 0d3c6c12..de4e73a7 100644 --- a/consul/resource_consul_acl_role_test.go +++ b/consul/resource_consul_acl_role_test.go @@ -18,58 +18,39 @@ func TestAccConsulACLRole_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testResourceACLRoleConfigBasic, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("consul_acl_role.test", "name", "foo"), + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("consul_acl_role.test", "description", "bar"), + resource.TestCheckResourceAttrSet("consul_acl_role.test", "id"), + resource.TestCheckResourceAttr("consul_acl_role.test", "name", "foo"), + resource.TestCheckResourceAttr("consul_acl_role.test", "namespace", ""), + resource.TestCheckResourceAttr("consul_acl_role.test", "node_identities.#", "0"), resource.TestCheckResourceAttr("consul_acl_role.test", "policies.#", "1"), resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.#", "1"), + resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.3690720679.datacenters.#", "0"), + resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.3690720679.service_name", "foo"), ), }, { Config: testResourceACLRoleConfigUpdate, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("consul_acl_role.test", "name", "baz"), + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("consul_acl_role.test", "description", ""), + resource.TestCheckResourceAttrSet("consul_acl_role.test", "id"), + resource.TestCheckResourceAttr("consul_acl_role.test", "name", "baz"), + resource.TestCheckResourceAttr("consul_acl_role.test", "namespace", ""), + resource.TestCheckResourceAttr("consul_acl_role.test", "node_identities.#", "1"), + resource.TestCheckResourceAttr("consul_acl_role.test", "node_identities.0.datacenter", "world"), + resource.TestCheckResourceAttr("consul_acl_role.test", "node_identities.0.node_name", "hello"), resource.TestCheckResourceAttr("consul_acl_role.test", "policies.#", "0"), resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.#", "1"), + resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.2708159462.datacenters.#", "0"), + resource.TestCheckResourceAttr("consul_acl_role.test", "service_identities.2708159462.service_name", "bar"), ), }, - }, - }) -} - -func TestAccConsulACLRole_import(t *testing.T) { - checkFn := func(s []*terraform.InstanceState) error { - if len(s) != 1 { - return fmt.Errorf("bad state: %s", s) - } - v, ok := s[0].Attributes["name"] - if !ok || v != "foo" { - return fmt.Errorf("bad name: %s", s) - } - v, ok = s[0].Attributes["description"] - if !ok || v != "bar" { - return fmt.Errorf("bad description: %s", s) - } - v, ok = s[0].Attributes["policies.#"] - if !ok || v != "1" { - return fmt.Errorf("bad policies: %s", s) - } - - return nil - } - - resource.Test(t, resource.TestCase{ - Providers: testAccProviders, - PreCheck: func() { testAccPreCheck(t) }, - Steps: []resource.TestStep{ - { - Config: testResourceACLRoleConfigBasic, - }, { - ResourceName: "consul_acl_role.test", - ImportState: true, - ImportStateCheck: checkFn, + Config: testResourceACLRoleConfigUpdate, + ResourceName: "consul_acl_role.test", + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -143,6 +124,11 @@ resource "consul_acl_role" "test" { service_identities { service_name = "bar" } + + node_identities { + node_name = "hello" + datacenter = "world" + } }` const testResourceACLRoleNamespaceCE = ` diff --git a/consul/resource_consul_acl_token.go b/consul/resource_consul_acl_token.go index 56fac9ed..9517f064 100644 --- a/consul/resource_consul_acl_token.go +++ b/consul/resource_consul_acl_token.go @@ -4,9 +4,11 @@ import ( "fmt" "log" "strings" + "time" consulapi "github.com/hashicorp/consul/api" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceConsulACLToken() *schema.Resource { @@ -48,14 +50,60 @@ func resourceConsulACLToken() *schema.Resource { }, Description: "List of roles", }, + "service_identities": { + Type: schema.TypeList, + Optional: true, + Description: "The list of service identities that should be applied to the token.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the service.", + }, + "datacenters": { + Type: schema.TypeList, + Optional: true, + Description: "Specifies the datacenters the effective policy is valid within.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "node_identities": { + Type: schema.TypeList, + Optional: true, + Description: "The list of node identities that should be applied to the token.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the node.", + }, + "datacenter": { + Type: schema.TypeString, + Required: true, + Description: "Specifies the node's datacenter.", + }, + }, + }, + }, "local": { Type: schema.TypeBool, ForceNew: true, Optional: true, - Default: false, Description: "Flag to set the token local to the current datacenter.", }, - + "expiration_time": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.ValidateRFC3339TimeString, + Description: "If set this represents the point after which a token should be considered revoked and is eligible for destruction.", + }, "namespace": { Type: schema.TypeString, Optional: true, @@ -102,12 +150,9 @@ func resourceConsulACLTokenRead(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] Read ACL token %q", id) - if err = d.Set("accessor_id", aclToken.AccessorID); err != nil { - return fmt.Errorf("Error while setting 'accessor_id': %s", err) - } - - if err = d.Set("description", aclToken.Description); err != nil { - return fmt.Errorf("Error while setting 'description': %s", err) + roles := make([]string, 0, len(aclToken.Roles)) + for _, roleLink := range aclToken.Roles { + roles = append(roles, roleLink.Name) } policies := make([]string, 0, len(aclToken.Policies)) @@ -115,24 +160,37 @@ func resourceConsulACLTokenRead(d *schema.ResourceData, meta interface{}) error policies = append(policies, policyLink.Name) } - if err = d.Set("policies", policies); err != nil { - return fmt.Errorf("Error while setting 'policies': %s", err) + var expirationTime string + if aclToken.ExpirationTime != nil { + expirationTime = aclToken.ExpirationTime.Format(time.RFC3339) } - roles := make([]string, 0, len(aclToken.Roles)) - for _, roleLink := range aclToken.Roles { - roles = append(roles, roleLink.Name) - } - - if err = d.Set("roles", roles); err != nil { - return fmt.Errorf("Error while setting 'roles': %s", err) + serviceIdentities := make([]interface{}, len(aclToken.ServiceIdentities)) + for i, si := range aclToken.ServiceIdentities { + serviceIdentities[i] = map[string]interface{}{ + "service_name": si.ServiceName, + "datacenters": si.Datacenters, + } } - - if err = d.Set("local", aclToken.Local); err != nil { - return fmt.Errorf("Error while setting 'local': %s", err) + nodeIdentities := make([]interface{}, len(aclToken.NodeIdentities)) + for i, ni := range aclToken.NodeIdentities { + nodeIdentities[i] = map[string]interface{}{ + "node_name": ni.NodeName, + "datacenter": ni.Datacenter, + } } - return nil + sw := newStateWriter(d) + sw.set("accessor_id", aclToken.AccessorID) + sw.set("description", aclToken.Description) + sw.set("policies", policies) + sw.set("roles", roles) + sw.set("service_identities", serviceIdentities) + sw.set("node_identities", nodeIdentities) + sw.set("local", aclToken.Local) + sw.set("expiration_time", expirationTime) + + return sw.error() } func resourceConsulACLTokenUpdate(d *schema.ResourceData, meta interface{}) error { @@ -193,5 +251,40 @@ func getToken(d *schema.ResourceData) *consulapi.ACLToken { } aclToken.Roles = roleLinks + serviceIdentities := []*consulapi.ACLServiceIdentity{} + for _, si := range d.Get("service_identities").([]interface{}) { + s := si.(map[string]interface{}) + + datacenters := []string{} + for _, d := range s["datacenters"].([]interface{}) { + datacenters = append(datacenters, d.(string)) + } + + serviceIdentities = append(serviceIdentities, &consulapi.ACLServiceIdentity{ + ServiceName: s["service_name"].(string), + Datacenters: datacenters, + }) + } + aclToken.ServiceIdentities = serviceIdentities + + nodeIdentities := []*consulapi.ACLNodeIdentity{} + for _, ni := range d.Get("node_identities").([]interface{}) { + n := ni.(map[string]interface{}) + + nodeIdentities = append(nodeIdentities, &consulapi.ACLNodeIdentity{ + NodeName: n["node_name"].(string), + Datacenter: n["datacenter"].(string), + }) + } + aclToken.NodeIdentities = nodeIdentities + + expirationTime := d.Get("expiration_time").(string) + if expirationTime != "" { + // the string has already been validated so there is no need to check + // the error here + t, _ := time.Parse(time.RFC3339, expirationTime) + aclToken.ExpirationTime = &t + } + return aclToken } diff --git a/consul/resource_consul_acl_token_test.go b/consul/resource_consul_acl_token_test.go index 1df8974d..b0b52c4b 100644 --- a/consul/resource_consul_acl_token_test.go +++ b/consul/resource_consul_acl_token_test.go @@ -32,22 +32,35 @@ func TestAccConsulACLToken_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testResourceACLTokenConfigBasic, - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("consul_acl_token.test", "accessor_id"), resource.TestCheckResourceAttr("consul_acl_token.test", "description", "test"), - resource.TestCheckResourceAttr("consul_acl_token.test", "roles.#", "0"), - resource.TestCheckResourceAttr("consul_acl_token.test", "policies.#", "1"), + resource.TestCheckResourceAttr("consul_acl_token.test", "expiration_time", ""), + resource.TestCheckResourceAttrSet("consul_acl_token.test", "id"), + resource.TestCheckResourceAttrSet("consul_acl_token.test", "local"), + resource.TestCheckResourceAttr("consul_acl_token.test", "node_identities.#", "0"), + resource.TestCheckResourceAttrSet("consul_acl_token.test", "policies.#"), resource.TestCheckResourceAttr("consul_acl_token.test", "policies.1785148924", "test"), - resource.TestCheckResourceAttr("consul_acl_token.test", "local", "true"), + resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.#", "0"), ), }, { Config: testResourceACLTokenConfigUpdate, - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("consul_acl_token.test", "accessor_id"), resource.TestCheckResourceAttr("consul_acl_token.test", "description", "test"), - resource.TestCheckResourceAttr("consul_acl_token.test", "roles.#", "0"), + resource.TestCheckResourceAttr("consul_acl_token.test", "expiration_time", ""), + resource.TestCheckResourceAttrSet("consul_acl_token.test", "id"), + resource.TestCheckResourceAttr("consul_acl_token.test", "local", "false"), + resource.TestCheckResourceAttr("consul_acl_token.test", "node_identities.#", "1"), + resource.TestCheckResourceAttr("consul_acl_token.test", "node_identities.0.datacenter", "bar"), + resource.TestCheckResourceAttr("consul_acl_token.test", "node_identities.0.node_name", "foo"), resource.TestCheckResourceAttr("consul_acl_token.test", "policies.#", "1"), resource.TestCheckResourceAttr("consul_acl_token.test", "policies.111830242", "test2"), - resource.TestCheckResourceAttr("consul_acl_token.test", "local", "false"), + resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.#", "1"), + resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.0.datacenters.#", "1"), + resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.0.datacenters.0", "world"), + resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.0.service_name", "hello"), ), }, { @@ -55,10 +68,17 @@ func TestAccConsulACLToken_basic(t *testing.T) { }, { Config: testResourceACLTokenConfigRole, - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("consul_acl_token.test", "accessor_id"), resource.TestCheckResourceAttr("consul_acl_token.test", "description", "test"), + resource.TestCheckResourceAttr("consul_acl_token.test", "expiration_time", ""), + resource.TestCheckResourceAttrSet("consul_acl_token.test", "id"), + resource.TestCheckResourceAttr("consul_acl_token.test", "local", "false"), + resource.TestCheckResourceAttr("consul_acl_token.test", "node_identities.#", "0"), + resource.TestCheckResourceAttr("consul_acl_token.test", "policies.#", "0"), resource.TestCheckResourceAttr("consul_acl_token.test", "roles.#", "1"), resource.TestCheckResourceAttr("consul_acl_token.test", "roles.1785148924", "test"), + resource.TestCheckResourceAttr("consul_acl_token.test", "service_identities.#", "0"), ), }, }, @@ -151,6 +171,16 @@ resource "consul_acl_policy" "test2" { resource "consul_acl_token" "test" { description = "test" policies = ["${consul_acl_policy.test2.name}"] + + service_identities { + service_name = "hello" + datacenters = ["world"] + } + + node_identities { + node_name = "foo" + datacenter = "bar" + } }` const testResourceACLTokenConfigRole = ` diff --git a/website/docs/d/acl_role.html.markdown b/website/docs/d/acl_role.html.markdown index d0435315..f4d6ea24 100644 --- a/website/docs/d/acl_role.html.markdown +++ b/website/docs/d/acl_role.html.markdown @@ -35,8 +35,9 @@ The following arguments are supported: The following attributes are exported: +* `name` - The name of the ACL Role. +* `namespace` - The namespace to lookup the role. * `description` - The description of the ACL Role. -* `policies` - The list of policies associated with the ACL Role. Each entry has - an `id` and a `name` attribute. -* `service_identities` - The list of service identities associated with the ACL - Role. Each entry has a `service_name` attribute and a list of `datacenters`. +* `policies` - The list of policies associated with the ACL Role. Each entry has an `id` and a `name` attribute. +* `service_identities` - The list of service identities associated with the ACL Role. Each entry has a `service_name` attribute and a list of `datacenters`. +* `node_identities` - The list of node identities associated with the ACL Role. Each entry has a `node_name` and a `datacenter` attributes. diff --git a/website/docs/d/acl_token.html.markdown b/website/docs/d/acl_token.html.markdown index 736a7b53..dc962f99 100644 --- a/website/docs/d/acl_token.html.markdown +++ b/website/docs/d/acl_token.html.markdown @@ -39,6 +39,9 @@ The following arguments are supported: The following attributes are exported: * `description` - The description of the ACL token. -* `policies` - A list of policies associated with the ACL token. Each entry has - an `id` and a `name` attribute. +* `policies` - A list of policies associated with the ACL token. Each entry has an `id` and a `name` attribute. +* `roles` - The list of roles attached to the token. +* `service_identities` - The list of service identities attached to the token. Each entry has a `service_name` and a `datacenters` attribute. +* `node_identities` - The list of node identities attached to the token. Each entry has a `node_name` and a `datacenter` attributes. * `local` - Whether the ACL token is local to the datacenter it was created within. +* `expiration_time` - If set this represents the point after which a token should be considered revoked and is eligible for destruction. diff --git a/website/docs/r/acl_role.markdown b/website/docs/r/acl_role.markdown index 2c8564e2..e4478e54 100644 --- a/website/docs/r/acl_role.markdown +++ b/website/docs/r/acl_role.markdown @@ -41,15 +41,20 @@ The following arguments are supported: * `name` - (Required) The name of the ACL role. * `description` - (Optional) A free form human readable description of the role. * `policies` - (Optional) The list of policies that should be applied to the role. -* `service_identities` - (Optional) The list of service identities that should -be applied to the role. +* `service_identities` - (Optional) The list of service identities that should be applied to the role. +* `node_identities` - (Optional) The list of node identities that should be applied to the role. * `namespace` - (Optional, Enterprise Only) The namespace to create the role within. -The `service_identities` supports: +The `service_identities` block supports: * `service_name` - (Required) The name of the service. * `datacenters` - (Optional) The datacenters the effective policy is valid within. +The `node_identities` block supports: + +* `node_name` - (Required) The name of the node. +* `datacenter` - (Required) The datacenter of the node. + ## Attributes Reference The following attributes are exported: @@ -58,8 +63,9 @@ The following attributes are exported: * `name` - The name of the ACL role. * `description` - A free form human readable description of the role. * `policies` - The list of policies that should be applied to the role. -* `service_identities` - The list of service identities that should -be applied to the role. +* `service_identities` - The list of service identities that should be applied to the role. +* `node_identities` - The list of node identities that should be applied to the role. +* `namespace` - The namespace to create the role within. ## Import diff --git a/website/docs/r/acl_token.html.markdown b/website/docs/r/acl_token.html.markdown index 309d60d7..89aec4e1 100644 --- a/website/docs/r/acl_token.html.markdown +++ b/website/docs/r/acl_token.html.markdown @@ -53,9 +53,22 @@ The following arguments are supported: * `description` - (Optional) The description of the token. * `policies` - (Optional) The list of policies attached to the token. * `roles` - (Optional) The list of roles attached to the token. +* `service_identities` - (Optional) The list of service identities that should be applied to the token. +* `node_identities` - (Optional) The list of node identities that should be applied to the token. * `local` - (Optional) The flag to set the token local to the current datacenter. +* `expiration_time` - (Optional) If set this represents the point after which a token should be considered revoked and is eligible for destruction. * `namespace` - (Optional, Enterprise Only) The namespace to create the token within. +The `service_identities` block supports the following arguments: + +* `service_name` - (Required) The name of the service. +* `datacenters` - (Required) The list of datacenters the policy is valid within. + +The `node_identities` block supports the following arguments: + +* `node_name` - (Optional) The name of the node. +* `datacenter` - (Optional) The datacenter of the node. + ## Attributes Reference The following attributes are exported: @@ -65,7 +78,11 @@ The following attributes are exported: * `description` - The description of the token. * `policies` - The list of policies attached to the token. * `roles` - The list of roles attached to the token. +* `service_identities` - The list of service identities that should be applied to the token. +* `node_identities` - The list of node identities that should be applied to the token. * `local` - The flag to set the token local to the current datacenter. +* `expiration_time` - If set this represents the point after which a token should be considered revoked and is eligible for destruction. +* `namespace` - The namespace to create the token within. ## Import