Skip to content

Commit

Permalink
Add support for setting labels to google_project
Browse files Browse the repository at this point in the history
  • Loading branch information
rnaveiras committed Sep 3, 2017
1 parent 6499b12 commit 4854e42
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 0 deletions.
22 changes: 22 additions & 0 deletions google/resource_google_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ func resourceGoogleProject() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
"labels": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
}
}
Expand All @@ -95,6 +101,10 @@ func resourceGoogleProjectCreate(d *schema.ResourceData, meta interface{}) error
},
}

if _, ok := d.GetOk("labels"); ok {
project.Labels = expandLabels(d)
}

op, err := config.clientResourceManager.Projects.Create(project).Do()
if err != nil {
return fmt.Errorf("Error creating project %s (%s): %s.", project.ProjectId, project.Name, err)
Expand Down Expand Up @@ -142,6 +152,7 @@ func resourceGoogleProjectRead(d *schema.ResourceData, meta interface{}) error {
d.Set("project_id", pid)
d.Set("number", strconv.FormatInt(int64(p.ProjectNumber), 10))
d.Set("name", p.Name)
d.Set("labels", p.Labels)

if p.Parent != nil {
d.Set("org_id", p.Parent.Id)
Expand Down Expand Up @@ -213,6 +224,17 @@ func resourceGoogleProjectUpdate(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("Error updating billing account %q for project %q: %v", name, prefixedProject(pid), err)
}
}

// Project Labels has changed
if ok := d.HasChange("labels"); ok {
p.Labels = expandLabels(d)

// Do Update on project
p, err = config.clientResourceManager.Projects.Update(p.ProjectId, p).Do()
if err != nil {
return fmt.Errorf("Error updating project %q: %s", p.Name, err)
}
}
return nil
}

Expand Down
162 changes: 162 additions & 0 deletions google/resource_google_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package google
import (
"fmt"
"os"
"reflect"
"strconv"
"strings"
"testing"

"github.com/davecgh/go-spew/spew"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
Expand Down Expand Up @@ -76,6 +79,23 @@ func TestAccGoogleProject_createBilling(t *testing.T) {
})
}

// Test that a Project resource can be created with labels
func TestAccGoogleProject_createLabels(t *testing.T) {
pid := "terraform-" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccGoogleProject_createLabels(pid, pname, org, "test", "that"),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectHasLabels("google_project.acceptance", pid, map[string]string{"test": "that"}),
),
},
},
})
}

// Test that a Project resource can be created and updated
// with billing account information
func TestAccGoogleProject_updateBilling(t *testing.T) {
Expand Down Expand Up @@ -154,6 +174,48 @@ func TestAccGoogleProject_merge(t *testing.T) {
})
}

// Test that a Project resource can be updated with labels
func TestAccGoogleProject_updateLabels(t *testing.T) {
pid := "terraform-" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
// create project without labels
{
Config: testAccGoogleProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
),
},
// update project with labels
{
Config: testAccGoogleProject_updateLabels(pid, pname, org, map[string]string{"label": "label-value"}),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
testAccCheckGoogleProjectHasLabels("google_project.acceptance", pid, map[string]string{"label": "label-value"}),
),
},
// update project with other labels
{
Config: testAccGoogleProject_updateLabels(pid, pname, org, map[string]string{"empty-label": ""}),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
testAccCheckGoogleProjectHasLabels("google_project.acceptance", pid, map[string]string{"empty-label": ""}),
),
},
// update project delete labels
{
Config: testAccGoogleProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
testAccCheckGoogleProjectHasNoLabels("google_project.acceptance", pid),
),
},
},
})
}

func testAccCheckGoogleProjectExists(r, pid string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[r]
Expand Down Expand Up @@ -212,6 +274,77 @@ func testAccCheckGoogleProjectHasMoreBindingsThan(pid string, count int) resourc
}
}

func testAccCheckGoogleProjectHasLabels(r, pid string, expected map[string]string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[r]
if !ok {
return fmt.Errorf("Not found: %s", r)
}

// State should have the same number of labels
if rs.Primary.Attributes["labels.%"] != strconv.Itoa(len(expected)) {
return fmt.Errorf("Expected %d labels, got %s", len(expected), rs.Primary.Attributes["labels.%"])
}

// Actual value in API should match state and expected
config := testAccProvider.Meta().(*Config)

found, err := config.clientResourceManager.Projects.Get(pid).Do()
if err != nil {
return err
}

actual := found.Labels
if !reflect.DeepEqual(actual, expected) {
// Determine only the different attributes
for k, v := range expected {
if av, ok := actual[k]; ok && v == av {
delete(expected, k)
delete(actual, k)
}
}

spewConf := spew.NewDefaultConfig()
spewConf.SortKeys = true
return fmt.Errorf(
"Labels not equivalent. Difference is shown below. Top is actual, bottom is expected."+
"\n\n%s\n\n%s",
spewConf.Sdump(actual), spewConf.Sdump(expected),
)
}
return nil
}
}

func testAccCheckGoogleProjectHasNoLabels(r, pid string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[r]
if !ok {
return fmt.Errorf("Not found: %s", r)
}

// State should have zero labels
if rs.Primary.Attributes["labels.%"] != "0" {
return fmt.Errorf("Expected 0 labels, got %s", rs.Primary.Attributes["labels.%"])
}

// Actual value in API should match state and expected
config := testAccProvider.Meta().(*Config)

found, err := config.clientResourceManager.Projects.Get(pid).Do()
if err != nil {
return err
}

spewConf := spew.NewDefaultConfig()
spewConf.SortKeys = true
if found.Labels != nil {
return fmt.Errorf("Labels should be empty. Actual \n%s", spewConf.Sdump(found.Labels))
}
return nil
}
}

func testAccGoogleProject_toMerge(pid, name, org string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
Expand Down Expand Up @@ -244,6 +377,35 @@ resource "google_project" "acceptance" {
}`, pid, name, org)
}

func testAccGoogleProject_createLabels(pid, name, org, key, value string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
labels {
"%s" = "%s"
}
}`, pid, name, org, key, value)
}

func testAccGoogleProject_updateLabels(pid, name, org string, labels map[string]string) string {
r := fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
labels {`, pid, name, org)

l := ""
for key, value := range labels {
l += fmt.Sprintf("%q = %q\n", key, value)
}

l += fmt.Sprintf("}\n}")
return r + l
}

func skipIfEnvNotSet(t *testing.T, envs ...string) {
for _, k := range envs {
if os.Getenv(k) == "" {
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/google_project.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ The following arguments are supported:
This argument is no longer supported, and will be removed in a future version
of Terraform. It should be replaced with a `google_project_iam_policy` resource.

* `labels` - (Optional) A set of key/value label pairs to assign to the project.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are
Expand Down

0 comments on commit 4854e42

Please sign in to comment.