diff --git a/builtin/providers/google/config.go b/builtin/providers/google/config.go index 218fda06f9ec..5467c6483b95 100644 --- a/builtin/providers/google/config.go +++ b/builtin/providers/google/config.go @@ -18,6 +18,7 @@ import ( "google.golang.org/api/dns/v1" "google.golang.org/api/sqladmin/v1beta4" "google.golang.org/api/storage/v1" + "google.golang.org/api/pubsub/v1" ) // Config is the configuration structure used to instantiate the Google @@ -32,6 +33,7 @@ type Config struct { clientDns *dns.Service clientStorage *storage.Service clientSqlAdmin *sqladmin.Service + clientPubsub *pubsub.Service } func (c *Config) loadAndValidate() error { @@ -128,6 +130,13 @@ func (c *Config) loadAndValidate() error { } c.clientSqlAdmin.UserAgent = userAgent + log.Printf("[INFO] Instatiating Google Pubsub Client...") + c.clientPubsub, err = pubsub.New(client) + if err != nil { + return err + } + c.clientPubsub.UserAgent = userAgent + return nil } diff --git a/builtin/providers/google/provider.go b/builtin/providers/google/provider.go index b2d083bc2583..3fa46c7d5646 100644 --- a/builtin/providers/google/provider.go +++ b/builtin/providers/google/provider.go @@ -70,6 +70,8 @@ func Provider() terraform.ResourceProvider { "google_dns_record_set": resourceDnsRecordSet(), "google_sql_database": resourceSqlDatabase(), "google_sql_database_instance": resourceSqlDatabaseInstance(), + "google_pubsub_topic": resourcePubsubTopic(), + "google_pubsub_subscription": resourcePubsubSubscription(), "google_storage_bucket": resourceStorageBucket(), "google_storage_bucket_acl": resourceStorageBucketAcl(), "google_storage_bucket_object": resourceStorageBucketObject(), diff --git a/builtin/providers/google/resource_pubsub_subscription.go b/builtin/providers/google/resource_pubsub_subscription.go new file mode 100644 index 000000000000..6a1f19da731a --- /dev/null +++ b/builtin/providers/google/resource_pubsub_subscription.go @@ -0,0 +1,134 @@ +package google + +import ( + "fmt" + "google.golang.org/api/pubsub/v1" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourcePubsubSubscription() *schema.Resource { + return &schema.Resource{ + Create: resourcePubsubSubscriptionCreate, + Read: resourcePubsubSubscriptionRead, + Delete: resourcePubsubSubscriptionDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "ack_deadline_seconds": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + + "push_config": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Elem: schema.TypeString, + }, + + "push_endpoint": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + + "topic": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + }, + } +} + +func cleanAdditionalArgs(args map[string]interface{}) map[string]string { + cleaned_args := make(map[string]string) + for k,v := range args { + cleaned_args[k] = v.(string) + } + return cleaned_args +} + +func resourcePubsubSubscriptionCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + name := fmt.Sprintf("projects/%s/subscriptions/%s", config.Project, d.Get("name").(string)) + computed_topic_name := fmt.Sprintf("projects/%s/topics/%s", config.Project, d.Get("topic").(string)) + + // process optional parameters + var ackDeadlineSeconds int64 + ackDeadlineSeconds = 10 + if v, ok := d.GetOk("ack_deadline_seconds"); ok { + ackDeadlineSeconds = v.(int64) + } + + var subscription *pubsub.Subscription + if v, ok := d.GetOk("push_config"); ok { + push_configs := v.([]interface{}) + + if len(push_configs) > 1 { + return fmt.Errorf("At most one PushConfig is allowed per subscription!") + } + + push_config := push_configs[0].(map[string]interface{}) + attributes := push_config["attributes"].(map[string]interface{}) + attributesClean := cleanAdditionalArgs(attributes) + pushConfig := &pubsub.PushConfig{Attributes: attributesClean, PushEndpoint: push_config["push_endpoint"].(string)} + subscription = &pubsub.Subscription{AckDeadlineSeconds: ackDeadlineSeconds, Topic: computed_topic_name, PushConfig: pushConfig} + } else { + subscription = &pubsub.Subscription{AckDeadlineSeconds: ackDeadlineSeconds, Topic: computed_topic_name} + } + + call := config.clientPubsub.Projects.Subscriptions.Create(name, subscription) + res, err := call.Do() + if err != nil { + return err + } + + d.SetId(res.Name) + + return nil +} + +func resourcePubsubSubscriptionRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + name := d.Id() + call := config.clientPubsub.Projects.Subscriptions.Get(name) + _, err := call.Do() + if err != nil { + return err + } + + return nil +} + + +func resourcePubsubSubscriptionDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + name := d.Id() + call := config.clientPubsub.Projects.Subscriptions.Delete(name) + _, err := call.Do() + if err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/google/resource_pubsub_subscription_test.go b/builtin/providers/google/resource_pubsub_subscription_test.go new file mode 100644 index 000000000000..b0eb2a25ba91 --- /dev/null +++ b/builtin/providers/google/resource_pubsub_subscription_test.go @@ -0,0 +1,74 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccPubsubSubscriptionCreate(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPubsubSubscriptionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccPubsubSubscription, + Check: resource.ComposeTestCheckFunc( + testAccPubsubSubscriptionExists( + "google_pubsub_subscription.foobar_sub"), + ), + }, + }, + }) +} + +func testAccCheckPubsubSubscriptionDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_pubsub_subscription" { + continue + } + + config := testAccProvider.Meta().(*Config) + _, err := config.clientPubsub.Projects.Subscriptions.Get(rs.Primary.ID).Do() + if err != nil { + fmt.Errorf("Subscription still present") + } + } + + return nil +} + +func testAccPubsubSubscriptionExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + config := testAccProvider.Meta().(*Config) + _, err := config.clientPubsub.Projects.Subscriptions.Get(rs.Primary.ID).Do() + if err != nil { + fmt.Errorf("Subscription still present") + } + + return nil + } +} + +const testAccPubsubSubscription = ` +resource "google_pubsub_topic" "foobar_sub" { + name = "foobar_sub" +} + +resource "google_pubsub_subscription" "foobar_sub" { + name = "foobar_sub" + topic = "${google_pubsub_topic.foobar_sub.name}" +}` + diff --git a/builtin/providers/google/resource_pubsub_topic.go b/builtin/providers/google/resource_pubsub_topic.go new file mode 100644 index 000000000000..c6ec7cf0fe78 --- /dev/null +++ b/builtin/providers/google/resource_pubsub_topic.go @@ -0,0 +1,68 @@ +package google + +import ( + "fmt" + "google.golang.org/api/pubsub/v1" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourcePubsubTopic() *schema.Resource { + return &schema.Resource{ + Create: resourcePubsubTopicCreate, + Read: resourcePubsubTopicRead, + Delete: resourcePubsubTopicDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + }, + } +} + +func resourcePubsubTopicCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + name := fmt.Sprintf("projects/%s/topics/%s", config.Project, d.Get("name").(string)) + topic := &pubsub.Topic{} + + call := config.clientPubsub.Projects.Topics.Create(name, topic) + res, err := call.Do() + if err != nil { + return err + } + + d.SetId(res.Name) + + return nil +} + +func resourcePubsubTopicRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + name := d.Id() + call := config.clientPubsub.Projects.Topics.Get(name) + _, err := call.Do() + if err != nil { + return err + } + + return nil +} + + +func resourcePubsubTopicDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + name := d.Id() + call := config.clientPubsub.Projects.Topics.Delete(name) + _, err := call.Do() + if err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/google/resource_pubsub_topic_test.go b/builtin/providers/google/resource_pubsub_topic_test.go new file mode 100644 index 000000000000..3d6c655c7d48 --- /dev/null +++ b/builtin/providers/google/resource_pubsub_topic_test.go @@ -0,0 +1,68 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccPubsubTopicCreate(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPubsubTopicDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccPubsubTopic, + Check: resource.ComposeTestCheckFunc( + testAccPubsubTopicExists( + "google_pubsub_topic.foobar"), + ), + }, + }, + }) +} + +func testAccCheckPubsubTopicDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_pubsub_topic" { + continue + } + + config := testAccProvider.Meta().(*Config) + _, err := config.clientPubsub.Projects.Topics.Get(rs.Primary.ID).Do() + if err != nil { + fmt.Errorf("Topic still present") + } + } + + return nil +} + +func testAccPubsubTopicExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + config := testAccProvider.Meta().(*Config) + _, err := config.clientPubsub.Projects.Topics.Get(rs.Primary.ID).Do() + if err != nil { + fmt.Errorf("Topic still present") + } + + return nil + } +} + +const testAccPubsubTopic = ` +resource "google_pubsub_topic" "foobar" { + name = "foobar" +}` diff --git a/website/source/docs/providers/google/r/pubsub_subscription.html.markdown b/website/source/docs/providers/google/r/pubsub_subscription.html.markdown new file mode 100644 index 000000000000..d1f43ef4151c --- /dev/null +++ b/website/source/docs/providers/google/r/pubsub_subscription.html.markdown @@ -0,0 +1,39 @@ +--- +layout: "google" +page_title: "Google: google_pubsub_subscription" +sidebar_current: "docs-google-pubsub-subscription" +description: |- + Creates a subscription in Google's pubsub queueing system +--- + +# google\_pubsub\_subscripion + +Creates a subscription in Google's pubsub queueing system. For more information see +[the official documentation](https://cloud.google.com/pubsub/docs) and +[API](https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions). + + +## Example Usage + +``` +resource "google_pubsub_subscription" "default" { + name = "default-subscription" + topic = "default-topic" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A unique name for the resource, required by pubsub. + Changing this forces a new resource to be created. +* `topic` - (Required) A topic to bind this subscription to, required by pubsub. + Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `name` - The name of the resource. +* `topic` - The topic to bind this resource to. diff --git a/website/source/docs/providers/google/r/pubsub_topic.html.markdown b/website/source/docs/providers/google/r/pubsub_topic.html.markdown new file mode 100644 index 000000000000..e371ddef196a --- /dev/null +++ b/website/source/docs/providers/google/r/pubsub_topic.html.markdown @@ -0,0 +1,35 @@ +--- +layout: "google" +page_title: "Google: google_pubsub_topic" +sidebar_current: "docs-google-pubsub-topic" +description: |- + Creates a topic in Google's pubsub queueing system +--- + +# google\_pubsub\_topic + +Creates a topic in Google's pubsub queueing system. For more information see +[the official documentation](https://cloud.google.com/pubsub/docs) and +[API](https://cloud.google.com/pubsub/reference/rest/v1/projects.topics). + + +## Example Usage + +``` +resource "google_pubsub_topic" "default" { + name = "default-topic" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A unique name for the resource, required by pubsub. + Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `name` - The name of the resource. diff --git a/website/source/layouts/google.erb b/website/source/layouts/google.erb index a8b9b3f2aad2..2ffae1958356 100644 --- a/website/source/layouts/google.erb +++ b/website/source/layouts/google.erb @@ -129,6 +129,19 @@ + > + Google PubSub Resources + + + > Google SQL Resources