diff --git a/.changelog/33402.txt b/.changelog/33402.txt new file mode 100644 index 000000000000..a634238068b7 --- /dev/null +++ b/.changelog/33402.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_ssm_patch_baseline: Add `json` attribute to facilitate use with S3 buckets +``` + +```release-note:enhancement +data-source/aws_ssm_patch_baseline: Add `json` attribute to facilitate use with S3 buckets +``` \ No newline at end of file diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go index 4121b3b00491..c37a06456d30 100644 --- a/internal/acctest/acctest.go +++ b/internal/acctest/acctest.go @@ -683,6 +683,8 @@ func CheckResourceAttrJMES(name, key, jmesPath, value string) resource.TestCheck v = x case float64: v = strconv.FormatFloat(x, 'f', -1, 64) + case bool: + v = fmt.Sprint(x) default: return fmt.Errorf(`%[1]s: Attribute %[2]q, JMESPath %[3]q got "%#[4]v" (%[4]T)`, name, key, jmesPath, result) } @@ -729,6 +731,8 @@ func CheckResourceAttrJMESPair(nameFirst, keyFirst, jmesPath, nameSecond, keySec value = x case float64: value = strconv.FormatFloat(x, 'f', -1, 64) + case bool: + value = fmt.Sprint(x) default: return fmt.Errorf(`%[1]s: Attribute %[2]q, JMESPath %[3]q got "%#[4]v" (%[4]T)`, nameFirst, keyFirst, jmesPath, result) } diff --git a/internal/service/ssm/patch_baseline.go b/internal/service/ssm/patch_baseline.go index 0cd41f900a64..a663a5a60f23 100644 --- a/internal/service/ssm/patch_baseline.go +++ b/internal/service/ssm/patch_baseline.go @@ -5,6 +5,7 @@ package ssm import ( "context" + "encoding/json" "fmt" "log" "strings" @@ -220,6 +221,10 @@ func ResourcePatchBaseline() *schema.Resource { }, }, }, + "json": { + Type: schema.TypeString, + Computed: true, + }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), @@ -313,9 +318,18 @@ func resourcePatchBaselineRead(ctx context.Context, d *schema.ResourceData, meta AccountID: meta.(*conns.AWSClient).AccountID, Resource: fmt.Sprintf("patchbaseline/%s", strings.TrimPrefix(d.Id(), "/")), } + + jsonDoc, err := json.MarshalIndent(resp, "", " ") + if err != nil { + // should never happen if the above code is correct + return sdkdiag.AppendErrorf(diags, "Formatting json representation: formatting JSON: %s", err) + } + jsonString := string(jsonDoc) + d.Set("arn", arn.String()) d.Set("name", resp.Name) d.Set("description", resp.Description) + d.Set("json", jsonString) d.Set("operating_system", resp.OperatingSystem) d.Set("approved_patches_compliance_level", resp.ApprovedPatchesComplianceLevel) d.Set("approved_patches", flex.FlattenStringList(resp.ApprovedPatches)) diff --git a/internal/service/ssm/patch_baseline_data_source.go b/internal/service/ssm/patch_baseline_data_source.go index 5ae469620aca..3e91dd56b49e 100644 --- a/internal/service/ssm/patch_baseline_data_source.go +++ b/internal/service/ssm/patch_baseline_data_source.go @@ -5,6 +5,7 @@ package ssm import ( "context" + "encoding/json" "log" "github.com/aws/aws-sdk-go/aws" @@ -100,6 +101,10 @@ func DataSourcePatchBaseline() *schema.Resource { }, }, }, + "json": { + Type: schema.TypeString, + Computed: true, + }, "name": { Type: schema.TypeString, Computed: true, @@ -225,6 +230,13 @@ func dataPatchBaselineRead(ctx context.Context, d *schema.ResourceData, meta int return sdkdiag.AppendErrorf(diags, "getting SSM PatchBaseline: %s", err) } + jsonDoc, err := json.MarshalIndent(output, "", " ") + if err != nil { + // should never happen if the above code is correct + return sdkdiag.AppendErrorf(diags, "Formatting json representation: formatting JSON: %s", err) + } + jsonString := string(jsonDoc) + d.SetId(aws.StringValue(baseline.BaselineId)) d.Set("approved_patches", aws.StringValueSlice(output.ApprovedPatches)) d.Set("approved_patches_compliance_level", output.ApprovedPatchesComplianceLevel) @@ -233,6 +245,7 @@ func dataPatchBaselineRead(ctx context.Context, d *schema.ResourceData, meta int d.Set("default_baseline", baseline.DefaultBaseline) d.Set("description", baseline.BaselineDescription) d.Set("global_filter", flattenPatchFilterGroup(output.GlobalFilters)) + d.Set("json", jsonString) d.Set("name", baseline.BaselineName) d.Set("operating_system", baseline.OperatingSystem) d.Set("rejected_patches", aws.StringValueSlice(output.RejectedPatches)) diff --git a/internal/service/ssm/patch_baseline_data_source_test.go b/internal/service/ssm/patch_baseline_data_source_test.go index f075cc4c702d..8ee6b04d61c9 100644 --- a/internal/service/ssm/patch_baseline_data_source_test.go +++ b/internal/service/ssm/patch_baseline_data_source_test.go @@ -36,6 +36,11 @@ func TestAccSSMPatchBaselineDataSource_existingBaseline(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "rejected_patches.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "rejected_patches_action", "ALLOW_AS_DEPENDENCY"), resource.TestCheckResourceAttr(dataSourceName, "source.#", "0"), + acctest.CheckResourceAttrJMES(dataSourceName, "json", "ApprovedPatches|length(@)", "0"), + acctest.CheckResourceAttrJMESPair(dataSourceName, "json", "Name", dataSourceName, "name"), + acctest.CheckResourceAttrJMESPair(dataSourceName, "json", "Description", dataSourceName, "description"), + acctest.CheckResourceAttrJMESPair(dataSourceName, "json", "ApprovedPatchesEnableNonSecurity", dataSourceName, "approved_patches_enable_non_security"), + acctest.CheckResourceAttrJMESPair(dataSourceName, "json", "OperatingSystem", dataSourceName, "operating_system"), ), }, }, diff --git a/internal/service/ssm/patch_baseline_test.go b/internal/service/ssm/patch_baseline_test.go index 9c778ff648c6..170528814f62 100644 --- a/internal/service/ssm/patch_baseline_test.go +++ b/internal/service/ssm/patch_baseline_test.go @@ -42,6 +42,13 @@ func TestAccSSMPatchBaseline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "Baseline containing all updates approved for production systems"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttr(resourceName, "approved_patches_enable_non_security", "false"), + acctest.CheckResourceAttrJMES(resourceName, "json", "ApprovedPatchesEnableNonSecurity", "false"), + acctest.CheckResourceAttrJMES(resourceName, "json", "ApprovedPatches|length(@)", "1"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "ApprovedPatches[0]", resourceName, "approved_patches.0"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "Name", resourceName, "name"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "Description", resourceName, "description"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "ApprovedPatchesEnableNonSecurity", resourceName, "approved_patches_enable_non_security"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "OperatingSystem", resourceName, "operating_system"), ), }, { @@ -61,6 +68,9 @@ func TestAccSSMPatchBaseline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "approved_patches_compliance_level", ssm.PatchComplianceLevelHigh), resource.TestCheckResourceAttr(resourceName, "description", "Baseline containing all updates approved for production systems - August 2017"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "ApprovedPatches[0]", resourceName, "approved_patches.1"), + acctest.CheckResourceAttrJMESPair(resourceName, "json", "ApprovedPatches[1]", resourceName, "approved_patches.0"), + acctest.CheckResourceAttrJMES(resourceName, "json", "ApprovedPatches|length(@)", "2"), func(*terraform.State) error { if aws.StringValue(before.BaselineId) != aws.StringValue(after.BaselineId) { t.Fatal("Baseline IDs changed unexpectedly") @@ -277,6 +287,7 @@ func TestAccSSMPatchBaseline_sources(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "source.1.configuration", "[amzn-main] \nname=amzn-main-Base\nmirrorlist=http://repo./$awsregion./$awsdomain//$releasever/main/mirror.list //nmirrorlist_expire=300//nmetadata_expire=300 \npriority=10 \nfailovermethod=priority \nfastestmirror_enabled=0 \ngpgcheck=1 \ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-ga \nenabled=1 \nretries=3 \ntimeout=5\nreport_instanceid=yes"), resource.TestCheckResourceAttr(resourceName, "source.1.products.#", "1"), resource.TestCheckResourceAttr(resourceName, "source.1.products.0", "AmazonLinux2018.03"), + func(*terraform.State) error { if aws.StringValue(before.BaselineId) != aws.StringValue(after.BaselineId) { t.Fatal("Baseline IDs changed unexpectedly") diff --git a/website/docs/d/ssm_patch_baseline.html.markdown b/website/docs/d/ssm_patch_baseline.html.markdown index 66d1a1e97b4f..0e67dd0d7c3c 100644 --- a/website/docs/d/ssm_patch_baseline.html.markdown +++ b/website/docs/d/ssm_patch_baseline.html.markdown @@ -35,11 +35,14 @@ data "aws_ssm_patch_baseline" "default_custom" { ## Argument Reference -This data source supports the following arguments: +The following arguments are required: * `owner` - (Required) Owner of the baseline. Valid values: `All`, `AWS`, `Self` (the current account). -* `name_prefix` - (Optional) Filter results by the baseline name prefix. + +The following arguments are optional: + * `default_baseline` - (Optional) Filters the results against the baselines default_baseline field. +* `name_prefix` - (Optional) Filter results by the baseline name prefix. * `operating_system` - (Optional) Specified OS for the baseline. Valid values: `AMAZON_LINUX`, `AMAZON_LINUX_2`, `UBUNTU`, `REDHAT_ENTERPRISE_LINUX`, `SUSE`, `CENTOS`, `ORACLE_LINUX`, `DEBIAN`, `MACOS`, `RASPBIAN` and `ROCKY_LINUX`. ## Attribute Reference @@ -47,25 +50,26 @@ This data source supports the following arguments: This data source exports the following attributes in addition to the arguments above: * `approved_patches` - List of explicitly approved patches for the baseline. -* `approved_patches_compliance_level` - The compliance level for approved patches. +* `approved_patches_compliance_level` - Compliance level for approved patches. * `approved_patches_enable_non_security` - Indicates whether the list of approved patches includes non-security updates that should be applied to the instances. * `approval_rule` - List of rules used to include patches in the baseline. - * `approve_after_days` - The number of days after the release date of each patch matched by the rule the patch is marked as approved in the patch baseline. - * `approve_until_date` - The cutoff date for auto approval of released patches. Any patches released on or before this date are installed automatically. Date is formatted as `YYYY-MM-DD`. Conflicts with `approve_after_days` - * `compliance_level` - The compliance level for patches approved by this rule. + * `approve_after_days` - Number of days after the release date of each patch matched by the rule the patch is marked as approved in the patch baseline. + * `approve_until_date` - Cutoff date for auto approval of released patches. Any patches released on or before this date are installed automatically. Date is formatted as `YYYY-MM-DD`. Conflicts with `approve_after_days` + * `compliance_level` - Compliance level for patches approved by this rule. * `enable_non_security` - Boolean enabling the application of non-security updates. - * `patch_filter` - The patch filter group that defines the criteria for the rule. - * `key` - The key for the filter. - * `values` - The value for the filter. + * `patch_filter` - Patch filter group that defines the criteria for the rule. + * `key` - Key for the filter. + * `values` - Value for the filter. * `global_filter` - Set of global filters used to exclude patches from the baseline. - * `key` - The key for the filter. - * `values` - The value for the filter. + * `key` - Key for the filter. + * `values` - Value for the filter. * `id` - ID of the baseline. +* `json` - JSON representation of the baseline. * `name` - Name of the baseline. * `description` - Description of the baseline. * `rejected_patches` - List of rejected patches. -* `rejected_patches_action` - The action specified to take on patches included in the `rejected_patches` list. +* `rejected_patches_action` - Action specified to take on patches included in the `rejected_patches` list. * `source` - Information about the patches to use to update the managed nodes, including target operating systems and source repositories. - * `configuration` - The value of the yum repo configuration. - * `name` - The name specified to identify the patch source. - * `products` - The specific operating system versions a patch repository applies to. + * `configuration` - Value of the yum repo configuration. + * `name` - Name specified to identify the patch source. + * `products` - Specific operating system versions a patch repository applies to. diff --git a/website/docs/r/ssm_patch_baseline.html.markdown b/website/docs/r/ssm_patch_baseline.html.markdown index d13826fb2375..42eef2a08d64 100644 --- a/website/docs/r/ssm_patch_baseline.html.markdown +++ b/website/docs/r/ssm_patch_baseline.html.markdown @@ -158,90 +158,50 @@ EOF ## Argument Reference -This resource supports the following arguments: - -* `name` - (Required) The name of the patch baseline. -* `description` - (Optional) The description of the patch baseline. -* `operating_system` - (Optional) The operating system the patch baseline applies to. - Valid values are - `ALMA_LINUX`, - `AMAZON_LINUX`, - `AMAZON_LINUX_2`, - `AMAZON_LINUX_2022`, - `AMAZON_LINUX_2023`, - `CENTOS`, - `DEBIAN`, - `MACOS`, - `ORACLE_LINUX`, - `RASPBIAN`, - `REDHAT_ENTERPRISE_LINUX`, - `ROCKY_LINUX`, - `SUSE`, - `UBUNTU`, and - `WINDOWS`. - The default value is `WINDOWS`. -* `approved_patches_compliance_level` - (Optional) The compliance level for approved patches. - This means that if an approved patch is reported as missing, this is the severity of the compliance violation. - Valid values are `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, `INFORMATIONAL`, `UNSPECIFIED`. - The default value is `UNSPECIFIED`. -* `approved_patches` - (Optional) A list of explicitly approved patches for the baseline. - Cannot be specified with `approval_rule`. -* `rejected_patches` - (Optional) A list of rejected patches. -* `global_filter` - (Optional) A set of global filters used to exclude patches from the baseline. - Up to 4 global filters can be specified using Key/Value pairs. - Valid Keys are `PRODUCT`, `CLASSIFICATION`, `MSRC_SEVERITY`, and `PATCH_ID`. -* `approval_rule` - (Optional) A set of rules used to include patches in the baseline. - Up to 10 approval rules can be specified. - See [`approval_rule`](#approval_rule-block) below. -* `source` - (Optional) Configuration block with alternate sources for patches. - Applies to Linux instances only. - See [`source`](#source-block) below. -* `rejected_patches_action` - (Optional) The action for Patch Manager to take on patches included in the `rejected_patches` list. - Valid values are `ALLOW_AS_DEPENDENCY` and `BLOCK`. -* `approved_patches_enable_non_security` - (Optional) Indicates whether the list of approved patches includes non-security updates that should be applied to the instances. - Applies to Linux instances only. -* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +The following arguments are required: + +* `name` - (Required) Name of the patch baseline. + +The following arguments are optional: + +* `approval_rule` - (Optional) Set of rules used to include patches in the baseline. Up to 10 approval rules can be specified. See [`approval_rule`](#approval_rule-block) below. +* `approved_patches_compliance_level` - (Optional) Compliance level for approved patches. This means that if an approved patch is reported as missing, this is the severity of the compliance violation. Valid values are `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, `INFORMATIONAL`, `UNSPECIFIED`. The default value is `UNSPECIFIED`. +* `approved_patches_enable_non_security` - (Optional) Whether the list of approved patches includes non-security updates that should be applied to the instances. Applies to Linux instances only. +* `approved_patches` - (Optional) List of explicitly approved patches for the baseline. Cannot be specified with `approval_rule`. +* `description` - (Optional) Description of the patch baseline. +* `global_filter` - (Optional) Set of global filters used to exclude patches from the baseline. Up to 4 global filters can be specified using Key/Value pairs. Valid Keys are `PRODUCT`, `CLASSIFICATION`, `MSRC_SEVERITY`, and `PATCH_ID`. +* `operating_system` - (Optional) Operating system the patch baseline applies to. Valid values are `ALMA_LINUX`, `AMAZON_LINUX`, `AMAZON_LINUX_2`, `AMAZON_LINUX_2022`, `AMAZON_LINUX_2023`, `CENTOS`, `DEBIAN`, `MACOS`, `ORACLE_LINUX`, `RASPBIAN`, `REDHAT_ENTERPRISE_LINUX`, `ROCKY_LINUX`, `SUSE`, `UBUNTU`, and `WINDOWS`. The default value is `WINDOWS`. +* `rejected_patches_action` - (Optional) Action for Patch Manager to take on patches included in the `rejected_patches` list. Valid values are `ALLOW_AS_DEPENDENCY` and `BLOCK`. +* `rejected_patches` - (Optional) List of rejected patches. +* `source` - (Optional) Configuration block with alternate sources for patches. Applies to Linux instances only. See [`source`](#source-block) below. +* `tags` - (Optional) Map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### `approval_rule` Block The `approval_rule` block supports: -* `approve_after_days` - (Optional) The number of days after the release date of each patch matched by the rule the patch is marked as approved in the patch baseline. - Valid Range: 0 to 100. - Conflicts with `approve_until_date`. -* `approve_until_date` - (Optional) The cutoff date for auto approval of released patches. - Any patches released on or before this date are installed automatically. - Date is formatted as `YYYY-MM-DD`. - Conflicts with `approve_after_days` -* `patch_filter` - (Required) The patch filter group that defines the criteria for the rule. - Up to 5 patch filters can be specified per approval rule using Key/Value pairs. - Valid combinations of these Keys and the `operating_system` value can be found in the [SSM DescribePatchProperties API Reference](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_DescribePatchProperties.html). - Valid Values are exact values for the patch property given as the key, or a wildcard `*`, which matches all values. - * `PATCH_SET` defaults to `OS` if unspecified -* `compliance_level` - (Optional) The compliance level for patches approved by this rule. - Valid values are `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, `INFORMATIONAL`, and `UNSPECIFIED`. - The default value is `UNSPECIFIED`. -* `enable_non_security` - (Optional) Boolean enabling the application of non-security updates. - The default value is `false`. - Valid for Linux instances only. +* `approve_after_days` - (Optional) Number of days after the release date of each patch matched by the rule the patch is marked as approved in the patch baseline. Valid Range: 0 to 100. Conflicts with `approve_until_date`. +* `approve_until_date` - (Optional) Cutoff date for auto approval of released patches. Any patches released on or before this date are installed automatically. Date is formatted as `YYYY-MM-DD`. Conflicts with `approve_after_days` +* `compliance_level` - (Optional) Compliance level for patches approved by this rule. Valid values are `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, `INFORMATIONAL`, and `UNSPECIFIED`. The default value is `UNSPECIFIED`. +* `enable_non_security` - (Optional) Boolean enabling the application of non-security updates. The default value is `false`. Valid for Linux instances only. +* `patch_filter` - (Required) Patch filter group that defines the criteria for the rule. Up to 5 patch filters can be specified per approval rule using Key/Value pairs. Valid combinations of these Keys and the `operating_system` value can be found in the [SSM DescribePatchProperties API Reference](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_DescribePatchProperties.html). Valid Values are exact values for the patch property given as the key, or a wildcard `*`, which matches all values. `PATCH_SET` defaults to `OS` if unspecified ### `source` Block The `source` block supports: -* `name` - (Required) The name specified to identify the patch source. -* `configuration` - (Required) The value of the yum repo configuration. - For information about other options available for your yum repository configuration, see the [`dnf.conf` documentation](https://man7.org/linux/man-pages/man5/dnf.conf.5.html) -* `products` - (Required) The specific operating system versions a patch repository applies to, such as `"Ubuntu16.04"`, `"AmazonLinux2016.09"`, `"RedhatEnterpriseLinux7.2"` or `"Suse12.7"`. - For lists of supported product values, see [PatchFilter](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_PatchFilter.html). +* `configuration` - (Required) Value of the yum repo configuration. For information about other options available for your yum repository configuration, see the [`dnf.conf` documentation](https://man7.org/linux/man-pages/man5/dnf.conf.5.html) +* `name` - (Required) Name specified to identify the patch source. +* `products` - (Required) Specific operating system versions a patch repository applies to, such as `"Ubuntu16.04"`, `"AmazonLinux2016.09"`, `"RedhatEnterpriseLinux7.2"` or `"Suse12.7"`. For lists of supported product values, see [PatchFilter](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_PatchFilter.html). ## Attribute Reference This resource exports the following attributes in addition to the arguments above: -* `id` - The ID of the patch baseline. -* `arn` - The ARN of the patch baseline. -* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). +* `arn` - ARN of the baseline. +* `id` - ID of the baseline. +* `json` - JSON definition of the baseline. +* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Import