forked from gophercloud/gophercloud
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Key manager v1: add secret data source (gophercloud#815)
- Loading branch information
1 parent
316002a
commit c0784af
Showing
5 changed files
with
466 additions
and
0 deletions.
There are no files selected for viewing
284 changes: 284 additions & 0 deletions
284
openstack/data_source_openstack_keymanager_secret_v1.go
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,284 @@ | ||
package openstack | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"regexp" | ||
"strings" | ||
"time" | ||
|
||
"github.com/gophercloud/gophercloud/openstack/keymanager/v1/secrets" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/helper/validation" | ||
) | ||
|
||
var validDateFilters = []string{ | ||
string(secrets.DateFilterGT), | ||
string(secrets.DateFilterGTE), | ||
string(secrets.DateFilterLT), | ||
string(secrets.DateFilterLTE), | ||
} | ||
|
||
func dataSourceKeyManagerSecretV1() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceKeyManagerSecretV1Read, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"region": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
|
||
"name": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
|
||
"bit_length": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
}, | ||
|
||
"algorithm": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
|
||
"mode": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
|
||
"secret_type": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
"symmetric", "public", "private", "passphrase", "certificate", "opaque", | ||
}, false), | ||
}, | ||
|
||
"acl_only": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
}, | ||
|
||
"expiration_filter": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ValidateFunc: dataSourceValidateDateFilter, | ||
}, | ||
|
||
"created_at_filter": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ValidateFunc: dataSourceValidateDateFilter, | ||
}, | ||
|
||
"updated_at_filter": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ValidateFunc: dataSourceValidateDateFilter, | ||
}, | ||
|
||
// computed | ||
"secret_ref": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"creator_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"expiration": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"created_at": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"updated_at": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"content_types": { | ||
Type: schema.TypeMap, | ||
Computed: true, | ||
}, | ||
|
||
"status": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"payload": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"payload_content_type": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"payload_content_encoding": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"metadata": { | ||
Type: schema.TypeMap, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceKeyManagerSecretV1Read(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
kmClient, err := config.keyManagerV1Client(GetRegion(d, config)) | ||
if err != nil { | ||
return fmt.Errorf("Error creating OpenStack barbican client: %s", err) | ||
} | ||
|
||
aclOnly := d.Get("acl_only").(bool) | ||
|
||
listOpts := secrets.ListOpts{ | ||
Name: d.Get("name").(string), | ||
Bits: d.Get("bit_length").(int), | ||
Alg: d.Get("algorithm").(string), | ||
Mode: d.Get("mode").(string), | ||
SecretType: secrets.SecretType(d.Get("secret_type").(string)), | ||
ACLOnly: &aclOnly, | ||
CreatedQuery: dataSourceParseDateFilter(d.Get("created_at_filter").(string)), | ||
UpdatedQuery: dataSourceParseDateFilter(d.Get("updated_at_filter").(string)), | ||
ExpirationQuery: dataSourceParseDateFilter(d.Get("expiration_filter").(string)), | ||
} | ||
|
||
log.Printf("[DEBUG] %#+v List Options: %#v", dataSourceParseDateFilter(d.Get("updated_at_filter").(string)), listOpts) | ||
|
||
allPages, err := secrets.List(kmClient, listOpts).AllPages() | ||
if err != nil { | ||
return fmt.Errorf("Unable to query secrets: %s", err) | ||
} | ||
|
||
allSecrets, err := secrets.ExtractSecrets(allPages) | ||
if err != nil { | ||
return fmt.Errorf("Unable to retrieve secrets: %s", err) | ||
} | ||
|
||
if len(allSecrets) < 1 { | ||
return fmt.Errorf("Your query returned no results. " + | ||
"Please change your search criteria and try again.") | ||
} | ||
|
||
if len(allSecrets) > 1 { | ||
log.Printf("[DEBUG] Multiple results found: %#v", allSecrets) | ||
return fmt.Errorf("Your query returned more than one result. Please try a more " + | ||
"specific search criteria.") | ||
} | ||
|
||
secret := allSecrets[0] | ||
|
||
log.Printf("[DEBUG] Retrieved openstack_keymanager_secret_v1 %s: %#v", d.Id(), secret) | ||
|
||
uuid := keyManagerSecretV1GetUUIDfromSecretRef(secret.SecretRef) | ||
|
||
d.SetId(uuid) | ||
d.Set("name", secret.Name) | ||
d.Set("bit_length", secret.BitLength) | ||
d.Set("algorithm", secret.Algorithm) | ||
d.Set("creator_id", secret.CreatorID) | ||
d.Set("mode", secret.Mode) | ||
d.Set("secret_ref", secret.SecretRef) | ||
d.Set("secret_type", secret.SecretType) | ||
d.Set("status", secret.Status) | ||
d.Set("created_at", secret.Created.Format(time.RFC3339)) | ||
d.Set("updated_at", secret.Updated.Format(time.RFC3339)) | ||
d.Set("content_types", secret.ContentTypes) | ||
|
||
// don't fail, if the default key doesn't exist | ||
payloadContentType, _ := secret.ContentTypes["default"] | ||
d.Set("payload_content_type", payloadContentType) | ||
|
||
d.Set("payload", keyManagerSecretV1GetPayload(kmClient, d.Id())) | ||
metadataMap, err := secrets.GetMetadata(kmClient, d.Id()).Extract() | ||
if err != nil { | ||
log.Printf("[DEBUG] Unable to get metadata: %s", err) | ||
} | ||
d.Set("metadata", metadataMap) | ||
|
||
if secret.Expiration == (time.Time{}) { | ||
d.Set("expiration", "") | ||
} else { | ||
d.Set("expiration", secret.Expiration.Format(time.RFC3339)) | ||
} | ||
|
||
// Set the region | ||
d.Set("region", GetRegion(d, config)) | ||
|
||
return nil | ||
} | ||
|
||
func dataSourceParseDateFilter(date string) *secrets.DateQuery { | ||
// error checks are not necessary, since they were validated by terraform validate functions | ||
var parts []string | ||
if regexp.MustCompile("^" + strings.Join(validDateFilters, "|") + ":").Match([]byte(date)) { | ||
parts = strings.SplitN(date, ":", 2) | ||
} else { | ||
parts = []string{date} | ||
} | ||
|
||
var parsedTime time.Time | ||
var filter *secrets.DateQuery | ||
|
||
if len(parts) == 2 { | ||
parsedTime, _ = time.Parse(time.RFC3339, parts[1]) | ||
|
||
filter = &secrets.DateQuery{Date: parsedTime, Filter: secrets.DateFilter(parts[0])} | ||
} else { | ||
parsedTime, _ = time.Parse(time.RFC3339, parts[0]) | ||
|
||
filter = &secrets.DateQuery{Date: parsedTime} | ||
} | ||
|
||
if parsedTime == (time.Time{}) { | ||
return nil | ||
} | ||
|
||
return filter | ||
} | ||
|
||
func dataSourceValidateDateFilter(v interface{}, k string) (ws []string, errors []error) { | ||
var parts []string | ||
if regexp.MustCompile("^" + strings.Join(validDateFilters, "|") + ":").Match([]byte(v.(string))) { | ||
parts = strings.SplitN(v.(string), ":", 2) | ||
} else { | ||
parts = []string{v.(string)} | ||
} | ||
|
||
if len(parts) == 2 { | ||
if !strSliceContains(validDateFilters, parts[0]) { | ||
errors = append(errors, fmt.Errorf("Invalid %q date filter, supported: %+q", parts[0], validDateFilters)) | ||
} | ||
|
||
_, err := time.Parse(time.RFC3339, parts[1]) | ||
if err != nil { | ||
errors = append(errors, err) | ||
} | ||
|
||
return | ||
} | ||
|
||
_, err := time.Parse(time.RFC3339, parts[0]) | ||
if err != nil { | ||
errors = append(errors, err) | ||
} | ||
|
||
return | ||
} |
73 changes: 73 additions & 0 deletions
73
openstack/data_source_openstack_keymanager_secret_v1_test.go
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,73 @@ | ||
package openstack | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccKeyManagerSecretV1DataSource_basic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheckKeyManager(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckNetworkingV2PortDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccKeyManagerSecretV1DataSource_basic, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrPair( | ||
"data.openstack_keymanager_secret_v1.secret_1", "id", | ||
"openstack_keymanager_secret_v1.secret_1", "id"), | ||
resource.TestCheckResourceAttrPair( | ||
"data.openstack_keymanager_secret_v1.secret_2", "id", | ||
"openstack_keymanager_secret_v1.secret_2", "id"), | ||
resource.TestCheckResourceAttrPair( | ||
"data.openstack_keymanager_secret_v1.secret_1", "payload", | ||
"openstack_keymanager_secret_v1.secret_1", "payload"), | ||
resource.TestCheckResourceAttrPair( | ||
"data.openstack_keymanager_secret_v1.secret_2", "payload", | ||
"openstack_keymanager_secret_v1.secret_2", "payload"), | ||
resource.TestCheckResourceAttr( | ||
"data.openstack_keymanager_secret_v1.secret_1", "metadata.foo", "update"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
const testAccKeyManagerSecretV1DataSource_basic = ` | ||
resource "openstack_keymanager_secret_v1" "secret_1" { | ||
algorithm = "aes" | ||
bit_length = 192 | ||
mode = "cbc" | ||
name = "mysecret" | ||
payload = "foobar" | ||
secret_type = "passphrase" | ||
payload_content_type = "text/plain" | ||
metadata = { | ||
foo = "update" | ||
} | ||
} | ||
resource "openstack_keymanager_secret_v1" "secret_2" { | ||
algorithm = "aes" | ||
bit_length = 256 | ||
mode = "cbc" | ||
name = "mysecret" | ||
secret_type = "passphrase" | ||
payload = "foo" | ||
expiration = "3000-07-31T12:02:46Z" | ||
payload_content_type = "text/plain" | ||
} | ||
data "openstack_keymanager_secret_v1" "secret_1" { | ||
bit_length = "${openstack_keymanager_secret_v1.secret_1.bit_length}" | ||
secret_type = "passphrase" | ||
} | ||
data "openstack_keymanager_secret_v1" "secret_2" { | ||
mode = "cbc" | ||
secret_type = "passphrase" | ||
expiration_filter = "${openstack_keymanager_secret_v1.secret_2.expiration}" | ||
} | ||
` |
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
Oops, something went wrong.