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

Inspec Support for cloud spanner #2479

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions api/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,20 @@ module Fields
attr_reader :input # If set to true value is used only on creation
attr_reader :url_param_only # If, true will not be send in request body
attr_reader :required

attr_reader :update_verb
attr_reader :update_url
# Some updates only allow updating certain fields at once (generally each
# top-level field can be updated one-at-a-time). If this is set, we group
# fields to update by (verb, url, fingerprint, id) instead of just
# (verb, url, fingerprint), to allow multiple fields to reuse the same
# endpoints.
attr_reader :update_id
# THe fingerprint value required to update this field. Downstreams should
# GET the resource and parse the fingerprint value while doing each update
# call. This ensures we can supply the fingerprint to each distinct
# request.
attr_reader :fingerprint_name
# If true, we will include the empty value in requests made including
# this attribute (both creates and updates). This rarely needs to be
# set to true, and corresponds to both the "NullFields" and
Expand Down Expand Up @@ -91,6 +103,8 @@ def validate
default: @__resource&.update_verb

check :update_url, type: ::String
check :update_id, type: ::String
check :fingerprint_name, type: ::String
check :pattern, type: ::String

check_default_value_property
Expand Down
2 changes: 1 addition & 1 deletion build/ansible
2 changes: 1 addition & 1 deletion build/terraform
2 changes: 1 addition & 1 deletion build/terraform-beta
2 changes: 1 addition & 1 deletion build/terraform-mapper
5 changes: 5 additions & 0 deletions products/compute/ansible.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ overrides: !ruby/object:Overrides::ResourceOverrides
* https://www.googleapis.com/compute/v1/projects/project/global/gateways/default-internet-gateway
* projects/project/global/gateways/default-internet-gateway
* global/gateways/default-internet-gateway
Subnetwork: !ruby/object:Overrides::Ansible::ResourceOverride
properties:
fingerprint: !ruby/object:Overrides::Ansible::PropertyOverride
update_verb: :PATCH
update_url: projects/{{project}}/regions/{{region}}/subnetworks/{{name}}
TargetPool: !ruby/object:Overrides::Ansible::ResourceOverride
transport: !ruby/object:Overrides::Ansible::Transport
encoder: encode_request
Expand Down
12 changes: 12 additions & 0 deletions products/compute/ansible_version_added.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,12 @@
:version_added: '2.6'
:type:
:version_added: '2.6'
:setPublicPtr:
:version_added: '2.10'
:publicPtrDomainName:
:version_added: '2.10'
:networkTier:
:version_added: '2.10'
:aliasIpRanges:
:version_added: '2.6'
:ipCidrRange:
Expand Down Expand Up @@ -767,6 +773,12 @@
:version_added: '2.6'
:type:
:version_added: '2.6'
:setPublicPtr:
:version_added: '2.10'
:publicPtrDomainName:
:version_added: '2.10'
:networkTier:
:version_added: '2.10'
:aliasIpRanges:
:version_added: '2.6'
:ipCidrRange:
Expand Down
59 changes: 57 additions & 2 deletions products/compute/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3836,6 +3836,31 @@ objects:
values:
- :ONE_TO_ONE_NAT
required: true
- !ruby/object:Api::Type::Boolean
name: 'setPublicPtr'
description: |
Specifies whether a public DNS PTR record should be
created to map the external IP address of the instance
to a DNS domain name.
- !ruby/object:Api::Type::String
name: 'publicPtrDomainName'
description: |
The DNS domain name for the public PTR record. You can
set this field only if the setPublicPtr field is
enabled.
- !ruby/object:Api::Type::Enum
name: 'networkTier'
description: |
This signifies the networking tier used for configuring
this access configuration. If an AccessConfig is
specified without a valid external IP address, an
ephemeral IP will be created with this networkTier. If an
AccessConfig with a valid external IP address is
specified, it must match that of the networkTier
associated with the Address resource owning that IP.
values:
- :PREMIUM
- :STANDARD
- !ruby/object:Api::Type::Array
name: 'aliasIpRanges'
description: |
Expand Down Expand Up @@ -4634,6 +4659,31 @@ objects:
values:
- :ONE_TO_ONE_NAT
required: true
- !ruby/object:Api::Type::Boolean
name: 'setPublicPtr'
description: |
Specifies whether a public DNS PTR record should be
created to map the external IP address of the instance
to a DNS domain name.
- !ruby/object:Api::Type::String
name: 'publicPtrDomainName'
description: |
The DNS domain name for the public PTR record. You can
set this field only if the setPublicPtr field is
enabled.
- !ruby/object:Api::Type::Enum
name: 'networkTier'
description: |
This signifies the networking tier used for configuring
this access configuration. If an AccessConfig is
specified without a valid external IP address, an
ephemeral IP will be created with this networkTier. If an
AccessConfig with a valid external IP address is
specified, it must match that of the networkTier
associated with the Address resource owning that IP.
values:
- :PREMIUM
- :STANDARD
- !ruby/object:Api::Type::Array
name: 'aliasIpRanges'
description: |
Expand Down Expand Up @@ -8672,14 +8722,15 @@ objects:
Whether to enable flow logging for this subnetwork.
update_verb: :PATCH
update_url: projects/{{project}}/regions/{{region}}/subnetworks/{{name}}
update_id: 'enableFlowLogs'
fingerprint_name: 'fingerprint'
send_empty_value: true
# TODO(rileykarson): Work with rambleraptor to remove this field from downstreams.
- !ruby/object:Api::Type::Fingerprint
name: 'fingerprint'
description: |
Fingerprint of this resource. This field is used internally during
updates of this resource.
update_verb: :PATCH
update_url: projects/{{project}}/regions/{{region}}/subnetworks/{{name}}
- !ruby/object:Api::Type::Enum
name: 'purpose'
min_version: beta
Expand All @@ -8700,6 +8751,8 @@ objects:
min_version: beta
update_verb: :PATCH
update_url: projects/{{project}}/regions/{{region}}/subnetworks/{{name}}
update_id: 'role'
fingerprint_name: 'fingerprint'
values:
- :ACTIVE
- :BACKUP
Expand All @@ -8718,6 +8771,8 @@ objects:
to either primary or secondary ranges.
update_verb: :PATCH
update_url: projects/{{project}}/regions/{{region}}/subnetworks/{{name}}
update_id: 'secondaryIpRanges'
fingerprint_name: 'fingerprint'
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ __metaclass__ = type
-%>

<%
update_props = properties_by_custom_update(object.all_user_properties)
update_props = properties_by_custom_update(object.all_user_properties, :old)
import = 'from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest'
import += ', remove_nones_from_dict' unless properties_with_classes(object.all_user_properties).empty?
import += ', replace_resource_dict' if nonreadonly_rrefs(object)
Expand Down
28 changes: 28 additions & 0 deletions products/spanner/inspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

--- !ruby/object:Provider::Inspec::Config
overrides: !ruby/object:Overrides::ResourceOverrides
InstanceConfig: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: true
Instance: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: false
properties:
state: !ruby/object:Overrides::Inspec::PropertyOverride
exclude: true
Database: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: false
properties:
state: !ruby/object:Overrides::Inspec::PropertyOverride
exclude: true

2 changes: 1 addition & 1 deletion products/storage/helpers/ansible/object_template.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ __metaclass__ = type
-%>

<%
update_props = properties_by_custom_update(object.all_user_properties)
update_props = properties_by_custom_update(object.all_user_properties, :old)
import = 'from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest'
import += ', remove_nones_from_dict' unless properties_with_classes(object.all_user_properties).empty?
import += ', replace_resource_dict' if nonreadonly_rrefs(object)
Expand Down
9 changes: 0 additions & 9 deletions provider/ansible.rb
Original file line number Diff line number Diff line change
Expand Up @@ -290,15 +290,6 @@ def compile_datasource(data)
File.join(target_folder,
"plugins/modules/#{name}_info.py"),
self)

# Generate symlink for old `facts` modules.
return if version_added(data.object, :facts) >= '2.9'

deprecated_facts_path = File.join(target_folder,
"plugins/modules/_#{name}_facts.py")
return if File.exist?(deprecated_facts_path)

File.symlink "#{name}_info.py", deprecated_facts_path
end

def generate_objects(output_folder, types)
Expand Down
25 changes: 20 additions & 5 deletions provider/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,22 +282,37 @@ def build_env

# Filter the properties to keep only the ones requiring custom update
# method and group them by update url & verb.
def properties_by_custom_update(properties)
def properties_by_custom_update(properties, behavior = :new)
update_props = properties.reject do |p|
p.update_url.nil? || p.update_verb.nil? || p.update_verb == :NOOP
end
update_props.group_by do |p|
{ update_url: p.update_url, update_verb: p.update_verb }

# TODO(rambleraptor): Add support to Ansible for one-at-a-time updates.
if behavior == :old
update_props.group_by do |p|
{ update_url: p.update_url, update_verb: p.update_verb }
end
else
update_props.group_by do |p|
{
update_url: p.update_url,
update_verb: p.update_verb,
update_id: p.update_id,
fingerprint_name: p.fingerprint_name
}
end
end
end

# Takes a update_url and returns the list of custom updatable properties
# that can be updated at that URL. This allows flattened objects
# to determine which parent property in the API should be updated with
# the contents of the flattened object
def custom_update_properties_by_url(properties, update_url)
def custom_update_properties_by_key(properties, key)
properties_by_custom_update(properties).select do |k, _|
k[:update_url] == update_url
k[:update_url] == key[:update_url] &&
k[:update_id] == key[:update_id] &&
k[:fingerprint_name] == key[:fingerprint_name]
end.first.last
# .first is to grab the element from the select which returns a list
# .last is because properties_by_custom_update returns a list of
Expand Down
21 changes: 18 additions & 3 deletions spec/provider_terraform_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,25 @@ class << self

it do
is_expected.to eq(
{ update_url: 'url1', update_verb: :POST } =>
{
update_url: 'url1',
update_verb: :POST,
update_id: nil,
fingerprint_name: nil
} =>
[postUrl1, otherPostUrl1],
{ update_url: 'url2', update_verb: :POST } => [postUrl2],
{ update_url: 'url2', update_verb: :PUT } => [putUrl2]
{
update_url: 'url2',
update_verb: :POST,
update_id: nil,
fingerprint_name: nil
} => [postUrl2],
{
update_url: 'url2',
update_verb: :PUT,
update_id: nil,
fingerprint_name: nil
} => [putUrl2]
)
end
end
Expand Down
9 changes: 1 addition & 8 deletions templates/ansible/facts.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ DOCUMENTATION = '''
---
<%= ansible_style_yaml({
'module' => "#{module_name(object)}_info",
'description' => ["Gather info for GCP #{object.name}",
(version_added(object, :facts) < '2.9' ? "This module was called C(#{module_name(object)}_facts) before Ansible 2.9. The usage has not changed." : nil)
].compact,
'description' => ["Gather info for GCP #{object.name}"],
'short_description' => "Gather info for GCP #{object.name}",
'version_added' => version_added(object, :facts),
'author' => "Google Inc. (@googlecloudplatform)",
Expand Down Expand Up @@ -91,11 +89,6 @@ def main():
})), 12)
-%>
)
<% if version_added(object, :facts) < '2.9' -%>

if module._name == '<%= module_name(object) -%>_facts':
module.deprecate("The '<%= module_name(object) -%>_facts' module has been renamed to '<%= module_name(object) -%>_info'", version='2.13')
<% end -%>

if not module.params['scopes']:
module.params['scopes'] = <%= python_literal(object.__product.scopes) %>
Expand Down
2 changes: 1 addition & 1 deletion templates/ansible/resource.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ __metaclass__ = type
.map(&:resource_ref)
.uniq

update_props = properties_by_custom_update(object.all_user_properties)
update_props = properties_by_custom_update(object.all_user_properties, :old)
-%>

<%
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<% gcp_project_id = "#{external_attribute('gcp_project_id', doc_generation)}" -%>
<% spannerdatabase = grab_attributes['spannerdatabase'] -%>

describe google_spanner_database(project: <%= gcp_project_id -%>, , instance: <%= doc_generation ? "'#{spannerdatabase['instance']}'" : "spannerdatabase['instance']" -%>, name: <%= doc_generation ? "'#{spannerdatabase['name']}'" : "spannerdatabase['name']" -%>) do
it { should exist }
its('name') { should eq <%= doc_generation ? "'#{spannerdatabase['name']}'" : "spannerdatabase['name']" -%> }
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gcp_project_id = attribute(:gcp_project_id, default: '<%= external_attribute('gcp_project_id') -%>', description: 'The GCP project identifier.')
spannerdatabase = attribute('spannerdatabase', default: <%= JSON.pretty_generate(grab_attributes['spannerdatabase']) -%>, description: 'Cloud Spanner definition')
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<% gcp_project_id = "#{external_attribute('gcp_project_id', doc_generation)}" -%>
<% spannerdatabase = grab_attributes['spannerdatabase'] -%>

describe google_spanner_databases(project: <%= gcp_project_id -%>, , instance: <%= doc_generation ? "'#{spannerdatabase['instance']}'" : "spannerdatabase['instance']" -%>) do
its('instance') { should eq <%= doc_generation ? "'#{spannerdatabase['instance']}'" : "spannerdatabase['instance']" -%> }
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% gcp_project_id = "#{external_attribute('gcp_project_id', doc_generation)}" -%>
<% spannerinstance = grab_attributes['spannerinstance'] -%>

describe google_spanner_instance(project: <%= gcp_project_id -%>, name: <%= doc_generation ? "'#{spannerinstance['name']}'" : "spannerinstance['name']" -%>, config: <%= doc_generation ? "'#{spannerinstance['config']}'" : "spannerinstance['config']" -%>) do
it { should exist }
its('config') { should eq <%= doc_generation ? "'projects/#{gcp_project_id}/instanceConfigs/#{spannerinstance['config']}'" : "projects/#{gcp_project_id}/instanceConfigs/spannerinstance['config']" -%> }
its('name') { should eq <%= doc_generation ? "'#{spannerinstance['name']}'" : "spannerinstance['name']" -%> }
its('display_name') { should eq <%= doc_generation ? "'#{spannerinstance['display_name']}'" : "spannerinstance['display_name']" -%> }
its('node_count') { should eq <%= doc_generation ? "'#{spannerinstance['node_count']}'" : "spannerinstance['node_count']" -%> }
its('labels') { should eq <%= doc_generation ? "'#{spannerinstance['labels']}'" : "spannerinstance['labels']" -%> }
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gcp_project_id = attribute(:gcp_project_id, default: '<%= external_attribute('gcp_project_id') -%>', description: 'The GCP project identifier.')
spannerinstance = attribute('spannerinstance', default: <%= JSON.pretty_generate(grab_attributes['spannerinstance']) -%>, description: 'Cloud Spanner definition')
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<% gcp_project_id = "#{external_attribute('gcp_project_id', doc_generation)}" -%>
<% spannerinstance = grab_attributes['spannerinstance'] -%>

describe google_spanner_instances(project: <%= gcp_project_id -%>, config: <%= doc_generation ? "'#{spannerinstance['config']}'" : "spannerinstance['config']" -%>) do
its('config') { should eq <%= doc_generation ? "'#{spannerinstance['config']}'" : "spannerinstance['config']" -%> }
end
Loading