From 9021b0ca16a0693cd5988589c6d4553ec7c9fa40 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 6 Dec 2024 16:17:04 -0800 Subject: [PATCH] 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"), ), }, {