Skip to content

Commit

Permalink
add signed url key resource/fields for backend bucket
Browse files Browse the repository at this point in the history
  • Loading branch information
emilymye committed Mar 28, 2019
1 parent f8a4137 commit 3cbbf7a
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 59 deletions.
4 changes: 4 additions & 0 deletions products/compute/ansible.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ manifest: !ruby/object:Provider::Ansible::Manifest
datasources: !ruby/object:Overrides::ResourceOverrides
Autoscaler: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
BackendBucketSignedUrlKey: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
Snapshot: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
ManagedSslCertificate: !ruby/object:Overrides::Ansible::ResourceOverride
Expand Down Expand Up @@ -223,6 +225,8 @@ overrides: !ruby/object:Overrides::ResourceOverrides
# Not yet implemented.
Autoscaler: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
BackendBucketSignedUrlKey: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
RegionAutoscaler: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
Snapshot: !ruby/object:Overrides::Ansible::ResourceOverride
Expand Down
133 changes: 131 additions & 2 deletions products/compute/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,45 @@ objects:
guides:
'Using a Cloud Storage bucket as a load balancer backend': 'https://cloud.google.com/compute/docs/load-balancing/http/backend-bucket'
api: 'https://cloud.google.com/compute/docs/reference/v1/backendBuckets'
<%= indent(compile_file({}, 'templates/global_async.yaml.erb'), 4) %>
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
kind: 'compute#operation'
path: 'name'
base_url: 'projects/{{project}}/global/operations/{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
path: 'targetLink'
status: !ruby/object:Api::Async::Status
path: 'status'
complete: 'DONE'
allowed:
- 'PENDING'
- 'RUNNING'
- 'DONE'
error: !ruby/object:Api::Async::Error
path: 'error/errors'
message: 'message'
properties:
- !ruby/object:Api::Type::String
name: 'bucketName'
description: 'Cloud Storage bucket name.'
required: true
- !ruby/object:Api::Type::NestedObject
name: 'cdnPolicy'
description: 'Cloud CDN configuration for this Backend Bucket.'
properties:
- !ruby/object:Api::Type::Integer
name: 'signedUrlCacheMaxAgeSec'
default_value: 3600
description: |
Maximum number of seconds the response to a signed URL request will
be considered fresh. Defaults to 1hr (3600s). After this time period,
the response will be revalidated before being served.
When serving responses to signed URL requests,
Cloud CDN will internally behave as though
all responses from this backend had a "Cache-Control: public,
max-age=[TTL]" header, regardless of any existing Cache-Control
header. The actual headers served in responses will not be altered.
- !ruby/object:Api::Type::Time
name: 'creationTimestamp'
description: 'Creation timestamp in RFC3339 text format.'
Expand Down Expand Up @@ -239,6 +272,71 @@ objects:
last character, which cannot be a dash.
input: true
required: true
- !ruby/object:Api::Resource
name: 'BackendBucketSignedUrlKey'
kind: 'compute#BackendBucketSignedUrlKey'
input: true
base_url: projects/{{project}}/global/backendBuckets/{{backend_bucket}}
create_url: projects/{{project}}/global/backendBuckets/{{backend_bucket}}/addSignedUrlKey
create_verb: :POST
delete_url: projects/{{project}}/global/backendBuckets/{{backend_bucket}}/deleteSignedUrlKey?keyName={{name}}
delete_verb: :POST
self_link: projects/{{project}}/global/backendBuckets/{{backend_bucket}}
identity:
- name
nested_query: !ruby/object:Api::Resource::NestedQuery
keys:
- cdnPolicy
- signedUrlKeyNames
is_list_of_ids: true
description: |
A key for signing Cloud CDN signed URLs for BackendBuckets.
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Using Signed URLs': 'https://cloud.google.com/cdn/docs/using-signed-urls/'
api: 'https://cloud.google.com/compute/docs/reference/rest/v1/backendBuckets'
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
kind: 'compute#operation'
path: 'name'
base_url: 'projects/{{project}}/global/operations/{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
path: 'targetLink'
status: !ruby/object:Api::Async::Status
path: 'status'
complete: 'DONE'
allowed:
- 'PENDING'
- 'RUNNING'
- 'DONE'
error: !ruby/object:Api::Async::Error
path: 'error/errors'
message: 'message'
parameters:
- !ruby/object:Api::Type::ResourceRef
name: 'backendBucket'
resource: 'BackendBucket'
imports: 'name'
description: |
The backend bucket this signed URL key belongs.
required: true
input: true
properties:
- !ruby/object:Api::Type::String
name: 'name'
api_name: 'keyName'
description: |
Name of the signed URL key.
required: true
input: true
- !ruby/object:Api::Type::String
name: 'keyValue'
description: |
128-bit key value used for signing the URL. The key value must be a
valid RFC 4648 Section 5 base64url encoded string.
required: true
input: true
- !ruby/object:Api::Resource
name: 'BackendService'
kind: 'compute#backendService'
Expand All @@ -250,7 +348,24 @@ objects:
description: |
Creates a BackendService resource in the specified project using the data
included in the request.
<%= indent(compile_file({}, 'templates/global_async.yaml.erb'), 4) %>
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
kind: 'compute#operation'
path: 'name'
base_url: 'projects/{{project}}/global/operations/{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
path: 'targetLink'
status: !ruby/object:Api::Async::Status
path: 'status'
complete: 'DONE'
allowed:
- 'PENDING'
- 'RUNNING'
- 'DONE'
error: !ruby/object:Api::Async::Error
path: 'error/errors'
message: 'message'
properties:
- !ruby/object:Api::Type::Integer
name: 'affinityCookieTtlSec'
Expand Down Expand Up @@ -408,6 +523,20 @@ objects:
'&' and '=' will be percent encoded and not treated as
delimiters.
item_type: Api::Type::String
- !ruby/object:Api::Type::Integer
name: 'signedUrlCacheMaxAgeSec'
default_value: 3600
description: |
Maximum number of seconds the response to a signed URL request
will be considered fresh, defaults to 1hr (3600s). After this
time period, the response will be revalidated before
being served.
When serving responses to signed URL requests, Cloud CDN will
internally behave as though all responses from this backend had a
"Cache-Control: public, max-age=[TTL]" header, regardless of any
existing Cache-Control header. The actual headers served in
responses will not be altered.
- !ruby/object:Api::Type::NestedObject
name: 'connectionDraining'
description: 'Settings for connection draining'
Expand Down
2 changes: 2 additions & 0 deletions products/compute/inspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ manifest: !ruby/object:Provider::Inspec::Manifest
overrides: !ruby/object:Overrides::ResourceOverrides
Address: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: true
BackendBucketSignedUrlKey: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: true
DiskType: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: true
Firewall: !ruby/object:Overrides::Inspec::ResourceOverride
Expand Down
29 changes: 29 additions & 0 deletions products/compute/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,35 @@ overrides: !ruby/object:Overrides::ResourceOverrides
name: !ruby/object:Overrides::Terraform::PropertyOverride
validation: !ruby/object:Provider::Terraform::Validation
regex: '^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$'
cdnPolicy: !ruby/object:Overrides::Terraform::PropertyOverride
default_from_api: true
BackendBucketSignedUrlKey: !ruby/object:Overrides::Terraform::ResourceOverride
exclude_import: true
mutex: signedUrlKey/{{project}}/backendBuckets/{{backend_bucket}}/
examples:
- !ruby/object:Provider::Terraform::Examples
name: "backend_bucket_signed_url_key"
primary_resource_id: "backend_key"
vars:
key_name: "test-key"
backend_name: "test-signed-backend-bucket"
bucket_name: "test-storage-bucket"
skip_test: true
properties:
backendBucket: !ruby/object:Overrides::Terraform::PropertyOverride
ignore_read: true
name: !ruby/object:Overrides::Terraform::PropertyOverride
validation: !ruby/object:Provider::Terraform::Validation
regex: '^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$'
keyValue: !ruby/object:Overrides::Terraform::PropertyOverride
sensitive: true
ignore_read: true
docs: !ruby/object:Provider::Terraform::Docs
warning: |
All arguments including the key's value will be stored in the raw
state as plain-text. [Read more about sensitive data in state](/docs/state/sensitive-data.html).
Because the API does not return the sensitive key value,
we cannot confirm or reverse changes to a key outside of Terraform.
BackendService: !ruby/object:Overrides::Terraform::ResourceOverride
exclude: true
Disk: !ruby/object:Overrides::Terraform::ResourceOverride
Expand Down
17 changes: 17 additions & 0 deletions templates/terraform/examples/backend_bucket_signed_url_key.tf.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "google_compute_backend_bucket_signed_url_key" "backend_key" {
name = "<%= ctx[:vars]['key_name'] %>"
key_value = "pPsVemX8GM46QVeezid6Rw=="
backend_bucket = "${google_compute_backend_bucket.test_backend.name}"
}

resource "google_compute_backend_bucket" "test_backend" {
name = "<%= ctx[:vars]['backend_name'] %>"
description = "Contains beautiful images"
bucket_name = "${google_storage_bucket.bucket.name}"
enable_cdn = true
}

resource "google_storage_bucket" "bucket" {
name = "<%= ctx[:vars]['bucket_name'] %>"
location = "EU"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package google

import (
"fmt"
"testing"

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

func TestAccComputeBackendBucketSignedUrlKey_basic(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": acctest.RandString(10),
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendBucketSignedUrlKeyDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeBackendBucketSignedUrlKey_basic(context),
Check: testAccCheckComputeBackendBucketSignedUrlKeyCreated,
},
},
})
}

func testAccComputeBackendBucketSignedUrlKey_basic(context map[string]interface{}) string {
return Nprintf(`
resource "google_compute_backend_bucket_signed_url_key" "backend_key" {
name = "test-key-%{random_suffix}"
key_value = "iAmAFakeKeyRandomBytes=="
backend_bucket = "${google_compute_backend_bucket.test_backend.name}"
}
resource "google_compute_backend_bucket" "test_backend" {
name = "test-signed-backend-bucket-%{random_suffix}"
description = "Contains beautiful images"
bucket_name = "${google_storage_bucket.bucket.name}"
enable_cdn = true
}
resource "google_storage_bucket" "bucket" {
name = "test-storage-bucket-%{random_suffix}"
location = "EU"
}
`, context)
}

func testAccCheckComputeBackendBucketSignedUrlKeyDestroy(s *terraform.State) error {
exists, err := checkComputeBackendBucketSignedUrlKeyExists(s)
if err != nil && !isGoogleApiErrorWithCode(err, 404) {
return err
}
if exists {
return fmt.Errorf("ComputeBackendBucketSignedUrlKey still exists")
}
return nil
}

func testAccCheckComputeBackendBucketSignedUrlKeyCreated(s *terraform.State) error {
exists, err := checkComputeBackendBucketSignedUrlKeyExists(s)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("expected ComputeBackendBucketSignedUrlKey to have been created")
}
return nil
}

func checkComputeBackendBucketSignedUrlKeyExists(s *terraform.State) (bool, error) {
for name, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_backend_bucket_signed_url_key" {
continue
}
if strings.HasPrefix(name, "data.") {
continue
}

config := testAccProvider.Meta().(*Config)
keyName := rs.Primary.ID

url, err := replaceVarsForTest(rs, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/backendBuckets/{{backend_bucket}}")
if err != nil {
return false, err
}

res, err := sendRequest(config, "GET", url, nil)
if err == nil {
policyRaw, ok := res["cdnPolicy"]
if !ok {
return false, nil
}

policy := policyRaw.(map[string]interface{})
keyNames, ok := policy["signedUrlKeyNames"]
if !ok {
return false, nil
}

// Because the sensitive key value is not returned, all we can do is verify a
// key with this name exists and assume the key value hasn't been changed.
for _, k := range keyNames.([]interface{}) {
if k.(string) == keyName {
// Just return empty map to indicate key was found
return true, nil
}
}
}
}

return false, nil
}
Loading

0 comments on commit 3cbbf7a

Please sign in to comment.