Skip to content

Commit 1a7a1f6

Browse files
rileykarsonmodular-magician
authored andcommitted
Add convenience field support to Terraform, generate Network (#1489)
Merged PR #1489.
1 parent aa423c4 commit 1a7a1f6

23 files changed

+289
-385
lines changed

api/type.rb

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ module Fields
2626
attr_reader :description
2727
attr_reader :exclude
2828

29+
# Add a deprecation message for a field that's been deprecated in the API
30+
# use the YAML chomping folding indicator (>-) if this is a multiline
31+
# string, as providers expect a single-line one w/o a newline.
32+
attr_reader :deprecation_message
33+
2934
attr_reader :output # If set value will not be sent to server on sync
3035
attr_reader :input # If set to true value is used only on creation
3136
attr_reader :url_param_only # If, true will not be send in request body
@@ -57,6 +62,7 @@ def validate
5762
super
5863
check :description, type: ::String, required: true
5964
check :exclude, type: :boolean, default: false, required: true
65+
check :deprecation_message, type: ::String
6066
check :min_version, type: ::String
6167
check :output, type: :boolean
6268
check :required, type: :boolean
@@ -214,6 +220,10 @@ def nested_properties?
214220
!nested_properties.empty?
215221
end
216222

223+
def deprecated?
224+
!(@deprecation_message.nil? || @deprecation_message == '')
225+
end
226+
217227
private
218228

219229
# A constant value to be provided as field

build/terraform

build/terraform-beta

overrides/terraform/property_override.rb

+24
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,25 @@ def self.attributes
6464
# Names of attributes that can't be set alongside this one
6565
:conflicts_with,
6666

67+
# ====================
68+
# Schema Modifications
69+
# ====================
70+
# Schema modifications change the schema of a resource in some
71+
# fundamental way. They're not very portable, and will be hard to
72+
# generate so we should limit their use. Generally, if you're not
73+
# converting existing Terraform resources, these shouldn't be used.
74+
#
75+
# With great power comes great responsibility.
76+
77+
# Flatten the child field of a NestedObject into "convenience fields"
78+
# that are addressed as if they were top level fields.
79+
#
80+
# We need this for cases where a field inside a nested object has a
81+
# default, if we can't spend a breaking change to fix a misshapen
82+
# field, or if the UX is _much_ better otherwise. Nesting flattened
83+
# NestedObjects is inadvisable.
84+
:flatten_object,
85+
6786
# ===========
6887
# Custom code
6988
# ===========
@@ -121,6 +140,11 @@ def apply(api_property)
121140
api_property.description)
122141
end
123142

143+
if @flatten_object && !api_property.is_a?(Api::Type::NestedObject)
144+
raise 'Only NestedObjects can be flattened with flatten_object. Type'\
145+
" is #{api_property.class} for property #{api_property.name}"
146+
end
147+
124148
unless api_property.is_a?(Api::Type::Array) ||
125149
api_property.is_a?(Api::Type::Map)
126150
if @is_set

products/compute/api.yaml

+30-33
Original file line numberDiff line numberDiff line change
@@ -2635,58 +2635,53 @@ objects:
26352635
collection_url_response: !ruby/object:Api::Resource::ResponseList
26362636
kind: 'compute#networkList'
26372637
items: 'items'
2638-
update_verb: :PATCH
2638+
input: true
26392639
has_self_link: true
26402640
references: !ruby/object:Api::Resource::ReferenceLinks
26412641
guides:
26422642
'Official Documentation': 'https://cloud.google.com/vpc/docs/vpc'
26432643
api: 'https://cloud.google.com/compute/docs/reference/rest/v1/networks'
26442644
description: |
2645-
Represents a Network resource.
2646-
2647-
Your Cloud Platform Console project can contain multiple networks, and
2648-
each network can have multiple instances attached to it. A network allows
2649-
you to define a gateway IP and the network range for the instances
2650-
attached to that network. Every project is provided with a default network
2651-
with preset configurations and firewall rules. You can choose to customize
2652-
the default network by adding or removing rules, or you can create new
2653-
networks in that project. Generally, most users only need one network,
2654-
although you can have up to five networks per project by default.
2655-
2656-
A network belongs to only one project, and each instance can only belong
2657-
to one network. All Compute Engine networks use the IPv4 protocol. Compute
2658-
Engine currently does not support IPv6. However, Google is a major
2659-
advocate of IPv6 and it is an important future direction.
2645+
Manages a VPC network or legacy network resource on GCP.
26602646
<%= indent(compile_file({}, 'templates/global_async.yaml.erb'), 4) %>
26612647
properties:
26622648
- !ruby/object:Api::Type::String
26632649
name: 'description'
26642650
description: |
2665-
An optional description of this resource. Provide this property when
2666-
you create the resource.
2651+
An optional description of this resource. The resource must be
2652+
recreated to modify this field.
26672653
input: true
26682654
- !ruby/object:Api::Type::String
26692655
name: 'gateway_ipv4'
2670-
description: |
2671-
A gateway address for default routing to other networks. This value is
2672-
read only and is selected by the Google Compute Engine, typically as
2673-
the first usable address in the IPv4Range.
2656+
# We override this in api.yaml so that the name is more aesthetic
26742657
api_name: 'gatewayIPv4'
26752658
output: true
2659+
description: |
2660+
The gateway address for default routing out of the network. This value
2661+
is selected by GCP.
26762662
- !ruby/object:Api::Type::Integer
26772663
name: 'id'
26782664
description: 'The unique identifier for the resource.'
26792665
output: true
26802666
- !ruby/object:Api::Type::String
26812667
name: 'ipv4_range'
2682-
description: |
2683-
The range of internal addresses that are legal on this network. This
2684-
range is a CIDR specification, for example: 192.168.0.0/16. Provided
2685-
by the client when the network is created.
2668+
# We override this in api.yaml so that the name is more aesthetic
26862669
api_name: 'IPv4Range'
2670+
deprecation_message: >-
2671+
Legacy Networks are deprecated and you will no longer be able to
2672+
create them using this field from Feb 1, 2020 onwards.
26872673
input: true
26882674
conflicts:
26892675
- autoCreateSubnetworks
2676+
description: |
2677+
If this field is specified, a deprecated legacy network is created.
2678+
You will no longer be able to create a legacy network on Feb 1, 2020.
2679+
See the [legacy network docs](https://cloud.google.com/vpc/docs/legacy)
2680+
for more details.
2681+
2682+
The range of internal addresses that are legal on this legacy network.
2683+
This range is a CIDR specification, for example: `192.168.0.0/16`.
2684+
The resource must be recreated to modify this field.
26902685
- !ruby/object:Api::Type::String
26912686
name: 'name'
26922687
description: |
@@ -2710,19 +2705,21 @@ objects:
27102705
- !ruby/object:Api::Type::Boolean
27112706
name: 'autoCreateSubnetworks'
27122707
description: |
2713-
When set to true, the network is created in "auto subnet mode". When
2714-
set to false, the network is in "custom subnet mode".
2708+
When set to `true`, the network is created in "auto subnet mode" and
2709+
it will create a subnet for each region automatically across the
2710+
`10.128.0.0/9` address range.
27152711
2716-
In "auto subnet mode", a newly created network is assigned the default
2717-
CIDR of 10.128.0.0/9 and it automatically creates one subnetwork per
2718-
region.
2712+
When set to `false`, the network is created in "custom subnet mode" so
2713+
the user can explicitly connect subnetwork resources.
27192714
input: true
27202715
- !ruby/object:Api::Type::Time
27212716
name: 'creationTimestamp'
27222717
description: 'Creation timestamp in RFC3339 text format.'
27232718
output: true
27242719
- !ruby/object:Api::Type::NestedObject
27252720
name: 'routingConfig'
2721+
update_verb: :PATCH
2722+
update_url: projects/{{project}}/global/networks/{{name}}
27262723
description: |
27272724
The network-level routing configuration for this network. Used by Cloud
27282725
Router to determine what type of network-wide routing behavior to
@@ -2732,9 +2729,9 @@ objects:
27322729
name: 'routingMode'
27332730
required: true
27342731
description: |
2735-
The network-wide routing mode to use. If set to REGIONAL, this
2732+
The network-wide routing mode to use. If set to `REGIONAL`, this
27362733
network's cloud routers will only advertise routes with subnetworks
2737-
of this network in the same region as the router. If set to GLOBAL,
2734+
of this network in the same region as the router. If set to `GLOBAL`,
27382735
this network's cloud routers will advertise routes with all
27392736
subnetworks of this network, across regions.
27402737
values:

products/compute/terraform.yaml

+33-1
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,39 @@ overrides: !ruby/object:Overrides::ResourceOverrides
509509
MachineType: !ruby/object:Overrides::Terraform::ResourceOverride
510510
exclude: true
511511
Network: !ruby/object:Overrides::Terraform::ResourceOverride
512-
exclude: true
512+
examples:
513+
- !ruby/object:Provider::Terraform::Examples
514+
name: "network_basic"
515+
primary_resource_id: "vpc_network"
516+
vars:
517+
network_name: "vpc-network"
518+
properties:
519+
id: !ruby/object:Overrides::Terraform::PropertyOverride
520+
exclude: true
521+
# We want this to be the smallest change possible, so exclude this for now.
522+
# TODO: remove exclusion
523+
creationTimestamp: !ruby/object:Overrides::Terraform::PropertyOverride
524+
exclude: true
525+
# We could include this, but it won't be correct mid-apply when subnetworks
526+
# are modified, so it's probably better to exclude.
527+
subnetworks: !ruby/object:Overrides::Terraform::PropertyOverride
528+
exclude: true
529+
autoCreateSubnetworks: !ruby/object:Overrides::Terraform::PropertyOverride
530+
default_value: True
531+
# autoCreateSubnetworks defaults to true, so we need to disable it explicitly
532+
conflicts: []
533+
ipv4_range: !ruby/object:Overrides::Terraform::PropertyOverride
534+
# autoCreateSubnetworks defaults to true, so we need to disable it explicitly
535+
conflicts: []
536+
routingConfig: !ruby/object:Overrides::Terraform::PropertyOverride
537+
flatten_object: true
538+
routingConfig.routingMode: !ruby/object:Overrides::Terraform::PropertyOverride
539+
# while required inside routingConfig, routingMode is an optional convenience
540+
# field.
541+
required: false
542+
default_from_api: true
543+
custom_code: !ruby/object:Provider::Terraform::CustomCode
544+
encoder: templates/terraform/encoders/network.erb
513545
Region: !ruby/object:Overrides::Terraform::ResourceOverride
514546
exclude: true
515547
RegionAutoscaler: !ruby/object:Overrides::Terraform::ResourceOverride
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
if _, ok := d.GetOk("ipv4_range"); !ok {
2+
obj["autoCreateSubnetworks"] = d.Get("auto_create_subnetworks")
3+
}
4+
5+
return obj, nil
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
resource "google_compute_network" "<%= ctx[:primary_resource_id] %>" {
2+
name = "<%= ctx[:vars]['network_name'] %>"
3+
}

templates/terraform/expand_property_method.erb

+29-5
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ func expand<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d T
3535
}
3636
transformed["<%= prop.api_name -%>"] = transformed<%= titlelize_property(prop) -%>
3737

38-
<% end -%>
38+
<% end -%>
3939

4040
m[original["<%= property.key_name -%>"].(string)] = transformed
4141
}
4242
return m, nil
4343
}
4444

45-
<% property.nested_properties.each do |prop| -%>
46-
<% next if prop.name == property.key_name -%>
47-
<%= lines(build_expand_method(prefix + titlelize_property(property), prop), 1) -%>
48-
<% end -%>
45+
<% property.nested_properties.each do |prop| -%>
46+
<% next if prop.name == property.key_name -%>
47+
<%= lines(build_expand_method(prefix + titlelize_property(property), prop), 1) -%>
48+
<% end -%>
4949
<% elsif property.is_a?(Api::Type::KeyValuePairs) -%>
5050
func expand<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
5151
if v == nil {
@@ -57,6 +57,30 @@ func expand<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d T
5757
}
5858
return m, nil
5959
}
60+
<% elsif property.flatten_object -%>
61+
func expand<%= prefix -%><%= titlelize_property(property) -%>(d TerraformResourceData, config *Config) (interface{}, error) {
62+
transformed := make(map[string]interface{})
63+
<% property.nested_properties.each do |prop| -%>
64+
// Note that nesting flattened objects won't work because we don't handle them properly here.
65+
transformed<%= titlelize_property(prop) -%>, err := expand<%= prefix -%><%= titlelize_property(property) -%><%= titlelize_property(prop) -%>(d.Get("<%= prop.name.underscore -%>"), d, config)
66+
if err != nil {
67+
return nil, err
68+
<% unless prop.send_empty_value -%>
69+
} else if val := reflect.ValueOf(transformed<%= titlelize_property(prop) -%>); val.IsValid() && !isEmptyValue(val) {
70+
transformed["<%= prop.api_name -%>"] = transformed<%= titlelize_property(prop) -%>
71+
<% else -%>
72+
} else {
73+
transformed["<%= prop.api_name -%>"] = transformed<%= titlelize_property(prop) -%>
74+
<% end -%>
75+
}
76+
77+
return transformed, nil
78+
<% end -%>
79+
}
80+
81+
<% property.nested_properties.each do |prop| -%>
82+
<%= lines(build_expand_method(prefix + titlelize_property(property), prop), 1) -%>
83+
<% end -%>
6084
<% elsif tf_types.include?(property.class) -%>
6185
func expand<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
6286
<% if property.is_set -%>

templates/terraform/flatten_property_method.erb

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
<%= lines(compile_template(property.custom_flatten,
1717
prefix: prefix,
1818
property: property)) -%>
19+
<% elsif property.flatten_object -%>
20+
<% if property.nested_properties? -%>
21+
<% property.nested_properties.each do |prop| -%>
22+
<%= lines(build_flatten_method(prefix + titlelize_property(property), prop), 1) -%>
23+
<% end -%>
24+
<% end -%>
1925
<% else -%>
2026
<% if tf_types.include?(property.class) -%>
2127
func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData) interface{} {

templates/terraform/nested_property_documentation.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
<%
3-
if property.nested_properties?
3+
if property.nested_properties? && (property.flatten_object.nil? || !property.flatten_object)
44
-%>
55
The `<%= property.name.underscore -%>` block <%= if property.output then "contains" else "supports" end -%>:
66
<%- if property.is_a?(Api::Type::Map) %>

templates/terraform/objectlib/base.go.erb

+13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ func Get<%= resource_name -%>CaiObject(d TerraformResourceData, config *Config)
3131
func Get<%= resource_name -%>ApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
3232
obj := make(map[string]interface{})
3333
<% object.settable_properties.each do |prop| -%>
34+
<% if prop.flatten_object -%>
35+
<%= prop.api_name -%>Prop, err := expand<%= resource_name -%><%= titlelize_property(prop) -%>(d, config)
36+
if err != nil {
37+
return nil, err
38+
<% unless prop.send_empty_value -%>
39+
} else if !isEmptyValue(reflect.ValueOf(<%= prop.api_name -%>Prop)) {
40+
<% else -%>
41+
} else {
42+
<% end -%>
43+
obj["<%= prop.api_name -%>"] = <%= prop.api_name -%>Prop
44+
}
45+
<% else -%>
3446
<%= prop.api_name -%>Prop, err := expand<%= resource_name -%><%= titlelize_property(prop) -%>(d.Get("<%= prop.name.underscore -%>"), d, config)
3547
if err != nil {
3648
return nil, err
@@ -41,6 +53,7 @@ func Get<%= resource_name -%>ApiObject(d TerraformResourceData, config *Config)
4153
<% end -%>
4254
obj["<%= prop.api_name -%>"] = <%= prop.api_name -%>Prop
4355
}
56+
<% end -%>
4457
<% end -%>
4558

4659
<% if object.custom_code.encoder -%>

templates/terraform/property_documentation.erb

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
<% end -%>
99
<% else -%>
1010
<% if property.required -%>
11-
(Required)
11+
(Required<% if property.deprecated? -%>, Deprecated<% end -%>)
1212
<% elsif !property.output -%>
13-
(Optional)
13+
(Optional<% if property.deprecated? -%>, Deprecated<% end -%>)
1414
<% end -%>
1515
<% end -%>
1616
<%= indent(property.description.strip.gsub("\n\n", "\n"), 2) -%>

0 commit comments

Comments
 (0)