This repository has been archived by the owner on Sep 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #147 from rawkode/feat/project-api-keys
feat: add project API key resource
- Loading branch information
Showing
7 changed files
with
391 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
page_title: "Equinix Metal: Metal Project API Key" | ||
subcategory: "" | ||
description: |- | ||
Create Equinix Metal Project API Keys | ||
--- | ||
# metal_project_api_key | ||
|
||
Use this resource to create Metal Project API Key resources in Equinix Metal. Project API keys can be used to create and read resources in a single project. Each API key contains a token which can be used for authentication in Equinix Metal HTTP API (in HTTP request header `X-Auth-Token`). | ||
|
||
|
||
Read-only keys only allow to list and view existing resources, read-write keys can also be used to create resources. | ||
|
||
|
||
## Example Usage | ||
|
||
```hcl | ||
# Create a new read-only API key in existing project | ||
resource "metal_project_api_key" "test" { | ||
project_id = local.existing_project_id | ||
description = "Read-only key scoped to a projct" | ||
read_only = true | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
* `project_id` - UUID of the project where the API key is scoped to | ||
* `description` - Description string for the Project API Key resource | ||
* `read-only` - Flag indicating whether the API key shoud be read-only | ||
|
||
## Attributes Reference | ||
|
||
* `token` - API token which can be used in Equinix Metal API clients |
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,34 @@ | ||
--- | ||
page_title: "Equinix Metal: Metal User API Key" | ||
subcategory: "" | ||
description: |- | ||
Create Equinix Metal User API Keys | ||
--- | ||
# metal_user_api_key | ||
|
||
Use this resource to create Metal User API Key resources in Equinix Metal. Each API key contains a token which can be used for authentication in Equinix Metal HTTP API (in HTTP request header `X-Auth-Token`). | ||
|
||
Read-only keys only allow to list and view existing resources, read-write keys can also be used to create resources. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
# Create a new read-only API key | ||
resource "metal_user_api_key" "test" { | ||
description = "Read-only user key" | ||
read_only = true | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
* `description` - Description string for the User API Key resource | ||
* `read-only` - Flag indicating whether the API key shoud be read-only | ||
|
||
## Attributes Reference | ||
|
||
* `user_id` - UUID of the owner of the API key | ||
* `token` - API token which can be used in Equinix Metal API clients |
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,143 @@ | ||
package metal | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/packethost/packngo" | ||
) | ||
|
||
func schemaMetalAPIKey() map[string]*schema.Schema { | ||
return map[string]*schema.Schema{ | ||
"read_only": { | ||
Type: schema.TypeBool, | ||
ForceNew: true, | ||
Required: true, | ||
Description: "Flag indicating whether the API key shoud be read-only", | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Description: "Description string for the API key", | ||
}, | ||
"token": { | ||
Type: schema.TypeString, | ||
Sensitive: true, | ||
Computed: true, | ||
Description: "API token for API clients", | ||
}, | ||
} | ||
} | ||
|
||
func resourceMetalProjectAPIKey() *schema.Resource { | ||
projectKeySchema := schemaMetalAPIKey() | ||
projectKeySchema["project_id"] = &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Description: "UUID of project which the new API key is scoped to", | ||
} | ||
return &schema.Resource{ | ||
Create: resourceMetalAPIKeyCreate, | ||
Read: resourceMetalAPIKeyRead, | ||
Delete: resourceMetalAPIKeyDelete, | ||
Schema: projectKeySchema, | ||
} | ||
} | ||
|
||
func resourceMetalAPIKeyCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*packngo.Client) | ||
|
||
projectId := "" | ||
|
||
projectIdRaw, projectIdOk := d.GetOk("project_id") | ||
if projectIdOk { | ||
projectId = projectIdRaw.(string) | ||
} | ||
|
||
createRequest := &packngo.APIKeyCreateRequest{ | ||
ProjectID: projectId, | ||
ReadOnly: d.Get("read_only").(bool), | ||
Description: d.Get("description").(string), | ||
} | ||
|
||
apiKey, _, err := client.APIKeys.Create(createRequest) | ||
if err != nil { | ||
return friendlyError(err) | ||
} | ||
|
||
d.SetId(apiKey.ID) | ||
|
||
return resourceMetalAPIKeyRead(d, meta) | ||
} | ||
|
||
func projectIdFromResourceData(d *schema.ResourceData) string { | ||
projectIdRaw, projectIdOk := d.GetOk("project_id") | ||
if projectIdOk { | ||
return projectIdRaw.(string) | ||
} | ||
return "" | ||
} | ||
|
||
func resourceMetalAPIKeyRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*packngo.Client) | ||
|
||
projectId := projectIdFromResourceData(d) | ||
|
||
var apiKey *packngo.APIKey | ||
var err error | ||
|
||
// if project has been set in the resource, look up project API key | ||
// (this is the reason project API key can't be imported) | ||
if projectId != "" { | ||
apiKey, err = client.APIKeys.ProjectGet(projectId, d.Id(), | ||
&packngo.GetOptions{Includes: []string{"project"}}) | ||
} else { | ||
apiKey, err = client.APIKeys.UserGet(d.Id(), | ||
&packngo.GetOptions{Includes: []string{"user"}}) | ||
} | ||
|
||
if err != nil { | ||
err = friendlyError(err) | ||
// If the key is somehow already destroyed, mark as | ||
// succesfully gone | ||
if isNotFound(err) { | ||
log.Printf("[WARN] Project APIKey (%s) not found, removing from state", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
return err | ||
} | ||
|
||
d.SetId(apiKey.ID) | ||
attrMap := map[string]interface{}{ | ||
"description": apiKey.Description, | ||
"read_only": apiKey.ReadOnly, | ||
"token": apiKey.Token, | ||
} | ||
|
||
// this is kind of unnecessary as the project ID most likely already set, | ||
// because project API key can't be imported. But let's refresh the | ||
// project ID for future-proofing | ||
if apiKey.Project != nil && apiKey.Project.ID != "" { | ||
attrMap["project_id"] = apiKey.Project.ID | ||
} | ||
if apiKey.User != nil && apiKey.User.ID != "" { | ||
attrMap["user_id"] = apiKey.User.ID | ||
} | ||
|
||
return setMap(d, attrMap) | ||
} | ||
|
||
func resourceMetalAPIKeyDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*packngo.Client) | ||
|
||
resp, err := client.APIKeys.Delete(d.Id()) | ||
if ignoreResponseErrors(httpForbidden, httpNotFound)(resp, err) != nil { | ||
return friendlyError(err) | ||
} | ||
|
||
d.SetId("") | ||
return nil | ||
} |
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,57 @@ | ||
package metal | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
"github.com/packethost/packngo" | ||
) | ||
|
||
func testAccMetalProjectAPIKeyDestroy(s *terraform.State) error { | ||
client := testAccProvider.Meta().(*packngo.Client) | ||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "metal_project_api_key" { | ||
continue | ||
} | ||
if _, err := client.APIKeys.ProjectGet(rs.Primary.ID, rs.Primary.Attributes["project_id"], nil); err == nil { | ||
return fmt.Errorf("ProjectAPI key still exists") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func testAccMetalProjectAPIKeyConfig_Basic() string { | ||
return fmt.Sprintf(` | ||
resource "metal_project" "test" { | ||
name = "tfacc-project-key-test" | ||
} | ||
resource "metal_project_api_key" "test" { | ||
project_id = metal_project.test.id | ||
description = "tfacc-project-key" | ||
read_only = true | ||
}`) | ||
} | ||
|
||
func TestAccMetalProjectAPIKey_Basic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccMetalProjectAPIKeyDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccMetalProjectAPIKeyConfig_Basic(), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrSet( | ||
"metal_project_api_key.test", "token"), | ||
resource.TestCheckResourceAttrPair( | ||
"metal_project_api_key.test", "project_id", | ||
"metal_project.test", "id"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} |
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,24 @@ | ||
package metal | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func resourceMetalUserAPIKey() *schema.Resource { | ||
userKeySchema := schemaMetalAPIKey() | ||
userKeySchema["user_id"] = &schema.Schema{ | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "UUID of user owning this key", | ||
} | ||
return &schema.Resource{ | ||
Create: resourceMetalAPIKeyCreate, | ||
Read: resourceMetalAPIKeyRead, | ||
Delete: resourceMetalAPIKeyDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: userKeySchema, | ||
} | ||
} |
Oops, something went wrong.