Add key, bucket, bucket_key, bucket_global_alias and bucket_local_alias resources

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@prologin.org>
This commit is contained in:
Marc 'risson' Schmitt 2022-12-10 17:48:33 +01:00
parent de766103db
commit 2b61749be3
No known key found for this signature in database
GPG Key ID: 9C3FA22FABF1AA8D
19 changed files with 1059 additions and 2 deletions

62
docs/resources/bucket.md Normal file
View File

@ -0,0 +1,62 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "garage_bucket Resource - terraform-provider-garage"
subcategory: ""
description: |-
This resource can be used to manage Garage buckets.
---
# garage_bucket (Resource)
This resource can be used to manage Garage buckets.
## Example Usage
```terraform
resource "garage_bucket" "bucket" {}
resource "garage_bucket" "bucket-with-website" {
website_access_enabled = true
website_config_index_document = "index.html"
website_config_error_document = "error.html"
}
resource "garage_bucket" "bucket-with-quota" {
quota_max_size = 1024
quota_max_objects = 100
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Optional
- `quota_max_objects` (Number)
- `quota_max_size` (Number)
- `website_access_enabled` (Boolean)
- `website_config_error_document` (String)
- `website_config_index_document` (String)
### Read-Only
- `bytes` (Number)
- `global_aliases` (List of String)
- `id` (String) The ID of this resource.
- `keys` (Set of Object) (see [below for nested schema](#nestedatt--keys))
- `objects` (Number)
- `unfinished_uploads` (Number)
<a id="nestedatt--keys"></a>
### Nested Schema for `keys`
Read-Only:
- `access_key_id` (String)
- `local_aliases` (List of String)
- `name` (String)
- `permissions_owner` (Boolean)
- `permissions_read` (Boolean)
- `permissions_write` (Boolean)

View File

@ -0,0 +1,41 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "garage_bucket_global_alias Resource - terraform-provider-garage"
subcategory: ""
description: |-
This resource can be used to manage Garage bucket global aliases.
---
# garage_bucket_global_alias (Resource)
This resource can be used to manage Garage bucket global aliases.
## Example Usage
```terraform
resource "garage_bucket" "website" {}
resource "garage_bucket_global_alias" "website" {
bucket_id = garage_bucket.website.id
alias = "website"
}
resource "garage_bucket_global_alias" "www" {
bucket_id = garage_bucket.website.id
alias = "www"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `alias` (String)
- `bucket_id` (String)
### Read-Only
- `id` (String) The ID of this resource.

View File

@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "garage_bucket_key Resource - terraform-provider-garage"
subcategory: ""
description: |-
This resource can be used to manage Garage bucket global aliases.
---
# garage_bucket_key (Resource)
This resource can be used to manage Garage bucket global aliases.
## Example Usage
```terraform
resource "garage_key" "key" {
name = "my_key"
}
resource "garage_bucket" "bucket" {}
resource "garage_bucket_key" "bucket_key_read-only" {
bucket_id = garage_bucket.bucket.id
access_key_id = garage_key.key.acccess_key_id
read = true
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `access_key_id` (String)
- `bucket_id` (String)
### Optional
- `owner` (Boolean)
- `read` (Boolean)
- `write` (Boolean)
### Read-Only
- `id` (String) The ID of this resource.

View File

@ -0,0 +1,42 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "garage_bucket_local_alias Resource - terraform-provider-garage"
subcategory: ""
description: |-
This resource can be used to manage Garage bucket global aliases.
---
# garage_bucket_local_alias (Resource)
This resource can be used to manage Garage bucket global aliases.
## Example Usage
```terraform
resource "garage_key" "key" {
name = "key"
}
resource "garage_bucket" "bucket" {}
resource "garage_bucket_local_alias" "bucket_key_private-files" {
bucket_id = garage_bucket.bucket.id
access_key_id = garage_key.key.access_key_id
alias = "private-files"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `access_key_id` (String)
- `alias` (String)
- `bucket_id` (String)
### Read-Only
- `id` (String) The ID of this resource.

38
docs/resources/key.md Normal file
View File

@ -0,0 +1,38 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "garage_key Resource - terraform-provider-garage"
subcategory: ""
description: |-
This resource can be used to manage Garage keys.
---
# garage_key (Resource)
This resource can be used to manage Garage keys.
## Example Usage
```terraform
resource "garage_key" "key" {
name = "key"
permissions = {
create_bucket = true // defaults to false
}
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Optional
- `access_key_id` (String)
- `name` (String) The name of the key.
- `permissions` (Map of Boolean)
- `secret_access_key` (String, Sensitive)
### Read-Only
- `id` (String) The ID of this resource.

View File

View File

@ -0,0 +1,12 @@
resource "garage_bucket" "bucket" {}
resource "garage_bucket" "bucket-with-website" {
website_access_enabled = true
website_config_index_document = "index.html"
website_config_error_document = "error.html"
}
resource "garage_bucket" "bucket-with-quota" {
quota_max_size = 1024
quota_max_objects = 100
}

View File

@ -0,0 +1,11 @@
resource "garage_bucket" "website" {}
resource "garage_bucket_global_alias" "website" {
bucket_id = garage_bucket.website.id
alias = "website"
}
resource "garage_bucket_global_alias" "www" {
bucket_id = garage_bucket.website.id
alias = "www"
}

View File

@ -0,0 +1,11 @@
resource "garage_key" "key" {
name = "my_key"
}
resource "garage_bucket" "bucket" {}
resource "garage_bucket_key" "bucket_key_read-only" {
bucket_id = garage_bucket.bucket.id
access_key_id = garage_key.key.acccess_key_id
read = true
}

View File

@ -0,0 +1,11 @@
resource "garage_key" "key" {
name = "key"
}
resource "garage_bucket" "bucket" {}
resource "garage_bucket_local_alias" "bucket_key_private-files" {
bucket_id = garage_bucket.bucket.id
access_key_id = garage_key.key.access_key_id
alias = "private-files"
}

View File

@ -0,0 +1,6 @@
resource "garage_key" "key" {
name = "key"
permissions = {
create_bucket = true // defaults to false
}
}

View File

@ -8,6 +8,15 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
type garageProvider struct {
client *garage.APIClient
ctx context.Context
}
func updateContext(tfCtx context.Context, p *garageProvider) context.Context {
return context.WithValue(tfCtx, garage.ContextAccessToken, p.ctx.Value(garage.ContextAccessToken))
}
// Provider -
func Provider() *schema.Provider {
return &schema.Provider{
@ -29,7 +38,13 @@ func Provider() *schema.Provider {
DefaultFunc: schema.EnvDefaultFunc("GARAGE_TOKEN", nil),
},
},
ResourcesMap: map[string]*schema.Resource{},
ResourcesMap: map[string]*schema.Resource{
"garage_bucket": resourceBucket(),
"garage_bucket_global_alias": resourceBucketGlobalAlias(),
"garage_bucket_key": resourceBucketKey(),
"garage_bucket_local_alias": resourceBucketLocalAlias(),
"garage_key": resourceKey(),
},
DataSourcesMap: map[string]*schema.Resource{},
ConfigureContextFunc: providerConfigure,
}
@ -60,5 +75,8 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}
ctx = context.WithValue(ctx, garage.ContextAccessToken, token)
return client, diags
return &garageProvider{
client: client,
ctx: ctx,
}, diags
}

255
garage/resource_bucket.go Normal file
View File

@ -0,0 +1,255 @@
package garage
import (
"context"
garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/thoas/go-funk"
)
func schemaBucket() map[string]*schema.Schema {
return map[string]*schema.Schema{
"website_access_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"website_config_index_document": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"website_config_error_document": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"quota_max_size": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"quota_max_objects": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
// Computed
"global_aliases": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Computed: true,
},
"keys": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"access_key_id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"permissions_read": {
Type: schema.TypeBool,
Computed: true,
},
"permissions_write": {
Type: schema.TypeBool,
Computed: true,
},
"permissions_owner": {
Type: schema.TypeBool,
Computed: true,
},
"local_aliases": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Computed: true,
},
},
},
},
"objects": {
Type: schema.TypeInt,
Computed: true,
},
"bytes": {
Type: schema.TypeInt,
Computed: true,
},
"unfinished_uploads": {
Type: schema.TypeInt,
Computed: true,
},
}
}
func resourceBucket() *schema.Resource {
return &schema.Resource{
Description: "This resource can be used to manage Garage buckets.",
CreateContext: resourceBucketCreate,
ReadContext: resourceBucketRead,
UpdateContext: resourceBucketUpdate,
DeleteContext: resourceBucketDelete,
Schema: schemaBucket(),
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
}
}
func flattenBucketKey(bucketKey garage.BucketKeyInfo) interface{} {
return map[string]interface{}{
"access_key_id": *bucketKey.AccessKeyId,
"name": *bucketKey.Name,
"permissions_read": *bucketKey.Permissions.Read,
"permissions_write": *bucketKey.Permissions.Write,
"permissions_owner": *bucketKey.Permissions.Owner,
}
}
func flattenBucketInfo(bucket *garage.BucketInfo) interface{} {
b := map[string]interface{}{}
b["global_aliases"] = bucket.GlobalAliases
if bucket.HasWebsiteAccess() {
b["website_access_enabled"] = bucket.GetWebsiteAccess()
}
if bucket.HasWebsiteConfig() {
b["website_config_index_document"] = bucket.GetWebsiteConfig().IndexDocument
b["website_config_error_document"] = bucket.GetWebsiteConfig().ErrorDocument
}
if bucket.HasQuotas() {
if bucket.Quotas.MaxSize.IsSet() {
b["quota_max_size"] = bucket.GetQuotas().MaxSize.Get()
}
if bucket.Quotas.MaxObjects.IsSet() {
b["quota_max_objects"] = bucket.GetQuotas().MaxObjects.Get()
}
}
b["keys"] = funk.Map(bucket.GetKeys(), flattenBucketKey)
b["objects"] = *bucket.Objects
b["bytes"] = *bucket.Bytes
b["unfinished_uploads"] = *bucket.UnfinishedUploads
return b
}
func resourceBucketCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketInfo, _, err := p.client.BucketApi.CreateBucket(updateContext(ctx, p)).CreateBucketRequest(garage.CreateBucketRequest{}).Execute()
if err != nil {
return diag.FromErr(err)
}
d.SetId(*bucketInfo.Id)
diags = resourceBucketUpdate(ctx, d, m)
return diags
}
func resourceBucketRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Id()
bucketInfo, _, err := p.client.BucketApi.GetBucketInfo(updateContext(ctx, p), bucketID).Execute()
if err != nil {
return diag.FromErr(err)
}
for key, value := range flattenBucketInfo(bucketInfo).(map[string]interface{}) {
err := d.Set(key, value)
if err != nil {
return diag.FromErr(err)
}
}
return diags
}
func resourceBucketUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
webAccessEnabled := false
var webConfigIndexDoc *string
webConfigIndexDoc = nil
var webConfigErrorDoc *string
webConfigErrorDoc = nil
if webAccessEnabledVal, ok := d.GetOk("website_access_enabled"); ok {
webAccessEnabled = webAccessEnabledVal.(bool)
}
if webConfigIndexDocVal, ok := d.GetOk("website_config_index_document"); ok {
webConfigIndexDocVal := webConfigIndexDocVal.(string)
webConfigIndexDoc = &webConfigIndexDocVal
}
if webConfigErrorDocVal, ok := d.GetOk("website_config_error_document"); ok {
webConfigErrorDocVal := webConfigErrorDocVal.(string)
webConfigErrorDoc = &webConfigErrorDocVal
}
var quotaMaxSize *int32
quotaMaxSize = nil
var quotaMaxObjects *int32
quotaMaxObjects = nil
if quotaMaxSizeVal, ok := d.GetOk("quota_max_size"); ok {
quotaMaxSizeVal := int32(quotaMaxSizeVal.(int))
quotaMaxSize = &quotaMaxSizeVal
}
if quotaMaxObjectsVal, ok := d.GetOk("quota_max_objects"); ok {
quotaMaxObjectsVal := int32(quotaMaxObjectsVal.(int))
quotaMaxObjects = &quotaMaxObjectsVal
}
updateBucketRequest := garage.UpdateBucketRequest{
WebsiteAccess: &garage.UpdateBucketRequestWebsiteAccess{
Enabled: &webAccessEnabled,
IndexDocument: webConfigIndexDoc,
ErrorDocument: webConfigErrorDoc,
},
Quotas: &garage.UpdateBucketRequestQuotas{
MaxSize: *garage.NewNullableInt32(quotaMaxSize),
MaxObjects: *garage.NewNullableInt32(quotaMaxObjects),
},
}
_, _, err := p.client.BucketApi.UpdateBucket(updateContext(ctx, p), d.Id()).UpdateBucketRequest(updateBucketRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
diags = resourceBucketRead(ctx, d, m)
return diags
}
func resourceBucketDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
_, err := p.client.BucketApi.DeleteBucket(updateContext(ctx, p), d.Id()).Execute()
if err != nil {
return diag.FromErr(err)
}
return diags
}

View File

@ -0,0 +1,72 @@
package garage
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func schemaBucketGlobalAlias() map[string]*schema.Schema {
return map[string]*schema.Schema{
"bucket_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"alias": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
}
}
func resourceBucketGlobalAlias() *schema.Resource {
return &schema.Resource{
Description: "This resource can be used to manage Garage bucket global aliases.",
CreateContext: resourceBucketGlobalAliasCreate,
ReadContext: resourceBucketGlobalAliasRead,
DeleteContext: resourceBucketGlobalAliasDelete,
Schema: schemaBucketGlobalAlias(),
}
}
func resourceBucketGlobalAliasCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Get("bucket_id").(string)
alias := d.Get("alias").(string)
_, _, err := p.client.BucketApi.PutBucketGlobalAlias(updateContext(ctx, p)).Id(bucketID).Alias(alias).Execute()
if err != nil {
return diag.FromErr(err)
}
d.SetId(fmt.Sprintf("%s/%s", bucketID, alias))
return diags
}
func resourceBucketGlobalAliasRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
// Noop
return diags
}
func resourceBucketGlobalAliasDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Get("bucket_id").(string)
alias := d.Get("alias").(string)
_, _, err := p.client.BucketApi.DeleteBucketGlobalAlias(updateContext(ctx, p)).Id(bucketID).Alias(alias).Execute()
if err != nil {
return diag.FromErr(err)
}
return diags
}

View File

@ -0,0 +1,125 @@
package garage
import (
"context"
"fmt"
garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func schemaBucketKey() map[string]*schema.Schema {
return map[string]*schema.Schema{
"bucket_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"access_key_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"read": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"write": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"owner": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
}
}
func resourceBucketKey() *schema.Resource {
return &schema.Resource{
Description: "This resource can be used to manage Garage bucket global aliases.",
CreateContext: resourceBucketKeyCreateOrUpdate,
ReadContext: resourceBucketKeyRead,
UpdateContext: resourceBucketKeyCreateOrUpdate,
DeleteContext: resourceBucketKeyDelete,
Schema: schemaBucketKey(),
}
}
func resourceBucketKeyCreateOrUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Get("bucket_id").(string)
accessKeyID := d.Get("access_key_id").(string)
read := d.Get("read").(bool)
write := d.Get("write").(bool)
owner := d.Get("owner").(bool)
allowBucketKeyRequest := garage.AllowBucketKeyRequest{
BucketId: bucketID,
AccessKeyId: accessKeyID,
Permissions: garage.AllowBucketKeyRequestPermissions{
Read: read,
Write: write,
Owner: owner,
},
}
denyBucketKeyRequest := garage.AllowBucketKeyRequest{
BucketId: bucketID,
AccessKeyId: accessKeyID,
Permissions: garage.AllowBucketKeyRequestPermissions{
Read: !read,
Write: !write,
Owner: !owner,
},
}
_, _, err := p.client.BucketApi.AllowBucketKey(updateContext(ctx, p)).AllowBucketKeyRequest(allowBucketKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
_, _, err = p.client.BucketApi.DenyBucketKey(updateContext(ctx, p)).AllowBucketKeyRequest(denyBucketKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
d.SetId(fmt.Sprintf("%s/%s", bucketID, accessKeyID))
return diags
}
func resourceBucketKeyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
// Noop
return diags
}
func resourceBucketKeyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Get("bucket_id").(string)
accessKeyID := d.Get("access_key_id").(string)
denyBucketKeyRequest := garage.AllowBucketKeyRequest{
BucketId: bucketID,
AccessKeyId: accessKeyID,
Permissions: garage.AllowBucketKeyRequestPermissions{
Read: true,
Write: true,
Owner: true,
},
}
_, _, err := p.client.BucketApi.DenyBucketKey(updateContext(ctx, p)).AllowBucketKeyRequest(denyBucketKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
return diags
}

View File

@ -0,0 +1,79 @@
package garage
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func schemaBucketLocalAlias() map[string]*schema.Schema {
return map[string]*schema.Schema{
"bucket_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"access_key_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"alias": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
}
}
func resourceBucketLocalAlias() *schema.Resource {
return &schema.Resource{
Description: "This resource can be used to manage Garage bucket global aliases.",
CreateContext: resourceBucketLocalAliasCreate,
ReadContext: resourceBucketLocalAliasRead,
DeleteContext: resourceBucketLocalAliasDelete,
Schema: schemaBucketLocalAlias(),
}
}
func resourceBucketLocalAliasCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Get("bucket_id").(string)
accessKeyID := d.Get("access_key_id").(string)
alias := d.Get("alias").(string)
_, _, err := p.client.BucketApi.PutBucketLocalAlias(updateContext(ctx, p)).Id(bucketID).AccessKeyId(accessKeyID).Alias(alias).Execute()
if err != nil {
return diag.FromErr(err)
}
d.SetId(fmt.Sprintf("%s/%s/%s", bucketID, accessKeyID, alias))
return diags
}
func resourceBucketLocalAliasRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
// Noop
return diags
}
func resourceBucketLocalAliasDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
bucketID := d.Get("bucket_id").(string)
accessKeyID := d.Get("access_key_id").(string)
alias := d.Get("alias").(string)
_, _, err := p.client.BucketApi.DeleteBucketLocalAlias(updateContext(ctx, p)).Id(bucketID).AccessKeyId(accessKeyID).Alias(alias).Execute()
if err != nil {
return diag.FromErr(err)
}
return diags
}

224
garage/resource_key.go Normal file
View File

@ -0,0 +1,224 @@
package garage
import (
"context"
garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func schemaKey() map[string]*schema.Schema {
return map[string]*schema.Schema{
// Properties
"name": {
Description: "The name of the key.",
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"access_key_id": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
},
"secret_access_key": {
Type: schema.TypeString,
Computed: true,
Optional: true,
Sensitive: true,
ForceNew: true,
},
"permissions": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeBool,
},
Default: map[string]bool{
"create_bucket": false,
},
},
// Computed
// TODO: buckets
}
}
func resourceKey() *schema.Resource {
return &schema.Resource{
Description: "This resource can be used to manage Garage keys.",
CreateContext: resourceKeyCreate,
ReadContext: resourceKeyRead,
UpdateContext: resourceKeyUpdate,
DeleteContext: resourceKeyDelete,
Schema: schemaKey(),
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
}
}
func flattenKeyInfo(keyInfo *garage.KeyInfo) interface{} {
return map[string]interface{}{
"name": keyInfo.Name,
"access_key_id": keyInfo.AccessKeyId,
"secret_access_key": keyInfo.SecretAccessKey,
"permissions": map[string]interface{}{
"create_bucket": keyInfo.Permissions.CreateBucket,
},
}
}
func resourceKeyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
var name *string
name = nil
accessKeyID := ""
secretAccessKey := ""
if nameVal, ok := d.GetOk("name"); ok {
nameVal := nameVal.(string)
name = &nameVal
}
if accessKeyIDVal, ok := d.GetOk("access_key_id"); ok {
accessKeyID = accessKeyIDVal.(string)
}
if secretAccessKeyVal, ok := d.GetOk("access_key_id"); ok {
secretAccessKey = secretAccessKeyVal.(string)
}
var keyInfo *garage.KeyInfo
if accessKeyID != "" || secretAccessKey != "" {
importKeyRequest := *garage.NewImportKeyRequest(*name, accessKeyID, secretAccessKey)
resp, _, err := p.client.KeyApi.ImportKey(updateContext(ctx, p)).ImportKeyRequest(importKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
keyInfo = resp
} else {
addKeyRequest := *garage.NewAddKeyRequest()
addKeyRequest.Name = name
resp, _, err := p.client.KeyApi.AddKey(updateContext(ctx, p)).AddKeyRequest(addKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
keyInfo = resp
}
d.SetId(*keyInfo.AccessKeyId)
if permissions, ok := d.GetOk("permissions"); ok {
permissions := permissions.(map[string]interface{})
allowCreateBucket := permissions["create_bucket"].(bool)
denyCreateBucket := !permissions["create_bucket"].(bool)
allow := garage.UpdateKeyRequestAllow{
CreateBucket: &allowCreateBucket,
}
deny := garage.UpdateKeyRequestDeny{
CreateBucket: &denyCreateBucket,
}
updateKeyRequest := garage.UpdateKeyRequest{
Allow: &allow,
Deny: &deny,
}
_, _, err := p.client.KeyApi.UpdateKey(updateContext(ctx, p), d.Id()).UpdateKeyRequest(updateKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
}
diags = resourceKeyRead(ctx, d, m)
return diags
}
func resourceKeyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
accessKeyID := d.Id()
keyInfo, _, err := p.client.KeyApi.GetKey(updateContext(ctx, p), accessKeyID).Execute()
if err != nil {
return diag.FromErr(err)
}
for key, value := range flattenKeyInfo(keyInfo).(map[string]interface{}) {
err := d.Set(key, value)
if err != nil {
return diag.FromErr(err)
}
}
return diags
}
func resourceKeyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
var name *string
name = nil
var allow *garage.UpdateKeyRequestAllow
allow = nil
var deny *garage.UpdateKeyRequestDeny
deny = nil
if nameVal, ok := d.GetOk("name"); ok {
nameVal := nameVal.(string)
name = &nameVal
}
if permissions, ok := d.GetOk("permissions"); ok {
permissions := permissions.(map[string]interface{})
allowCreateBucket := permissions["create_bucket"].(bool)
denyCreateBucket := !permissions["create_bucket"].(bool)
allow = &garage.UpdateKeyRequestAllow{
CreateBucket: &allowCreateBucket,
}
deny = &garage.UpdateKeyRequestDeny{
CreateBucket: &denyCreateBucket,
}
}
updateKeyRequest := garage.UpdateKeyRequest{
Name: name,
Allow: allow,
Deny: deny,
}
_, _, err := p.client.KeyApi.UpdateKey(updateContext(ctx, p), d.Id()).UpdateKeyRequest(updateKeyRequest).Execute()
if err != nil {
return diag.FromErr(err)
}
diags = resourceKeyRead(ctx, d, m)
return diags
}
func resourceKeyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
p := m.(*garageProvider)
var diags diag.Diagnostics
accessKeyID := d.Id()
_, err := p.client.KeyApi.DeleteKey(updateContext(ctx, p), accessKeyID).Execute()
if err != nil {
return diag.FromErr(err)
}
return diags
}

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.19
require (
git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang v0.0.0-20221113145120-d012cff7c554
github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
github.com/thoas/go-funk v0.9.2
)
require (

2
go.sum
View File

@ -190,6 +190,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/thoas/go-funk v0.9.2 h1:oKlNYv0AY5nyf9g+/GhMgS/UO2ces0QRdPKwkhY3VCk=
github.com/thoas/go-funk v0.9.2/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=