mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-01 16:21:06 +00:00
Merge pull request #1434 from terraform-providers/paddy_revert_beta
Revert beta removal
This commit is contained in:
commit
118cd71201
254
google/api_versions.go
Normal file
254
google/api_versions.go
Normal file
@ -0,0 +1,254 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ApiVersion uint8
|
||||
|
||||
const (
|
||||
v1 ApiVersion = iota
|
||||
v0beta
|
||||
v1beta1
|
||||
)
|
||||
|
||||
var OrderedComputeApiVersions = []ApiVersion{
|
||||
v0beta,
|
||||
v1,
|
||||
}
|
||||
|
||||
var OrderedContainerApiVersions = []ApiVersion{
|
||||
v1beta1,
|
||||
v1,
|
||||
}
|
||||
|
||||
// Convert between two types by converting to/from JSON. Intended to switch
|
||||
// between multiple API versions, as they are strict supersets of one another.
|
||||
// item and out are pointers to structs
|
||||
func Convert(item, out interface{}) error {
|
||||
bytes, err := json.Marshal(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bytes, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Converting between maps and structs only occurs when autogenerated resources convert the result
|
||||
// of an HTTP request. Those results do not contain omitted fields, so no need to set them.
|
||||
if _, ok := item.(map[string]interface{}); !ok {
|
||||
setOmittedFields(item, out)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setOmittedFields(item, out interface{}) {
|
||||
// Both inputs must be pointers, see https://blog.golang.org/laws-of-reflection:
|
||||
// "To modify a reflection object, the value must be settable."
|
||||
iVal := reflect.ValueOf(item).Elem()
|
||||
oVal := reflect.ValueOf(out).Elem()
|
||||
|
||||
// Loop through all the fields of the struct to look for omitted fields and nested fields
|
||||
for i := 0; i < iVal.NumField(); i++ {
|
||||
iField := iVal.Field(i)
|
||||
if isEmptyValue(iField) {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldInfo := iVal.Type().Field(i)
|
||||
oField := oVal.FieldByName(fieldInfo.Name)
|
||||
|
||||
// Only look at fields that exist in the output struct
|
||||
if !oField.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the field contains a 'json:"="' tag, then it was omitted from the Marshal/Unmarshal
|
||||
// call and needs to be added back in.
|
||||
if fieldInfo.Tag.Get("json") == "-" {
|
||||
oField.Set(iField)
|
||||
}
|
||||
|
||||
// If this field is a struct, *struct, []struct, or []*struct, recurse.
|
||||
if iField.Kind() == reflect.Struct {
|
||||
setOmittedFields(iField.Addr().Interface(), oField.Addr().Interface())
|
||||
}
|
||||
if iField.Kind() == reflect.Ptr && iField.Type().Elem().Kind() == reflect.Struct {
|
||||
setOmittedFields(iField.Interface(), oField.Interface())
|
||||
}
|
||||
if iField.Kind() == reflect.Slice && iField.Type().Elem().Kind() == reflect.Struct {
|
||||
for j := 0; j < iField.Len(); j++ {
|
||||
setOmittedFields(iField.Index(j).Addr().Interface(), oField.Index(j).Addr().Interface())
|
||||
}
|
||||
}
|
||||
if iField.Kind() == reflect.Slice && iField.Type().Elem().Kind() == reflect.Ptr &&
|
||||
iField.Type().Elem().Elem().Kind() == reflect.Struct {
|
||||
for j := 0; j < iField.Len(); j++ {
|
||||
setOmittedFields(iField.Index(j).Interface(), oField.Index(j).Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TerraformResourceData interface {
|
||||
HasChange(string) bool
|
||||
GetOk(string) (interface{}, bool)
|
||||
Set(string, interface{}) error
|
||||
SetId(string)
|
||||
Id() string
|
||||
}
|
||||
|
||||
// Compare the fields set in schema against a list of features and their versions to determine
|
||||
// what version of the API is required in order to manage the resource.
|
||||
func getApiVersion(d TerraformResourceData, resourceVersion ApiVersion, features []Feature, maxVersionFunc func(map[ApiVersion]struct{}) ApiVersion) ApiVersion {
|
||||
versions := map[ApiVersion]struct{}{resourceVersion: struct{}{}}
|
||||
for _, feature := range features {
|
||||
if feature.InUseByDefault(d) {
|
||||
versions[feature.Version] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return maxVersionFunc(versions)
|
||||
}
|
||||
|
||||
func getComputeApiVersion(d TerraformResourceData, resourceVersion ApiVersion, features []Feature) ApiVersion {
|
||||
return getApiVersion(d, resourceVersion, features, maxComputeVersion)
|
||||
}
|
||||
|
||||
func getContainerApiVersion(d TerraformResourceData, resourceVersion ApiVersion, features []Feature) ApiVersion {
|
||||
return getApiVersion(d, resourceVersion, features, maxContainerVersion)
|
||||
}
|
||||
|
||||
// Compare the fields set in schema against a list of features and their version, and a
|
||||
// list of features that exist at the base resource version that can only be update at some other
|
||||
// version, to determine what version of the API is required in order to update the resource.
|
||||
func getApiVersionUpdate(d TerraformResourceData, resourceVersion ApiVersion, features, updateOnlyFields []Feature, maxVersionFunc func(map[ApiVersion]struct{}) ApiVersion) ApiVersion {
|
||||
versions := map[ApiVersion]struct{}{resourceVersion: struct{}{}}
|
||||
|
||||
for _, feature := range features {
|
||||
if feature.InUseByUpdate(d) {
|
||||
versions[feature.Version] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for _, feature := range updateOnlyFields {
|
||||
if feature.HasChangeBy(d) {
|
||||
versions[feature.Version] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return maxVersionFunc(versions)
|
||||
}
|
||||
|
||||
func getComputeApiVersionUpdate(d TerraformResourceData, resourceVersion ApiVersion, features, updateOnlyFields []Feature) ApiVersion {
|
||||
return getApiVersionUpdate(d, resourceVersion, features, updateOnlyFields, maxComputeVersion)
|
||||
}
|
||||
|
||||
func getContainerApiVersionUpdate(d TerraformResourceData, resourceVersion ApiVersion, features, updateOnlyFields []Feature) ApiVersion {
|
||||
return getApiVersionUpdate(d, resourceVersion, features, updateOnlyFields, maxContainerVersion)
|
||||
}
|
||||
|
||||
// A field of a resource and the version of the Compute API required to use it.
|
||||
type Feature struct {
|
||||
Version ApiVersion
|
||||
// Path to the beta field.
|
||||
//
|
||||
// The feature is considered to be in-use if the field referenced by "Item" is set in the state.
|
||||
// The path can reference:
|
||||
// - a beta field at the top-level (e.g. "min_cpu_platform").
|
||||
// - a beta field nested inside a list (e.g. "network_interface.*.alias_ip_range" is considered to be
|
||||
// in-use if the "alias_ip_range" field is set in the state for any of the network interfaces).
|
||||
//
|
||||
// Note: beta field nested inside a SET are NOT supported at the moment.
|
||||
Item string
|
||||
|
||||
// Optional, only set if your field has a default value.
|
||||
// If the value for the field is equal to the DefaultValue, we assume the beta feature is not activated.
|
||||
DefaultValue interface{}
|
||||
}
|
||||
|
||||
// Returns true when a feature has been modified.
|
||||
// This is most important when updating a resource to remove versioned feature usage; if the
|
||||
// resource is reverting to its base version, it needs to perform a final update at the higher
|
||||
// version in order to remove high version features.
|
||||
func (s Feature) HasChangeBy(d TerraformResourceData) bool {
|
||||
return d.HasChange(s.Item)
|
||||
}
|
||||
|
||||
type InUseFunc func(d TerraformResourceData, path string, defaultValue interface{}) bool
|
||||
|
||||
func defaultInUseFunc(d TerraformResourceData, path string, defaultValue interface{}) bool {
|
||||
// At read and delete time, there is no change.
|
||||
// At create time, all fields are marked has changed. We should only consider the feature active if the field has
|
||||
// a value set and that this value is not the default value.
|
||||
value, ok := d.GetOk(path)
|
||||
return ok && value != defaultValue
|
||||
}
|
||||
|
||||
func updateInUseFunc(d TerraformResourceData, path string, defaultValue interface{}) bool {
|
||||
// During a resource update, if the beta field has changes, the feature is considered active even if the new value
|
||||
// is the default value. This is because the beta API must be called to change the value of the field back to the
|
||||
// default value.
|
||||
value, ok := d.GetOk(path)
|
||||
return (ok && value != defaultValue) || d.HasChange(path)
|
||||
}
|
||||
|
||||
// Return true when a feature appears in schema and doesn't hold the default value.
|
||||
func (s Feature) InUseByDefault(d TerraformResourceData) bool {
|
||||
return inUseBy(d, s.Item, s.DefaultValue, defaultInUseFunc)
|
||||
}
|
||||
|
||||
func (s Feature) InUseByUpdate(d TerraformResourceData) bool {
|
||||
return inUseBy(d, s.Item, s.DefaultValue, updateInUseFunc)
|
||||
}
|
||||
|
||||
func inUseBy(d TerraformResourceData, path string, defaultValue interface{}, inUseFunc InUseFunc) bool {
|
||||
pos := strings.Index(path, "*")
|
||||
if pos == -1 {
|
||||
return inUseFunc(d, path, defaultValue)
|
||||
}
|
||||
|
||||
prefix := path[0:pos]
|
||||
suffix := path[pos+1:]
|
||||
|
||||
v, ok := d.GetOk(prefix + "#")
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
count := v.(int)
|
||||
for i := 0; i < count; i++ {
|
||||
nestedPath := fmt.Sprintf("%s%d%s", prefix, i, suffix)
|
||||
if inUseBy(d, nestedPath, defaultValue, inUseFunc) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func maxVersion(versionsInUse map[ApiVersion]struct{}, orderedVersions []ApiVersion) ApiVersion {
|
||||
for _, version := range orderedVersions {
|
||||
if _, ok := versionsInUse[version]; ok {
|
||||
return version
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to the final, most stable version
|
||||
return orderedVersions[len(orderedVersions)-1]
|
||||
}
|
||||
|
||||
func maxComputeVersion(versionsInUse map[ApiVersion]struct{}) ApiVersion {
|
||||
return maxVersion(versionsInUse, OrderedComputeApiVersions)
|
||||
}
|
||||
|
||||
func maxContainerVersion(versionsInUse map[ApiVersion]struct{}) ApiVersion {
|
||||
return maxVersion(versionsInUse, OrderedContainerApiVersions)
|
||||
}
|
326
google/api_versions_test.go
Normal file
326
google/api_versions_test.go
Normal file
@ -0,0 +1,326 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ExpectedApiVersions struct {
|
||||
Create ApiVersion
|
||||
ReadDelete ApiVersion
|
||||
Update ApiVersion
|
||||
}
|
||||
|
||||
func TestApiVersion(t *testing.T) {
|
||||
baseVersion := v1
|
||||
betaVersion := v0beta
|
||||
maxTestApiVersion := func(versionsInUse map[ApiVersion]struct{}) ApiVersion {
|
||||
if _, ok := versionsInUse[betaVersion]; ok {
|
||||
return betaVersion
|
||||
}
|
||||
return baseVersion
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
Features []Feature
|
||||
FieldsInSchema map[string]interface{}
|
||||
UpdatedFields []string
|
||||
UpdateOnlyFields []Feature
|
||||
ExpectedApiVersions
|
||||
}{
|
||||
"no beta field": {
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"normal_field": "foo",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: baseVersion,
|
||||
},
|
||||
},
|
||||
"beta field not set": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "beta_field"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"normal_field": "foo",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: baseVersion,
|
||||
},
|
||||
},
|
||||
"beta field set": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "beta_field"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"normal_field": "foo",
|
||||
"beta_field": "bar",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: betaVersion,
|
||||
ReadDelete: betaVersion,
|
||||
Update: betaVersion,
|
||||
},
|
||||
},
|
||||
"update only beta field": {
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"normal_field": "foo",
|
||||
},
|
||||
UpdatedFields: []string{"beta_update_field"},
|
||||
UpdateOnlyFields: []Feature{{Version: betaVersion, Item: "beta_update_field"}},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: betaVersion,
|
||||
},
|
||||
},
|
||||
"nested beta field not set": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "list_field.*.beta_nested_field"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"list_field.#": 2,
|
||||
"list_field.0.normal_field": "foo",
|
||||
"list_field.1.normal_field": "bar",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: baseVersion,
|
||||
},
|
||||
},
|
||||
"nested beta field set": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "list_field.*.beta_nested_field"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"list_field.#": 2,
|
||||
"list_field.0.normal_field": "foo",
|
||||
"list_field.1.normal_field": "bar",
|
||||
"list_field.1.beta_nested_field": "baz",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: betaVersion,
|
||||
ReadDelete: betaVersion,
|
||||
Update: betaVersion,
|
||||
},
|
||||
},
|
||||
"double nested fields set": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "list_field.*.nested_list_field.*.beta_nested_field"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"list_field.#": 1,
|
||||
"list_field.0.nested_list_field.#": 1,
|
||||
"list_field.0.nested_list_field.0.beta_nested_field": "foo",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: betaVersion,
|
||||
ReadDelete: betaVersion,
|
||||
Update: betaVersion,
|
||||
},
|
||||
},
|
||||
"beta field has default value": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "beta_field", DefaultValue: "bar"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"normal_field": "foo",
|
||||
"beta_field": "bar",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: baseVersion,
|
||||
},
|
||||
},
|
||||
"beta field is updated to default value": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "beta_field", DefaultValue: "bar"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"normal_field": "foo",
|
||||
"beta_field": "bar",
|
||||
},
|
||||
UpdatedFields: []string{"beta_field"},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: betaVersion,
|
||||
},
|
||||
},
|
||||
"nested beta field has default value": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "list_field.*.beta_nested_field", DefaultValue: "baz"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"list_field.#": 2,
|
||||
"list_field.0.normal_field": "foo",
|
||||
"list_field.1.normal_field": "bar",
|
||||
"list_field.1.beta_nested_field": "baz",
|
||||
},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: baseVersion,
|
||||
},
|
||||
},
|
||||
"nested beta field is updated default value": {
|
||||
Features: []Feature{{Version: betaVersion, Item: "list_field.*.beta_nested_field", DefaultValue: "baz"}},
|
||||
FieldsInSchema: map[string]interface{}{
|
||||
"list_field.#": 2,
|
||||
"list_field.0.normal_field": "foo",
|
||||
"list_field.1.normal_field": "bar",
|
||||
"list_field.1.beta_nested_field": "baz",
|
||||
},
|
||||
UpdatedFields: []string{"list_field.1.beta_nested_field"},
|
||||
ExpectedApiVersions: ExpectedApiVersions{
|
||||
Create: baseVersion,
|
||||
ReadDelete: baseVersion,
|
||||
Update: betaVersion,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range cases {
|
||||
// Create
|
||||
// All fields with value have HasChange set to true.
|
||||
keys := make([]string, 0, len(tc.FieldsInSchema))
|
||||
for key := range tc.FieldsInSchema {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
d := &ResourceDataMock{
|
||||
FieldsInSchema: tc.FieldsInSchema,
|
||||
FieldsWithHasChange: keys,
|
||||
}
|
||||
|
||||
apiVersion := getApiVersion(d, v1, tc.Features, maxTestApiVersion)
|
||||
if apiVersion != tc.ExpectedApiVersions.Create {
|
||||
t.Errorf("bad: %s, Expected to see version %v for create, got version %v", tn, tc.ExpectedApiVersions.Create, apiVersion)
|
||||
}
|
||||
|
||||
// Read/Delete
|
||||
// All fields have HasChange set to false.
|
||||
d = &ResourceDataMock{
|
||||
FieldsInSchema: tc.FieldsInSchema,
|
||||
}
|
||||
|
||||
apiVersion = getApiVersion(d, v1, tc.Features, maxTestApiVersion)
|
||||
if apiVersion != tc.ExpectedApiVersions.ReadDelete {
|
||||
t.Errorf("bad: %s, Expected to see version %v for read/delete, got version %v", tn, tc.ExpectedApiVersions.ReadDelete, apiVersion)
|
||||
}
|
||||
|
||||
// Update
|
||||
// Only fields defined as updated in the test case have HasChange set to true.
|
||||
d = &ResourceDataMock{
|
||||
FieldsInSchema: tc.FieldsInSchema,
|
||||
FieldsWithHasChange: tc.UpdatedFields,
|
||||
}
|
||||
|
||||
apiVersion = getApiVersionUpdate(d, v1, tc.Features, tc.UpdateOnlyFields, maxTestApiVersion)
|
||||
if apiVersion != tc.ExpectedApiVersions.Update {
|
||||
t.Errorf("bad: %s, Expected to see version %v for update, got version %v", tn, tc.ExpectedApiVersions.Update, apiVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetOmittedFields(t *testing.T) {
|
||||
type Inner struct {
|
||||
InnerNotOmitted string `json:"notOmitted"`
|
||||
InnerOmitted []string `json:"-"`
|
||||
}
|
||||
type InputOuter struct {
|
||||
NotOmitted string `json:"notOmitted"`
|
||||
Omitted []string `json:"-"`
|
||||
Struct Inner
|
||||
Pointer *Inner
|
||||
StructSlice []Inner
|
||||
PointerSlice []*Inner
|
||||
Unset *Inner
|
||||
OnlyInInputType *Inner
|
||||
}
|
||||
type OutputOuter struct {
|
||||
NotOmitted string `json:"notOmitted"`
|
||||
Omitted []string `json:"-"`
|
||||
Struct Inner
|
||||
Pointer *Inner
|
||||
StructSlice []Inner
|
||||
PointerSlice []*Inner
|
||||
Unset *Inner
|
||||
OnlyInOutputType *Inner
|
||||
}
|
||||
|
||||
input := &InputOuter{
|
||||
NotOmitted: "foo",
|
||||
Omitted: []string{"foo"},
|
||||
Struct: Inner{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
},
|
||||
Pointer: &Inner{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
},
|
||||
StructSlice: []Inner{
|
||||
{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
}, {
|
||||
InnerNotOmitted: "bar",
|
||||
InnerOmitted: []string{"bar"},
|
||||
},
|
||||
},
|
||||
PointerSlice: []*Inner{
|
||||
{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
}, {
|
||||
InnerNotOmitted: "bar",
|
||||
InnerOmitted: []string{"bar"},
|
||||
},
|
||||
},
|
||||
OnlyInInputType: &Inner{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
},
|
||||
}
|
||||
output := &OutputOuter{}
|
||||
Convert(input, output)
|
||||
if input.NotOmitted != output.NotOmitted ||
|
||||
!reflect.DeepEqual(input.Omitted, output.Omitted) ||
|
||||
!reflect.DeepEqual(input.Struct, output.Struct) ||
|
||||
!reflect.DeepEqual(input.Pointer, output.Pointer) ||
|
||||
!reflect.DeepEqual(input.StructSlice, output.StructSlice) ||
|
||||
!reflect.DeepEqual(input.PointerSlice, output.PointerSlice) ||
|
||||
!(input.Unset == nil && output.Unset == nil) {
|
||||
t.Errorf("Structs were not equivalent after conversion:\nInput:%#v\nOutput: %#v", input, output)
|
||||
}
|
||||
}
|
||||
|
||||
type ResourceDataMock struct {
|
||||
FieldsInSchema map[string]interface{}
|
||||
FieldsWithHasChange []string
|
||||
id string
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) HasChange(key string) bool {
|
||||
exists := false
|
||||
for _, val := range d.FieldsWithHasChange {
|
||||
if key == val {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
|
||||
return exists
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) GetOk(key string) (interface{}, bool) {
|
||||
for k, v := range d.FieldsInSchema {
|
||||
if key == k {
|
||||
return v, true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) Set(key string, value interface{}) error {
|
||||
d.FieldsInSchema[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) SetId(v string) {
|
||||
d.id = v
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) Id() string {
|
||||
return d.id
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Convert between two types by converting to/from JSON. Intended to switch
|
||||
// between multiple API versions, as they are strict supersets of one another.
|
||||
// item and out are pointers to structs
|
||||
func Convert(item, out interface{}) error {
|
||||
bytes, err := json.Marshal(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bytes, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Converting between maps and structs only occurs when autogenerated resources convert the result
|
||||
// of an HTTP request. Those results do not contain omitted fields, so no need to set them.
|
||||
if _, ok := item.(map[string]interface{}); !ok {
|
||||
setOmittedFields(item, out)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setOmittedFields(item, out interface{}) {
|
||||
// Both inputs must be pointers, see https://blog.golang.org/laws-of-reflection:
|
||||
// "To modify a reflection object, the value must be settable."
|
||||
iVal := reflect.ValueOf(item).Elem()
|
||||
oVal := reflect.ValueOf(out).Elem()
|
||||
|
||||
// Loop through all the fields of the struct to look for omitted fields and nested fields
|
||||
for i := 0; i < iVal.NumField(); i++ {
|
||||
iField := iVal.Field(i)
|
||||
if isEmptyValue(iField) {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldInfo := iVal.Type().Field(i)
|
||||
oField := oVal.FieldByName(fieldInfo.Name)
|
||||
|
||||
// Only look at fields that exist in the output struct
|
||||
if !oField.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the field contains a 'json:"="' tag, then it was omitted from the Marshal/Unmarshal
|
||||
// call and needs to be added back in.
|
||||
if fieldInfo.Tag.Get("json") == "-" {
|
||||
oField.Set(iField)
|
||||
}
|
||||
|
||||
// If this field is a struct, *struct, []struct, or []*struct, recurse.
|
||||
if iField.Kind() == reflect.Struct {
|
||||
setOmittedFields(iField.Addr().Interface(), oField.Addr().Interface())
|
||||
}
|
||||
if iField.Kind() == reflect.Ptr && iField.Type().Elem().Kind() == reflect.Struct {
|
||||
setOmittedFields(iField.Interface(), oField.Interface())
|
||||
}
|
||||
if iField.Kind() == reflect.Slice && iField.Type().Elem().Kind() == reflect.Struct {
|
||||
for j := 0; j < iField.Len(); j++ {
|
||||
setOmittedFields(iField.Index(j).Addr().Interface(), oField.Index(j).Addr().Interface())
|
||||
}
|
||||
}
|
||||
if iField.Kind() == reflect.Slice && iField.Type().Elem().Kind() == reflect.Ptr &&
|
||||
iField.Type().Elem().Elem().Kind() == reflect.Struct {
|
||||
for j := 0; j < iField.Len(); j++ {
|
||||
setOmittedFields(iField.Index(j).Interface(), oField.Index(j).Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetOmittedFields(t *testing.T) {
|
||||
type Inner struct {
|
||||
InnerNotOmitted string `json:"notOmitted"`
|
||||
InnerOmitted []string `json:"-"`
|
||||
}
|
||||
type InputOuter struct {
|
||||
NotOmitted string `json:"notOmitted"`
|
||||
Omitted []string `json:"-"`
|
||||
Struct Inner
|
||||
Pointer *Inner
|
||||
StructSlice []Inner
|
||||
PointerSlice []*Inner
|
||||
Unset *Inner
|
||||
OnlyInInputType *Inner
|
||||
}
|
||||
type OutputOuter struct {
|
||||
NotOmitted string `json:"notOmitted"`
|
||||
Omitted []string `json:"-"`
|
||||
Struct Inner
|
||||
Pointer *Inner
|
||||
StructSlice []Inner
|
||||
PointerSlice []*Inner
|
||||
Unset *Inner
|
||||
OnlyInOutputType *Inner
|
||||
}
|
||||
|
||||
input := &InputOuter{
|
||||
NotOmitted: "foo",
|
||||
Omitted: []string{"foo"},
|
||||
Struct: Inner{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
},
|
||||
Pointer: &Inner{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
},
|
||||
StructSlice: []Inner{
|
||||
{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
}, {
|
||||
InnerNotOmitted: "bar",
|
||||
InnerOmitted: []string{"bar"},
|
||||
},
|
||||
},
|
||||
PointerSlice: []*Inner{
|
||||
{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
}, {
|
||||
InnerNotOmitted: "bar",
|
||||
InnerOmitted: []string{"bar"},
|
||||
},
|
||||
},
|
||||
OnlyInInputType: &Inner{
|
||||
InnerNotOmitted: "foo",
|
||||
InnerOmitted: []string{"foo"},
|
||||
},
|
||||
}
|
||||
output := &OutputOuter{}
|
||||
Convert(input, output)
|
||||
if input.NotOmitted != output.NotOmitted ||
|
||||
!reflect.DeepEqual(input.Omitted, output.Omitted) ||
|
||||
!reflect.DeepEqual(input.Struct, output.Struct) ||
|
||||
!reflect.DeepEqual(input.Pointer, output.Pointer) ||
|
||||
!reflect.DeepEqual(input.StructSlice, output.StructSlice) ||
|
||||
!reflect.DeepEqual(input.PointerSlice, output.PointerSlice) ||
|
||||
!(input.Unset == nil && output.Unset == nil) {
|
||||
t.Errorf("Structs were not equivalent after conversion:\nInput:%#v\nOutput: %#v", input, output)
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
@ -124,7 +123,3 @@ func flattenSecondaryRanges(secondaryRanges []*compute.SubnetworkSecondaryRange)
|
||||
func createSubnetID(s *compute.Subnetwork) string {
|
||||
return fmt.Sprintf("%s/%s", s.Region, s.Name)
|
||||
}
|
||||
|
||||
func createSubnetIDBeta(s *computeBeta.Subnetwork) string {
|
||||
return fmt.Sprintf("%s/%s", s.Region, s.Name)
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ import (
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var BackendServiceBaseApiVersion = v1
|
||||
var BackendServiceVersionedFeatures = []Feature{Feature{Version: v0beta, Item: "security_policy"}}
|
||||
|
||||
func resourceComputeBackendService() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeBackendServiceCreate,
|
||||
@ -285,6 +288,7 @@ func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{
|
||||
}
|
||||
|
||||
func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, BackendServiceBaseApiVersion, BackendServiceVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -292,9 +296,25 @@ func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{})
|
||||
return err
|
||||
}
|
||||
|
||||
service, err := config.clientComputeBeta.BackendServices.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
|
||||
service := &computeBeta.BackendService{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
v1Service, err := config.clientCompute.BackendServices.Get(
|
||||
project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
|
||||
}
|
||||
err = Convert(v1Service, service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case v0beta:
|
||||
var err error
|
||||
service, err = config.clientComputeBeta.BackendServices.Get(
|
||||
project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
|
||||
}
|
||||
}
|
||||
|
||||
d.Set("name", service.Name)
|
||||
|
@ -10,8 +10,12 @@ import (
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var FirewallBaseApiVersion = v1
|
||||
var FirewallVersionedFeatures = []Feature{}
|
||||
|
||||
func resourceComputeFirewall() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeFirewallCreate,
|
||||
@ -189,6 +193,7 @@ func resourceComputeFirewallRuleHash(v interface{}) int {
|
||||
}
|
||||
|
||||
func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, FirewallBaseApiVersion, FirewallVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -201,9 +206,30 @@ func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) err
|
||||
return err
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.Firewalls.Insert(project, firewall).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating firewall: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
firewallV1 := &compute.Firewall{}
|
||||
err = Convert(firewall, firewallV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.Firewalls.Insert(project, firewallV1).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating firewall: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
firewallV0Beta := &computeBeta.Firewall{}
|
||||
err = Convert(firewall, firewallV0Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.Firewalls.Insert(project, firewallV0Beta).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating firewall: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// It probably maybe worked, so store the ID now
|
||||
@ -242,6 +268,7 @@ func flattenFirewallDenied(denied []*computeBeta.FirewallDenied) []map[string]in
|
||||
}
|
||||
|
||||
func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, FirewallBaseApiVersion, FirewallVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -249,9 +276,28 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error
|
||||
return err
|
||||
}
|
||||
|
||||
firewall, err := config.clientComputeBeta.Firewalls.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string)))
|
||||
firewall := &computeBeta.Firewall{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
firewallV1, err := config.clientCompute.Firewalls.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
err = Convert(firewallV1, firewall)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case v0beta:
|
||||
firewallV0Beta, err := config.clientComputeBeta.Firewalls.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
err = Convert(firewallV0Beta, firewall)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.Set("self_link", ConvertSelfLinkToV1(firewall.SelfLink))
|
||||
@ -273,6 +319,7 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error
|
||||
}
|
||||
|
||||
func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersionUpdate(d, FirewallBaseApiVersion, FirewallVersionedFeatures, []Feature{})
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -287,9 +334,30 @@ func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) err
|
||||
return err
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.Firewalls.Update(project, d.Id(), firewall).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating firewall: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
firewallV1 := &compute.Firewall{}
|
||||
err = Convert(firewall, firewallV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.Firewalls.Update(project, d.Id(), firewallV1).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating firewall: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
firewallV0Beta := &computeBeta.Firewall{}
|
||||
err = Convert(firewall, firewallV0Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.Firewalls.Update(project, d.Id(), firewallV0Beta).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating firewall: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating Firewall")
|
||||
@ -303,6 +371,7 @@ func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) err
|
||||
}
|
||||
|
||||
func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, FirewallBaseApiVersion, FirewallVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -311,9 +380,18 @@ func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) err
|
||||
}
|
||||
|
||||
// Delete the firewall
|
||||
op, err := config.clientComputeBeta.Firewalls.Delete(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting firewall: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.Firewalls.Delete(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting firewall: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.Firewalls.Delete(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting firewall: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = computeSharedOperationWait(config.clientCompute, op, project, "Deleting Firewall")
|
||||
|
@ -8,9 +8,14 @@ import (
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var GlobalForwardingRuleBaseApiVersion = v1
|
||||
var GlobalForwardingRuleVersionedFeatures = []Feature{
|
||||
{Version: v0beta, Item: "labels"},
|
||||
}
|
||||
|
||||
func resourceComputeGlobalForwardingRule() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeGlobalForwardingRuleCreate,
|
||||
@ -104,6 +109,7 @@ func resourceComputeGlobalForwardingRule() *schema.Resource {
|
||||
}
|
||||
|
||||
func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, GlobalForwardingRuleBaseApiVersion, GlobalForwardingRuleVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -121,9 +127,30 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte
|
||||
Target: d.Get("target").(string),
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.GlobalForwardingRules.Insert(project, frule).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Global Forwarding Rule: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
v1Frule := &compute.ForwardingRule{}
|
||||
err = Convert(frule, v1Frule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.GlobalForwardingRules.Insert(project, v1Frule).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Global Forwarding Rule: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
v0BetaFrule := &computeBeta.ForwardingRule{}
|
||||
err = Convert(frule, v0BetaFrule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.GlobalForwardingRules.Insert(project, v0BetaFrule).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Global Forwarding Rule: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// It probably maybe worked, so store the ID now
|
||||
@ -138,12 +165,12 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte
|
||||
if _, ok := d.GetOk("labels"); ok {
|
||||
labels := expandLabels(d)
|
||||
// Do a read to get the fingerprint value so we can update
|
||||
fingerprint, err := resourceComputeGlobalForwardingRuleReadLabelFingerprint(config, project, frule.Name)
|
||||
fingerprint, err := resourceComputeGlobalForwardingRuleReadLabelFingerprint(config, computeApiVersion, project, frule.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = resourceComputeGlobalForwardingRuleSetLabels(config, project, frule.Name, labels, fingerprint)
|
||||
err = resourceComputeGlobalForwardingRuleSetLabels(config, computeApiVersion, project, frule.Name, labels, fingerprint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -153,6 +180,7 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
func resourceComputeGlobalForwardingRuleUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersionUpdate(d, GlobalForwardingRuleBaseApiVersion, GlobalForwardingRuleVersionedFeatures, []Feature{})
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -164,12 +192,34 @@ func resourceComputeGlobalForwardingRuleUpdate(d *schema.ResourceData, meta inte
|
||||
|
||||
if d.HasChange("target") {
|
||||
target := d.Get("target").(string)
|
||||
targetRef := &compute.TargetReference{Target: target}
|
||||
targetRef := &computeBeta.TargetReference{Target: target}
|
||||
|
||||
op, err := config.clientCompute.GlobalForwardingRules.SetTarget(
|
||||
project, d.Id(), targetRef).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating target: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
v1TargetRef := &compute.TargetReference{}
|
||||
err = Convert(targetRef, v1TargetRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.GlobalForwardingRules.SetTarget(
|
||||
project, d.Id(), v1TargetRef).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating target: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
v0BetaTargetRef := &compute.TargetReference{}
|
||||
err = Convert(targetRef, v0BetaTargetRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.GlobalForwardingRules.SetTarget(
|
||||
project, d.Id(), v0BetaTargetRef).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating target: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating Global Forwarding Rule")
|
||||
@ -183,7 +233,7 @@ func resourceComputeGlobalForwardingRuleUpdate(d *schema.ResourceData, meta inte
|
||||
labels := expandLabels(d)
|
||||
fingerprint := d.Get("label_fingerprint").(string)
|
||||
|
||||
err = resourceComputeGlobalForwardingRuleSetLabels(config, project, d.Get("name").(string), labels, fingerprint)
|
||||
err = resourceComputeGlobalForwardingRuleSetLabels(config, computeApiVersion, project, d.Get("name").(string), labels, fingerprint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -197,6 +247,7 @@ func resourceComputeGlobalForwardingRuleUpdate(d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
func resourceComputeGlobalForwardingRuleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, GlobalForwardingRuleBaseApiVersion, GlobalForwardingRuleVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -204,9 +255,28 @@ func resourceComputeGlobalForwardingRuleRead(d *schema.ResourceData, meta interf
|
||||
return err
|
||||
}
|
||||
|
||||
frule, err := config.clientComputeBeta.GlobalForwardingRules.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Global Forwarding Rule %q", d.Get("name").(string)))
|
||||
frule := &computeBeta.ForwardingRule{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
v1Frule, err := config.clientCompute.GlobalForwardingRules.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Global Forwarding Rule %q", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
err = Convert(v1Frule, frule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case v0beta:
|
||||
v0BetaFrule, err := config.clientComputeBeta.GlobalForwardingRules.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Global Forwarding Rule %q", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
err = Convert(v0BetaFrule, frule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.Set("name", frule.Name)
|
||||
@ -225,6 +295,7 @@ func resourceComputeGlobalForwardingRuleRead(d *schema.ResourceData, meta interf
|
||||
}
|
||||
|
||||
func resourceComputeGlobalForwardingRuleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, GlobalForwardingRuleBaseApiVersion, GlobalForwardingRuleVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -234,10 +305,20 @@ func resourceComputeGlobalForwardingRuleDelete(d *schema.ResourceData, meta inte
|
||||
|
||||
// Delete the GlobalForwardingRule
|
||||
log.Printf("[DEBUG] GlobalForwardingRule delete request")
|
||||
op, err := config.clientCompute.GlobalForwardingRules.Delete(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting GlobalForwardingRule: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.GlobalForwardingRules.Delete(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting GlobalForwardingRule: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.GlobalForwardingRules.Delete(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting GlobalForwardingRule: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = computeSharedOperationWait(config.clientCompute, op, project, "Deleting GlobalForwarding Rule")
|
||||
if err != nil {
|
||||
return err
|
||||
@ -249,24 +330,43 @@ func resourceComputeGlobalForwardingRuleDelete(d *schema.ResourceData, meta inte
|
||||
|
||||
// resourceComputeGlobalForwardingRuleReadLabelFingerprint performs a read on the remote resource and returns only the
|
||||
// fingerprint. Used on create when setting labels as we don't know the label fingerprint initially.
|
||||
func resourceComputeGlobalForwardingRuleReadLabelFingerprint(config *Config, project, name string) (string, error) {
|
||||
frule, err := config.clientComputeBeta.GlobalForwardingRules.Get(project, name).Do()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to read global forwarding rule to update labels: %s", err)
|
||||
}
|
||||
func resourceComputeGlobalForwardingRuleReadLabelFingerprint(config *Config, computeApiVersion ApiVersion,
|
||||
project, name string) (string, error) {
|
||||
switch computeApiVersion {
|
||||
case v0beta:
|
||||
frule, err := config.clientComputeBeta.GlobalForwardingRules.Get(project, name).Do()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to read global forwarding rule to update labels: %s", err)
|
||||
}
|
||||
|
||||
return frule.LabelFingerprint, nil
|
||||
return frule.LabelFingerprint, nil
|
||||
default:
|
||||
return "", fmt.Errorf(
|
||||
"Unable to read label fingerprint due to an internal error: can only handle v0beta but compute api logic indicates %d",
|
||||
computeApiVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// resourceComputeGlobalForwardingRuleSetLabels sets the Labels attribute on a forwarding rule.
|
||||
func resourceComputeGlobalForwardingRuleSetLabels(config *Config, project, name string, labels map[string]string, fingerprint string) error {
|
||||
setLabels := computeBeta.GlobalSetLabelsRequest{
|
||||
Labels: labels,
|
||||
LabelFingerprint: fingerprint,
|
||||
}
|
||||
op, err := config.clientComputeBeta.GlobalForwardingRules.SetLabels(project, name, &setLabels).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
func resourceComputeGlobalForwardingRuleSetLabels(config *Config, computeApiVersion ApiVersion, project,
|
||||
name string, labels map[string]string, fingerprint string) error {
|
||||
var op interface{}
|
||||
var err error
|
||||
|
||||
switch computeApiVersion {
|
||||
case v0beta:
|
||||
setLabels := computeBeta.GlobalSetLabelsRequest{
|
||||
Labels: labels,
|
||||
LabelFingerprint: fingerprint,
|
||||
}
|
||||
op, err = config.clientComputeBeta.GlobalForwardingRules.SetLabels(project, name, &setLabels).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"Unable to set labels due to an internal error: can only handle v0beta but compute api logic indicates %d",
|
||||
computeApiVersion)
|
||||
}
|
||||
|
||||
err = computeSharedOperationWait(config.clientCompute, op, project, "Setting labels on Global Forwarding Rule")
|
||||
|
@ -19,6 +19,9 @@ import (
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
var InstanceBaseApiVersion = v1
|
||||
var InstanceVersionedFeatures = []Feature{}
|
||||
|
||||
func resourceComputeInstance() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeInstanceCreate,
|
||||
@ -592,9 +595,21 @@ func getInstance(config *Config, d *schema.ResourceData) (*computeBeta.Instance,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance, err := config.clientComputeBeta.Instances.Get(project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return nil, handleNotFoundError(err, d, fmt.Sprintf("Instance %s", d.Get("name").(string)))
|
||||
instance := &computeBeta.Instance{}
|
||||
switch getComputeApiVersion(d, InstanceBaseApiVersion, InstanceVersionedFeatures) {
|
||||
case v1:
|
||||
instanceV1, err := config.clientCompute.Instances.Get(project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return nil, handleNotFoundError(err, d, fmt.Sprintf("Instance %s", d.Get("name").(string)))
|
||||
}
|
||||
if err := Convert(instanceV1, instance); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case v0beta:
|
||||
instance, err = config.clientComputeBeta.Instances.Get(project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return nil, handleNotFoundError(err, d, fmt.Sprintf("Instance %s", d.Get("name").(string)))
|
||||
}
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
@ -730,7 +745,17 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Requesting instance creation")
|
||||
op, err := config.clientComputeBeta.Instances.Insert(project, zone.Name, instance).Do()
|
||||
var op interface{}
|
||||
switch getComputeApiVersion(d, InstanceBaseApiVersion, InstanceVersionedFeatures) {
|
||||
case v1:
|
||||
instanceV1 := &compute.Instance{}
|
||||
if err := Convert(instance, instanceV1); err != nil {
|
||||
return err
|
||||
}
|
||||
op, err = config.clientCompute.Instances.Insert(project, zone.Name, instanceV1).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.Instances.Insert(project, zone.Name, instance).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating instance: %s", err)
|
||||
}
|
||||
|
@ -14,6 +14,12 @@ import (
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var InstanceGroupManagerBaseApiVersion = v1
|
||||
var InstanceGroupManagerVersionedFeatures = []Feature{
|
||||
Feature{Version: v0beta, Item: "auto_healing_policies"},
|
||||
Feature{Version: v0beta, Item: "rolling_update_policy"},
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManager() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeInstanceGroupManagerCreate,
|
||||
@ -228,6 +234,7 @@ func getNamedPortsBeta(nps []interface{}) []*computeBeta.NamedPort {
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -259,8 +266,29 @@ func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] InstanceGroupManager insert request: %#v", manager)
|
||||
op, err := config.clientComputeBeta.InstanceGroupManagers.Insert(
|
||||
project, zone, manager).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
managerV1 := &compute.InstanceGroupManager{}
|
||||
err = Convert(manager, managerV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
managerV1.ForceSendFields = manager.ForceSendFields
|
||||
op, err = config.clientCompute.InstanceGroupManagers.Insert(
|
||||
project, zone, managerV1).Do()
|
||||
case v0beta:
|
||||
managerV0beta := &computeBeta.InstanceGroupManager{}
|
||||
err = Convert(manager, managerV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
managerV0beta.ForceSendFields = manager.ForceSendFields
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.Insert(
|
||||
project, zone, managerV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating InstanceGroupManager: %s", err)
|
||||
@ -291,6 +319,7 @@ func flattenNamedPortsBeta(namedPorts []*computeBeta.NamedPort) []map[string]int
|
||||
}
|
||||
|
||||
func getManager(d *schema.ResourceData, meta interface{}) (*computeBeta.InstanceGroupManager, error) {
|
||||
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -303,38 +332,82 @@ func getManager(d *schema.ResourceData, meta interface{}) (*computeBeta.Instance
|
||||
return nil, err
|
||||
}
|
||||
|
||||
getInstanceGroupManager := func(zone string) (interface{}, error) {
|
||||
return config.clientComputeBeta.InstanceGroupManagers.Get(project, zone, d.Id()).Do()
|
||||
}
|
||||
|
||||
var manager *computeBeta.InstanceGroupManager
|
||||
var e error
|
||||
if zone, _ := getZone(d, config); zone != "" {
|
||||
manager, e = config.clientComputeBeta.InstanceGroupManagers.Get(project, zone, d.Id()).Do()
|
||||
|
||||
if e != nil {
|
||||
return nil, handleNotFoundError(e, d, fmt.Sprintf("Instance Group Manager %q", d.Get("name").(string)))
|
||||
}
|
||||
} else {
|
||||
// If the resource was imported, the only info we have is the ID. Try to find the resource
|
||||
// by searching in the region of the project.
|
||||
var resource interface{}
|
||||
resource, e = getZonalBetaResourceFromRegion(getInstanceGroupManager, region, config.clientComputeBeta, project)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
manager := &computeBeta.InstanceGroupManager{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
getInstanceGroupManager := func(zone string) (interface{}, error) {
|
||||
return config.clientCompute.InstanceGroupManagers.Get(project, zone, d.Id()).Do()
|
||||
}
|
||||
|
||||
manager = resource.(*computeBeta.InstanceGroupManager)
|
||||
var v1Manager *compute.InstanceGroupManager
|
||||
var e error
|
||||
if zone, _ := getZone(d, config); zone != "" {
|
||||
v1Manager, e = config.clientCompute.InstanceGroupManagers.Get(project, zone, d.Id()).Do()
|
||||
|
||||
if e != nil {
|
||||
return nil, handleNotFoundError(e, d, fmt.Sprintf("Instance Group Manager %q", d.Get("name").(string)))
|
||||
}
|
||||
} else {
|
||||
// If the resource was imported, the only info we have is the ID. Try to find the resource
|
||||
// by searching in the region of the project.
|
||||
var resource interface{}
|
||||
resource, e = getZonalResourceFromRegion(getInstanceGroupManager, region, config.clientCompute, project)
|
||||
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
v1Manager = resource.(*compute.InstanceGroupManager)
|
||||
}
|
||||
|
||||
if v1Manager == nil {
|
||||
log.Printf("[WARN] Removing Instance Group Manager %q because it's gone", d.Get("name").(string))
|
||||
|
||||
// The resource doesn't exist anymore
|
||||
d.SetId("")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err = Convert(v1Manager, manager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case v0beta:
|
||||
getInstanceGroupManager := func(zone string) (interface{}, error) {
|
||||
return config.clientComputeBeta.InstanceGroupManagers.Get(project, zone, d.Id()).Do()
|
||||
}
|
||||
|
||||
var v0betaManager *computeBeta.InstanceGroupManager
|
||||
var e error
|
||||
if zone, _ := getZone(d, config); zone != "" {
|
||||
v0betaManager, e = config.clientComputeBeta.InstanceGroupManagers.Get(project, zone, d.Id()).Do()
|
||||
|
||||
if e != nil {
|
||||
return nil, handleNotFoundError(e, d, fmt.Sprintf("Instance Group Manager %q", d.Get("name").(string)))
|
||||
}
|
||||
} else {
|
||||
// If the resource was imported, the only info we have is the ID. Try to find the resource
|
||||
// by searching in the region of the project.
|
||||
var resource interface{}
|
||||
resource, e = getZonalBetaResourceFromRegion(getInstanceGroupManager, region, config.clientComputeBeta, project)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
v0betaManager = resource.(*computeBeta.InstanceGroupManager)
|
||||
}
|
||||
|
||||
if v0betaManager == nil {
|
||||
log.Printf("[WARN] Removing Instance Group Manager %q because it's gone", d.Get("name").(string))
|
||||
|
||||
// The resource doesn't exist anymore
|
||||
d.SetId("")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
manager = v0betaManager
|
||||
}
|
||||
|
||||
if manager == nil {
|
||||
log.Printf("[WARN] Removing Instance Group Manager %q because it's gone", d.Get("name").(string))
|
||||
|
||||
// The resource doesn't exist anymore
|
||||
d.SetId("")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
@ -386,6 +459,7 @@ func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interf
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersionUpdate(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures, []Feature{})
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -414,8 +488,27 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
TargetPools: targetPools,
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.InstanceGroupManagers.SetTargetPools(
|
||||
project, zone, d.Id(), setTargetPools).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
setTargetPoolsV1 := &compute.InstanceGroupManagersSetTargetPoolsRequest{}
|
||||
err = Convert(setTargetPools, setTargetPoolsV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.InstanceGroupManagers.SetTargetPools(
|
||||
project, zone, d.Id(), setTargetPoolsV1).Do()
|
||||
case v0beta:
|
||||
setTargetPoolsV0beta := &computeBeta.InstanceGroupManagersSetTargetPoolsRequest{}
|
||||
err = Convert(setTargetPools, setTargetPoolsV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.SetTargetPools(
|
||||
project, zone, d.Id(), setTargetPoolsV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
@ -437,8 +530,27 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
InstanceTemplate: d.Get("instance_template").(string),
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.InstanceGroupManagers.SetInstanceTemplate(
|
||||
project, zone, d.Id(), setInstanceTemplate).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
setInstanceTemplateV1 := &compute.InstanceGroupManagersSetInstanceTemplateRequest{}
|
||||
err = Convert(setInstanceTemplate, setInstanceTemplateV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.InstanceGroupManagers.SetInstanceTemplate(
|
||||
project, zone, d.Id(), setInstanceTemplateV1).Do()
|
||||
case v0beta:
|
||||
setInstanceTemplateV0beta := &computeBeta.InstanceGroupManagersSetInstanceTemplateRequest{}
|
||||
err = Convert(setInstanceTemplate, setInstanceTemplateV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.SetInstanceTemplate(
|
||||
project, zone, d.Id(), setInstanceTemplateV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
@ -451,10 +563,30 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
if d.Get("update_strategy").(string) == "RESTART" {
|
||||
managedInstances, err := config.clientComputeBeta.InstanceGroupManagers.ListManagedInstances(
|
||||
project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting instance group managers instances: %s", err)
|
||||
managedInstances := &computeBeta.InstanceGroupManagersListManagedInstancesResponse{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
managedInstancesV1, err := config.clientCompute.InstanceGroupManagers.ListManagedInstances(
|
||||
project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting instance group managers instances: %s", err)
|
||||
}
|
||||
|
||||
err = Convert(managedInstancesV1, managedInstances)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case v0beta:
|
||||
managedInstancesV0beta, err := config.clientComputeBeta.InstanceGroupManagers.ListManagedInstances(
|
||||
project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting instance group managers instances: %s", err)
|
||||
}
|
||||
|
||||
err = Convert(managedInstancesV0beta, managedInstances)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
managedInstanceCount := len(managedInstances.ManagedInstances)
|
||||
@ -467,10 +599,32 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
Instances: instances,
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.RecreateInstances(
|
||||
project, zone, d.Id(), recreateInstances).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error restarting instance group managers instances: %s", err)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
recreateInstancesV1 := &compute.InstanceGroupManagersRecreateInstancesRequest{}
|
||||
err = Convert(recreateInstances, recreateInstancesV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.InstanceGroupManagers.RecreateInstances(
|
||||
project, zone, d.Id(), recreateInstancesV1).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error restarting instance group managers instances: %s", err)
|
||||
}
|
||||
case v0beta:
|
||||
recreateInstancesV0beta := &computeBeta.InstanceGroupManagersRecreateInstancesRequest{}
|
||||
err = Convert(recreateInstances, recreateInstancesV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.RecreateInstances(
|
||||
project, zone, d.Id(), recreateInstancesV0beta).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error restarting instance group managers instances: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the operation to complete
|
||||
@ -515,8 +669,27 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
// Make the request:
|
||||
op, err := config.clientComputeBeta.InstanceGroups.SetNamedPorts(
|
||||
project, zone, d.Id(), setNamedPorts).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
setNamedPortsV1 := &compute.InstanceGroupsSetNamedPortsRequest{}
|
||||
err = Convert(setNamedPorts, setNamedPortsV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.InstanceGroups.SetNamedPorts(
|
||||
project, zone, d.Id(), setNamedPortsV1).Do()
|
||||
case v0beta:
|
||||
setNamedPortsV0beta := &computeBeta.InstanceGroupsSetNamedPortsRequest{}
|
||||
err = Convert(setNamedPorts, setNamedPortsV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.InstanceGroups.SetNamedPorts(
|
||||
project, zone, d.Id(), setNamedPortsV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
@ -533,8 +706,15 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
|
||||
if d.HasChange("target_size") {
|
||||
targetSize := int64(d.Get("target_size").(int))
|
||||
op, err := config.clientComputeBeta.InstanceGroupManagers.Resize(
|
||||
project, zone, d.Id(), targetSize).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.InstanceGroupManagers.Resize(
|
||||
project, zone, d.Id(), targetSize).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.Resize(
|
||||
project, zone, d.Id(), targetSize).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
@ -578,6 +758,7 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -590,12 +771,24 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte
|
||||
return err
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.InstanceGroupManagers.Delete(project, zone, d.Id()).Do()
|
||||
attempt := 0
|
||||
for err != nil && attempt < 20 {
|
||||
attempt++
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do()
|
||||
attempt := 0
|
||||
for err != nil && attempt < 20 {
|
||||
attempt++
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
op, err = config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do()
|
||||
}
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.Delete(project, zone, d.Id()).Do()
|
||||
attempt := 0
|
||||
for err != nil && attempt < 20 {
|
||||
attempt++
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
op, err = config.clientComputeBeta.InstanceGroupManagers.Delete(project, zone, d.Id()).Do()
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -612,13 +805,25 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte
|
||||
return err
|
||||
}
|
||||
|
||||
instanceGroup, err := config.clientComputeBeta.InstanceGroups.Get(
|
||||
project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting instance group size: %s", err)
|
||||
}
|
||||
var instanceGroupSize int64
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
instanceGroup, err := config.clientCompute.InstanceGroups.Get(
|
||||
project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting instance group size: %s", err)
|
||||
}
|
||||
|
||||
instanceGroupSize := instanceGroup.Size
|
||||
instanceGroupSize = instanceGroup.Size
|
||||
case v0beta:
|
||||
instanceGroup, err := config.clientComputeBeta.InstanceGroups.Get(
|
||||
project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting instance group size: %s", err)
|
||||
}
|
||||
|
||||
instanceGroupSize = instanceGroup.Size
|
||||
}
|
||||
|
||||
if instanceGroupSize >= currentSize {
|
||||
return fmt.Errorf("Error, instance group isn't shrinking during delete")
|
||||
|
@ -292,11 +292,9 @@ func TestAccInstanceGroupManager_autoHealingPolicies(t *testing.T) {
|
||||
testAccCheckInstanceGroupManagerAutoHealingPolicies("google_compute_instance_group_manager.igm-basic", hck, 10),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
ResourceName: "google_compute_instance_group_manager.igm-basic",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
// TODO: Add import test for auto healing policies
|
||||
// Import doesn't work for auto healing policies because import is not supported
|
||||
// for beta features. See https://github.com/terraform-providers/terraform-provider-google/issues/694
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -6,9 +6,13 @@ import (
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
var InstanceTemplateBaseApiVersion = v1
|
||||
var InstanceTemplateVersionedFeatures = []Feature{}
|
||||
|
||||
func resourceComputeInstanceTemplate() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeInstanceTemplateCreate,
|
||||
@ -606,7 +610,17 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac
|
||||
Name: itName,
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.InstanceTemplates.Insert(project, instanceTemplate).Do()
|
||||
var op interface{}
|
||||
switch getComputeApiVersion(d, InstanceTemplateBaseApiVersion, InstanceGroupManagerVersionedFeatures) {
|
||||
case v1:
|
||||
instanceTemplateV1 := &compute.InstanceTemplate{}
|
||||
if err := Convert(instanceTemplate, instanceTemplateV1); err != nil {
|
||||
return err
|
||||
}
|
||||
op, err = config.clientCompute.InstanceTemplates.Insert(project, instanceTemplateV1).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.InstanceTemplates.Insert(project, instanceTemplate).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating instance template: %s", err)
|
||||
}
|
||||
@ -656,9 +670,22 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{
|
||||
return err
|
||||
}
|
||||
|
||||
instanceTemplate, err := config.clientComputeBeta.InstanceTemplates.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Instance Template %q", d.Get("name").(string)))
|
||||
instanceTemplate := &computeBeta.InstanceTemplate{}
|
||||
switch getComputeApiVersion(d, InstanceBaseApiVersion, InstanceVersionedFeatures) {
|
||||
case v1:
|
||||
instanceTemplateV1, err := config.clientCompute.InstanceTemplates.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Instance Template %q", d.Get("name").(string)))
|
||||
}
|
||||
if err := Convert(instanceTemplateV1, instanceTemplate); err != nil {
|
||||
return err
|
||||
}
|
||||
case v0beta:
|
||||
var err error
|
||||
instanceTemplate, err = config.clientComputeBeta.InstanceTemplates.Get(project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Instance Template %q", d.Get("name").(string)))
|
||||
}
|
||||
}
|
||||
|
||||
// Set the metadata fingerprint if there is one.
|
||||
|
@ -8,6 +8,9 @@ import (
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var ProjectMetadataBaseApiVersion = v1
|
||||
var ProjectMetadataVersionedFeatures = []Feature{}
|
||||
|
||||
func resourceComputeProjectMetadata() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeProjectMetadataCreate,
|
||||
|
@ -12,8 +12,16 @@ import (
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var RegionInstanceGroupManagerBaseApiVersion = v1
|
||||
var RegionInstanceGroupManagerVersionedFeatures = []Feature{
|
||||
Feature{Version: v0beta, Item: "auto_healing_policies"},
|
||||
Feature{Version: v0beta, Item: "distribution_policy_zones"},
|
||||
Feature{Version: v0beta, Item: "rolling_update_policy"},
|
||||
}
|
||||
|
||||
func resourceComputeRegionInstanceGroupManager() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeRegionInstanceGroupManagerCreate,
|
||||
@ -222,6 +230,7 @@ func resourceComputeRegionInstanceGroupManager() *schema.Resource {
|
||||
}
|
||||
|
||||
func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, RegionInstanceGroupManagerBaseApiVersion, RegionInstanceGroupManagerVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -247,7 +256,19 @@ func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, met
|
||||
ForceSendFields: []string{"TargetSize"},
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.RegionInstanceGroupManagers.Insert(project, d.Get("region").(string), manager).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
managerV1 := &compute.InstanceGroupManager{}
|
||||
err = Convert(manager, managerV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
managerV1.ForceSendFields = manager.ForceSendFields
|
||||
op, err = config.clientCompute.RegionInstanceGroupManagers.Insert(project, d.Get("region").(string), managerV1).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.RegionInstanceGroupManagers.Insert(project, d.Get("region").(string), manager).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating RegionInstanceGroupManager: %s", err)
|
||||
@ -266,6 +287,7 @@ func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, met
|
||||
type getInstanceManagerFunc func(*schema.ResourceData, interface{}) (*computeBeta.InstanceGroupManager, error)
|
||||
|
||||
func getRegionalManager(d *schema.ResourceData, meta interface{}) (*computeBeta.InstanceGroupManager, error) {
|
||||
computeApiVersion := getComputeApiVersion(d, RegionInstanceGroupManagerBaseApiVersion, RegionInstanceGroupManagerVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -274,12 +296,32 @@ func getRegionalManager(d *schema.ResourceData, meta interface{}) (*computeBeta.
|
||||
}
|
||||
|
||||
region := d.Get("region").(string)
|
||||
manager := &computeBeta.InstanceGroupManager{}
|
||||
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
v1Manager := &compute.InstanceGroupManager{}
|
||||
v1Manager, err = config.clientCompute.RegionInstanceGroupManagers.Get(project, region, d.Id()).Do()
|
||||
|
||||
if v1Manager == nil {
|
||||
log.Printf("[WARN] Removing Region Instance Group Manager %q because it's gone", d.Get("name").(string))
|
||||
|
||||
// The resource doesn't exist anymore
|
||||
d.SetId("")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err = Convert(v1Manager, manager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case v0beta:
|
||||
manager, err = config.clientComputeBeta.RegionInstanceGroupManagers.Get(project, region, d.Id()).Do()
|
||||
}
|
||||
|
||||
manager, err := config.clientComputeBeta.RegionInstanceGroupManagers.Get(project, region, d.Id()).Do()
|
||||
if err != nil {
|
||||
return nil, handleNotFoundError(err, d, fmt.Sprintf("Region Instance Manager %q", d.Get("name").(string)))
|
||||
}
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
@ -344,6 +386,7 @@ func resourceComputeRegionInstanceGroupManagerRead(d *schema.ResourceData, meta
|
||||
}
|
||||
|
||||
func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersionUpdate(d, RegionInstanceGroupManagerBaseApiVersion, RegionInstanceGroupManagerVersionedFeatures, []Feature{})
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -368,8 +411,27 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
|
||||
TargetPools: targetPools,
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.RegionInstanceGroupManagers.SetTargetPools(
|
||||
project, region, d.Id(), setTargetPools).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
setTargetPoolsV1 := &compute.RegionInstanceGroupManagersSetTargetPoolsRequest{}
|
||||
err = Convert(setTargetPools, setTargetPoolsV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.RegionInstanceGroupManagers.SetTargetPools(
|
||||
project, region, d.Id(), setTargetPoolsV1).Do()
|
||||
case v0beta:
|
||||
setTargetPoolsV0beta := &computeBeta.RegionInstanceGroupManagersSetTargetPoolsRequest{}
|
||||
err = Convert(setTargetPools, setTargetPoolsV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.RegionInstanceGroupManagers.SetTargetPools(
|
||||
project, region, d.Id(), setTargetPoolsV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating RegionInstanceGroupManager: %s", err)
|
||||
@ -390,8 +452,27 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
|
||||
InstanceTemplate: d.Get("instance_template").(string),
|
||||
}
|
||||
|
||||
op, err := config.clientComputeBeta.RegionInstanceGroupManagers.SetInstanceTemplate(
|
||||
project, region, d.Id(), setInstanceTemplate).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
setInstanceTemplateV1 := &compute.RegionInstanceGroupManagersSetTemplateRequest{}
|
||||
err = Convert(setInstanceTemplate, setInstanceTemplateV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.RegionInstanceGroupManagers.SetInstanceTemplate(
|
||||
project, region, d.Id(), setInstanceTemplateV1).Do()
|
||||
case v0beta:
|
||||
setInstanceTemplateV0beta := &computeBeta.RegionInstanceGroupManagersSetTemplateRequest{}
|
||||
err = Convert(setInstanceTemplate, setInstanceTemplateV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.RegionInstanceGroupManagers.SetInstanceTemplate(
|
||||
project, region, d.Id(), setInstanceTemplateV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating RegionInstanceGroupManager: %s", err)
|
||||
@ -436,8 +517,27 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
|
||||
}
|
||||
|
||||
// Make the request:
|
||||
op, err := config.clientComputeBeta.RegionInstanceGroups.SetNamedPorts(
|
||||
project, region, d.Id(), setNamedPorts).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
setNamedPortsV1 := &compute.RegionInstanceGroupsSetNamedPortsRequest{}
|
||||
err = Convert(setNamedPorts, setNamedPortsV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.RegionInstanceGroups.SetNamedPorts(
|
||||
project, region, d.Id(), setNamedPortsV1).Do()
|
||||
case v0beta:
|
||||
setNamedPortsV0beta := &computeBeta.RegionInstanceGroupsSetNamedPortsRequest{}
|
||||
err = Convert(setNamedPorts, setNamedPortsV0beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientComputeBeta.RegionInstanceGroups.SetNamedPorts(
|
||||
project, region, d.Id(), setNamedPortsV0beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating RegionInstanceGroupManager: %s", err)
|
||||
@ -454,8 +554,15 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
|
||||
|
||||
if d.HasChange("target_size") {
|
||||
targetSize := int64(d.Get("target_size").(int))
|
||||
op, err := config.clientComputeBeta.RegionInstanceGroupManagers.Resize(
|
||||
project, region, d.Id(), targetSize).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.RegionInstanceGroupManagers.Resize(
|
||||
project, region, d.Id(), targetSize).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.RegionInstanceGroupManagers.Resize(
|
||||
project, region, d.Id(), targetSize).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error resizing RegionInstanceGroupManager: %s", err)
|
||||
@ -498,6 +605,7 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
|
||||
}
|
||||
|
||||
func resourceComputeRegionInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, RegionInstanceGroupManagerBaseApiVersion, RegionInstanceGroupManagerVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -507,7 +615,13 @@ func resourceComputeRegionInstanceGroupManagerDelete(d *schema.ResourceData, met
|
||||
|
||||
region := d.Get("region").(string)
|
||||
|
||||
op, err := config.clientComputeBeta.RegionInstanceGroupManagers.Delete(project, region, d.Id()).Do()
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.RegionInstanceGroupManagers.Delete(project, region, d.Id()).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.RegionInstanceGroupManagers.Delete(project, region, d.Id()).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting region instance group manager: %s", err)
|
||||
|
@ -14,6 +14,14 @@ import (
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
SubnetworkBaseApiVersion = v1
|
||||
SubnetworkVersionedFeatures = []Feature{
|
||||
{Version: v0beta, Item: "secondary_ip_range"},
|
||||
{Version: v0beta, Item: "enable_flow_logs"},
|
||||
}
|
||||
)
|
||||
|
||||
func resourceComputeSubnetwork() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeSubnetworkCreate,
|
||||
@ -122,6 +130,7 @@ func resourceComputeSubnetwork() *schema.Resource {
|
||||
}
|
||||
|
||||
func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
network, err := ParseNetworkFieldValue(d.Get("network").(string), d, config)
|
||||
if err != nil {
|
||||
@ -151,7 +160,21 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
|
||||
|
||||
log.Printf("[DEBUG] Subnetwork insert request: %#v", subnetwork)
|
||||
|
||||
op, err := config.clientComputeBeta.Subnetworks.Insert(project, region, subnetwork).Do()
|
||||
subnetworkV1 := &compute.Subnetwork{}
|
||||
err = Convert(subnetwork, subnetworkV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subnetworkV1.ForceSendFields = subnetwork.ForceSendFields
|
||||
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.Subnetworks.Insert(project, region, subnetworkV1).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.Subnetworks.Insert(project, region, subnetwork).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating subnetwork: %s", err)
|
||||
}
|
||||
@ -161,8 +184,9 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
|
||||
// "When creating a new subnetwork, its name has to be unique in that project for that region, even across networks.
|
||||
// The same name can appear twice in a project, as long as each one is in a different region."
|
||||
// https://cloud.google.com/compute/docs/subnetworks
|
||||
subnetworkV1.Region = region
|
||||
subnetwork.Region = region
|
||||
d.SetId(createSubnetIDBeta(subnetwork))
|
||||
d.SetId(createSubnetID(subnetworkV1))
|
||||
|
||||
err = computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutCreate).Minutes()), "Creating Subnetwork")
|
||||
if err != nil {
|
||||
@ -173,6 +197,45 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
|
||||
}
|
||||
|
||||
func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
|
||||
if computeApiVersion == v0beta {
|
||||
return resourceComputeSubnetworkReadV0Beta(d, meta)
|
||||
}
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
subnetwork, err := config.clientCompute.Subnetworks.Get(project, region, name).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Subnetwork %q", name))
|
||||
}
|
||||
|
||||
d.Set("name", subnetwork.Name)
|
||||
d.Set("ip_cidr_range", subnetwork.IpCidrRange)
|
||||
d.Set("network", subnetwork.Network)
|
||||
d.Set("description", subnetwork.Description)
|
||||
d.Set("private_ip_google_access", subnetwork.PrivateIpGoogleAccess)
|
||||
d.Set("gateway_address", subnetwork.GatewayAddress)
|
||||
d.Set("secondary_ip_range", flattenSecondaryRanges(subnetwork.SecondaryIpRanges))
|
||||
d.Set("project", project)
|
||||
d.Set("region", region)
|
||||
d.Set("self_link", ConvertSelfLinkToV1(subnetwork.SelfLink))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeSubnetworkReadV0Beta(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
@ -209,6 +272,7 @@ func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) err
|
||||
}
|
||||
|
||||
func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
@ -264,7 +328,7 @@ func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) e
|
||||
d.SetPartial("ip_cidr_range")
|
||||
}
|
||||
|
||||
if d.HasChange("secondary_ip_range") || d.HasChange("enable_flow_logs") {
|
||||
if (d.HasChange("secondary_ip_range") || d.HasChange("enable_flow_logs")) && computeApiVersion == v0beta {
|
||||
v0BetaSubnetwork := &computeBeta.Subnetwork{
|
||||
Fingerprint: d.Get("fingerprint").(string),
|
||||
}
|
||||
|
@ -193,11 +193,7 @@ func TestAccComputeSubnetwork_flowLogs(t *testing.T) {
|
||||
"enable_flow_logs", "true"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_compute_subnetwork.network-with-flow-logs",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
// no import, as import currently doesn't work for beta
|
||||
{
|
||||
Config: testAccComputeSubnetwork_flowLogs(cnName, subnetworkName, false),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
@ -207,11 +203,6 @@ func TestAccComputeSubnetwork_flowLogs(t *testing.T) {
|
||||
"enable_flow_logs", "false"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_compute_subnetwork.network-with-flow-logs",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -12,12 +12,23 @@ import (
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
"google.golang.org/api/container/v1"
|
||||
containerBeta "google.golang.org/api/container/v1beta1"
|
||||
)
|
||||
|
||||
var (
|
||||
instanceGroupManagerURL = regexp.MustCompile(fmt.Sprintf("^https://www.googleapis.com/compute/v1/projects/(%s)/zones/([a-z0-9-]*)/instanceGroupManagers/([^/]*)", ProjectRegex))
|
||||
|
||||
ContainerClusterBaseApiVersion = v1
|
||||
ContainerClusterVersionedFeatures = []Feature{
|
||||
{Version: v1beta1, Item: "pod_security_policy_config"},
|
||||
{Version: v1beta1, Item: "node_config.*.taint"},
|
||||
{Version: v1beta1, Item: "node_config.*.workload_metadata_config"},
|
||||
{Version: v1beta1, Item: "private_cluster"},
|
||||
{Version: v1beta1, Item: "master_ipv4_cidr_block"},
|
||||
{Version: v1beta1, Item: "region"},
|
||||
}
|
||||
|
||||
networkConfig = &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"cidr_blocks": {
|
||||
@ -464,6 +475,7 @@ func resourceContainerCluster() *schema.Resource {
|
||||
}
|
||||
|
||||
func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
containerAPIVersion := getContainerApiVersion(d, ContainerClusterBaseApiVersion, ContainerClusterVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -639,8 +651,25 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er
|
||||
mutexKV.Lock(containerClusterMutexKey(project, location, clusterName))
|
||||
defer mutexKV.Unlock(containerClusterMutexKey(project, location, clusterName))
|
||||
|
||||
parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.Create(parent, req).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
reqV1 := &container.CreateClusterRequest{}
|
||||
err = Convert(req, reqV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.Create(project, location, reqV1).Do()
|
||||
case v1beta1:
|
||||
reqV1Beta := &containerBeta.CreateClusterRequest{}
|
||||
err = Convert(req, reqV1Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.Create(parent, reqV1Beta).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -658,8 +687,15 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er
|
||||
log.Printf("[INFO] GKE cluster %s has been created", clusterName)
|
||||
|
||||
if d.Get("remove_default_node_pool").(bool) {
|
||||
parent := fmt.Sprintf("%s/nodePools/%s", containerClusterFullName(project, location, clusterName), "default-pool")
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.NodePools.Delete(parent).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.NodePools.Delete(
|
||||
project, location, clusterName, "default-pool").Do()
|
||||
case v1beta1:
|
||||
parent := fmt.Sprintf("%s/nodePools/%s", containerClusterFullName(project, location, clusterName), "default-pool")
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.NodePools.Delete(parent).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error deleting default node pool: {{err}}", err)
|
||||
}
|
||||
@ -673,6 +709,7 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er
|
||||
}
|
||||
|
||||
func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) error {
|
||||
containerAPIVersion := getContainerApiVersion(d, ContainerClusterBaseApiVersion, ContainerClusterVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -686,9 +723,20 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro
|
||||
}
|
||||
|
||||
cluster := &containerBeta.Cluster{}
|
||||
var clust interface{}
|
||||
err = resource.Retry(2*time.Minute, func() *resource.RetryError {
|
||||
name := containerClusterFullName(project, location, d.Get("name").(string))
|
||||
cluster, err = config.clientContainerBeta.Projects.Locations.Clusters.Get(name).Do()
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
clust, err = config.clientContainer.Projects.Zones.Clusters.Get(
|
||||
project, location, d.Get("name").(string)).Do()
|
||||
case v1beta1:
|
||||
name := containerClusterFullName(project, location, d.Get("name").(string))
|
||||
clust, err = config.clientContainerBeta.Projects.Locations.Clusters.Get(name).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
err = Convert(clust, cluster)
|
||||
if err != nil {
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
@ -786,6 +834,7 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro
|
||||
}
|
||||
|
||||
func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
containerAPIVersion := getContainerApiVersion(d, ContainerClusterBaseApiVersion, ContainerClusterVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
@ -805,10 +854,22 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
|
||||
lockKey := containerClusterMutexKey(project, location, clusterName)
|
||||
|
||||
updateFunc := func(req *containerBeta.UpdateClusterRequest, updateDescription string) func() error {
|
||||
updateFunc := func(req *container.UpdateClusterRequest, updateDescription string) func() error {
|
||||
return func() error {
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.Update(name, req).Do()
|
||||
var err error
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.Update(project, location, clusterName, req).Do()
|
||||
case v1beta1:
|
||||
reqV1Beta := &containerBeta.UpdateClusterRequest{}
|
||||
err = Convert(req, reqV1Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.Update(name, reqV1Beta).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -822,9 +883,14 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
// if the order of updating fields does matter, it is called out explicitly.
|
||||
if d.HasChange("master_authorized_networks_config") {
|
||||
c := d.Get("master_authorized_networks_config")
|
||||
req := &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
DesiredMasterAuthorizedNetworksConfig: expandMasterAuthorizedNetworksConfig(c),
|
||||
conf := &container.MasterAuthorizedNetworksConfig{}
|
||||
err := Convert(expandMasterAuthorizedNetworksConfig(c), conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredMasterAuthorizedNetworksConfig: conf,
|
||||
},
|
||||
}
|
||||
|
||||
@ -852,8 +918,8 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
|
||||
// Only upgrade the master if the current version is lower than the desired version
|
||||
if cur.LessThan(des) {
|
||||
req := &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
req := &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredMasterVersion: desiredMasterVersion,
|
||||
},
|
||||
}
|
||||
@ -870,8 +936,8 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
|
||||
if d.HasChange("node_version") {
|
||||
desiredNodeVersion := d.Get("node_version").(string)
|
||||
req := &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
req := &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredNodeVersion: desiredNodeVersion,
|
||||
},
|
||||
}
|
||||
@ -889,9 +955,14 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
|
||||
if d.HasChange("addons_config") {
|
||||
if ac, ok := d.GetOk("addons_config"); ok {
|
||||
req := &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
DesiredAddonsConfig: expandClusterAddonsConfig(ac),
|
||||
conf := &container.AddonsConfig{}
|
||||
err := Convert(expandClusterAddonsConfig(ac), conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredAddonsConfig: conf,
|
||||
},
|
||||
}
|
||||
|
||||
@ -908,20 +979,37 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
}
|
||||
|
||||
if d.HasChange("maintenance_policy") {
|
||||
var req *containerBeta.SetMaintenancePolicyRequest
|
||||
var req *container.SetMaintenancePolicyRequest
|
||||
if mp, ok := d.GetOk("maintenance_policy"); ok {
|
||||
req = &containerBeta.SetMaintenancePolicyRequest{
|
||||
MaintenancePolicy: expandMaintenancePolicy(mp),
|
||||
pol := &container.MaintenancePolicy{}
|
||||
err := Convert(expandMaintenancePolicy(mp), pol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req = &container.SetMaintenancePolicyRequest{
|
||||
MaintenancePolicy: pol,
|
||||
}
|
||||
} else {
|
||||
req = &containerBeta.SetMaintenancePolicyRequest{
|
||||
req = &container.SetMaintenancePolicyRequest{
|
||||
NullFields: []string{"MaintenancePolicy"},
|
||||
}
|
||||
}
|
||||
|
||||
updateF := func() error {
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.SetMaintenancePolicy(name, req).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.SetMaintenancePolicy(
|
||||
project, location, clusterName, req).Do()
|
||||
case v1beta1:
|
||||
reqV1Beta := &containerBeta.SetMaintenancePolicyRequest{}
|
||||
err = Convert(req, reqV1Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.SetMaintenancePolicy(name, reqV1Beta).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -956,8 +1044,8 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
azSet.Add(location)
|
||||
}
|
||||
|
||||
req := &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
req := &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredLocations: convertStringSet(azSet),
|
||||
},
|
||||
}
|
||||
@ -972,8 +1060,8 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
azSetNew.Add(location)
|
||||
}
|
||||
if !azSet.Equal(azSetNew) {
|
||||
req = &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
req = &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredLocations: convertStringSet(azSetNew),
|
||||
},
|
||||
}
|
||||
@ -992,15 +1080,26 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
|
||||
if d.HasChange("enable_legacy_abac") {
|
||||
enabled := d.Get("enable_legacy_abac").(bool)
|
||||
req := &containerBeta.SetLegacyAbacRequest{
|
||||
req := &container.SetLegacyAbacRequest{
|
||||
Enabled: enabled,
|
||||
ForceSendFields: []string{"Enabled"},
|
||||
}
|
||||
|
||||
updateF := func() error {
|
||||
log.Println("[DEBUG] updating enable_legacy_abac")
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.SetLegacyAbac(name, req).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.LegacyAbac(project, location, clusterName, req).Do()
|
||||
case v1beta1:
|
||||
reqV1Beta := &containerBeta.SetLegacyAbacRequest{}
|
||||
err = Convert(req, reqV1Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.SetLegacyAbac(name, reqV1Beta).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1024,8 +1123,8 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
if d.HasChange("monitoring_service") {
|
||||
desiredMonitoringService := d.Get("monitoring_service").(string)
|
||||
|
||||
req := &containerBeta.UpdateClusterRequest{
|
||||
Update: &containerBeta.ClusterUpdate{
|
||||
req := &container.UpdateClusterRequest{
|
||||
Update: &container.ClusterUpdate{
|
||||
DesiredMonitoringService: desiredMonitoringService,
|
||||
},
|
||||
}
|
||||
@ -1043,14 +1142,32 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
|
||||
if d.HasChange("network_policy") {
|
||||
np := d.Get("network_policy")
|
||||
req := &containerBeta.SetNetworkPolicyRequest{
|
||||
NetworkPolicy: expandNetworkPolicy(np),
|
||||
|
||||
pol := &container.NetworkPolicy{}
|
||||
err := Convert(expandNetworkPolicy(np), pol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := &container.SetNetworkPolicyRequest{
|
||||
NetworkPolicy: pol,
|
||||
}
|
||||
|
||||
updateF := func() error {
|
||||
log.Println("[DEBUG] updating network_policy")
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.SetNetworkPolicy(name, req).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.SetNetworkPolicy(
|
||||
project, location, clusterName, req).Do()
|
||||
case v1beta1:
|
||||
reqV1Beta := &containerBeta.SetNetworkPolicyRequest{}
|
||||
err = Convert(req, reqV1Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.SetNetworkPolicy(name, reqV1Beta).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1089,12 +1206,24 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
if d.HasChange("logging_service") {
|
||||
logging := d.Get("logging_service").(string)
|
||||
|
||||
req := &containerBeta.SetLoggingServiceRequest{
|
||||
req := &container.SetLoggingServiceRequest{
|
||||
LoggingService: logging,
|
||||
}
|
||||
updateF := func() error {
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.SetLogging(name, req).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.Logging(
|
||||
project, location, clusterName, req).Do()
|
||||
case v1beta1:
|
||||
reqV1Beta := &containerBeta.SetLoggingServiceRequest{}
|
||||
err = Convert(req, reqV1Beta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := containerClusterFullName(project, location, clusterName)
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.SetLogging(name, reqV1Beta).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1138,8 +1267,15 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
||||
}
|
||||
|
||||
if d.HasChange("remove_default_node_pool") && d.Get("remove_default_node_pool").(bool) {
|
||||
name := fmt.Sprintf("%s/nodePools/%s", containerClusterFullName(project, location, clusterName), "default-pool")
|
||||
op, err := config.clientContainerBeta.Projects.Locations.Clusters.NodePools.Delete(name).Do()
|
||||
var op interface{}
|
||||
switch containerAPIVersion {
|
||||
case v1:
|
||||
op, err = config.clientContainer.Projects.Zones.Clusters.NodePools.Delete(
|
||||
project, location, clusterName, "default-pool").Do()
|
||||
case v1beta1:
|
||||
name := fmt.Sprintf("%s/nodePools/%s", containerClusterFullName(project, location, clusterName), "default-pool")
|
||||
op, err = config.clientContainerBeta.Projects.Locations.Clusters.NodePools.Delete(name).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error deleting default node pool: {{err}}", err)
|
||||
}
|
||||
|
@ -431,6 +431,9 @@ func TestAccContainerCluster_withPrivateCluster(t *testing.T) {
|
||||
ImportStateIdPrefix: "us-central1-a/",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{
|
||||
"private_cluster",
|
||||
"master_ipv4_cidr_block"},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -639,11 +642,17 @@ func TestAccContainerCluster_withWorkloadMetadataConfig(t *testing.T) {
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_container_cluster.with_workload_metadata_config",
|
||||
ImportStateIdPrefix: "us-central1-a/",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{"min_master_version"},
|
||||
ResourceName: "google_container_cluster.with_workload_metadata_config",
|
||||
ImportStateIdPrefix: "us-central1-a/",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
// Import always uses the v1 API, so beta features don't get imported.
|
||||
ImportStateVerifyIgnore: []string{
|
||||
"node_config.0.workload_metadata_config.#",
|
||||
"node_config.0.workload_metadata_config.0.node_metadata",
|
||||
"node_pool.0.node_config.0.workload_metadata_config.#",
|
||||
"node_pool.0.node_config.0.workload_metadata_config.0.node_metadata",
|
||||
"min_master_version"},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -1116,6 +1125,8 @@ func TestAccContainerCluster_withPodSecurityPolicy(t *testing.T) {
|
||||
ImportStateIdPrefix: "us-central1-a/",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
// Import always uses the v1 API, so beta features don't get imported.
|
||||
ImportStateVerifyIgnore: []string{"pod_security_policy_config.#", "pod_security_policy_config.0.enabled"},
|
||||
},
|
||||
{
|
||||
Config: testAccContainerCluster_withPodSecurityPolicy(clusterName, false),
|
||||
@ -1129,6 +1140,8 @@ func TestAccContainerCluster_withPodSecurityPolicy(t *testing.T) {
|
||||
ImportStateIdPrefix: "us-central1-a/",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
// Import always uses the v1 API, so beta features don't get imported.
|
||||
ImportStateVerifyIgnore: []string{"pod_security_policy_config.#", "pod_security_policy_config.0.enabled"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -1,41 +0,0 @@
|
||||
package google
|
||||
|
||||
type ResourceDataMock struct {
|
||||
FieldsInSchema map[string]interface{}
|
||||
FieldsWithHasChange []string
|
||||
id string
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) HasChange(key string) bool {
|
||||
exists := false
|
||||
for _, val := range d.FieldsWithHasChange {
|
||||
if key == val {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
|
||||
return exists
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) GetOk(key string) (interface{}, bool) {
|
||||
for k, v := range d.FieldsInSchema {
|
||||
if key == k {
|
||||
return v, true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) Set(key string, value interface{}) error {
|
||||
d.FieldsInSchema[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) SetId(v string) {
|
||||
d.id = v
|
||||
}
|
||||
|
||||
func (d *ResourceDataMock) Id() string {
|
||||
return d.id
|
||||
}
|
@ -17,14 +17,6 @@ import (
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
type TerraformResourceData interface {
|
||||
HasChange(string) bool
|
||||
GetOk(string) (interface{}, bool)
|
||||
Set(string, interface{}) error
|
||||
SetId(string)
|
||||
Id() string
|
||||
}
|
||||
|
||||
// getRegionFromZone returns the region from a zone for Google cloud.
|
||||
func getRegionFromZone(zone string) string {
|
||||
if zone != "" && len(zone) > 2 {
|
||||
|
@ -112,6 +112,5 @@ deprecation policy, and no SLA, but are otherwise considered to be feature-compl
|
||||
with only minor outstanding issues after their Alpha period. Beta is when a GCP feature
|
||||
is publicly announced, and is when they generally become publicly available.
|
||||
|
||||
Terraform resources that support beta features will always use the Beta APIs to provision
|
||||
the resource. Importing a resource that supports beta features will always import those
|
||||
features, even if the resource was created in a matter that was not explicitly beta.
|
||||
Resources will automatically be provisioned using Beta APIs when you specify a feature
|
||||
marked Beta in your Terraform config file.
|
||||
|
Loading…
Reference in New Issue
Block a user