Skip to content

Commit

Permalink
Add resource for enabling firebase (#3281) (#1885)
Browse files Browse the repository at this point in the history
* Add resource for enabling firebase

* removing whitespace for GA terraform

* Change skip_delete to resource level property

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Mar 24, 2020
1 parent 61737b6 commit c1eeb70
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .changelog/3281.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
firebase: Add the `google_firebase_project` resource which will enable Firebase for a referenced Google project.
```
3 changes: 3 additions & 0 deletions google-beta/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type Config struct {
DialogflowBasePath string
DNSBasePath string
FilestoreBasePath string
FirebaseBasePath string
FirestoreBasePath string
GameServicesBasePath string
HealthcareBasePath string
Expand Down Expand Up @@ -242,6 +243,7 @@ var DeploymentManagerDefaultBasePath = "https://www.googleapis.com/deploymentman
var DialogflowDefaultBasePath = "https://dialogflow.googleapis.com/v2/"
var DNSDefaultBasePath = "https://www.googleapis.com/dns/v1beta2/"
var FilestoreDefaultBasePath = "https://file.googleapis.com/v1/"
var FirebaseDefaultBasePath = "https://firebase.googleapis.com/v1beta1/"
var FirestoreDefaultBasePath = "https://firestore.googleapis.com/v1/"
var GameServicesDefaultBasePath = "https://gameservices.googleapis.com/v1beta/"
var HealthcareDefaultBasePath = "https://healthcare.googleapis.com/v1beta1/"
Expand Down Expand Up @@ -758,6 +760,7 @@ func ConfigureBasePaths(c *Config) {
c.DialogflowBasePath = DialogflowDefaultBasePath
c.DNSBasePath = DNSDefaultBasePath
c.FilestoreBasePath = FilestoreDefaultBasePath
c.FirebaseBasePath = FirebaseDefaultBasePath
c.FirestoreBasePath = FirestoreDefaultBasePath
c.GameServicesBasePath = GameServicesDefaultBasePath
c.HealthcareBasePath = HealthcareDefaultBasePath
Expand Down
71 changes: 71 additions & 0 deletions google-beta/firebase_operation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------
package google

import (
"encoding/json"
"fmt"
)

type FirebaseOperationWaiter struct {
Config *Config
Project string
CommonOperationWaiter
}

func (w *FirebaseOperationWaiter) QueryOp() (interface{}, error) {
if w == nil {
return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
}
// Returns the proper get.
url := fmt.Sprintf("https://firebase.googleapis.com/v1beta1/%s", w.CommonOperationWaiter.Op.Name)
return sendRequest(w.Config, "GET", w.Project, url, nil)
}

func createFirebaseWaiter(config *Config, op map[string]interface{}, project, activity string) (*FirebaseOperationWaiter, error) {
if val, ok := op["name"]; !ok || val == "" {
// This was a synchronous call - there is no operation to wait for.
return nil, nil
}
w := &FirebaseOperationWaiter{
Config: config,
Project: project,
}
if err := w.CommonOperationWaiter.SetOp(op); err != nil {
return nil, err
}
return w, nil
}

// nolint: deadcode,unused
func firebaseOperationWaitTimeWithResponse(config *Config, op map[string]interface{}, response *map[string]interface{}, project, activity string, timeoutMinutes int) error {
w, err := createFirebaseWaiter(config, op, project, activity)
if err != nil || w == nil {
// If w is nil, the op was synchronous.
return err
}
if err := OperationWait(w, activity, timeoutMinutes, config.PollInterval); err != nil {
return err
}
return json.Unmarshal([]byte(w.CommonOperationWaiter.Op.Response), response)
}

func firebaseOperationWaitTime(config *Config, op map[string]interface{}, project, activity string, timeoutMinutes int) error {
w, err := createFirebaseWaiter(config, op, project, activity)
if err != nil || w == nil {
// If w is nil, the op was synchronous.
return err
}
return OperationWait(w, activity, timeoutMinutes, config.PollInterval)
}
14 changes: 12 additions & 2 deletions google-beta/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ func Provider() terraform.ResourceProvider {
"GOOGLE_FILESTORE_CUSTOM_ENDPOINT",
}, FilestoreDefaultBasePath),
},
"firebase_custom_endpoint": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateCustomEndpoint,
DefaultFunc: schema.MultiEnvDefaultFunc([]string{
"GOOGLE_FIREBASE_CUSTOM_ENDPOINT",
}, FirebaseDefaultBasePath),
},
"firestore_custom_endpoint": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -578,9 +586,9 @@ func Provider() terraform.ResourceProvider {
return provider
}

// Generated resources: 134
// Generated resources: 135
// Generated IAM resources: 54
// Total generated resources: 188
// Total generated resources: 189
func ResourceMap() map[string]*schema.Resource {
resourceMap, _ := ResourceMapWithErrors()
return resourceMap
Expand Down Expand Up @@ -690,6 +698,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
"google_dns_managed_zone": resourceDNSManagedZone(),
"google_dns_policy": resourceDNSPolicy(),
"google_filestore_instance": resourceFilestoreInstance(),
"google_firebase_project": resourceFirebaseProject(),
"google_firestore_index": resourceFirestoreIndex(),
"google_game_services_realm": resourceGameServicesRealm(),
"google_game_services_game_server_cluster": resourceGameServicesGameServerCluster(),
Expand Down Expand Up @@ -960,6 +969,7 @@ func providerConfigure(d *schema.ResourceData, p *schema.Provider, terraformVers
config.DialogflowBasePath = d.Get("dialogflow_custom_endpoint").(string)
config.DNSBasePath = d.Get("dns_custom_endpoint").(string)
config.FilestoreBasePath = d.Get("filestore_custom_endpoint").(string)
config.FirebaseBasePath = d.Get("firebase_custom_endpoint").(string)
config.FirestoreBasePath = d.Get("firestore_custom_endpoint").(string)
config.GameServicesBasePath = d.Get("game_services_custom_endpoint").(string)
config.HealthcareBasePath = d.Get("healthcare_custom_endpoint").(string)
Expand Down
168 changes: 168 additions & 0 deletions google-beta/resource_firebase_project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceFirebaseProject() *schema.Resource {
return &schema.Resource{
Create: resourceFirebaseProjectCreate,
Read: resourceFirebaseProjectRead,
Delete: resourceFirebaseProjectDelete,

Importer: &schema.ResourceImporter{
State: resourceFirebaseProjectImport,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(10 * time.Minute),
},

Schema: map[string]*schema.Schema{
"display_name": {
Type: schema.TypeString,
Computed: true,
Description: `The GCP project display name`,
},
"project_number": {
Type: schema.TypeString,
Computed: true,
Description: `The number of the google project that firebase is enabled on.`,
},
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}
}

func resourceFirebaseProjectCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

obj := make(map[string]interface{})

url, err := replaceVars(d, config, "{{FirebaseBasePath}}projects/{{project}}:addFirebase")
if err != nil {
return err
}

log.Printf("[DEBUG] Creating new Project: %#v", obj)
project, err := getProject(d, config)
if err != nil {
return err
}
res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate))
if err != nil {
return fmt.Errorf("Error creating Project: %s", err)
}

// Store the ID now
id, err := replaceVars(d, config, "projects/{{project}}/{{name}}")
if err != nil {
return fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)

err = firebaseOperationWaitTime(
config, res, project, "Creating Project",
int(d.Timeout(schema.TimeoutCreate).Minutes()))

if err != nil {
// The resource didn't actually create
d.SetId("")
return fmt.Errorf("Error waiting to create Project: %s", err)
}

log.Printf("[DEBUG] Finished creating Project %q: %#v", d.Id(), res)

return resourceFirebaseProjectRead(d, meta)
}

func resourceFirebaseProjectRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

url, err := replaceVars(d, config, "{{FirebaseBasePath}}projects/{{project}}/{{name}}")
if err != nil {
return err
}

project, err := getProject(d, config)
if err != nil {
return err
}
res, err := sendRequest(config, "GET", project, url, nil)
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("FirebaseProject %q", d.Id()))
}

if err := d.Set("project", project); err != nil {
return fmt.Errorf("Error reading Project: %s", err)
}

if err := d.Set("project_number", flattenFirebaseProjectProjectNumber(res["projectNumber"], d, config)); err != nil {
return fmt.Errorf("Error reading Project: %s", err)
}
if err := d.Set("display_name", flattenFirebaseProjectDisplayName(res["displayName"], d, config)); err != nil {
return fmt.Errorf("Error reading Project: %s", err)
}

return nil
}

func resourceFirebaseProjectDelete(d *schema.ResourceData, meta interface{}) error {
log.Printf("[WARNING] Firebase Project resources"+
" cannot be deleted from GCP. The resource %s will be removed from Terraform"+
" state, but will still be present on the server.", d.Id())
d.SetId("")

return nil
}

func resourceFirebaseProjectImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
config := meta.(*Config)
if err := parseImportId([]string{
"projects/(?P<project>[^/]+)",
"(?P<project>[^/]+)",
}, d, config); err != nil {
return nil, err
}

// Replace import id for the resource id
id, err := replaceVars(d, config, "projects/{{project}}/{{name}}")
if err != nil {
return nil, fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)

return []*schema.ResourceData{d}, nil
}

func flattenFirebaseProjectProjectNumber(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenFirebaseProjectDisplayName(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}
58 changes: 58 additions & 0 deletions google-beta/resource_firebase_project_generated_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

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

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProvidersOiCS,
Steps: []resource.TestStep{
{
Config: testAccFirebaseProject_firebaseProjectBasicExample(context),
},
},
})
}

func testAccFirebaseProject_firebaseProjectBasicExample(context map[string]interface{}) string {
return Nprintf(`
resource "google_project" "default" {
provider = google-beta
project_id = "tf-test%{random_suffix}"
name = "tf-test%{random_suffix}"
org_id = "%{org_id}"
}
resource "google_firebase_project" "default" {
provider = google-beta
project = google_project.default.project_id
}
`, context)
}
Loading

0 comments on commit c1eeb70

Please sign in to comment.