changes to make it easier to autogen address (#1607)

This commit is contained in:
Dana Hoffman 2018-06-08 16:35:36 -07:00 committed by GitHub
parent 877f8107f8
commit c505255556
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 248 deletions

View File

@ -2,11 +2,18 @@ package google
import (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/hashicorp/terraform/helper/schema"
)
var (
computeAddressIdTemplate = "projects/%s/regions/%s/addresses/%s"
computeAddressLinkRegex = regexp.MustCompile("projects/(.+)/regions/(.+)/addresses/(.+)$")
)
func dataSourceGoogleComputeAddress() *schema.Resource {
return &schema.Resource{
Read: dataSourceGoogleComputeAddressRead,
@ -74,3 +81,63 @@ func dataSourceGoogleComputeAddressRead(d *schema.ResourceData, meta interface{}
d.SetId(strconv.FormatUint(uint64(address.Id), 10))
return nil
}
type computeAddressId struct {
Project string
Region string
Name string
}
func (s computeAddressId) canonicalId() string {
return fmt.Sprintf(computeAddressIdTemplate, s.Project, s.Region, s.Name)
}
func parseComputeAddressId(id string, config *Config) (*computeAddressId, error) {
var parts []string
if computeAddressLinkRegex.MatchString(id) {
parts = computeAddressLinkRegex.FindStringSubmatch(id)
return &computeAddressId{
Project: parts[1],
Region: parts[2],
Name: parts[3],
}, nil
} else {
parts = strings.Split(id, "/")
}
if len(parts) == 3 {
return &computeAddressId{
Project: parts[0],
Region: parts[1],
Name: parts[2],
}, nil
} else if len(parts) == 2 {
// Project is optional.
if config.Project == "" {
return nil, fmt.Errorf("The default project for the provider must be set when using the `{region}/{name}` id format.")
}
return &computeAddressId{
Project: config.Project,
Region: parts[0],
Name: parts[1],
}, nil
} else if len(parts) == 1 {
// Project and region is optional
if config.Project == "" {
return nil, fmt.Errorf("The default project for the provider must be set when using the `{name}` id format.")
}
if config.Region == "" {
return nil, fmt.Errorf("The default region for the provider must be set when using the `{name}` id format.")
}
return &computeAddressId{
Project: config.Project,
Region: config.Region,
Name: parts[0],
}, nil
}
return nil, fmt.Errorf("Invalid compute address id. Expecting resource link, `{project}/{region}/{name}`, `{region}/{name}` or `{name}` format.")
}

View File

@ -8,6 +8,66 @@ import (
"github.com/hashicorp/terraform/terraform"
)
func TestComputeAddressIdParsing(t *testing.T) {
cases := map[string]struct {
ImportId string
ExpectedError bool
ExpectedCanonicalId string
Config *Config
}{
"id is a full self link": {
ImportId: "https://www.googleapis.com/compute/v1/projects/test-project/regions/us-central1/addresses/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/test-project/regions/us-central1/addresses/test-address",
},
"id is a partial self link": {
ImportId: "projects/test-project/regions/us-central1/addresses/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/test-project/regions/us-central1/addresses/test-address",
},
"id is project/region/address": {
ImportId: "test-project/us-central1/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/test-project/regions/us-central1/addresses/test-address",
},
"id is region/address": {
ImportId: "us-central1/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/default-project/regions/us-central1/addresses/test-address",
Config: &Config{Project: "default-project"},
},
"id is address": {
ImportId: "test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/default-project/regions/us-east1/addresses/test-address",
Config: &Config{Project: "default-project", Region: "us-east1"},
},
"id has invalid format": {
ImportId: "i/n/v/a/l/i/d",
ExpectedError: true,
},
}
for tn, tc := range cases {
addressId, err := parseComputeAddressId(tc.ImportId, tc.Config)
if tc.ExpectedError && err == nil {
t.Fatalf("bad: %s, expected an error", tn)
}
if err != nil {
if tc.ExpectedError {
continue
}
t.Fatalf("bad: %s, err: %#v", tn, err)
}
if addressId.canonicalId() != tc.ExpectedCanonicalId {
t.Fatalf("bad: %s, expected canonical id to be `%s` but is `%s`", tn, tc.ExpectedCanonicalId, addressId.canonicalId())
}
}
}
func TestAccDataSourceComputeAddress(t *testing.T) {
t.Parallel()

View File

@ -3,8 +3,6 @@ package google
import (
"fmt"
"regexp"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
computeBeta "google.golang.org/api/compute/v0.beta"
@ -15,11 +13,6 @@ const (
addressTypeInternal = "INTERNAL"
)
var (
computeAddressIdTemplate = "projects/%s/regions/%s/addresses/%s"
computeAddressLinkRegex = regexp.MustCompile("projects/(.+)/regions/(.+)/addresses/(.+)$")
)
func resourceComputeAddress() *schema.Resource {
return &schema.Resource{
Create: resourceComputeAddressCreate,
@ -29,9 +22,6 @@ func resourceComputeAddress() *schema.Resource {
State: resourceComputeAddressImportState,
},
SchemaVersion: 1,
MigrateState: resourceComputeAddressMigrateState,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,

View File

@ -1,109 +0,0 @@
package google
import (
"fmt"
"github.com/hashicorp/terraform/terraform"
"log"
"strings"
)
func resourceComputeAddressMigrateState(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
if is.Empty() {
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
return is, nil
}
switch v {
case 0:
log.Println("[INFO] Found Container Node Pool State v0; migrating to v1")
return migrateComputeAddressV0toV1(is, meta)
default:
return is, fmt.Errorf("Unexpected schema version: %d", v)
}
}
func migrateComputeAddressV0toV1(is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)
log.Printf("[DEBUG] ID before migration: %s", is.ID)
config := meta.(*Config)
project, err := getProjectFromInstanceState(is, config)
if err != nil {
return is, err
}
region, err := getRegionFromInstanceState(is, config)
if err != nil {
return is, err
}
is.ID = computeAddressId{
Project: project,
Region: region,
Name: is.Attributes["name"],
}.canonicalId()
log.Printf("[DEBUG] ID after migration: %s", is.ID)
return is, nil
}
type computeAddressId struct {
Project string
Region string
Name string
}
func (s computeAddressId) canonicalId() string {
return fmt.Sprintf(computeAddressIdTemplate, s.Project, s.Region, s.Name)
}
func parseComputeAddressId(id string, config *Config) (*computeAddressId, error) {
var parts []string
if computeAddressLinkRegex.MatchString(id) {
parts = computeAddressLinkRegex.FindStringSubmatch(id)
return &computeAddressId{
Project: parts[1],
Region: parts[2],
Name: parts[3],
}, nil
} else {
parts = strings.Split(id, "/")
}
if len(parts) == 3 {
return &computeAddressId{
Project: parts[0],
Region: parts[1],
Name: parts[2],
}, nil
} else if len(parts) == 2 {
// Project is optional.
if config.Project == "" {
return nil, fmt.Errorf("The default project for the provider must be set when using the `{region}/{name}` id format.")
}
return &computeAddressId{
Project: config.Project,
Region: parts[0],
Name: parts[1],
}, nil
} else if len(parts) == 1 {
// Project and region is optional
if config.Project == "" {
return nil, fmt.Errorf("The default project for the provider must be set when using the `{name}` id format.")
}
if config.Region == "" {
return nil, fmt.Errorf("The default region for the provider must be set when using the `{name}` id format.")
}
return &computeAddressId{
Project: config.Project,
Region: config.Region,
Name: parts[0],
}, nil
}
return nil, fmt.Errorf("Invalid compute address id. Expecting resource link, `{project}/{region}/{name}`, `{region}/{name}` or `{name}` format.")
}

View File

@ -1,65 +0,0 @@
package google
import (
"github.com/hashicorp/terraform/terraform"
"testing"
)
func TestComputeAddressMigrateState(t *testing.T) {
cases := map[string]struct {
StateVersion int
Attributes map[string]string
ExpectedId string
Meta interface{}
}{
"update id from name to region/name": {
StateVersion: 0,
Attributes: map[string]string{
"name": "address-1",
},
ExpectedId: "projects/gcp-project/regions/us-central1/addresses/address-1",
Meta: &Config{Region: "us-central1", Project: "gcp-project"},
},
}
for tn, tc := range cases {
is := &terraform.InstanceState{
ID: tc.Attributes["name"],
Attributes: tc.Attributes,
}
is, err := resourceComputeAddressMigrateState(tc.StateVersion, is, tc.Meta)
if err != nil {
t.Fatalf("bad: %s, err: %#v", tn, err)
}
if is.ID != tc.ExpectedId {
t.Fatalf("Id should be set to `%s` but is `%s`", tc.ExpectedId, is.ID)
}
}
}
func TestComputeAddressMigrateState_empty(t *testing.T) {
var is *terraform.InstanceState
var meta *Config
// should handle nil
is, err := resourceComputeAddressMigrateState(0, is, meta)
if err != nil {
t.Fatalf("err: %#v", err)
}
if is != nil {
t.Fatalf("expected nil instancestate, got: %#v", is)
}
// should handle non-nil but empty
is = &terraform.InstanceState{}
is, err = resourceComputeAddressMigrateState(0, is, meta)
if err != nil {
t.Fatalf("err: %#v", err)
}
}

View File

@ -11,70 +11,6 @@ import (
"google.golang.org/api/compute/v1"
)
// Unit tests
func TestComputeAddressIdParsing(t *testing.T) {
cases := map[string]struct {
ImportId string
ExpectedError bool
ExpectedCanonicalId string
Config *Config
}{
"id is a full self link": {
ImportId: "https://www.googleapis.com/compute/v1/projects/test-project/regions/us-central1/addresses/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/test-project/regions/us-central1/addresses/test-address",
},
"id is a partial self link": {
ImportId: "projects/test-project/regions/us-central1/addresses/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/test-project/regions/us-central1/addresses/test-address",
},
"id is project/region/address": {
ImportId: "test-project/us-central1/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/test-project/regions/us-central1/addresses/test-address",
},
"id is region/address": {
ImportId: "us-central1/test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/default-project/regions/us-central1/addresses/test-address",
Config: &Config{Project: "default-project"},
},
"id is address": {
ImportId: "test-address",
ExpectedError: false,
ExpectedCanonicalId: "projects/default-project/regions/us-east1/addresses/test-address",
Config: &Config{Project: "default-project", Region: "us-east1"},
},
"id has invalid format": {
ImportId: "i/n/v/a/l/i/d",
ExpectedError: true,
},
}
for tn, tc := range cases {
addressId, err := parseComputeAddressId(tc.ImportId, tc.Config)
if tc.ExpectedError && err == nil {
t.Fatalf("bad: %s, expected an error", tn)
}
if err != nil {
if tc.ExpectedError {
continue
}
t.Fatalf("bad: %s, err: %#v", tn, err)
}
if addressId.canonicalId() != tc.ExpectedCanonicalId {
t.Fatalf("bad: %s, expected canonical id to be `%s` but is `%s`", tn, tc.ExpectedCanonicalId, addressId.canonicalId())
}
}
}
// Acceptance tests
func TestAccComputeAddress_basic(t *testing.T) {
t.Parallel()