diff --git a/README.md b/README.md index bcd679c8..59a0bab6 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,7 @@ The following resources are available in the InSpec GCP Profile | [google_logging_project_sink](docs/resources/google_logging_project_sink.md) | [google_logging_project_sinks](docs/resources/google_logging_project_sinks.md) | | [google_memcache_instance](docs/resources/google_memcache_instance.md) | [google_memcache_instances](docs/resources/google_memcache_instances.md) | | [google_ml_engine_model](docs/resources/google_ml_engine_model.md) | [google_ml_engine_models](docs/resources/google_ml_engine_models.md) | +| [google_monitoring_group](docs/resources/google_monitoring_group.md) | [google_monitoring_groups](docs/resources/google_monitoring_groups.md) | | [google_organization](docs/resources/google_organization.md) | [google_organizations](docs/resources/google_organizations.md) | | No Singular Resource | [google_orgpolicy_folder_constraints](docs/resources/google_orgpolicy_folder_constraints.md) | | No Singular Resource | [google_orgpolicy_organization_constraints](docs/resources/google_orgpolicy_project_constraints.md) | diff --git a/docs/resources/google_monitoring_group.md b/docs/resources/google_monitoring_group.md new file mode 100644 index 00000000..199edf51 --- /dev/null +++ b/docs/resources/google_monitoring_group.md @@ -0,0 +1,58 @@ ++++ + +title = "google_monitoring_group Resource" +platform = "gcp" +draft = false +gh_repo = "inspec-gcp" + + +[menu.inspec] + +title = "google_monitoring_group" +identifier = "inspec/resources/gcp/google_monitoring_group Resource" +parent = "inspec/resources/gcp" ++++ + +Use the `google_monitoring_group` InSpec audit resource to test the properties of a test a Google Group. + +## Installation +{{% inspec_gcp_install %}} + +## Syntax +A `google_monitoring_group` is used to test a Google Group resource + +## Examples +``` +describe google_monitoring_group(name: 'projects/*/groups/value_group_id') do + it { should exist } + its('name') { should cmp 'value_name' } + its('display_name') { should cmp 'value_displayname' } + its('filter') { should cmp 'value_filter' } +end + +describe google_monitoring_group(name: "does_not_exit") do + it { should_not exist } +end +``` + +## Parameters +Properties that can be accessed from the `google_monitoring_group` resource: + +## Properties +Properties that can be accessed from the `google_monitoring_group` resource: + + + * `name`: Output only. The name of this group. The format is: projects/[PROJECT_ID_OR_NUMBER]/groups/[GROUP_ID] When creating a group, this field is ignored and a new name is created consisting of the project specified in the call to CreateGroup and a unique [GROUP_ID] that is generated automatically. + + * `display_name`: A user-assigned name for this group, used only for display purposes. + + * `parent_name`: The name of the group's parent, if it has one. The format is: projects/[PROJECT_ID_OR_NUMBER]/groups/[GROUP_ID] For groups with no parent, parent_name is the empty string, "". + + * `filter`: The filter used to determine which monitored resources belong to this group. + + * `is_cluster`: If true, the members of this group are considered to be a cluster. The system can perform additional analysis on groups that are clusters. + + +## GCP Permissions + +Ensure the [Stackdriver Monitoring API](https://console.cloud.google.com/apis/library/monitoring.googleapis.com/) is enabled for the current project. diff --git a/docs/resources/google_monitoring_groups.md b/docs/resources/google_monitoring_groups.md new file mode 100644 index 00000000..2b1e20b5 --- /dev/null +++ b/docs/resources/google_monitoring_groups.md @@ -0,0 +1,59 @@ ++++ + +title = "google_monitoring_groups Resource" +platform = "gcp" +draft = false +gh_repo = "inspec-gcp" + + +[menu.inspec] + +title = "google_monitoring_groups" +identifier = "inspec/resources/gcp/google_monitoring_groups Resource" +parent = "inspec/resources/gcp" ++++ + +Use the `google_monitoring_groups` InSpec audit resource to test the properties of a test a Google Group. + +## Installation +{{% inspec_gcp_install %}} + +## Syntax +A `google_monitoring_groups` is used to test a Google Group resource + +## Examples +``` + describe google_monitoring_groups(name: 'projects/*') do + it { should exist } + its('names') { should include 'value_name' } + its('display_names') { should include 'value_displayname' } + its('filters') { should include 'value_filter' } + end +``` + +## Parameters +Properties that can be accessed from the `google_monitoring_groups` resource: + +See [google_monitoring_group.md](google_monitoring_group.md) for more detailed information +* `names`: an array of `google_monitoring_group` name +* `display_names`: an array of `google_monitoring_group` display_name +* `parent_names`: an array of `google_monitoring_group` parent_name +* `filters`: an array of `google_monitoring_group` filter +* `is_clusters`: an array of `google_monitoring_group` is_cluster +## Properties +Properties that can be accessed from the `google_monitoring_groups` resource: + +See [google_monitoring_group.md](google_monitoring_group.md) for more detailed information +* `names`: an array of `google_monitoring_group` name +* `display_names`: an array of `google_monitoring_group` display_name +* `parent_names`: an array of `google_monitoring_group` parent_name +* `filters`: an array of `google_monitoring_group` filter +* `is_clusters`: an array of `google_monitoring_group` is_cluster + +## Filter Criteria +This resource supports all of the above properties as filter criteria, which can be used +with `where` as a block or a method. + +## GCP Permissions + +Ensure the [Stackdriver Monitoring API](https://console.cloud.google.com/apis/library/monitoring.googleapis.com/) is enabled for the current project. diff --git a/libraries/google_monitoring_group.rb b/libraries/google_monitoring_group.rb new file mode 100644 index 00000000..42893fe5 --- /dev/null +++ b/libraries/google_monitoring_group.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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' + +# A provider to manage Cloud (Stackdriver) Monitoring resources. +class MonitoringGroup < GcpResourceBase + name 'google_monitoring_group' + desc 'Group' + supports platform: 'gcp' + + attr_reader :params + attr_reader :name + attr_reader :display_name + attr_reader :parent_name + attr_reader :filter + attr_reader :is_cluster + + def initialize(params) + super(params.merge({ use_http_transport: true })) + @params = params + @fetched = @connection.fetch(product_url(params[:beta]), resource_base_url, params, 'Get') + parse unless @fetched.nil? + end + + def parse + @name = @fetched['name'] + @display_name = @fetched['displayName'] + @parent_name = @fetched['parentName'] + @filter = @fetched['filter'] + @is_cluster = @fetched['isCluster'] + end + + def exists? + !@fetched.nil? + end + + def to_s + "Group #{@params[:name]}" + end + + private + + def product_url(_ = nil) + 'https://monitoring.googleapis.com/v3/' + end + + def resource_base_url + '{{name}}' + end +end diff --git a/libraries/google_monitoring_groups.rb b/libraries/google_monitoring_groups.rb new file mode 100644 index 00000000..044c06f5 --- /dev/null +++ b/libraries/google_monitoring_groups.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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 MonitoringGroups < GcpResourceBase + name 'google_monitoring_groups' + desc 'Group plural resource' + supports platform: 'gcp' + + attr_reader :table + + filter_table_config = FilterTable.create + + filter_table_config.add(:names, field: :name) + filter_table_config.add(:display_names, field: :display_name) + filter_table_config.add(:parent_names, field: :parent_name) + filter_table_config.add(:filters, field: :filter) + filter_table_config.add(:is_clusters, field: :is_cluster) + + filter_table_config.connect(self, :table) + + def initialize(params = {}) + super(params.merge({ use_http_transport: true })) + @params = params + @table = fetch_wrapped_resource('group') + 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 + converted.push(hash_with_symbols) + end + end + + converted + end + + def transform(key, value) + return transformers[key].call(value) if transformers.key?(key) + + [key.to_sym, value] + end + + def transformers + { + 'name' => ->(obj) { [:name, obj['name']] }, + 'displayName' => ->(obj) { [:display_name, obj['displayName']] }, + 'parentName' => ->(obj) { [:parent_name, obj['parentName']] }, + 'filter' => ->(obj) { [:filter, obj['filter']] }, + 'isCluster' => ->(obj) { [:is_cluster, obj['isCluster']] }, + } + end + + private + + def product_url(_ = nil) + 'https://monitoring.googleapis.com/v3/' + end + + def resource_base_url + '{{name}}/groups' + end +end diff --git a/test/integration/build/gcp-mm.tf b/test/integration/build/gcp-mm.tf index 978e3965..c91986be 100644 --- a/test/integration/build/gcp-mm.tf +++ b/test/integration/build/gcp-mm.tf @@ -272,6 +272,9 @@ variable "cloud_run_jobs" { variable "dataproc_serverless_batches" { type = any } +variable "monitoring_group" { + type = any +} resource "google_compute_ssl_policy" "custom-ssl-policy" { name = var.ssl_policy["name"] min_tls_version = var.ssl_policy["min_tls_version"] @@ -2272,3 +2275,8 @@ resource "google_dataproc_batch" "inspec_batch_spark" { jar_file_uris = [var.dataproc_serverless_batches.path] } } +resource "google_monitoring_group" "inspec-test-group" { + project = var.gcp_project_id + display_name = var.monitoring_group.name + filter = var.monitoring_group.filter +} diff --git a/test/integration/configuration/mm-attributes.yml b/test/integration/configuration/mm-attributes.yml index 837515e5..e6ec72bb 100644 --- a/test/integration/configuration/mm-attributes.yml +++ b/test/integration/configuration/mm-attributes.yml @@ -758,3 +758,7 @@ dataproc_serverless_batches: main_class: "org.apache.spark.examples.SparkPi" args: "10" path: "file:///usr/lib/spark/examples/jars/spark-examples.jar" + +monitoring_group: + name: "inspec-test-group" + filter: "resource.metadata.name = has_substring(\"inspec\")" diff --git a/test/integration/verify/controls/google_monitoring_group.rb b/test/integration/verify/controls/google_monitoring_group.rb new file mode 100644 index 00000000..426951ca --- /dev/null +++ b/test/integration/verify/controls/google_monitoring_group.rb @@ -0,0 +1,39 @@ +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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. +# +# ---------------------------------------------------------------------------- + +title 'Test GCP google_monitoring_group resource.' + +gcp_project_id = input(:gcp_project_id, value: 'gcp_project_id', description: 'The GCP project identifier.') + +group = input('group', value: { + "name": "projects/ppradhan/groups/1973775459523949291", + "display_name": "inspec-test-group", + "parent_name": "projects/ppradhan", + "filter": "resource.metadata.name = has_substring(\"inspec\")" +}, description: 'group description') +control 'google_monitoring_group-1.0' do + impact 1.0 + title 'google_monitoring_group resource test' + + describe google_monitoring_group(name: group['name']) do + it { should exist } + its('name') { should cmp group['name'] } + its('display_name') { should cmp group['display_name'] } + its('filter') { should cmp group['filter'] } + end + + describe google_monitoring_group(name: "does_not_exit") do + it { should_not exist } + end +end diff --git a/test/integration/verify/controls/google_monitoring_groups.rb b/test/integration/verify/controls/google_monitoring_groups.rb new file mode 100644 index 00000000..e56b5fcf --- /dev/null +++ b/test/integration/verify/controls/google_monitoring_groups.rb @@ -0,0 +1,35 @@ +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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. +# +# ---------------------------------------------------------------------------- + +title 'Test GCP google_monitoring_groups resource.' + +gcp_project_id = input(:gcp_project_id, value: 'gcp_project_id', description: 'The GCP project identifier.') + +group = input('group', value: { + "name": "projects/ppradhan/groups/1973775459523949291", + "display_name": "inspec-test-group", + "parent_name": "projects/ppradhan", + "filter": "resource.metadata.name = has_substring(\"inspec\")" +}, description: 'group description') +control 'google_monitoring_groups-1.0' do + impact 1.0 + title 'google_monitoring_groups resource test' + + describe google_monitoring_groups(name: group['name']) do + it { should exist } + its('names') { should include group['name'] } + its('display_names') { should include group['display_name'] } + its('filters') { should include group['filter'] } + end +end