Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vault_quota_rate_limit resource #825

Merged
merged 7 commits into from
Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,10 @@ var (
Resource: pkiSecretBackendSignResource(),
PathInventory: []string{"/pki/sign/{role}"},
},
"vault_quota_rate_limit": {
Resource: quotaRateLimitResource(),
PathInventory: []string{"/sys/quotas/rate-limit/{name}"},
},
"vault_transit_secret_backend_key": {
Resource: transitSecretBackendKeyResource(),
PathInventory: []string{"/transit/keys/{name}"},
Expand Down
163 changes: 163 additions & 0 deletions vault/resource_quota_rate_limit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package vault

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/vault/api"
)

func quotaRateLimitPath(name string) string {
return "sys/quotas/rate-limit/" + name
}

func quotaRateLimitResource() *schema.Resource {
return &schema.Resource{
Create: quotaRateLimitCreate,
Read: quotaRateLimitRead,
Update: quotaRateLimitUpdate,
Delete: quotaRateLimitDelete,
Exists: quotaRateLimitExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the quota.",
ForceNew: true,
},
"path": {
Type: schema.TypeString,
Optional: true,
Description: "Path of the mount or namespace to apply the quota. A blank path configures a global rate limit quota.",
},
"rate": {
Type: schema.TypeFloat,
Required: true,
Description: "The maximum number of requests at any given second to be allowed by the quota rule. The rate must be positive.",
catsby marked this conversation as resolved.
Show resolved Hide resolved
},
},
}
}

func quotaRateLimitUpdateFields(d *schema.ResourceData, data map[string]interface{}) {
catsby marked this conversation as resolved.
Show resolved Hide resolved
if v, ok := d.GetOk("path"); ok {
data["path"] = v.(string)
}

if v, ok := d.GetOk("rate"); ok {
data["rate"] = v.(float64)
}
}

func quotaRateLimitCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Get("name").(string)
path := quotaRateLimitPath(name)
d.SetId(name)

log.Printf("[DEBUG] Creating Resource Rate Limit Quota %s", name)

data := map[string]interface{}{}
data["path"] = d.Get("path").(string)
data["rate"] = d.Get("rate").(float64)

_, err := client.Logical().Write(path, data)
if err != nil {
d.SetId("")
return fmt.Errorf("Error creating Resource Rate Limit Quota %s: %s", name, err)
}
log.Printf("[DEBUG] Created Resource Rate Limit Quota %s", name)

return quotaRateLimitRead(d, meta)
}

func quotaRateLimitRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Id()
path := quotaRateLimitPath(name)

log.Printf("[DEBUG] Reading Resource Rate Limit Quota %s", name)
resp, err := client.Logical().Read(path)
if err != nil {
return fmt.Errorf("error reading Resource Rate Limit Quota %s: %s", name, err)
}

if resp == nil {
log.Printf("[WARN] Resource Rate Limit Quota %s not found, removing from state", name)
d.SetId("")
return nil
}

for _, k := range []string{"path", "rate"} {
v, ok := resp.Data[k]
if ok {
if err := d.Set(k, v); err != nil {
return fmt.Errorf("error setting %s for Resource Rate Limit Quota %s: %q", k, name, err)
}
}
}

return nil
}

func quotaRateLimitUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Id()
path := quotaRateLimitPath(name)

log.Printf("[DEBUG] Updating Resource Rate Limit Quota %s", name)

data := map[string]interface{}{}
data["path"] = d.Get("path").(string)
data["rate"] = d.Get("rate").(float64)

_, err := client.Logical().Write(path, data)
if err != nil {
d.SetId("")
return fmt.Errorf("Error updating Resource Rate Limit Quota %s: %s", name, err)
}
log.Printf("[DEBUG] Updated Resource Rate Limit Quota %s", name)

return quotaRateLimitRead(d, meta)
}

func quotaRateLimitDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Id()
path := quotaRateLimitPath(name)

log.Printf("[DEBUG] Deleting Resource Rate Limit Quota %s", name)
_, err := client.Logical().Delete(path)
if err != nil {
return fmt.Errorf("Error deleting Resource Rate Limit Quota %s", name)
}
log.Printf("[DEBUG] Deleted Resource Rate Limit Quota %s", name)

return nil
}

func quotaRateLimitExists(d *schema.ResourceData, meta interface{}) (bool, error) {
client := meta.(*api.Client)

name := d.Id()
path := quotaRateLimitPath(name)

log.Printf("[DEBUG] Checking if Resource Rate Limit Quota %s exists", name)

secret, err := client.Logical().Read(path)
if err != nil {
return true, fmt.Errorf("error checking if Resource Rate Limit Quota %s exists: %s", name, err)
}

log.Printf("[DEBUG] Checked if Resource Rate Limit Quota %s exists", name)
return secret != nil, nil
}
77 changes: 77 additions & 0 deletions vault/resource_quota_rate_limit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package vault

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/hashicorp/vault/api"
)

func TestQuotaRateLimit(t *testing.T) {
name := acctest.RandomWithPrefix("tf-test")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testQuotaRateLimitCheckDestroy,
Steps: []resource.TestStep{
{
Config: testQuotaRateLimit_Config(name, "", "1000.0"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "name", name),
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "path", ""),
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "rate", "1000"),
),
},
{
Config: testQuotaRateLimit_Config(name, "", "1234.5"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "name", name),
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "path", ""),
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "rate", "1234.5"),
),
},
{
Config: testQuotaRateLimit_Config(name, "sys/", "1234.5"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "name", name),
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "path", "sys/"),
resource.TestCheckResourceAttr("vault_quota_rate_limit.foobar", "rate", "1234.5"),
),
},
},
})
}

func testQuotaRateLimitCheckDestroy(s *terraform.State) error {
client := testProvider.Meta().(*api.Client)

for _, rs := range s.RootModule().Resources {
if rs.Type != "vault_quota_rate_limit" {
continue
}
name := rs.Primary.Attributes["name"]
resp, err := client.Logical().Read(quotaRateLimitPath(name))
if err != nil {
return err
}

if resp != nil {
return fmt.Errorf("Resource Quota Rate Limit %s still exists", name)
}
}
return nil
}

// Caution: Don't set test rate values too low or other tests running concurrently might fail
func testQuotaRateLimit_Config(name, path, rate string) string {
return fmt.Sprintf(`
resource "vault_quota_rate_limit" "foobar" {
name = "%s"
path = "%s"
rate = %s
}
`, name, path, rate)
}
56 changes: 56 additions & 0 deletions website/docs/r/quota_rate_limit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
layout: "vault"
page_title: "Vault: vault_quota_rate_limit resource"
sidebar_current: "docs-vault-quota-rate-limit"
description: |-
Manage Rate Limit Quota
---

# vault\_pki\_secret\_backend\_intermediate\_cert\_request

Generates a new private key and a CSR for signing the PKI Secret Backend.

~> **Important** All data provided in the resource configuration will be
written in cleartext to state and plan files generated by Terraform, and
will appear in the console output when Terraform runs. Protect these
artifacts accordingly. See
[the main provider documentation](../index.html)
for more details.
catsby marked this conversation as resolved.
Show resolved Hide resolved

## Example Usage

```hcl
resource "vault_quota_rate_limit" "global" {
name = "global"
path = ""
rate = 100
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) Name of the rate limit quota

* `path` - (Optional) Path of the mount or namespace to apply the quota. A blank path configures a
global rate limit quota. For example `namespace1/` adds a quota to a full namespace,
`namespace1/auth/userpass` adds a `quota` to `userpass` in `namespace1`.
Updating this field on an existing quota can have "moving" effects. For example, updating
`auth/userpass` to `namespace1/auth/userpass` moves this quota from being a global mount quota to
a namespace specific mount quota. **Note, namespaces are supported in Enterprise only.**

* `rate` - (Required) The maximum number of requests at any given second to be allowed by the quota
rule. The `rate` must be positive.

## Attributes Reference

No additional attributes are exported by this resource.

## Import

Rate limit quotas can be imported using their names

```
$ terraform import vault_quota_rate_limit.global global
```
4 changes: 4 additions & 0 deletions website/vault.erb
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@
<a href="/docs/providers/vault/r/rgp_policy.html">vault_rgp_policy</a>
</li>

<li<%= sidebar_current("docs-vault-quota-rate-limit") %>>
<a href="/docs/providers/vault/r/quota_rate_limit.html">vault_quota_rate_limit</a>
</li>

<li<%= sidebar_current("docs-vault-resource-token") %>>
<a href="/docs/providers/vault/r/token.html">vault_token</a>
</li>
Expand Down