|
| 1 | +package provider |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "errors" |
| 6 | + "fmt" |
| 7 | + "strings" |
| 8 | + |
| 9 | + "github.com/datastax/astra-client-go/v2/astra" |
| 10 | + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" |
| 11 | + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| 12 | +) |
| 13 | + |
| 14 | +func resourceRole() *schema.Resource { |
| 15 | + return &schema.Resource{ |
| 16 | + Description: "`astra_role` resource represents custom roles for a particular Astra Org. Custom roles can be assigned to an Astra user is to grant them granular permissions when the default roles in the UI are not specific enough. Roles are composed of policies which are granted to resources.", |
| 17 | + CreateContext: resourceRoleCreate, |
| 18 | + ReadContext: resourceRoleRead, |
| 19 | + DeleteContext: resourceRoleDelete, |
| 20 | + |
| 21 | + Importer: &schema.ResourceImporter{ |
| 22 | + StateContext: schema.ImportStatePassthroughContext, |
| 23 | + }, |
| 24 | + |
| 25 | + Schema: map[string]*schema.Schema{ |
| 26 | + // Required |
| 27 | + "role_name": { |
| 28 | + Description: "Role name", |
| 29 | + Type: schema.TypeString, |
| 30 | + Required: true, |
| 31 | + ForceNew: true, |
| 32 | + }, |
| 33 | + "description": { |
| 34 | + Description: "Role description", |
| 35 | + Type: schema.TypeString, |
| 36 | + Required: true, |
| 37 | + ForceNew: true, |
| 38 | + }, |
| 39 | + "effect": { |
| 40 | + Description: "Role effect", |
| 41 | + Type: schema.TypeString, |
| 42 | + Required: true, |
| 43 | + ForceNew: true, |
| 44 | + }, |
| 45 | + "resources": { |
| 46 | + Description: "Resources for which role is applicable", |
| 47 | + Type: schema.TypeList, |
| 48 | + Required: true, |
| 49 | + ForceNew: true, |
| 50 | + Elem: &schema.Schema{ |
| 51 | + Type: schema.TypeString, |
| 52 | + }, |
| 53 | + }, |
| 54 | + |
| 55 | + "policy": { |
| 56 | + Description: "List of policies for the role.", |
| 57 | + Type: schema.TypeList, |
| 58 | + Required: true, |
| 59 | + ForceNew: true, |
| 60 | + Elem: &schema.Schema{ |
| 61 | + Type: schema.TypeString, |
| 62 | + }, |
| 63 | + }, |
| 64 | + "role_id": { |
| 65 | + Description: "Role ID, system generated", |
| 66 | + Type: schema.TypeString, |
| 67 | + Computed: true, |
| 68 | + ForceNew: true, |
| 69 | + }, |
| 70 | + }, |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
| 75 | + client := meta.(*astra.ClientWithResponses) |
| 76 | + |
| 77 | + roleName := d.Get("role_name").(string) |
| 78 | + description := d.Get("description").(string) |
| 79 | + effect := d.Get("effect").(string) |
| 80 | + resourcesRaw := d.Get("resources").([]interface{}) |
| 81 | + policyRaw := d.Get("policy") |
| 82 | + |
| 83 | + actions := policyRaw.([]interface{}) |
| 84 | + |
| 85 | + |
| 86 | + resourcesList := make([]string, len(actions)) |
| 87 | + actionsList := make([]astra.PolicyActions, len(actions)) |
| 88 | + |
| 89 | + for k, v := range resourcesRaw { |
| 90 | + resourcesList[k] = v.(string) |
| 91 | + } |
| 92 | + for k, v := range policyRaw.([]interface{}) { |
| 93 | + actionsList[k] = astra.PolicyActions(v.(string)) |
| 94 | + } |
| 95 | + policy := astra.Policy{ |
| 96 | + Actions: actionsList, |
| 97 | + Description: description, |
| 98 | + Effect: astra.PolicyEffect(effect), |
| 99 | + Resources: resourcesList, |
| 100 | + } |
| 101 | + |
| 102 | + |
| 103 | + roleJSON := astra.AddOrganizationRoleJSONRequestBody{ |
| 104 | + Name: roleName, |
| 105 | + Policy: policy, |
| 106 | + } |
| 107 | + resp, err := client.AddOrganizationRoleWithResponse(ctx, |
| 108 | + roleJSON, |
| 109 | + ) |
| 110 | + |
| 111 | + if err != nil { |
| 112 | + return diag.FromErr(err) |
| 113 | + } else if resp.StatusCode() >= 400 { |
| 114 | + return diag.Errorf("error adding role to org: %s", resp.Body) |
| 115 | + } |
| 116 | + |
| 117 | + role := resp.JSON201 |
| 118 | + if err := setRoleData(d, *role.Id); err != nil { |
| 119 | + return diag.FromErr(err) |
| 120 | + } |
| 121 | + |
| 122 | + return nil |
| 123 | +} |
| 124 | + |
| 125 | +func resourceRoleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
| 126 | + client := meta.(*astra.ClientWithResponses) |
| 127 | + |
| 128 | + id := d.Id() |
| 129 | + |
| 130 | + roleID, err := parseRoleID(id) |
| 131 | + if err != nil { |
| 132 | + return diag.FromErr(err) |
| 133 | + } |
| 134 | + |
| 135 | + roleParam := astra.RoleIdParam(roleID) |
| 136 | + client.DeleteOrganizationRoleWithResponse(ctx, roleParam) |
| 137 | + |
| 138 | + return nil |
| 139 | +} |
| 140 | + |
| 141 | +func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
| 142 | + client := meta.(*astra.ClientWithResponses) |
| 143 | + |
| 144 | + id := d.Id() |
| 145 | + |
| 146 | + roleID, err := parseRoleID(id) |
| 147 | + if err != nil { |
| 148 | + return diag.FromErr(err) |
| 149 | + } |
| 150 | + |
| 151 | + role, err := listRole(ctx, client, roleID) |
| 152 | + if err != nil { |
| 153 | + return diag.FromErr(err) |
| 154 | + } |
| 155 | + |
| 156 | + |
| 157 | + if role["id"].(string) == roleID { |
| 158 | + if err := setRoleData(d, roleID); err != nil { |
| 159 | + return diag.FromErr(err) |
| 160 | + } |
| 161 | + return nil |
| 162 | + } |
| 163 | + |
| 164 | + // Not found. Remove from state. |
| 165 | + d.SetId("") |
| 166 | + |
| 167 | + return nil |
| 168 | +} |
| 169 | + |
| 170 | +func setRoleData(d *schema.ResourceData, roleID string) error { |
| 171 | + d.SetId(fmt.Sprintf("%s", roleID)) |
| 172 | + |
| 173 | + if err := d.Set("role_id", roleID); err != nil { |
| 174 | + return err |
| 175 | + } |
| 176 | + |
| 177 | + return nil |
| 178 | +} |
| 179 | + |
| 180 | +func parseRoleID(id string) (string, error) { |
| 181 | + idParts := strings.Split(strings.ToLower(id), "/") |
| 182 | + if len(idParts) != 1 { |
| 183 | + return "", errors.New("invalid role id format: expected roleID/") |
| 184 | + } |
| 185 | + return idParts[0], nil |
| 186 | +} |
0 commit comments