-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Cloud functions #899
Cloud functions #899
Changes from 33 commits
eedd890
5c394fa
93f5856
8288741
c74e219
70c6fe9
c169968
b0939d0
6fd1f58
28ca0a8
127b69c
463af45
0c52870
e65ab5f
0180d8d
3696812
859ed3b
94c2e50
361691d
898cfad
5387b18
992b7a8
ea2abdb
45cace1
6623728
2e31b1d
02d5847
ee5da4a
ea9f204
172564a
3d13310
d9a36e8
f1e6cec
f466669
ea526b3
79db2cf
1478794
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"google.golang.org/api/cloudfunctions/v1" | ||
) | ||
|
||
type CloudFunctionsOperationWaiter struct { | ||
Service *cloudfunctions.Service | ||
Op *cloudfunctions.Operation | ||
} | ||
|
||
func (w *CloudFunctionsOperationWaiter) RefreshFunc() resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
op, err := w.Service.Operations.Get(w.Op.Name).Do() | ||
|
||
if err != nil { | ||
return nil, "", err | ||
} | ||
|
||
status := "PENDING" | ||
if op.Done == true { | ||
status = "DONE" | ||
} | ||
|
||
log.Printf("[DEBUG] Got %q when asking for operation %q", status, w.Op.Name) | ||
return op, status, nil | ||
} | ||
} | ||
|
||
func (w *CloudFunctionsOperationWaiter) Conf() *resource.StateChangeConf { | ||
return &resource.StateChangeConf{ | ||
Pending: []string{"PENDING"}, | ||
Target: []string{"DONE"}, | ||
Refresh: w.RefreshFunc(), | ||
} | ||
} | ||
|
||
func cloudFunctionsOperationWait(client *cloudfunctions.Service, | ||
op *cloudfunctions.Operation, activity string) error { | ||
return cloudFunctionsOperationWaitTime(client, op, activity, 4) | ||
} | ||
|
||
func cloudFunctionsOperationWaitTime(client *cloudfunctions.Service, op *cloudfunctions.Operation, | ||
activity string, timeoutMin int) error { | ||
w := &CloudFunctionsOperationWaiter{ | ||
Service: client, | ||
Op: op, | ||
} | ||
|
||
state := w.Conf() | ||
state.Delay = 10 * time.Second | ||
state.Timeout = time.Duration(timeoutMin) * time.Minute | ||
state.MinTimeout = 2 * time.Second | ||
opRaw, err := state.WaitForState() | ||
if err != nil { | ||
return fmt.Errorf("Error waiting for %s: %s", activity, err) | ||
} | ||
|
||
resultOp := opRaw.(*cloudfunctions.Operation) | ||
if resultOp.Error != nil { | ||
return fmt.Errorf(resultOp.Error.Message) | ||
} | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package google | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func dataSourceGoogleCloudFunctionsFunction() *schema.Resource { | ||
// Generate datasource schema from resource | ||
dsSchema := datasourceSchemaFromResourceSchema(resourceCloudFunctionsFunction().Schema) | ||
|
||
// Set 'Required' schema elements | ||
addRequiredFieldsToSchema(dsSchema, "name") | ||
|
||
// Set 'Optional' schema elements | ||
addOptionalFieldsToSchema(dsSchema, "source_archive_bucket", "source_archive_object") | ||
|
||
return &schema.Resource{ | ||
Read: dataSourceGoogleCloudFunctionsFunctionRead, | ||
Schema: dsSchema, | ||
} | ||
} | ||
|
||
func dataSourceGoogleCloudFunctionsFunctionRead(d *schema.ResourceData, meta interface{}) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this significantly different from the resource read function? If not, you should just call that one from this to save on some duplicated code. You might also be able to do a similar thing for the schema- check out data_source_google_container_cluster.go for an example of a data source that utilitzes the code from the resource really well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed, now code looks cleaner - thank you for heads up :) |
||
config := meta.(*Config) | ||
|
||
project, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
region, err := getRegion(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
cloudFuncId := &cloudFunctionId{ | ||
Project: project, | ||
Region: region, | ||
Name: d.Get("name").(string), | ||
} | ||
|
||
d.SetId(cloudFuncId.terraformId()) | ||
|
||
return resourceCloudFunctionsRead(d, meta) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccDataSourceGoogleCloudFunctionsFunction_basic(t *testing.T) { | ||
t.Parallel() | ||
|
||
funcDataNameHttp := "data.google_cloudfunctions_function.function_http" | ||
funcDataNamePubSub := "data.google_cloudfunctions_function.function_pubsub" | ||
funcDataNameBucket := "data.google_cloudfunctions_function.function_bucket" | ||
functionName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) | ||
bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) | ||
topicName := fmt.Sprintf("tf-test-sub-%s", acctest.RandString(10)) | ||
zipFilePath, err := createZIPArchiveForIndexJs(testHTTPTriggerPath) | ||
if err != nil { | ||
t.Fatal(err.Error()) | ||
} | ||
defer os.Remove(zipFilePath) // clean up | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckCloudFunctionsFunctionDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceGoogleCloudFunctionsFunctionConfig(functionName, | ||
bucketName, zipFilePath, topicName), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccDataSourceGoogleCloudFunctionsFunctionCheck(funcDataNameHttp, | ||
"google_cloudfunctions_function.function_http"), | ||
testAccDataSourceGoogleCloudFunctionsFunctionCheck(funcDataNamePubSub, | ||
"google_cloudfunctions_function.function_pubsub"), | ||
testAccDataSourceGoogleCloudFunctionsFunctionCheck(funcDataNameBucket, | ||
"google_cloudfunctions_function.function_bucket"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccDataSourceGoogleCloudFunctionsFunctionCheck(dataSourceName string, resourceName string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
ds, ok := s.RootModule().Resources[dataSourceName] | ||
if !ok { | ||
return fmt.Errorf("root module has no resource called %s", dataSourceName) | ||
} | ||
|
||
rs, ok := s.RootModule().Resources[resourceName] | ||
if !ok { | ||
return fmt.Errorf("can't find %s in state", resourceName) | ||
} | ||
|
||
dsAttr := ds.Primary.Attributes | ||
rsAttr := rs.Primary.Attributes | ||
|
||
cloudFuncAttrToCheck := []string{ | ||
"name", | ||
"region", | ||
"description", | ||
"available_memory_mb", | ||
"timeout", | ||
"storage_bucket", | ||
"storage_object", | ||
"entry_point", | ||
"trigger_http", | ||
"trigger_bucket", | ||
"trigger_topic", | ||
} | ||
|
||
for _, attr := range cloudFuncAttrToCheck { | ||
if dsAttr[attr] != rsAttr[attr] { | ||
return fmt.Errorf( | ||
"%s is %s; want %s", | ||
attr, | ||
dsAttr[attr], | ||
rsAttr[attr], | ||
) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccDataSourceGoogleCloudFunctionsFunctionConfig(functionName string, | ||
bucketName string, zipFilePath string, topicName string) string { | ||
return fmt.Sprintf(` | ||
resource "google_storage_bucket" "bucket" { | ||
name = "%s" | ||
} | ||
|
||
resource "google_storage_bucket_object" "archive" { | ||
name = "index.zip" | ||
bucket = "${google_storage_bucket.bucket.name}" | ||
source = "%s" | ||
} | ||
|
||
resource "google_cloudfunctions_function" "function_http" { | ||
name = "%s-http" | ||
description = "test function" | ||
available_memory_mb = 128 | ||
source_archive_bucket = "${google_storage_bucket.bucket.name}" | ||
source_archive_object = "${google_storage_bucket_object.archive.name}" | ||
trigger_http = true | ||
timeout = 61 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. found some more tabs for you here (and on the same line in the other tests in this file) |
||
entry_point = "helloGET" | ||
} | ||
|
||
resource "google_cloudfunctions_function" "function_bucket" { | ||
name = "%s-bucket" | ||
available_memory_mb = 128 | ||
source_archive_bucket = "${google_storage_bucket.bucket.name}" | ||
source_archive_object = "${google_storage_bucket_object.archive.name}" | ||
trigger_bucket = "${google_storage_bucket.bucket.name}" | ||
timeout = 61 | ||
entry_point = "helloGET" | ||
} | ||
|
||
resource "google_pubsub_topic" "sub" { | ||
name = "%s" | ||
} | ||
|
||
resource "google_cloudfunctions_function" "function_pubsub" { | ||
name = "%s-pubsub" | ||
available_memory_mb = 128 | ||
source_archive_bucket = "${google_storage_bucket.bucket.name}" | ||
source_archive_object = "${google_storage_bucket_object.archive.name}" | ||
trigger_topic = "${google_pubsub_topic.sub.name}" | ||
timeout = 61 | ||
entry_point = "helloGET" | ||
} | ||
|
||
data "google_cloudfunctions_function" "function_http" { | ||
name = "${google_cloudfunctions_function.function_http.name}" | ||
} | ||
|
||
data "google_cloudfunctions_function" "function_bucket" { | ||
name = "${google_cloudfunctions_function.function_bucket.name}" | ||
} | ||
|
||
data "google_cloudfunctions_function" "function_pubsub" { | ||
name = "${google_cloudfunctions_function.function_pubsub.name}" | ||
} | ||
`, bucketName, zipFilePath, functionName, functionName, | ||
topicName, functionName) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since nothing in the read function actually looks at the value of these in state, I don't think they need to be set to Optional. However, the read function does look at the values of project and region, so you should probably add those here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed