From 7deb203b20f583b7cce82117c6193cb56c421e9b Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 6 Dec 2024 16:17:04 -0800 Subject: [PATCH 1/4] Add validation for 'excluded_repositories' attribute Switch doc to be generated using terraform-plugin-docs plugin --- docs/resources/backup.md | 57 ++++++++++++------- .../resources/artifactory_backup/import.sh | 1 + .../resources/artifactory_backup/resource.tf | 12 ++++ .../resource_artifactory_backup.go | 39 +++++++------ .../resource_artifactory_backup_test.go | 1 + 5 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 examples/resources/artifactory_backup/import.sh create mode 100644 examples/resources/artifactory_backup/resource.tf diff --git a/docs/resources/backup.md b/docs/resources/backup.md index de8ef6e8c..3af062f56 100644 --- a/docs/resources/backup.md +++ b/docs/resources/backup.md @@ -1,25 +1,36 @@ --- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "artifactory_backup Resource - terraform-provider-artifactory" subcategory: "Configuration" +description: |- + This resource can be used to manage the automatic and periodic backups of the entire Artifactory instance. + When an artifactory_backup resource is configured and enabled to true, backup of the entire Artifactory system will be done automatically and periodically. + The backup process creates a time-stamped directory in the target backup directory. + See JFrog Artifactory Backup https://www.jfrog.com/confluence/display/JFROG/Backups for more details. + ~>Only supported in self-hosted environment. --- -# Artifactory Backup Resource + +# artifactory_backup (Resource) This resource can be used to manage the automatic and periodic backups of the entire Artifactory instance. When an `artifactory_backup` resource is configured and enabled to true, backup of the entire Artifactory system will be done automatically and periodically. + The backup process creates a time-stamped directory in the target backup directory. -~>The `artifactory_backup` resource utilizes endpoints which are blocked/removed in SaaS environments (i.e. in Artifactory online), rendering this resource incompatible with Artifactory SaaS environments. +See [JFrog Artifactory Backup](https://www.jfrog.com/confluence/display/JFROG/Backups) for more details. + +~>Only supported in self-hosted environment. ## Example Usage -```hcl -# Configure Artifactory Backup system config +```terraform resource "artifactory_backup" "backup_config_name" { key = "backup_config_name" enabled = true cron_exp = "0 0 12 * * ? *" retention_period_hours = 1000 - excluded_repositories = [] + excluded_repositories = ["my-docker-local"] create_archive = false exclude_new_repositories = true send_mail_on_error = true @@ -27,28 +38,30 @@ resource "artifactory_backup" "backup_config_name" { export_mission_control = true } ``` -Note: `Key` argument has to match to the resource name. -Reference Link: [JFrog Artifactory Backup](https://www.jfrog.com/confluence/display/JFROG/Backups) -## Argument Reference + +## Schema -The following arguments are supported: +### Required -* `key` - (Required) The unique ID of the artifactory backup config. -* `enabled` - (Optional) Flag to enable or disable the backup config. Default value is `true`. -* `cron_exp` - (Required) A valid CRON expression that you can use to control backup frequency. Eg: "0 0 12 * * ? *", "0 0 2 ? * MON-SAT *". Note: please use 7 character format - Seconds, Minutes Hours, Day Of Month, Month, Day Of Week, Year. Also, specifying both a day-of-week AND a day-of-month parameter is not supported. One of them should be replaced by `?`. Incorrect: `* 5,7,9 14/2 * * WED,SAT *`, correct: `* 5,7,9 14/2 ? * WED,SAT *`. See details in [Cron Trigger Tutorial](http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) and in [Cronexp package readme](https://github.com/gorhill/cronexpr#other-details). -* `retention_period_hours` - (Optional) The number of hours to keep a backup before Artifactory will clean it up to free up disk space. Applicable only to non-incremental backups. Default value is 168 hours ie: 7 days. -* `excluded_repositories` - (Optional) A list of excluded repositories from the backup. Default is empty list. -* `create_archive` - (Optional) If set, backups will be created within a Zip archive (Slow and CPU intensive). Default value is `false`. -* `exclude_new_repositories` - (Optional) When set, new repositories will not be automatically added to the backup. Default value is `false`. -* `send_mail_on_error` - (Optional) If set, all Artifactory administrators will be notified by email if any problem is encountered during backup. Default value is `true`. -* `verify_disk_space` - (Optional) If set, Artifactory will verify that the backup target location has enough disk space available to hold the backed up data. If there is not enough space available, Artifactory will abort the backup and write a message in the log file. Applicable only to non-incremental backups. -* `export_mission_control` - (Optional) When set to true, mission control will not be automatically added to the backup. Default value is `false`. +- `cron_exp` (String) A valid CRON expression that you can use to control backup frequency. Eg: `0 0 12 * * ? *`, `0 0 2 ? * MON-SAT *`. **Note:** please use 7 character format - Seconds, Minutes Hours, Day Of Month, Month, Day Of Week, Year. Also, specifying both a day-of-week AND a day-of-month parameter is not supported. One of them should be replaced by `?`. Incorrect: `* 5,7,9 14/2 * * WED,SAT *`, correct: `* 5,7,9 14/2 ? * WED,SAT *`. See details in [Cron Trigger Tutorial](http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) and in [Cronexp package readme](https://github.com/gorhill/cronexpr#other-details). +- `key` (String) + +### Optional + +- `create_archive` (Boolean) If set to true, backups will be created within a Zip archive (Slow and CPU intensive). Default value is `false` +- `enabled` (Boolean) Flag to enable or disable the backup config. Default value is `true`. +- `exclude_new_repositories` (Boolean) When set to true, new repositories will not be automatically added to the backup. Default value is `false`. +- `excluded_repositories` (List of String) List of excluded repositories from the backup. +- `export_mission_control` (Boolean) When set to true, mission control will not be automatically added to the backup. Default value is `false`. +- `retention_period_hours` (Number) The number of hours to keep a backup before Artifactory will clean it up to free up disk space. Applicable only to non-incremental backups. Default value is 168 hours i.e. 7 days. +- `send_mail_on_error` (Boolean) If set to true, all Artifactory administrators will be notified by email if any problem is encountered during backup. Default value is `true`. +- `verify_disk_space` (Boolean) If set, Artifactory will verify that the backup target location has enough disk space available to hold the backed up data. If there is not enough space available, Artifactory will abort the backup and write a message in the log file. Applicable only to non-incremental backups. Default value is `false`. ## Import -Backup config can be imported using the key, e.g. +Import is supported using the following syntax: -``` -$ terraform import artifactory_backup.backup_name backup_name +```shell +terraform import artifactory_backup.backup_name backup_name ``` diff --git a/examples/resources/artifactory_backup/import.sh b/examples/resources/artifactory_backup/import.sh new file mode 100644 index 000000000..6ddd2d3a7 --- /dev/null +++ b/examples/resources/artifactory_backup/import.sh @@ -0,0 +1 @@ +terraform import artifactory_backup.backup_name backup_name \ No newline at end of file diff --git a/examples/resources/artifactory_backup/resource.tf b/examples/resources/artifactory_backup/resource.tf new file mode 100644 index 000000000..844b1a500 --- /dev/null +++ b/examples/resources/artifactory_backup/resource.tf @@ -0,0 +1,12 @@ +resource "artifactory_backup" "backup_config_name" { + key = "backup_config_name" + enabled = true + cron_exp = "0 0 12 * * ? *" + retention_period_hours = 1000 + excluded_repositories = ["my-docker-local"] + create_archive = false + exclude_new_repositories = true + send_mail_on_error = true + verify_disk_space = true + export_mission_control = true +} \ No newline at end of file diff --git a/pkg/artifactory/resource/configuration/resource_artifactory_backup.go b/pkg/artifactory/resource/configuration/resource_artifactory_backup.go index f2dc01323..e5326c6bf 100644 --- a/pkg/artifactory/resource/configuration/resource_artifactory_backup.go +++ b/pkg/artifactory/resource/configuration/resource_artifactory_backup.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" @@ -24,16 +25,16 @@ import ( ) type BackupAPIModel struct { - Key string `xml:"key" yaml:"key"` - CronExp string `xml:"cronExp" yaml:"cronExp"` - Enabled bool `xml:"enabled" yaml:"enabled"` - RetentionPeriodHours int64 `xml:"retentionPeriodHours" yaml:"retentionPeriodHours"` - ExcludedRepositories *[]string `xml:"excludedRepositories>repositoryRef" yaml:"excludedRepositories"` - CreateArchive bool `xml:"createArchive" yaml:"createArchive"` - ExcludeNewRepositories bool `xml:"excludeNewRepositories" yaml:"excludeNewRepositories"` - SendMailOnError bool `xml:"sendMailOnError" yaml:"sendMailOnError"` - VerifyDiskSpace bool `xml:"precalculate" yaml:"precalculate"` - ExportMissionControl bool `xml:"exportMissionControl" yaml:"exportMissionControl"` + Key string `xml:"key" yaml:"key"` + CronExp string `xml:"cronExp" yaml:"cronExp"` + Enabled bool `xml:"enabled" yaml:"enabled"` + RetentionPeriodHours int64 `xml:"retentionPeriodHours" yaml:"retentionPeriodHours"` + ExcludedRepositories []string `xml:"excludedRepositories>repositoryRef" yaml:"excludedRepositories,omitempty"` + CreateArchive bool `xml:"createArchive" yaml:"createArchive"` + ExcludeNewRepositories bool `xml:"excludeNewRepositories" yaml:"excludeNewRepositories"` + SendMailOnError bool `xml:"sendMailOnError" yaml:"sendMailOnError"` + VerifyDiskSpace bool `xml:"precalculate" yaml:"precalculate"` + ExportMissionControl bool `xml:"exportMissionControl" yaml:"exportMissionControl"` } func (m BackupAPIModel) Id() string { @@ -60,7 +61,7 @@ type BackupResourceModel struct { func (r *BackupResourceModel) toAPIModel(ctx context.Context, backup *BackupAPIModel) diag.Diagnostics { // Convert from Terraform resource model into API model var excludedRepositories []string - diags := r.ExcludedRepositories.ElementsAs(ctx, &excludedRepositories, true) + diags := r.ExcludedRepositories.ElementsAs(ctx, &excludedRepositories, false) if diags != nil { return diags } @@ -73,7 +74,7 @@ func (r *BackupResourceModel) toAPIModel(ctx context.Context, backup *BackupAPIM CreateArchive: r.CreateArchive.ValueBool(), ExcludeNewRepositories: r.ExcludeNewRepositories.ValueBool(), SendMailOnError: r.SendMailOnError.ValueBool(), - ExcludedRepositories: &excludedRepositories, + ExcludedRepositories: excludedRepositories, VerifyDiskSpace: r.VerifyDiskSpace.ValueBool(), ExportMissionControl: r.ExportMissionControl.ValueBool(), } @@ -81,7 +82,7 @@ func (r *BackupResourceModel) toAPIModel(ctx context.Context, backup *BackupAPIM return nil } -func (r *BackupResourceModel) FromAPIModel(ctx context.Context, backup *BackupAPIModel) diag.Diagnostics { +func (r *BackupResourceModel) fromAPIModel(ctx context.Context, backup *BackupAPIModel) diag.Diagnostics { r.Key = types.StringValue(backup.Key) r.Enabled = types.BoolValue(backup.Enabled) r.CronExp = types.StringValue(backup.CronExp) @@ -94,6 +95,7 @@ func (r *BackupResourceModel) FromAPIModel(ctx context.Context, backup *BackupAP if diags != nil { return diags } + r.ExcludedRepositories = excludedRepositories r.VerifyDiskSpace = types.BoolValue(backup.VerifyDiskSpace) r.ExportMissionControl = types.BoolValue(backup.ExportMissionControl) @@ -118,7 +120,6 @@ func (r *BackupResource) Metadata(ctx context.Context, req resource.MetadataRequ func (r *BackupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ - MarkdownDescription: "Provides an Artifactory backup config resource. This resource configuration corresponds to backup config block in system configuration XML (REST endpoint: artifactory/api/system/configuration). Manages the automatic and periodic backups of the entire Artifactory instance.", Attributes: map[string]schema.Attribute{ "key": schema.StringAttribute{ Required: true, @@ -152,9 +153,12 @@ func (r *BackupResource) Schema(ctx context.Context, req resource.SchemaRequest, }, }, "excluded_repositories": schema.ListAttribute{ - MarkdownDescription: "List of excluded repositories from the backup. Default is empty list.", + MarkdownDescription: "List of excluded repositories from the backup.", Optional: true, ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + }, }, "create_archive": schema.BoolAttribute{ MarkdownDescription: "If set to true, backups will be created within a Zip archive (Slow and CPU intensive). Default value is `false`", @@ -187,6 +191,7 @@ func (r *BackupResource) Schema(ctx context.Context, req resource.SchemaRequest, Default: booldefault.StaticBool(false), }, }, + MarkdownDescription: "This resource can be used to manage the automatic and periodic backups of the entire Artifactory instance.\n\nWhen an `artifactory_backup` resource is configured and enabled to true, backup of the entire Artifactory system will be done automatically and periodically.\n\nThe backup process creates a time-stamped directory in the target backup directory.\n\nSee [JFrog Artifactory Backup](https://www.jfrog.com/confluence/display/JFROG/Backups) for more details.\n\n~>Only supported in self-hosted environment.", } } @@ -282,7 +287,7 @@ func (r *BackupResource) Read(ctx context.Context, req resource.ReadRequest, res // Convert from the API data model to the Terraform data model // and refresh any attribute values. - resp.Diagnostics.Append(state.FromAPIModel(ctx, matchedBackup)...) + resp.Diagnostics.Append(state.fromAPIModel(ctx, matchedBackup)...) if resp.Diagnostics.HasError() { return } @@ -331,7 +336,7 @@ func (r *BackupResource) Update(ctx context.Context, req resource.UpdateRequest, return } - resp.Diagnostics.Append(data.FromAPIModel(ctx, &backup)...) + resp.Diagnostics.Append(data.fromAPIModel(ctx, &backup)...) if resp.Diagnostics.HasError() { return } diff --git a/pkg/artifactory/resource/configuration/resource_artifactory_backup_test.go b/pkg/artifactory/resource/configuration/resource_artifactory_backup_test.go index 0933b7e2c..05e2fa881 100644 --- a/pkg/artifactory/resource/configuration/resource_artifactory_backup_test.go +++ b/pkg/artifactory/resource/configuration/resource_artifactory_backup_test.go @@ -72,6 +72,7 @@ resource "artifactory_backup" "{{ .resourceName }}" { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(fqrn, "enabled", "true"), resource.TestCheckResourceAttr(fqrn, "cron_exp", "0 0 2 ? * MON-SAT *"), + resource.TestCheckResourceAttr(fqrn, "excluded_repositories.#", "0"), ), }, { From 94d9637c0bb0ce44643413b1749ad4afe291f20f Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Mon, 9 Dec 2024 13:58:39 -0800 Subject: [PATCH 2/4] Update CHANGELOG --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2263833b..e7324f962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ -## 12.6.0 (December 10, 2024). Tested on Artifactory 7.98.10 with Terraform 1.10.1 and OpenTofu 1.8.7 +## 12.6.0 (December 10, 2024) FEATURES: **New Resource:** `artifactory_archive_policy` to support upcoming Archive Policy feature. PR: [#1146](https://github.com/jfrog/terraform-provider-artifactory/pull/1146) +BUG FIXES: + +* resource/artifactory_backup: Add size validation to `excluded_repositories` attribute to ensure at least 1 item. Issue: [#1143](https://github.com/jfrog/terraform-provider-artifactory/issues/1143) PR: [#1147](https://github.com/jfrog/terraform-provider-artifactory/pull/1147) + ## 12.5.1 (November 22, 2024) BUG FIXES: From ffb5692a298d117df9b08714c1f530809850da9b Mon Sep 17 00:00:00 2001 From: JFrog CI Date: Mon, 9 Dec 2024 22:30:36 +0000 Subject: [PATCH 3/4] JFrog Pipelines - Add Artifactory version to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7324f962..73b0b6623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 12.6.0 (December 10, 2024) +## 12.6.0 (December 10, 2024). Tested on Artifactory 7.98.10 with Terraform 1.10.1 and OpenTofu 1.8.7 FEATURES: From 611d8a3285bccd12cb20d5759582fc3b6c02e437 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Tue, 10 Dec 2024 10:30:59 -0800 Subject: [PATCH 4/4] Update Artifactory docker image tags --- scripts/run-artifactory-container.sh | 2 +- scripts/run-artifactory.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run-artifactory-container.sh b/scripts/run-artifactory-container.sh index 286cb530d..f7920d227 100755 --- a/scripts/run-artifactory-container.sh +++ b/scripts/run-artifactory-container.sh @@ -4,7 +4,7 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" source "${SCRIPT_DIR}/get-access-key.sh" source "${SCRIPT_DIR}/wait-for-rt.sh" -export ARTIFACTORY_VERSION=${ARTIFACTORY_VERSION:-7.90.8} +export ARTIFACTORY_VERSION=${ARTIFACTORY_VERSION:-7.98.10} echo "ARTIFACTORY_VERSION=${ARTIFACTORY_VERSION}" > /dev/stderr set -euf diff --git a/scripts/run-artifactory.sh b/scripts/run-artifactory.sh index c39d25e40..55fc4fbd2 100755 --- a/scripts/run-artifactory.sh +++ b/scripts/run-artifactory.sh @@ -3,7 +3,7 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" source "${SCRIPT_DIR}/get-access-key.sh" source "${SCRIPT_DIR}/wait-for-rt.sh" -export ARTIFACTORY_VERSION=${ARTIFACTORY_VERSION:-7.90.8} +export ARTIFACTORY_VERSION=${ARTIFACTORY_VERSION:-7.98.10} echo "ARTIFACTORY_VERSION=${ARTIFACTORY_VERSION}" set -euf