Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ansible documentation refactor #580

Merged
merged 12 commits into from
Oct 23, 2018
2 changes: 1 addition & 1 deletion build/ansible
Submodule ansible updated 88 files
+141 −133 lib/ansible/modules/cloud/google/gcp_compute_address.py
+81 −81 lib/ansible/modules/cloud/google/gcp_compute_address_facts.py
+75 −73 lib/ansible/modules/cloud/google/gcp_compute_backend_bucket.py
+49 −50 lib/ansible/modules/cloud/google/gcp_compute_backend_bucket_facts.py
+493 −465 lib/ansible/modules/cloud/google/gcp_compute_backend_service.py
+274 −268 lib/ansible/modules/cloud/google/gcp_compute_backend_service_facts.py
+314 −314 lib/ansible/modules/cloud/google/gcp_compute_disk.py
+200 −200 lib/ansible/modules/cloud/google/gcp_compute_disk_facts.py
+335 −325 lib/ansible/modules/cloud/google/gcp_compute_firewall.py
+182 −178 lib/ansible/modules/cloud/google/gcp_compute_firewall_facts.py
+313 −294 lib/ansible/modules/cloud/google/gcp_compute_forwarding_rule.py
+162 −159 lib/ansible/modules/cloud/google/gcp_compute_forwarding_rule_facts.py
+95 −89 lib/ansible/modules/cloud/google/gcp_compute_global_address.py
+63 −63 lib/ansible/modules/cloud/google/gcp_compute_global_address_facts.py
+279 −264 lib/ansible/modules/cloud/google/gcp_compute_global_forwarding_rule.py
+147 −145 lib/ansible/modules/cloud/google/gcp_compute_global_forwarding_rule_facts.py
+400 −385 lib/ansible/modules/cloud/google/gcp_compute_health_check.py
+223 −221 lib/ansible/modules/cloud/google/gcp_compute_health_check_facts.py
+137 −133 lib/ansible/modules/cloud/google/gcp_compute_http_health_check.py
+83 −83 lib/ansible/modules/cloud/google/gcp_compute_http_health_check_facts.py
+134 −131 lib/ansible/modules/cloud/google/gcp_compute_https_health_check.py
+83 −83 lib/ansible/modules/cloud/google/gcp_compute_https_health_check_facts.py
+328 −323 lib/ansible/modules/cloud/google/gcp_compute_image.py
+212 −209 lib/ansible/modules/cloud/google/gcp_compute_image_facts.py
+719 −697 lib/ansible/modules/cloud/google/gcp_compute_instance.py
+414 −404 lib/ansible/modules/cloud/google/gcp_compute_instance_facts.py
+145 −143 lib/ansible/modules/cloud/google/gcp_compute_instance_group.py
+89 −90 lib/ansible/modules/cloud/google/gcp_compute_instance_group_facts.py
+214 −210 lib/ansible/modules/cloud/google/gcp_compute_instance_group_manager.py
+164 −162 lib/ansible/modules/cloud/google/gcp_compute_instance_group_manager_facts.py
+723 −691 lib/ansible/modules/cloud/google/gcp_compute_instance_template.py
+400 −382 lib/ansible/modules/cloud/google/gcp_compute_instance_template_facts.py
+120 −118 lib/ansible/modules/cloud/google/gcp_compute_interconnect_attachment.py
+93 −93 lib/ansible/modules/cloud/google/gcp_compute_interconnect_attachment_facts.py
+135 −130 lib/ansible/modules/cloud/google/gcp_compute_network.py
+82 −82 lib/ansible/modules/cloud/google/gcp_compute_network_facts.py
+249 −249 lib/ansible/modules/cloud/google/gcp_compute_region_disk.py
+161 −162 lib/ansible/modules/cloud/google/gcp_compute_region_disk_facts.py
+164 −162 lib/ansible/modules/cloud/google/gcp_compute_route.py
+86 −87 lib/ansible/modules/cloud/google/gcp_compute_route_facts.py
+157 −150 lib/ansible/modules/cloud/google/gcp_compute_router.py
+99 −98 lib/ansible/modules/cloud/google/gcp_compute_router_facts.py
+74 −72 lib/ansible/modules/cloud/google/gcp_compute_ssl_certificate.py
+50 −51 lib/ansible/modules/cloud/google/gcp_compute_ssl_certificate_facts.py
+129 −118 lib/ansible/modules/cloud/google/gcp_compute_ssl_policy.py
+88 −88 lib/ansible/modules/cloud/google/gcp_compute_ssl_policy_facts.py
+183 −181 lib/ansible/modules/cloud/google/gcp_compute_subnetwork.py
+108 −108 lib/ansible/modules/cloud/google/gcp_compute_subnetwork_facts.py
+66 −63 lib/ansible/modules/cloud/google/gcp_compute_target_http_proxy.py
+44 −44 lib/ansible/modules/cloud/google/gcp_compute_target_http_proxy_facts.py
+100 −93 lib/ansible/modules/cloud/google/gcp_compute_target_https_proxy.py
+60 −59 lib/ansible/modules/cloud/google/gcp_compute_target_https_proxy_facts.py
+176 −171 lib/ansible/modules/cloud/google/gcp_compute_target_pool.py
+101 −102 lib/ansible/modules/cloud/google/gcp_compute_target_pool_facts.py
+91 −86 lib/ansible/modules/cloud/google/gcp_compute_target_ssl_proxy.py
+56 −56 lib/ansible/modules/cloud/google/gcp_compute_target_ssl_proxy_facts.py
+79 −75 lib/ansible/modules/cloud/google/gcp_compute_target_tcp_proxy.py
+49 −50 lib/ansible/modules/cloud/google/gcp_compute_target_tcp_proxy_facts.py
+83 −81 lib/ansible/modules/cloud/google/gcp_compute_target_vpn_gateway.py
+63 −63 lib/ansible/modules/cloud/google/gcp_compute_target_vpn_gateway_facts.py
+243 −235 lib/ansible/modules/cloud/google/gcp_compute_url_map.py
+142 −140 lib/ansible/modules/cloud/google/gcp_compute_url_map_facts.py
+163 −161 lib/ansible/modules/cloud/google/gcp_compute_vpn_tunnel.py
+101 −101 lib/ansible/modules/cloud/google/gcp_compute_vpn_tunnel_facts.py
+495 −478 lib/ansible/modules/cloud/google/gcp_container_cluster.py
+304 −299 lib/ansible/modules/cloud/google/gcp_container_cluster_facts.py
+344 −337 lib/ansible/modules/cloud/google/gcp_container_node_pool.py
+202 −200 lib/ansible/modules/cloud/google/gcp_container_node_pool_facts.py
+72 −70 lib/ansible/modules/cloud/google/gcp_dns_managed_zone.py
+52 −52 lib/ansible/modules/cloud/google/gcp_dns_managed_zone_facts.py
+80 −66 lib/ansible/modules/cloud/google/gcp_dns_resource_record_set.py
+44 −44 lib/ansible/modules/cloud/google/gcp_dns_resource_record_set_facts.py
+94 −92 lib/ansible/modules/cloud/google/gcp_pubsub_subscription.py
+52 −50 lib/ansible/modules/cloud/google/gcp_pubsub_subscription_facts.py
+20 −18 lib/ansible/modules/cloud/google/gcp_pubsub_topic.py
+14 −13 lib/ansible/modules/cloud/google/gcp_pubsub_topic_facts.py
+53 −49 lib/ansible/modules/cloud/google/gcp_spanner_database.py
+37 −36 lib/ansible/modules/cloud/google/gcp_spanner_database_facts.py
+96 −94 lib/ansible/modules/cloud/google/gcp_spanner_instance.py
+55 −53 lib/ansible/modules/cloud/google/gcp_spanner_instance_facts.py
+54 −52 lib/ansible/modules/cloud/google/gcp_sql_database.py
+38 −38 lib/ansible/modules/cloud/google/gcp_sql_database_facts.py
+464 −447 lib/ansible/modules/cloud/google/gcp_sql_instance.py
+271 −264 lib/ansible/modules/cloud/google/gcp_sql_instance_facts.py
+56 −54 lib/ansible/modules/cloud/google/gcp_sql_user.py
+39 −39 lib/ansible/modules/cloud/google/gcp_sql_user_facts.py
+682 −644 lib/ansible/modules/cloud/google/gcp_storage_bucket.py
+119 −113 lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py
2 changes: 1 addition & 1 deletion build/inspec
2 changes: 1 addition & 1 deletion build/terraform
2 changes: 1 addition & 1 deletion build/terraform-beta
9 changes: 9 additions & 0 deletions products/compute/ansible.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ overrides: !ruby/object:Provider::ResourceOverrides
Disk: !ruby/object:Provider::Ansible::ResourceOverride
editable: false
properties:
sourceSnapshot: !ruby/object:Provider::Ansible::PropertyOverride
description: |
The source snapshot used to create this disk. You can provide this as
a partial or full URL to the resource.
labels: !ruby/object:Provider::Ansible::PropertyOverride
version_added: '2.7'
type: !ruby/object:Provider::Ansible::PropertyOverride
Expand Down Expand Up @@ -276,6 +280,11 @@ overrides: !ruby/object:Provider::ResourceOverrides
version_added: '2.8'
RegionDisk: !ruby/object:Provider::Ansible::ResourceOverride
version_added: '2.8'
properties:
sourceSnapshot: !ruby/object:Provider::Ansible::PropertyOverride
description: |
The source snapshot used to create this disk. You can provide this as
a partial or full URL to the resource.
Route: !ruby/object:Provider::Ansible::ResourceOverride
properties:
description: !ruby/object:Provider::Ansible::PropertyOverride
Expand Down
236 changes: 75 additions & 161 deletions provider/ansible/documentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,189 +11,82 @@
# See the License for the specific language governing permissions and
# limitations under the License.

require 'api/object'
require 'compile/core'
require 'provider/config'
require 'provider/core'
require 'provider/ansible/manifest'

# Rubocop doesn't like this file because the hashes are complicated.
# Humans like this file because the hashes are explicit and easy to read.
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
module Provider
module Ansible
# Responsible for building out YAML documentation blocks.
# rubocop:disable Metrics/ModuleLength
module Documentation
# Takes a long string and divides each string into multiple paragraphs,
# where each paragraph is a properly indented multi-line bullet point.
#
# Example:
# - This is a paragraph
# that wraps under
# the bullet properly
# - This is the second
# paragraph.
def bullet_lines(line, spaces)
line.split(".\n").map { |paragraph| bullet_line(paragraph, spaces) }
end

# Takes in a string (representing a paragraph) and returns a multi-line
# string, where each line is less than max_length characters long and all
# subsequent lines are indented in by spaces characters
#
# Example:
# - This is a sentence
# that wraps under
# the bullet properly
#
# - |
# This is a sentence
# that wraps under
# the bullet properly
# because of the :
# character
# rubocop:disable Metrics/AbcSize
def bullet_line(paragraph, spaces, _multiline = true, add_period = true)
paragraph += '.' unless paragraph.end_with?('.') || !add_period
paragraph = format_url(paragraph)
paragraph = paragraph.tr("\n", ' ').strip

# Paragraph placed inside array to get bullet point.
yaml = [paragraph].to_yaml
# YAML documentation header is not necessary.
yaml = yaml.gsub("---\n", '') if yaml.include?("---\n")

# YAML dumper isn't very smart about line lengths.
# If any line is over 160 characters (with indents), build the YAML
# block using wrap_field.
# Using YAML.dump output ensures that all character escaping done
if yaml.split("\n").any? { |line| line.length > (160 - spaces) }
return wrap_field(
yaml.tr("\n", ' ').gsub(/\s+/, ' '),
spaces + 3
).each_with_index.map { |x, i| i.zero? ? x : indent(x, 2) }
end
yaml
end
# rubocop:enable Metrics/AbcSize

# Builds out a full YAML block for DOCUMENTATION
# This includes the YAML for the property as well as any nested props
def doc_property_yaml(prop, object, spaces)
block = minimal_doc_block(prop, object, spaces)
# Ansible linter does not support nesting options this deep.
if prop.is_a?(Api::Type::NestedObject)
block.concat(nested_doc(prop.properties, object, spaces))
elsif prop.is_a?(Api::Type::Array) &&
prop.item_type.is_a?(Api::Type::NestedObject)
block.concat(nested_doc(prop.item_type.properties, object, spaces))
else
block
end
end

# Builds out a full YAML block for RETURNS
# This includes the YAML for the property as well as any nested props
def return_property_yaml(prop, spaces)
block = minimal_return_block(prop, spaces)
if prop.is_a? Api::Type::NestedObject
block.concat(nested_return(prop.properties, spaces))
elsif prop.is_a?(Api::Type::Array) &&
prop.item_type.is_a?(Api::Type::NestedObject)
block.concat(nested_return(prop.item_type.properties, spaces))
def to_yaml(obj)
if obj.is_a?(::Hash)
obj.reject { |_, v| v.nil? }.to_yaml.sub("---\n", '')
else
block
obj.to_yaml.sub("---\n", '')
end
end

private

# Find URLs and surround with U()
def format_url(paragraph)
paragraph.gsub(%r{
https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]
[a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+
[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))
[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,}
}x, 'U(\\0)')
end

# Returns formatted nested documentation for a set of properties.
def nested_return(properties, spaces)
block = [indent('contains:', 4)]
block.concat(
properties.map do |p|
indent(return_property_yaml(p, spaces + 4), 8)
end
)
end

def nested_doc(properties, object, spaces)
block = [indent('suboptions:', 4)]
block.concat(
properties.map do |p|
indent(doc_property_yaml(p, object, spaces + 4), 8)
end
)
end

# Builds out the minimal YAML block for DOCUMENTATION
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/AbcSize
def minimal_doc_block(prop, _object, spaces)
required = prop.required && !prop.default_value ? 'true' : 'false'
[
"#{prop.name.underscore}:",
indent(
[
'description:',
# + 8 to compensate for name + description.
indent(bullet_lines(prop.description, spaces + 8), 4),
(indent(bullet_lines(resourceref_description(prop), spaces + 8), 4) \
# Builds out the DOCUMENTATION for a property.
# This will eventually be converted to YAML
def documentation_for_property(prop)
required = prop.required && !prop.default_value ? true : false
{
prop.name.underscore => {
'description' => [
format_description(prop.description),
(resourceref_description(prop) \
if prop.is_a?(Api::Type::ResourceRef) && !prop.resource_ref.readonly)
].compact, 4
),
indent([
"required: #{required}",
("default: #{prop.default_value}" if prop.default_value),
('type: bool' if prop.is_a? Api::Type::Boolean),
("aliases: [#{prop.aliases.join(', ')}]" if prop.aliases),
("version_added: #{prop.version_added}" if prop.version_added),
(if prop.is_a? Api::Type::Enum
[
'choices:',
"[#{prop.values.map { |x| quote_string(x.to_s) }.join(', ')}]"
].join(' ')
end)
].compact, 4)
]
].flatten.compact,
'required' => required,
'default' => (prop.default_value.to_s if prop.default_value),
'type' => ('bool' if prop.is_a? Api::Type::Boolean),
'aliases' => (prop.aliases if prop.aliases),
'version_added' => (prop.version_added.to_f if prop.version_added),
'choices' => (prop.values.map(&:to_s) if prop.is_a? Api::Type::Enum),
'suboptions' => (
if prop.is_a?(Api::Type::NestedObject)
prop.properties.map { |p| documentation_for_property(p) }.reduce({}, :merge)
elsif prop.is_a?(Api::Type::Array) && prop.item_type.is_a?(Api::Type::NestedObject)
prop.item_type.properties
.map { |p| documentation_for_property(p) }
.reduce({}, :merge)
end
)
}.reject { |_, v| v.nil? }
}
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/PerceivedComplexity

# Builds out the minimal YAML block for RETURNS
def minimal_return_block(prop, spaces)
# Builds out the RETURNS for a property.
# This will eventually be converted to YAML
def returns_for_property(prop)
type = python_type(prop)
# Complex types only mentioned in reference to RETURNS YAML block
# Complex types are nested objects traditionally, but arrays of nested
# objects will be included to avoid linting errors.
type = 'complex' if prop.is_a?(Api::Type::NestedObject) \
|| (prop.is_a?(Api::Type::Array) \
&& prop.item_type.is_a?(Api::Type::NestedObject))
[
"#{prop.name}:",
indent(
[
'description:',
# + 8 to compensate for name + description.
indent(bullet_lines(prop.description, spaces + 8), 4)
], 4
),
indent([
'returned: success',
"type: #{type}"
], 4)
]
{
prop.name => {
'description' => format_description(prop.description),
'returned' => 'success',
'type' => type,
'contains' => (
if prop.is_a?(Api::Type::NestedObject)
prop.properties.map { |p| returns_for_property(p) }.reduce({}, :merge)
elsif prop.is_a?(Api::Type::Array) && prop.item_type.is_a?(Api::Type::NestedObject)
prop.item_type.properties.map { |p| returns_for_property(p) }.reduce({}, :merge)
end
)
}.reject { |_, v| v.nil? }
}
end

def autogen_notice_contrib
Expand All @@ -212,7 +105,28 @@ def resourceref_description(prop)
"where the value is the #{prop.imports} of your #{prop.resource_ref.name}"
].join(' ')
end

# MM puts descriptions in a text block. Ansible needs it in bullets
def format_description(desc)
desc.split(".\n").map do |paragraph|
paragraph += '.' unless paragraph.end_with?('.')
paragraph = format_url(paragraph)
paragraph.tr("\n", ' ').strip.squeeze(' ')
end
end

# Find URLs and surround with U()
def format_url(paragraph)
paragraph.gsub(%r{
https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]
[a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+
[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))
[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,}
}x, 'U(\\0)')
end
end
# rubocop:enable Metrics/ModuleLength
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
18 changes: 13 additions & 5 deletions provider/terraform/resources/resource_compute_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func resourceComputeNetwork() *schema.Resource {
Optional: true,
ForceNew: true,
// This needs to remain deprecated until the API is retired
Removed: "Please use google_compute_subnetwork resources instead.",
Deprecated: "Please use google_compute_subnetwork resources instead.",
},

"project": &schema.Schema{
Expand Down Expand Up @@ -89,6 +89,9 @@ func resourceComputeNetworkCreate(d *schema.ResourceData, meta interface{}) erro
// - 2.b - Custom subnet mode - auto_create_subnetworks = false & ipv4_range not set,
//
autoCreateSubnetworks := d.Get("auto_create_subnetworks").(bool)
if autoCreateSubnetworks && d.Get("ipv4_range").(string) != "" {
return fmt.Errorf("ipv4_range can't be set if auto_create_subnetworks is true.")
}

// Build the network parameter
network := &compute.Network{
Expand All @@ -104,10 +107,14 @@ func resourceComputeNetworkCreate(d *schema.ResourceData, meta interface{}) erro
network.RoutingConfig = routingConfig
}

// make sure AutoCreateSubnetworks field is included in request otherwise
// google will create a network in legacy mode.
network.ForceSendFields = []string{"AutoCreateSubnetworks"}

if v, ok := d.GetOk("ipv4_range"); ok {
log.Printf("[DEBUG] Setting IPv4Range (%#v) for legacy network mode", v.(string))
network.IPv4Range = v.(string)
} else {
// custom subnet mode, so make sure AutoCreateSubnetworks field is included in request otherwise
// google will create a network in legacy mode.
network.ForceSendFields = []string{"AutoCreateSubnetworks"}
}
log.Printf("[DEBUG] Network insert request: %#v", network)
op, err := config.clientCompute.Networks.Insert(
project, network).Do()
Expand Down Expand Up @@ -144,6 +151,7 @@ func resourceComputeNetworkRead(d *schema.ResourceData, meta interface{}) error

d.Set("routing_mode", routingConfig.RoutingMode)
d.Set("gateway_ipv4", network.GatewayIPv4)
d.Set("ipv4_range", network.IPv4Range)
d.Set("self_link", network.SelfLink)
d.Set("name", network.Name)
d.Set("description", network.Description)
Expand Down
Loading