Skip to content

Commit

Permalink
Keymanager V1: secrets resource (#807)
Browse files Browse the repository at this point in the history
* Added new resources openstack_keymanager_secret_v1 and openstack_keymanager_secret_metadata_v1

* Added import test and documentation

* Refactor to comply with code cleanup (#456)

* Secret metadata is no longer its own resource, various small bugfixes

Removed secrets metadata resource from provider.go

Fixed unit test that wasn't running

Fixed unit test that wasn't running

* Turned tabs into whitespaces

* Fix style nits

* Small style corrections, add security notice

* vendor commit

* Fix various nits

Add content types to documentation

* Add DiffSuppressFunc for the "payload" parameter

* Bump vendor dependencies

* Introduce setting the expiration date

* Add base64 encoding support

* Update secrets docs

* Handle importing and applying with the metadata

Avoid the "Conflict. Key in request is already in the secret metadata" error message after updating the imported secret with the metadata.

* Fix the "payload_content_type" import

* Docs typo fix

* Update docs format

* Fix code typos

* Fix code typos

* Make secret name optional, as it is mentioned in the docs
  • Loading branch information
kayrus authored and ozerovandrei committed Jul 30, 2019
1 parent 4ab8aa2 commit bd3b959
Show file tree
Hide file tree
Showing 14 changed files with 1,860 additions and 1 deletion.
16 changes: 16 additions & 0 deletions openstack/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,19 @@ func (c *Config) sharedfilesystemV2Client(region string) (*gophercloud.ServiceCl

return client, nil
}

func (c *Config) keyManagerV1Client(region string) (*gophercloud.ServiceClient, error) {
client, err := openstack.NewKeyManagerV1(c.OsClient, gophercloud.EndpointOpts{
Region: c.determineRegion(region),
Availability: c.getEndpointType(),
})

if err != nil {
return client, err
}

// Check if an endpoint override was specified for the keymanager service.
client = c.determineEndpoint(client, "key-manager")

return client, nil
}
27 changes: 27 additions & 0 deletions openstack/import_openstack_keymanager_secret_v1_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package openstack

import (
"testing"

"github.com/hashicorp/terraform/helper/resource"
)

func TestAccKeyManagerSecretV1_importBasic(t *testing.T) {
resourceName := "openstack_keymanager_secret_v1.secret_1"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckKeyManager(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckSecretV1Destroy,
Steps: []resource.TestStep{
{
Config: testAccKeyManagerSecretV1_basic,
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
127 changes: 127 additions & 0 deletions openstack/keymanager_secret_v1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package openstack

import (
"encoding/base64"
"fmt"
"log"
"strings"

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/keymanager/v1/secrets"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)

func keyManagerSecretV1WaitForSecretDeletion(kmClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
err := secrets.Delete(kmClient, id).Err
if err == nil {
return "", "DELETED", nil
}

if _, ok := err.(gophercloud.ErrDefault404); ok {
return "", "DELETED", nil
}

return nil, "ACTIVE", err
}
}

func keyManagerSecretV1SecretType(v string) secrets.SecretType {
var stype secrets.SecretType
switch v {
case "symmetric":
stype = secrets.SymmetricSecret
case "public":
stype = secrets.PublicSecret
case "private":
stype = secrets.PrivateSecret
case "passphrase":
stype = secrets.PassphraseSecret
case "certificate":
stype = secrets.CertificateSecret
case "opaque":
stype = secrets.OpaqueSecret
}

return stype
}

func keyManagerSecretV1WaitForSecretCreation(kmClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
secret, err := secrets.Get(kmClient, id).Extract()
if err != nil {
if _, ok := err.(gophercloud.ErrDefault404); ok {
return "", "NOT_CREATED", nil
}

return "", "NOT_CREATED", err
}

if secret.Status == "ERROR" {
return "", secret.Status, fmt.Errorf("Error creating secret")
}

return secret, secret.Status, nil
}
}

func keyManagerSecretV1GetUUIDfromSecretRef(ref string) string {
// secret ref has form https://{barbican_host}/v1/secrets/{secret_uuid}
// so we are only interested in the last part
ref_split := strings.Split(ref, "/")
uuid := ref_split[len(ref_split)-1]
return uuid
}

func flattenKeyManagerSecretV1Metadata(d *schema.ResourceData) map[string]string {
m := make(map[string]string)
for key, val := range d.Get("metadata").(map[string]interface{}) {
m[key] = val.(string)
}
return m
}

func keyManagerSecretMetadataV1WaitForSecretMetadataCreation(kmClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
metadata, err := secrets.GetMetadata(kmClient, id).Extract()
if err != nil {
if _, ok := err.(gophercloud.ErrDefault404); ok {
return "", "NOT_CREATED", nil
}

return "", "NOT_CREATED", err
}
return metadata, "ACTIVE", nil
}
}

func keyManagerSecretV1GetPayload(kmClient *gophercloud.ServiceClient, id string) string {
payload, err := secrets.GetPayload(kmClient, id, nil).Extract()
if err != nil {
fmt.Errorf("Could not retrieve payload for secret with id %s: %s", id, err)
}
return string(payload)
}

func resourceSecretV1PayloadBase64CustomizeDiff(diff *schema.ResourceDiff) error {
encoding := diff.Get("payload_content_encoding").(string)
if diff.Id() != "" && diff.HasChange("payload") && encoding == "base64" {
o, n := diff.GetChange("payload")
oldPayload := o.(string)
newPayload := n.(string)

v, err := base64.StdEncoding.DecodeString(newPayload)
if err != nil {
return fmt.Errorf("The Payload is not in the defined base64 format: %s", err)
}
newPayloadDecoded := string(v)

if oldPayload == newPayloadDecoded {
log.Printf("[DEBUG] payload has not changed. clearing diff")
return diff.Clear("payload")
}
}

return nil
}
1 change: 1 addition & 0 deletions openstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ func Provider() terraform.ResourceProvider {
"openstack_sharedfilesystem_sharenetwork_v2": resourceSharedFilesystemShareNetworkV2(),
"openstack_sharedfilesystem_share_v2": resourceSharedFilesystemShareV2(),
"openstack_sharedfilesystem_share_access_v2": resourceSharedFilesystemShareAccessV2(),
"openstack_keymanager_secret_v1": resourceKeyManagerSecretV1(),
},

ConfigureFunc: configureProvider,
Expand Down
9 changes: 9 additions & 0 deletions openstack/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var (
OS_CONTAINER_INFRA_ENVIRONMENT = os.Getenv("OS_CONTAINER_INFRA_ENVIRONMENT")
OS_SFS_ENVIRONMENT = os.Getenv("OS_SFS_ENVIRONMENT")
OS_TRANSPARENT_VLAN_ENVIRONMENT = os.Getenv("OS_TRANSPARENT_VLAN_ENVIRONMENT")
OS_KEYMANAGER_ENVIRONMENT = os.Getenv("OS_KEYMANAGER_ENVIRONMENT")
)

var testAccProviders map[string]terraform.ResourceProvider
Expand Down Expand Up @@ -139,6 +140,14 @@ func testAccPreCheckVPN(t *testing.T) {
}
}

func testAccPreCheckKeyManager(t *testing.T) {
testAccPreCheckRequiredEnvVars(t)

if OS_KEYMANAGER_ENVIRONMENT == "" {
t.Skip("This environment does not support Barbican Keymanager tests")
}
}

func testAccPreCheckContainerInfra(t *testing.T) {
testAccPreCheckRequiredEnvVars(t)

Expand Down
Loading

0 comments on commit bd3b959

Please sign in to comment.