diff --git a/client/misc.go b/client/misc.go index e4f0ab8..bbe49b3 100644 --- a/client/misc.go +++ b/client/misc.go @@ -19,6 +19,9 @@ func GetSchedule(schedule string) (typefmt string, cronfmt string) { case "weekly", "0 0 0 * * 0": TypeStr = "Weekly" CronStr = "0 0 0 * * 0" + case "": + TypeStr = "None" + CronStr = "" default: TypeStr = "Custom" CronStr = schedule diff --git a/client/system.go b/client/system.go index fdb0be5..c6b08cd 100644 --- a/client/system.go +++ b/client/system.go @@ -16,6 +16,8 @@ func GetSystemBoby(d *schema.ResourceData, scheduleType string) models.SystemBod schedule = d.Get("schedule").(string) } else if scheduleType == "vuln" { schedule = d.Get("vulnerability_scan_policy").(string) + } else if scheduleType == "purgeaudit" { + schedule = d.Get("schedule").(string) } TypeStr, CronStr := GetSchedule(schedule) @@ -25,6 +27,9 @@ func GetSystemBoby(d *schema.ResourceData, scheduleType string) models.SystemBod body.Schedule.Cron = CronStr if scheduleType == "gc" { body.Parameters.DeleteUntagged = d.Get("delete_untagged").(bool) + } else if scheduleType == "purgeaudit" { + body.Parameters.AuditRetentionHour = d.Get("audit_retention_hour").(int) + body.Parameters.IncludeOperations = d.Get("include_operations").(string) } return body @@ -38,6 +43,8 @@ func (client *Client) SetSchedule(d *schema.ResourceData, scheduleType string) ( path = models.PathGC } else if scheduleType == "vuln" { path = models.PathVuln + } else if scheduleType == "purgeaudit" { + path = models.PathPurgeAudit } body := GetSystemBoby(d, scheduleType) diff --git a/docs/index.md b/docs/index.md index 3e79178..49fe838 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,6 +6,7 @@ The Harbor provider is used to configure an instance of Harbor. The provider nee * [Resource: harbor_config_system](resources/config_system.md) * [Resource: harbor_config_email](resources/config_email.md) * [Resource: harbor_garbage_collection](resources/garbage_collection.md) +* [Resource: harbor_purge_audit_log](resources/purge-audit-log.md) * [Resource: harbor_immutable_tag_rule](resources/immutable_tag_rule.md) * [Resource: harbor_interrogation_services](resources/interrogation_services.md) * [Resource: harbor_label](resources/label.md) diff --git a/docs/resources/purge-audit-log.md b/docs/resources/purge-audit-log.md new file mode 100644 index 0000000..95221d4 --- /dev/null +++ b/docs/resources/purge-audit-log.md @@ -0,0 +1,18 @@ +# Resource: harbor_purge_audit_log + +## Example Usage +```hcl +resource "harbor_purge_audit_log" "main" { + schedule = "Daily" + audit_retention_hour = 24 + include_operations = "create,pull" +} +``` + +## Argument Reference +The following arguments are supported: +* **schedule** - (Required) Sets the schedule how often the Garbage Collection will run. Can be to `"Hourly"`, `"Daily"`, `"Weekly"` or can be a custom cron string ie, `"5 4 * * *"` + +* **audit_retention_hour** - (Required) to configure how long audit logs should be kept. For example, if you set this to 24 Harbor will only purge audit logs that are 24 or more hours old. + +* **include_operations** - (Required) valid values are `create` `delete` `pull`, thoses values can be comma separated. When Create, Delete, or Pull is set, Harbor will include audit logs for those operations in the purge. \ No newline at end of file diff --git a/models/system.go b/models/system.go index d9ac5ea..257061c 100644 --- a/models/system.go +++ b/models/system.go @@ -6,9 +6,12 @@ var PathVuln = "/system/scanAll/schedule" var PathScanners = "/scanners" var PathGC = "/system/gc/schedule" +var PathPurgeAudit = "/system/purgeaudit/schedule" type JobParameters struct { - DeleteUntagged bool `json:"delete_untagged"` + DeleteUntagged bool `json:"delete_untagged,omitempty"` + AuditRetentionHour int `json:"audit_retention_hour,omitempty"` + IncludeOperations string `json:"include_operations,omitempty"` } type SystemBody struct { @@ -25,10 +28,12 @@ type SystemBody struct { CreationTime time.Time `json:"creation_time,omitempty"` UpdateTime time.Time `json:"update_time,omitempty"` Parameters struct { - DeleteUntagged bool `json:"delete_untagged,omitempty"` - AdditionalProp1 bool `json:"additionalProp1,omitempty"` - AdditionalProp2 bool `json:"additionalProp2,omitempty"` - AdditionalProp3 bool `json:"additionalProp3,omitempty"` + DeleteUntagged bool `json:"delete_untagged,omitempty"` + AuditRetentionHour int `json:"audit_retention_hour,omitempty"` + IncludeOperations string `json:"include_operations,omitempty"` + AdditionalProp1 bool `json:"additionalProp1,omitempty"` + AdditionalProp2 bool `json:"additionalProp2,omitempty"` + AdditionalProp3 bool `json:"additionalProp3,omitempty"` } `json:"parameters"` } diff --git a/provider/provider.go b/provider/provider.go index bef7745..5e9bf84 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -57,6 +57,7 @@ func Provider() *schema.Provider { "harbor_replication": resourceReplication(), "harbor_retention_policy": resourceRetention(), "harbor_garbage_collection": resourceGC(), + "harbor_purge_audit_log": resourcePurgeAudit(), "harbor_label": resourceLabel(), "harbor_immutable_tag_rule": resourceImmutableTagRule(), }, diff --git a/provider/resource_log_rotation.go b/provider/resource_log_rotation.go new file mode 100644 index 0000000..2862930 --- /dev/null +++ b/provider/resource_log_rotation.go @@ -0,0 +1,120 @@ +package provider + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/goharbor/terraform-provider-harbor/client" + "github.com/goharbor/terraform-provider-harbor/models" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourcePurgeAudit() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "schedule": { + Type: schema.TypeString, + Required: true, + }, + "audit_retention_hour": { + Type: schema.TypeInt, + Required: true, + }, + "include_operations": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateIncludeOperations, + }, + }, + Create: resourcePurgeAuditCreate, + Read: resourcePurgeAuditRead, + Update: resourcePurgeAuditUpdate, + Delete: resourcePurgeAuditDelete, + } +} + +func resourcePurgeAuditCreate(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + err := apiClient.SetSchedule(d, "purgeaudit") + if err != nil { + return err + } + d.SetId(models.PathPurgeAudit) + return resourcePurgeAuditRead(d, m) +} + +func resourcePurgeAuditRead(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + + resp, _, respCode, err := apiClient.SendRequest("GET", models.PathPurgeAudit, nil, 200) + if respCode == 404 && err != nil { + d.SetId("") + return fmt.Errorf("resource not found %s", d.Id()) + } + if len(resp) == 0 { + d.SetId("") + return nil + } + + var jsonData models.SystemBody + err = json.Unmarshal([]byte(resp), &jsonData) + if err != nil { + return err + } + jobParameters := jsonData.JobParameters + + var jsonJobParameters models.JobParameters + err = json.Unmarshal([]byte(jobParameters), &jsonJobParameters) + if err != nil { + fmt.Println(err) + } + + if jsonData.Schedule.Type == "Custom" { + d.Set("schedule", jsonData.Schedule.Cron) + } else { + d.Set("schedule", jsonData.Schedule.Type) + } + d.Set("audit_retention_hour", jsonJobParameters.AuditRetentionHour) + d.Set("include_operations", jsonJobParameters.IncludeOperations) + return nil +} + +func resourcePurgeAuditUpdate(d *schema.ResourceData, m interface{}) error { + return resourcePurgeAuditCreate(d, m) +} + +func resourcePurgeAuditDelete(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + d.Set("schedule", "") + err := apiClient.SetSchedule(d, "purgeaudit") + if err != nil { + return err + } + d.SetId("") + return nil +} + +func validateIncludeOperations(v interface{}, k string) (warns []string, errs []error) { + includeOperations := v.(string) + validValues := []string{"create", "pull", "delete"} + + ops := strings.Split(includeOperations, ",") + for _, op := range ops { + op = strings.TrimSpace(op) + if !containsString(validValues, op) { + errs = append(errs, fmt.Errorf("Invalid value %q in %q. Valid values are: create, pull, delete", op, k)) + } + } + + return warns, errs +} + +func containsString(arr []string, value string) bool { + for _, v := range arr { + if v == value { + return true + } + } + return false +} diff --git a/provider/resource_log_rotation_test.go b/provider/resource_log_rotation_test.go new file mode 100644 index 0000000..29b6c77 --- /dev/null +++ b/provider/resource_log_rotation_test.go @@ -0,0 +1,42 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const resourcePurgeAuditMain = "harbor_purge_audit_log.main" + +func TestAccPurgeAuditUpdate(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + // CheckDestroy: testAccCheckLabelDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPurgeAuditBasic(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(resourcePurgeAuditMain), + resource.TestCheckResourceAttr( + resourcePurgeAuditMain, "schedule", "Daily"), + resource.TestCheckResourceAttr( + resourcePurgeAuditMain, "audit_retention_hour", "24"), + resource.TestCheckResourceAttr( + resourcePurgeAuditMain, "include_operations", "create,pull"), + ), + }, + }, + }) +} + +func testAccCheckPurgeAuditBasic() string { + return fmt.Sprintf(` + resource "harbor_purge_audit_log" "main" { + schedule = "Daily" + audit_retention_hour = 24 + include_operations = "create,pull" + } + `) +}