diff --git a/mmv1/products/gkehub2/Feature.yaml b/mmv1/products/gkehub2/Feature.yaml index 32d917f0b708..67be3b1efc02 100644 --- a/mmv1/products/gkehub2/Feature.yaml +++ b/mmv1/products/gkehub2/Feature.yaml @@ -93,6 +93,21 @@ examples: skip_test: true primary_resource_name: 'fmt.Sprintf("configmanagement")' primary_resource_id: 'feature' + - !ruby/object:Provider::Terraform::Examples + name: 'enable_fleet_default_member_config_policycontroller' + skip_test: true + primary_resource_name: 'fmt.Sprintf("policycontroller")' + primary_resource_id: 'feature' + - !ruby/object:Provider::Terraform::Examples + name: 'enable_fleet_default_member_config_policycontroller_update' + skip_test: true + primary_resource_name: 'fmt.Sprintf("policycontroller")' + primary_resource_id: 'feature' + - !ruby/object:Provider::Terraform::Examples + name: 'enable_fleet_default_member_config_policycontroller_set_empty' + skip_test: true + primary_resource_name: 'fmt.Sprintf("policycontroller")' + primary_resource_id: 'feature' autogen_async: true # Skip sweeper gen since this is a child resource. skip_sweeper: true @@ -259,6 +274,161 @@ properties: - !ruby/object:Api::Type::String name: version description: 'Version of ACM installed' + - !ruby/object:Api::Type::NestedObject + name: policycontroller + description: Policy Controller spec + properties: + - !ruby/object:Api::Type::String + name: version + description: 'Configures the version of Policy Controller' + default_from_api: true + - !ruby/object:Api::Type::NestedObject + name: policyControllerHubConfig + description: 'Configuration of Policy Controller' + required: true + properties: + - !ruby/object:Api::Type::Enum + name: installSpec + description: 'Configures the mode of the Policy Controller installation' + values: + - :INSTALL_SPEC_UNSPECIFIED + - :INSTALL_SPEC_NOT_INSTALLED + - :INSTALL_SPEC_ENABLED + - :INSTALL_SPEC_SUSPENDED + - :INSTALL_SPEC_DETACHED + required: true + - !ruby/object:Api::Type::Integer + name: auditIntervalSeconds + description: 'Interval for Policy Controller Audit scans (in seconds). When set to 0, this disables audit functionality altogether.' + - !ruby/object:Api::Type::Array + name: exemptableNamespaces + description: 'The set of namespaces that are excluded from Policy Controller checks. Namespaces do not need to currently exist on the cluster.' + item_type: Api::Type::String + - !ruby/object:Api::Type::Boolean + name: logDeniesEnabled + description: 'Logs all denies and dry run failures.' + - !ruby/object:Api::Type::Boolean + name: mutationEnabled + description: 'Enables the ability to mutate resources using Policy Controller.' + - !ruby/object:Api::Type::Boolean + name: referentialRulesEnabled + description: 'Enables the ability to use Constraint Templates that reference to objects other than the object currently being evaluated.' + - !ruby/object:Api::Type::NestedObject + name: monitoring + description: 'Monitoring specifies the configuration of monitoring Policy Controller.' + default_from_api: true + properties: + - !ruby/object:Api::Type::Array + name: backends + description: 'Specifies the list of backends Policy Controller will export to. An empty list would effectively disable metrics export.' + default_from_api: true + item_type: !ruby/object:Api::Type::Enum + name: 'required but unused' + description: 'required but unused' + values: + - :MONITORING_BACKEND_UNSPECIFIED + - :PROMETHEUS + - :CLOUD_MONITORING + - !ruby/object:Api::Type::Integer + name: constraintViolationLimit + description: 'The maximum number of audit violations to be stored in a constraint. If not set, the internal default of 20 will be used.' + - !ruby/object:Api::Type::Map + name: deploymentConfigs + description: 'Map of deployment configs to deployments ("admission", "audit", "mutation").' + key_name: component + key_description: 'Specifies which component to apply the deployment config to. Accepted values are "admission", "audit" and "mutation".' + default_from_api: true + value_type: !ruby/object:Api::Type::NestedObject + name: deploymentConfig + description: 'Configures deployment-specific options, such as high availability.' + properties: + - !ruby/object:Api::Type::Integer + name: replicaCount + description: 'Pod replica count.' + send_empty_value: false + default_from_api: true + - !ruby/object:Api::Type::NestedObject + name: containerResources + description: 'Container resource requirements.' + properties: + - !ruby/object:Api::Type::NestedObject + name: limits + description: 'Limits describes the maximum amount of compute resources allowed for use by the running container.' + properties: + - !ruby/object:Api::Type::String + name: memory + description: 'Memory requirement expressed in Kubernetes resource units.' + - !ruby/object:Api::Type::String + name: cpu + description: 'CPU requirement expressed in Kubernetes resource units.' + - !ruby/object:Api::Type::NestedObject + name: requests + description: 'Requests describes the amount of compute resources reserved for the container by the kube-scheduler.' + properties: + - !ruby/object:Api::Type::String + name: memory + description: 'Memory requirement expressed in Kubernetes resource units.' + - !ruby/object:Api::Type::String + name: cpu + description: 'CPU requirement expressed in Kubernetes resource units.' + - !ruby/object:Api::Type::Enum + name: podAffinity + description: 'Pod affinity configuration.' + default_from_api: true + values: + - :AFFINITY_UNSPECIFIED + - :NO_AFFINITY + - :ANTI_AFFINITY + - !ruby/object:Api::Type::Array + name: podToleration + api_name: podTolerations + description: 'Pod tolerations of node taints.' + item_type: !ruby/object:Api::Type::NestedObject + name: 'required but unused' + description: 'required but unused' + properties: + - !ruby/object:Api::Type::String + name: key + description: 'Matches a taint key (not necessarily unique).' + - !ruby/object:Api::Type::String + name: operator + description: 'Matches a taint operator.' + - !ruby/object:Api::Type::String + name: value + description: 'Matches a taint value.' + - !ruby/object:Api::Type::String + name: effect + description: 'Matches a taint effect.' + - !ruby/object:Api::Type::NestedObject + name: policyContent + description: 'Specifies the desired policy content on the cluster.' + # default_from_api: true + properties: + - !ruby/object:Api::Type::NestedObject + name: templateLibrary + description: 'Configures the installation of the Template Library.' + default_from_api: true + properties: + - !ruby/object:Api::Type::Enum + name: installation + description: 'Configures the manner in which the template library is installed on the cluster.' + values: + - :INSTALATION_UNSPECIFIED + - :NOT_INSTALLED + - :ALL + - !ruby/object:Api::Type::Map + name: bundles + description: 'Configures which bundles to install and their corresponding install specs.' + key_name: bundle + key_description: 'A bundle name supported in this version. Values configure the exempted namespaces for this bundle.' + value_type: !ruby/object:Api::Type::NestedObject + name: bundleInstallSpec + description: 'The specification configuration for a single managed bundle.' + properties: + - !ruby/object:Api::Type::Array + name: exemptedNamespaces + description: 'The set of namespaces to be exempted from the bundle.' + item_type: Api::Type::String - !ruby/object:Api::Type::NestedObject name: state description: Output only. The Hub-wide Feature state diff --git a/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller.tf.erb b/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller.tf.erb new file mode 100644 index 000000000000..1d45cd87c706 --- /dev/null +++ b/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller.tf.erb @@ -0,0 +1,23 @@ +resource "google_gke_hub_feature" "feature" { + name = "policycontroller" + location = "global" + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_ENABLED" + exemptable_namespaces = ["foo"] + policy_content { + bundles { + bundle = "policy-essentials-v2022" + exempted_namespaces = ["foo", "bar"] + } + template_library { + installation = "ALL" + } + } + audit_interval_seconds = 30 + referential_rules_enabled = true + } + } + } +} diff --git a/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller_set_empty.tf.erb b/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller_set_empty.tf.erb new file mode 100644 index 000000000000..80d950a1ec89 --- /dev/null +++ b/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller_set_empty.tf.erb @@ -0,0 +1,20 @@ +resource "google_gke_hub_feature" "feature" { + name = "policycontroller" + location = "global" + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_ENABLED" + policy_content {} + constraint_violation_limit = 50 + referential_rules_enabled = true + log_denies_enabled = true + mutation_enabled = true + deployment_configs { + component = "admission" + } + monitoring {} + } + } + } +} diff --git a/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller_update.tf.erb b/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller_update.tf.erb new file mode 100644 index 000000000000..b5ae18f27781 --- /dev/null +++ b/mmv1/templates/terraform/examples/enable_fleet_default_member_config_policycontroller_update.tf.erb @@ -0,0 +1,57 @@ +resource "google_gke_hub_feature" "feature" { + name = "policycontroller" + location = "global" + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_SUSPENDED" + policy_content { + bundles { + bundle = "pci-dss-v3.2.1" + exempted_namespaces = ["baz", "bar"] + } + bundles { + bundle = "nist-sp-800-190" + exempted_namespaces = [] + } + template_library { + installation = "ALL" + } + } + constraint_violation_limit = 50 + referential_rules_enabled = true + log_denies_enabled = true + mutation_enabled = true + deployment_configs { + component = "admission" + replica_count = 2 + pod_affinity = "ANTI_AFFINITY" + } + deployment_configs { + component = "audit" + container_resources { + limits { + memory = "1Gi" + cpu = "1.5" + } + requests { + memory = "500Mi" + cpu = "150m" + } + } + pod_toleration { + key = "key1" + operator = "Equal" + value = "value1" + effect = "NoSchedule" + } + } + monitoring { + backends = [ + "PROMETHEUS" + ] + } + } + } + } +} diff --git a/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_feature_test.go.erb b/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_feature_test.go.erb index 6948ea1da0f4..f2c14b2d223f 100644 --- a/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_feature_test.go.erb +++ b/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_feature_test.go.erb @@ -504,6 +504,169 @@ resource "google_gke_hub_feature" "feature" { `, context) } +func TestAccGKEHubFeature_FleetDefaultMemberConfigPolicyController(t *testing.T) { + // VCR fails to handle batched project services + acctest.SkipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckGKEHubFeatureDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccGKEHubFeature_FleetDefaultMemberConfigPolicyController(context), + }, + { + ResourceName: "google_gke_hub_feature.feature", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"project", "update_time"}, + }, + { + Config: testAccGKEHubFeature_FleetDefaultMemberConfigPolicyControllerUpdate(context), + }, + { + ResourceName: "google_gke_hub_feature.feature", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGKEHubFeature_FleetDefaultMemberConfigPolicyControllerUpdateSetEmpty(context), + }, + { + ResourceName: "google_gke_hub_feature.feature", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccGKEHubFeature_FleetDefaultMemberConfigPolicyController(context map[string]interface{}) string { + return gkeHubFeatureProjectSetupForGA(context) + acctest.Nprintf(` +resource "google_gke_hub_feature" "feature" { + name = "policycontroller" + location = "global" + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_ENABLED" + exemptable_namespaces = ["foo"] + policy_content { + bundles { + bundle = "policy-essentials-v2022" + exempted_namespaces = ["foo", "bar"] + } + } + audit_interval_seconds = 30 + referential_rules_enabled = true + } + } + } + depends_on = [google_project_service.anthos, google_project_service.gkehub, google_project_service.poco] + project = google_project.project.project_id +} +`, context) +} + +func testAccGKEHubFeature_FleetDefaultMemberConfigPolicyControllerUpdate(context map[string]interface{}) string { + return gkeHubFeatureProjectSetupForGA(context) + acctest.Nprintf(` +resource "google_gke_hub_feature" "feature" { + name = "policycontroller" + location = "global" + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_SUSPENDED" + policy_content { + bundles { + bundle = "pci-dss-v3.2.1" + exempted_namespaces = ["baz", "bar"] + } + bundles { + bundle = "nist-sp-800-190" + exempted_namespaces = [] + } + template_library { + installation = "ALL" + } + } + constraint_violation_limit = 50 + referential_rules_enabled = true + log_denies_enabled = true + mutation_enabled = true + deployment_configs { + component = "admission" + replica_count = 2 + pod_affinity = "ANTI_AFFINITY" + } + deployment_configs { + component = "audit" + container_resources { + limits { + memory = "1Gi" + cpu = "1.5" + } + requests { + memory = "500Mi" + cpu = "150m" + } + } + pod_toleration { + key = "key1" + operator = "Equal" + value = "value1" + effect = "NoSchedule" + } + } + monitoring { + backends = [ + "PROMETHEUS" + ] + } + } + } + } + depends_on = [google_project_service.anthos, google_project_service.gkehub, google_project_service.poco] + project = google_project.project.project_id +} +`, context) +} + +func testAccGKEHubFeature_FleetDefaultMemberConfigPolicyControllerUpdateSetEmpty(context map[string]interface{}) string { + return gkeHubFeatureProjectSetupForGA(context) + acctest.Nprintf(` +resource "google_gke_hub_feature" "feature" { + name = "policycontroller" + location = "global" + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_ENABLED" + policy_content {} + constraint_violation_limit = 50 + referential_rules_enabled = true + log_denies_enabled = true + mutation_enabled = true + deployment_configs { + component = "admission" + } + monitoring {} + } + } + } + depends_on = [google_project_service.anthos, google_project_service.gkehub, google_project_service.poco] + project = google_project.project.project_id +} +`, context) +} + func TestAccGKEHubFeature_gkehubFeatureMcsd(t *testing.T) { // VCR fails to handle batched project services acctest.SkipIfVcr(t) @@ -595,6 +758,11 @@ resource "google_project_service" "acm" { service = "anthosconfigmanagement.googleapis.com" } +resource "google_project_service" "poco" { + project = google_project.project.project_id + service = "anthospolicycontroller.googleapis.com" +} + resource "google_project_service" "mcsd" { project = google_project.project.project_id service = "multiclusterservicediscovery.googleapis.com"