diff --git a/generate/gen-controls/bigquery_dataset.rb b/generate/gen-controls/bigquery_dataset.rb new file mode 100644 index 000000000..80513efb3 --- /dev/null +++ b/generate/gen-controls/bigquery_dataset.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'yaml' +require 'logger' + +title 'Test GCP google_bigquery_dataset resource.' +# rubocop:disable Metrics/BlockLength +control 'google_bigquery_dataset-1.0' do + impact 1.0 + title 'google_bigquery_dataset resource test' + + logger = Logger.new(STDOUT) + logger.level = Logger::WARN + logger.warn('Generating tests for google_bigquery_dataset') + filters = [] + ignored_fields = [] + output_folder = ENV['OUTPUT_PATH'] + + if output_folder.nil? + output_folder = File.join(File.dirname(__FILE__), '../../generated_tests') + logger.warn("Undefined output folder path at variable OUTPUT_PATH. Defaulting to #{File.expand_path(output_folder)}") + end + + Dir.mkdir(output_folder) unless File.exist?(output_folder) + template_path = File.join(File.dirname(__FILE__), '../../generated_test_template.erb') + config_folder = ENV['CNF_PATH'] + logger.warn('Undefined configuration folder path at variable CNF_PATH. Ignoring configuration files') + unless config_folder.nil? + file_name = File.join(config_folder, 'google_bigquery_dataset.yaml') + if File.file?(file_name) + config = YAML.load_file(file_name) + config_filters = config['filters'] + config_filters.each do + # This is not currently implemented + logger.warn('Filters are not currently supported, ignoring') + end + config_ignored = config['ignore_fields'] + ignored_fields += config_ignored + end + end + project_name = ENV['GCP_PROJECT_NAME'] + raise 'Undefined project name, please set the GCP_PROJECT_NAME variable' if project_name.nil? + plural_identifiers = [{ project: project_name }] + + all_identifiers = [] + i = 0 + plural_identifiers.each do |plural_identifier| + plural = google_bigquery_datasets(plural_identifier) + identifiers = plural.identifiers + + identifiers.each do |identifier| + all_identifiers.push(identifier) + resource = google_bigquery_dataset(identifier) + + unless filters.all? { |filter| filter.call(resource) } + next + end + resource.dump(output_folder, template_path, i, ignored_fields) + + output = "Writing #{File.expand_path(output_folder)}/Dataset_#{i}.rb" + describe output do + # Prints pretty message when writing controls to files + its('length') { should be >= 0 } + end + i += 1 + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/generate/gen-controls/bigquery_table.rb b/generate/gen-controls/bigquery_table.rb new file mode 100644 index 000000000..8a5d2f15f --- /dev/null +++ b/generate/gen-controls/bigquery_table.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'yaml' +require 'logger' + +title 'Test GCP google_bigquery_table resource.' +# rubocop:disable Metrics/BlockLength +control 'google_bigquery_table-1.0' do + impact 1.0 + title 'google_bigquery_table resource test' + + logger = Logger.new(STDOUT) + logger.level = Logger::WARN + logger.warn('Generating tests for google_bigquery_table') + filters = [] + ignored_fields = [] + output_folder = ENV['OUTPUT_PATH'] + + if output_folder.nil? + output_folder = File.join(File.dirname(__FILE__), '../../generated_tests') + logger.warn("Undefined output folder path at variable OUTPUT_PATH. Defaulting to #{File.expand_path(output_folder)}") + end + + Dir.mkdir(output_folder) unless File.exist?(output_folder) + template_path = File.join(File.dirname(__FILE__), '../../generated_test_template.erb') + config_folder = ENV['CNF_PATH'] + logger.warn('Undefined configuration folder path at variable CNF_PATH. Ignoring configuration files') + unless config_folder.nil? + file_name = File.join(config_folder, 'google_bigquery_table.yaml') + if File.file?(file_name) + config = YAML.load_file(file_name) + config_filters = config['filters'] + config_filters.each do + # This is not currently implemented + logger.warn('Filters are not currently supported, ignoring') + end + config_ignored = config['ignore_fields'] + ignored_fields += config_ignored + end + end + project_name = ENV['GCP_PROJECT_NAME'] + raise 'Undefined project name, please set the GCP_PROJECT_NAME variable' if project_name.nil? + plural_identifiers = [{ project: project_name }] + + next_identifiers = [] + dataset_ids = google_bigquery_datasets(project: project_name).ids + dataset_ids.each do |dataset_id| + plural_identifiers.each do |plural_identifier| + next_identifiers.push(plural_identifier.merge({ dataset: dataset_id.split(':').last })) + end + end + plural_identifiers = next_identifiers + + all_identifiers = [] + i = 0 + plural_identifiers.each do |plural_identifier| + plural = google_bigquery_tables(plural_identifier) + identifiers = plural.identifiers + + identifiers.each do |identifier| + all_identifiers.push(identifier) + resource = google_bigquery_table(identifier) + + unless filters.all? { |filter| filter.call(resource) } + next + end + resource.dump(output_folder, template_path, i, ignored_fields) + + output = "Writing #{File.expand_path(output_folder)}/Table_#{i}.rb" + describe output do + # Prints pretty message when writing controls to files + its('length') { should be >= 0 } + end + i += 1 + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/generate/gen-controls/compute_network.rb b/generate/gen-controls/compute_network.rb new file mode 100644 index 000000000..64be7a124 --- /dev/null +++ b/generate/gen-controls/compute_network.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'yaml' +require 'logger' + +title 'Test GCP google_compute_network resource.' +# rubocop:disable Metrics/BlockLength +control 'google_compute_network-1.0' do + impact 1.0 + title 'google_compute_network resource test' + + logger = Logger.new(STDOUT) + logger.level = Logger::WARN + logger.warn('Generating tests for google_compute_network') + filters = [] + ignored_fields = [] + output_folder = ENV['OUTPUT_PATH'] + + if output_folder.nil? + output_folder = File.join(File.dirname(__FILE__), '../../generated_tests') + logger.warn("Undefined output folder path at variable OUTPUT_PATH. Defaulting to #{File.expand_path(output_folder)}") + end + + Dir.mkdir(output_folder) unless File.exist?(output_folder) + template_path = File.join(File.dirname(__FILE__), '../../generated_test_template.erb') + config_folder = ENV['CNF_PATH'] + logger.warn('Undefined configuration folder path at variable CNF_PATH. Ignoring configuration files') + unless config_folder.nil? + file_name = File.join(config_folder, 'google_compute_network.yaml') + if File.file?(file_name) + config = YAML.load_file(file_name) + config_filters = config['filters'] + config_filters.each do + # This is not currently implemented + logger.warn('Filters are not currently supported, ignoring') + end + config_ignored = config['ignore_fields'] + ignored_fields += config_ignored + end + end + project_name = ENV['GCP_PROJECT_NAME'] + raise 'Undefined project name, please set the GCP_PROJECT_NAME variable' if project_name.nil? + plural_identifiers = [{ project: project_name }] + + all_identifiers = [] + i = 0 + plural_identifiers.each do |plural_identifier| + plural = google_compute_networks(plural_identifier) + identifiers = plural.identifiers + + identifiers.each do |identifier| + all_identifiers.push(identifier) + resource = google_compute_network(identifier) + + unless filters.all? { |filter| filter.call(resource) } + next + end + resource.dump(output_folder, template_path, i, ignored_fields) + + output = "Writing #{File.expand_path(output_folder)}/Network_#{i}.rb" + describe output do + # Prints pretty message when writing controls to files + its('length') { should be >= 0 } + end + i += 1 + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/generate/gen-controls/compute_subnetwork.rb b/generate/gen-controls/compute_subnetwork.rb new file mode 100644 index 000000000..729736fe0 --- /dev/null +++ b/generate/gen-controls/compute_subnetwork.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'yaml' +require 'logger' + +title 'Test GCP google_compute_subnetwork resource.' +# rubocop:disable Metrics/BlockLength +control 'google_compute_subnetwork-1.0' do + impact 1.0 + title 'google_compute_subnetwork resource test' + + logger = Logger.new(STDOUT) + logger.level = Logger::WARN + logger.warn('Generating tests for google_compute_subnetwork') + filters = [] + ignored_fields = [] + output_folder = ENV['OUTPUT_PATH'] + + if output_folder.nil? + output_folder = File.join(File.dirname(__FILE__), '../../generated_tests') + logger.warn("Undefined output folder path at variable OUTPUT_PATH. Defaulting to #{File.expand_path(output_folder)}") + end + + Dir.mkdir(output_folder) unless File.exist?(output_folder) + template_path = File.join(File.dirname(__FILE__), '../../generated_test_template.erb') + config_folder = ENV['CNF_PATH'] + logger.warn('Undefined configuration folder path at variable CNF_PATH. Ignoring configuration files') + unless config_folder.nil? + file_name = File.join(config_folder, 'google_compute_subnetwork.yaml') + if File.file?(file_name) + config = YAML.load_file(file_name) + config_filters = config['filters'] + config_filters.each do + # This is not currently implemented + logger.warn('Filters are not currently supported, ignoring') + end + config_ignored = config['ignore_fields'] + ignored_fields += config_ignored + end + end + project_name = ENV['GCP_PROJECT_NAME'] + raise 'Undefined project name, please set the GCP_PROJECT_NAME variable' if project_name.nil? + plural_identifiers = [{ project: project_name }] + + next_identifiers = [] + region_names = google_compute_regions(project: project_name).region_names + region_names.each do |region_name| + plural_identifiers.each do |plural_identifier| + next_identifiers.push(plural_identifier.merge({ region: region_name })) + end + end + plural_identifiers = next_identifiers + + all_identifiers = [] + i = 0 + plural_identifiers.each do |plural_identifier| + plural = google_compute_subnetworks(plural_identifier) + identifiers = plural.identifiers + + identifiers.each do |identifier| + all_identifiers.push(identifier) + resource = google_compute_subnetwork(identifier) + + unless filters.all? { |filter| filter.call(resource) } + next + end + resource.dump(output_folder, template_path, i, ignored_fields) + + output = "Writing #{File.expand_path(output_folder)}/Subnetwork_#{i}.rb" + describe output do + # Prints pretty message when writing controls to files + its('length') { should be >= 0 } + end + i += 1 + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/generate/libraries/google_bigquery_datasets.rb b/generate/libraries/google_bigquery_datasets.rb index b7c61c98b..67bacfe2c 100644 --- a/generate/libraries/google_bigquery_datasets.rb +++ b/generate/libraries/google_bigquery_datasets.rb @@ -94,7 +94,11 @@ def identifiers combo = item.merge(@params) item_identifiers = {} params.each do |param| - item_identifiers[param.to_sym] = combo[param.to_sym] + if param == 'name' + item_identifiers[param.to_sym] = item[:dataset_reference].dataset_id + else + item_identifiers[param.to_sym] = combo[param.to_sym] + end end result.push(item_identifiers) end diff --git a/generate/libraries/google_bigquery_tables.rb b/generate/libraries/google_bigquery_tables.rb index 19ae53787..f8d0ed05c 100644 --- a/generate/libraries/google_bigquery_tables.rb +++ b/generate/libraries/google_bigquery_tables.rb @@ -120,7 +120,11 @@ def identifiers combo = item.merge(@params) item_identifiers = {} params.each do |param| - item_identifiers[param.to_sym] = combo[param.to_sym] + if param == 'name' + item_identifiers[param.to_sym] = item[:table_reference].table_id + else + item_identifiers[param.to_sym] = combo[param.to_sym] + end end result.push(item_identifiers) end diff --git a/generate/libraries/google_compute_network.rb b/generate/libraries/google_compute_network.rb index 112f6a3a2..96214474f 100644 --- a/generate/libraries/google_compute_network.rb +++ b/generate/libraries/google_compute_network.rb @@ -1,48 +1,108 @@ -# frozen_string_literal: true +# frozen_string_literal: false +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- require 'gcp_backend' +require 'google/compute/property/network_routing_config' -module Inspec::Resources - class GoogleComputeNetwork < GcpResourceBase - name 'google_compute_network' - desc 'Verifies settings for a compute network' - - example " - describe google_compute_network(project: 'chef-inspec-gcp', name: 'gcp-inspec-network') do - it { should exist } - end - " - - def initialize(opts = {}) - # Call the parent class constructor - super(opts) - @display_name = opts[:name] - catch_gcp_errors do - @network = @gcp.gcp_compute_client.get_network(opts[:project], opts[:name]) - create_resource_methods(@network) - end - end +# A provider to manage Compute Engine resources. +class ComputeNetwork < GcpResourceBase + name 'google_compute_network' + desc 'Network' + supports platform: 'gcp' - def exists? - !@network.nil? - end + attr_reader :params + attr_reader :description + attr_reader :gateway_ipv4 + attr_reader :id + attr_reader :name + attr_reader :subnetworks + attr_reader :auto_create_subnetworks + attr_reader :creation_timestamp + attr_reader :routing_config - def legacy? - return false if @network.auto_create_subnetworks - return false if !defined?(@network.gateway_i_pv4) - return false if !defined?(@network.i_pv4_range) - return false if @network.i_pv4_range.nil? - return false if @network.gateway_i_pv4.nil? - true - end + def initialize(params) + super(params.merge({ use_http_transport: true })) + @params = params + @fetched = @connection.fetch(product_url, resource_base_url, params, 'Get') + parse unless @fetched.nil? + @params = params + end - def creation_timestamp_date - return false if !defined?(creation_timestamp) || creation_timestamp.nil? - Time.parse(creation_timestamp.to_s) - end + def parse + @description = @fetched['description'] + @gateway_ipv4 = @fetched['gatewayIPv4'] + @id = @fetched['id'] + @name = @fetched['name'] + @subnetworks = @fetched['subnetworks'] + @auto_create_subnetworks = @fetched['autoCreateSubnetworks'] + @creation_timestamp = parse_time_string(@fetched['creationTimestamp']) + @routing_config = GoogleInSpec::Compute::Property::NetworkRoutingConfig.new(@fetched['routingConfig'], to_s) + end - def to_s - "Network #{@display_name}" + # Handles parsing RFC3339 time string + def parse_time_string(time_string) + time_string ? Time.parse(time_string) : nil + end + + def exists? + !@fetched.nil? + end + + def to_s + "Network #{@params[:name]}" + end + + def un_parse + { + 'description' => ->(x, _) { x.nil? ? [] : ["its('description') { should cmp #{x.inspect} }"] }, + 'gateway_ipv4' => ->(x, _) { x.nil? ? [] : ["its('gateway_ipv4') { should cmp #{x.inspect} }"] }, + 'id' => ->(x, _) { x.nil? ? [] : ["its('id') { should cmp #{x.inspect} }"] }, + 'name' => ->(x, _) { x.nil? ? [] : ["its('name') { should cmp #{x.inspect} }"] }, + 'subnetworks' => ->(x, _) { x.nil? ? [] : x.map { |single| "its('subnetworks') { should include #{single.inspect} }" } }, + 'auto_create_subnetworks' => ->(x, _) { x.nil? ? [] : ["its('auto_create_subnetworks') { should cmp #{x.inspect} }"] }, + 'creation_timestamp' => ->(x, _) { x.nil? ? [] : ["its('creation_timestamp.to_s') { should cmp '#{x.inspect}' }"] }, + 'routing_config' => ->(x, _) { x.nil? ? [] : GoogleInSpec::Compute::Property::NetworkRoutingConfig.un_parse(x, 'routing_config') }, + } + end + + def dump(path, template_path, test_number, ignored_fields) + name = 'Network' + + arr = un_parse.map do |k, v| + next if ignored_fields.include?(k) + v.call(method(k.to_sym).call, k) + end + template_vars = { + name: name, + arr: arr, + type: 'google_compute_network', + identifiers: @params, + number: test_number, + } + File.open("#{path}/#{name}_#{test_number}.rb", 'w') do |file| + file.write(ERB.new(File.read(template_path)).result_with_hash(template_vars)) end end + + private + + def product_url + 'https://www.googleapis.com/compute/v1/' + end + + def resource_base_url + 'projects/{{project}}/global/networks/{{name}}' + end end diff --git a/generate/libraries/google_compute_networks.rb b/generate/libraries/google_compute_networks.rb index 3b074f42f..5bbdb0dc8 100644 --- a/generate/libraries/google_compute_networks.rb +++ b/generate/libraries/google_compute_networks.rb @@ -1,46 +1,113 @@ -# frozen_string_literal: true +# frozen_string_literal: false +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- require 'gcp_backend' +class ComputeNetworks < GcpResourceBase + name 'google_compute_networks' + desc 'Network plural resource' + supports platform: 'gcp' -module Inspec::Resources - class GoogleComputeNetworks < GcpResourceBase - name 'google_compute_networks' - desc 'Verifies settings for GCP compute networks in bulk' + attr_reader :table - example " - describe google_compute_networks(project: 'chef-inspec-gcp') do - it { should exist } - end - " + filter_table_config = FilterTable.create - def initialize(opts = {}) - # Call the parent class constructor - super(opts) - @project = opts[:project] - end + filter_table_config.add(:descriptions, field: :description) + filter_table_config.add(:gateway_ipv4s, field: :gateway_ipv4) + filter_table_config.add(:ids, field: :id) + filter_table_config.add(:names, field: :name) + filter_table_config.add(:subnetworks, field: :subnetworks) + filter_table_config.add(:auto_create_subnetworks, field: :auto_create_subnetworks) + filter_table_config.add(:creation_timestamps, field: :creation_timestamp) + filter_table_config.add(:routing_configs, field: :routing_config) - # FilterTable setup - filter_table_config = FilterTable.create - filter_table_config.add(:network_ids, field: :network_id) - filter_table_config.add(:network_names, field: :network_name) - filter_table_config.connect(self, :fetch_data) - - def fetch_data - network_rows = [] - next_page = nil - loop do - catch_gcp_errors do - @networks = @gcp.gcp_compute_client.list_networks(@project, page_token: next_page) - end - return [] if !@networks || !@networks.items - @networks.items.map do |network| - network_rows+=[{ network_id: network.id, - network_name: network.name }] + filter_table_config.connect(self, :table) + + def initialize(params = {}) + super(params.merge({ use_http_transport: true })) + @params = params + @table = fetch_wrapped_resource('items') + end + + def fetch_wrapped_resource(wrap_path) + # fetch_resource returns an array of responses (to handle pagination) + result = @connection.fetch_all(product_url, resource_base_url, @params, 'Get') + return if result.nil? + + # Conversion of string -> object hash to symbol -> object hash that InSpec needs + converted = [] + result.each do |response| + next if response.nil? || !response.key?(wrap_path) + response[wrap_path].each do |hash| + hash_with_symbols = {} + hash.each_key do |key| + name, value = transform(key, hash) + hash_with_symbols[name] = value end - next_page = @networks.next_page_token - break unless next_page + converted.push(hash_with_symbols) end - @table = network_rows end + + converted + end + + def transform(key, value) + return transformers[key].call(value) if transformers.key?(key) + + [key.to_sym, value] + end + + def transformers + { + 'description' => ->(obj) { return :description, obj['description'] }, + 'gatewayIPv4' => ->(obj) { return :gateway_ipv4, obj['gatewayIPv4'] }, + 'id' => ->(obj) { return :id, obj['id'] }, + 'name' => ->(obj) { return :name, obj['name'] }, + 'subnetworks' => ->(obj) { return :subnetworks, obj['subnetworks'] }, + 'autoCreateSubnetworks' => ->(obj) { return :auto_create_subnetworks, obj['autoCreateSubnetworks'] }, + 'creationTimestamp' => ->(obj) { return :creation_timestamp, parse_time_string(obj['creationTimestamp']) }, + 'routingConfig' => ->(obj) { return :routing_config, GoogleInSpec::Compute::Property::NetworkRoutingConfig.new(obj['routingConfig'], to_s) }, + } + end + + # Handles parsing RFC3339 time string + def parse_time_string(time_string) + time_string ? Time.parse(time_string) : nil + end + + def identifiers + params = %w{project name} + + result = [] + @table.each do |item| + combo = item.merge(@params) + item_identifiers = {} + params.each do |param| + item_identifiers[param.to_sym] = combo[param.to_sym] + end + result.push(item_identifiers) + end + result + end + + private + + def product_url + 'https://www.googleapis.com/compute/v1/' + end + + def resource_base_url + 'projects/{{project}}/global/networks' end end diff --git a/generate/libraries/google_compute_subnetwork.rb b/generate/libraries/google_compute_subnetwork.rb index 8819fe6ca..1cfe26cb4 100644 --- a/generate/libraries/google_compute_subnetwork.rb +++ b/generate/libraries/google_compute_subnetwork.rb @@ -1,39 +1,121 @@ -# frozen_string_literal: true +# frozen_string_literal: false +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- require 'gcp_backend' +require 'google/compute/property/subnetwork_log_config' +require 'google/compute/property/subnetwork_secondary_ip_ranges' -module Inspec::Resources - class GoogleComputeSubnetwork < GcpResourceBase - name 'google_compute_subnetwork' - desc 'Verifies settings for a compute subnetwork' - - example " - describe google_compute_subnetwork(project: 'chef-inspec-gcp', region: 'europe-west2', name: 'gcp-inspec-subnetwork') do - it { should exist } - end - " - - def initialize(opts = {}) - # Call the parent class constructor - super(opts) - @display_name = opts[:name] - catch_gcp_errors do - @subnetwork = @gcp.gcp_compute_client.get_subnetwork(opts[:project], opts[:region], opts[:name]) - create_resource_methods(@subnetwork) - end - end +# A provider to manage Compute Engine resources. +class ComputeSubnetwork < GcpResourceBase + name 'google_compute_subnetwork' + desc 'Subnetwork' + supports platform: 'gcp' - def creation_timestamp_date - return false if !defined?(creation_timestamp) || creation_timestamp.nil? - Time.parse(creation_timestamp.to_s) - end + attr_reader :params + attr_reader :creation_timestamp + attr_reader :description + attr_reader :gateway_address + attr_reader :id + attr_reader :ip_cidr_range + attr_reader :name + attr_reader :network + attr_reader :fingerprint + attr_reader :secondary_ip_ranges + attr_reader :private_ip_google_access + attr_reader :region + attr_reader :log_config - def exists? - !@subnetwork.nil? - end + def initialize(params) + super(params.merge({ use_http_transport: true })) + @params = params + @fetched = @connection.fetch(product_url, resource_base_url, params, 'Get') + parse unless @fetched.nil? + @params = params + end + + def parse + @creation_timestamp = parse_time_string(@fetched['creationTimestamp']) + @description = @fetched['description'] + @gateway_address = @fetched['gatewayAddress'] + @id = @fetched['id'] + @ip_cidr_range = @fetched['ipCidrRange'] + @name = @fetched['name'] + @network = @fetched['network'] + @fingerprint = @fetched['fingerprint'] + @secondary_ip_ranges = GoogleInSpec::Compute::Property::SubnetworkSecondaryIpRangesArray.parse(@fetched['secondaryIpRanges'], to_s) + @private_ip_google_access = @fetched['privateIpGoogleAccess'] + @region = @fetched['region'] + @log_config = GoogleInSpec::Compute::Property::SubnetworkLogConfig.new(@fetched['logConfig'], to_s) + end - def to_s - "Subnetwork #{@display_name}" + # Handles parsing RFC3339 time string + def parse_time_string(time_string) + time_string ? Time.parse(time_string) : nil + end + + def exists? + !@fetched.nil? + end + + def to_s + "Subnetwork #{@params[:name]}" + end + + def un_parse + { + 'creation_timestamp' => ->(x, _) { x.nil? ? [] : ["its('creation_timestamp.to_s') { should cmp '#{x.inspect}' }"] }, + 'description' => ->(x, _) { x.nil? ? [] : ["its('description') { should cmp #{x.inspect} }"] }, + 'gateway_address' => ->(x, _) { x.nil? ? [] : ["its('gateway_address') { should cmp #{x.inspect} }"] }, + 'id' => ->(x, _) { x.nil? ? [] : ["its('id') { should cmp #{x.inspect} }"] }, + 'ip_cidr_range' => ->(x, _) { x.nil? ? [] : ["its('ip_cidr_range') { should cmp #{x.inspect} }"] }, + 'name' => ->(x, _) { x.nil? ? [] : ["its('name') { should cmp #{x.inspect} }"] }, + 'network' => ->(x, _) { x.nil? ? [] : ["its('network') { should cmp #{x.inspect} }"] }, + 'fingerprint' => ->(x, _) { x.nil? ? [] : ["its('fingerprint') { should cmp #{x.inspect} }"] }, + 'secondary_ip_ranges' => ->(x, _) { x.nil? ? [] : x.map { |single| "its('secondary_ip_ranges') { should include '#{single.to_json}' }" } }, + 'private_ip_google_access' => ->(x, _) { x.nil? ? [] : ["its('private_ip_google_access') { should cmp #{x.inspect} }"] }, + 'region' => ->(x, _) { x.nil? ? [] : ["its('region') { should cmp #{x.inspect} }"] }, + 'log_config' => ->(x, _) { x.nil? ? [] : GoogleInSpec::Compute::Property::SubnetworkLogConfig.un_parse(x, 'log_config') }, + } + end + + def dump(path, template_path, test_number, ignored_fields) + name = 'Subnetwork' + + arr = un_parse.map do |k, v| + next if ignored_fields.include?(k) + v.call(method(k.to_sym).call, k) + end + template_vars = { + name: name, + arr: arr, + type: 'google_compute_subnetwork', + identifiers: @params, + number: test_number, + } + File.open("#{path}/#{name}_#{test_number}.rb", 'w') do |file| + file.write(ERB.new(File.read(template_path)).result_with_hash(template_vars)) end end + + private + + def product_url + 'https://www.googleapis.com/compute/v1/' + end + + def resource_base_url + 'projects/{{project}}/regions/{{region}}/subnetworks/{{name}}' + end end diff --git a/generate/libraries/google_compute_subnetworks.rb b/generate/libraries/google_compute_subnetworks.rb index c5e2af8a7..4768220c8 100644 --- a/generate/libraries/google_compute_subnetworks.rb +++ b/generate/libraries/google_compute_subnetworks.rb @@ -1,54 +1,121 @@ -# frozen_string_literal: true +# frozen_string_literal: false +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- require 'gcp_backend' +class ComputeSubnetworks < GcpResourceBase + name 'google_compute_subnetworks' + desc 'Subnetwork plural resource' + supports platform: 'gcp' -module Inspec::Resources - class GoogleComputeSubnetworks < GcpResourceBase - name 'google_compute_subnetworks' - desc 'Verifies settings for GCP compute subnetworks in bulk' + attr_reader :table - example " - describe google_compute_subnetworks(project: 'chef-inspec-gcp', region: 'europe-west2') do - it { should exist } - end - " + filter_table_config = FilterTable.create - def initialize(opts = {}) - # Call the parent class constructor - super(opts) - @project = opts[:project] - @region = opts[:region] - end + filter_table_config.add(:creation_timestamps, field: :creation_timestamp) + filter_table_config.add(:descriptions, field: :description) + filter_table_config.add(:gateway_addresses, field: :gateway_address) + filter_table_config.add(:ids, field: :id) + filter_table_config.add(:ip_cidr_ranges, field: :ip_cidr_range) + filter_table_config.add(:names, field: :name) + filter_table_config.add(:networks, field: :network) + filter_table_config.add(:fingerprints, field: :fingerprint) + filter_table_config.add(:secondary_ip_ranges, field: :secondary_ip_ranges) + filter_table_config.add(:private_ip_google_accesses, field: :private_ip_google_access) + filter_table_config.add(:regions, field: :region) + filter_table_config.add(:log_configs, field: :log_config) - # FilterTable setup - filter_table_config = FilterTable.create - filter_table_config.add(:subnetwork_ids, field: :subnetwork_id) - filter_table_config.add(:subnetwork_names, field: :subnetwork_name) - filter_table_config.add(:subnetwork_networks, field: :subnetwork_network) - filter_table_config.add(:enable_flow_logs, field: :enable_flow_log) - filter_table_config.connect(self, :fetch_data) - - def fetch_data - subnetwork_rows = [] - next_page = nil - loop do - catch_gcp_errors do - @subnetworks = @gcp.gcp_compute_client.list_subnetworks(@project, @region, page_token: next_page) - end - return [] if !@subnetworks || !@subnetworks.items - @subnetworks.items.map do |subnetwork| - catch_gcp_errors do - @flow_logs_enabled = !@gcp.gcp_compute_client.list_subnetworks(@project, @region, filter: "enableFlowLogs=true name=\"#{subnetwork.name}\"").items.nil? - end - subnetwork_rows+=[{ subnetwork_id: subnetwork.id, - subnetwork_name: subnetwork.name, - subnetwork_network: subnetwork.network.split('/').last, - enable_flow_log: @flow_logs_enabled }] + filter_table_config.connect(self, :table) + + def initialize(params = {}) + super(params.merge({ use_http_transport: true })) + @params = params + @table = fetch_wrapped_resource('items') + end + + def fetch_wrapped_resource(wrap_path) + # fetch_resource returns an array of responses (to handle pagination) + result = @connection.fetch_all(product_url, resource_base_url, @params, 'Get') + return if result.nil? + + # Conversion of string -> object hash to symbol -> object hash that InSpec needs + converted = [] + result.each do |response| + next if response.nil? || !response.key?(wrap_path) + response[wrap_path].each do |hash| + hash_with_symbols = {} + hash.each_key do |key| + name, value = transform(key, hash) + hash_with_symbols[name] = value end - next_page = @subnetworks.next_page_token - break unless next_page + converted.push(hash_with_symbols) end - @table = subnetwork_rows end + + converted + end + + def transform(key, value) + return transformers[key].call(value) if transformers.key?(key) + + [key.to_sym, value] + end + + def transformers + { + 'creationTimestamp' => ->(obj) { return :creation_timestamp, parse_time_string(obj['creationTimestamp']) }, + 'description' => ->(obj) { return :description, obj['description'] }, + 'gatewayAddress' => ->(obj) { return :gateway_address, obj['gatewayAddress'] }, + 'id' => ->(obj) { return :id, obj['id'] }, + 'ipCidrRange' => ->(obj) { return :ip_cidr_range, obj['ipCidrRange'] }, + 'name' => ->(obj) { return :name, obj['name'] }, + 'network' => ->(obj) { return :network, obj['network'] }, + 'fingerprint' => ->(obj) { return :fingerprint, obj['fingerprint'] }, + 'secondaryIpRanges' => ->(obj) { return :secondary_ip_ranges, GoogleInSpec::Compute::Property::SubnetworkSecondaryIpRangesArray.parse(obj['secondaryIpRanges'], to_s) }, + 'privateIpGoogleAccess' => ->(obj) { return :private_ip_google_access, obj['privateIpGoogleAccess'] }, + 'region' => ->(obj) { return :region, obj['region'] }, + 'logConfig' => ->(obj) { return :log_config, GoogleInSpec::Compute::Property::SubnetworkLogConfig.new(obj['logConfig'], to_s) }, + } + end + + # Handles parsing RFC3339 time string + def parse_time_string(time_string) + time_string ? Time.parse(time_string) : nil + end + + def identifiers + params = %w{project region name} + + result = [] + @table.each do |item| + combo = item.merge(@params) + item_identifiers = {} + params.each do |param| + item_identifiers[param.to_sym] = combo[param.to_sym] + end + result.push(item_identifiers) + end + result + end + + private + + def product_url + 'https://www.googleapis.com/compute/v1/' + end + + def resource_base_url + 'projects/{{project}}/regions/{{region}}/subnetworks' end end