From e6c3101fafedc1cf7d727dd2cb4be20d8ac57224 Mon Sep 17 00:00:00 2001 From: Andre Moeller Date: Fri, 24 Jun 2022 16:28:05 +0200 Subject: [PATCH] feat(repository): Add resource and data source for hosted gitlfs repository --- docs/data-sources/repository_gitlfs_hosted.md | 53 ++++++ docs/resources/repository_gitlfs_hosted.md | 72 ++++++++ .../data-source.tf | 3 + .../nexus_repository_gitlfs_hosted/import.sh | 2 + .../resource.tf | 10 ++ .../template-strings-repository-gitlfs.go | 7 + internal/provider/main.go | 2 + .../data_source_repository_gitlfs_hosted.go | 31 ++++ ...ta_source_repository_gitlfs_hosted_test.go | 50 ++++++ .../resource_repository_gitlfs_hosted.go | 154 ++++++++++++++++++ .../resource_repository_gitlfs_hosted_test.go | 82 ++++++++++ 11 files changed, 466 insertions(+) create mode 100644 docs/data-sources/repository_gitlfs_hosted.md create mode 100644 docs/resources/repository_gitlfs_hosted.md create mode 100644 examples/data-sources/nexus_repository_gitlfs_hosted/data-source.tf create mode 100644 examples/resources/nexus_repository_gitlfs_hosted/import.sh create mode 100644 examples/resources/nexus_repository_gitlfs_hosted/resource.tf create mode 100644 internal/acceptance/template-strings-repository-gitlfs.go create mode 100644 internal/services/repository/data_source_repository_gitlfs_hosted.go create mode 100644 internal/services/repository/data_source_repository_gitlfs_hosted_test.go create mode 100644 internal/services/repository/resource_repository_gitlfs_hosted.go create mode 100644 internal/services/repository/resource_repository_gitlfs_hosted_test.go diff --git a/docs/data-sources/repository_gitlfs_hosted.md b/docs/data-sources/repository_gitlfs_hosted.md new file mode 100644 index 00000000..b1c8d1cb --- /dev/null +++ b/docs/data-sources/repository_gitlfs_hosted.md @@ -0,0 +1,53 @@ +--- +page_title: "Data Source nexus_repository_gitlfs_hosted" +subcategory: "Repository" +description: |- + Use this data source to get an existing hosted yum repository. +--- +# Data Source nexus_repository_gitlfs_hosted +Use this data source to get an existing hosted yum repository. +## Example Usage +```terraform +data "nexus_repository_gitlfs_hosted" "internal" { + name = "gitlfs-internal" +} +``` + +## Schema + +### Required + +- `name` (String) A unique identifier for this repository + +### Read-Only + +- `cleanup` (List of Object) Cleanup policies (see [below for nested schema](#nestedatt--cleanup)) +- `component` (List of Object) Component configuration for the hosted repository (see [below for nested schema](#nestedatt--component)) +- `id` (String) Used to identify data source at nexus +- `online` (Boolean) Whether this repository accepts incoming requests +- `storage` (List of Object) The storage configuration of the repository (see [below for nested schema](#nestedatt--storage)) + + +### Nested Schema for `cleanup` + +Read-Only: + +- `policy_names` (Set of String) + + + +### Nested Schema for `component` + +Read-Only: + +- `proprietary_components` (Boolean) + + + +### Nested Schema for `storage` + +Read-Only: + +- `blob_store_name` (String) +- `strict_content_type_validation` (Boolean) +- `write_policy` (String) diff --git a/docs/resources/repository_gitlfs_hosted.md b/docs/resources/repository_gitlfs_hosted.md new file mode 100644 index 00000000..9fd3482b --- /dev/null +++ b/docs/resources/repository_gitlfs_hosted.md @@ -0,0 +1,72 @@ +--- +page_title: "Resource nexus_repository_gitlfs_hosted" +subcategory: "Repository" +description: |- + Use this resource to create a hosted gitlfs repository. +--- +# Resource nexus_repository_gitlfs_hosted +Use this resource to create a hosted gitlfs repository. +## Example Usage +```terraform +resource "nexus_repository_gitlfs_hosted" "internal" { + name = "gitlfs-internal" + online = true + + storage { + blob_store_name = "default" + strict_content_type_validation = false + write_policy = "ALLOW" + } +} +``` + +## Schema + +### Required + +- `name` (String) A unique identifier for this repository +- `storage` (Block List, Min: 1, Max: 1) The storage configuration of the repository (see [below for nested schema](#nestedblock--storage)) + +### Optional + +- `cleanup` (Block List) Cleanup policies (see [below for nested schema](#nestedblock--cleanup)) +- `component` (Block List, Max: 1) Component configuration for the hosted repository (see [below for nested schema](#nestedblock--component)) +- `online` (Boolean) Whether this repository accepts incoming requests + +### Read-Only + +- `id` (String) Used to identify resource at nexus + + +### Nested Schema for `storage` + +Required: + +- `blob_store_name` (String) Blob store used to store repository contents +- `strict_content_type_validation` (Boolean) Whether to validate uploaded content's MIME type appropriate for the repository format + +Optional: + +- `write_policy` (String) Controls if deployments of and updates to assets are allowed + + + +### Nested Schema for `cleanup` + +Optional: + +- `policy_names` (Set of String) List of policy names + + + +### Nested Schema for `component` + +Required: + +- `proprietary_components` (Boolean) Components in this repository count as proprietary for namespace conflict attacks (requires Sonatype Nexus Firewall) +## Import +Import is supported using the following syntax: +```shell +# import using the name of repository +terraform import nexus_repository_gitlfs_hosted.internal gitlfs-internal +``` diff --git a/examples/data-sources/nexus_repository_gitlfs_hosted/data-source.tf b/examples/data-sources/nexus_repository_gitlfs_hosted/data-source.tf new file mode 100644 index 00000000..bb2fd8d3 --- /dev/null +++ b/examples/data-sources/nexus_repository_gitlfs_hosted/data-source.tf @@ -0,0 +1,3 @@ +data "nexus_repository_gitlfs_hosted" "internal" { + name = "gitlfs-internal" +} diff --git a/examples/resources/nexus_repository_gitlfs_hosted/import.sh b/examples/resources/nexus_repository_gitlfs_hosted/import.sh new file mode 100644 index 00000000..7b13db5e --- /dev/null +++ b/examples/resources/nexus_repository_gitlfs_hosted/import.sh @@ -0,0 +1,2 @@ +# import using the name of repository +terraform import nexus_repository_gitlfs_hosted.internal gitlfs-internal diff --git a/examples/resources/nexus_repository_gitlfs_hosted/resource.tf b/examples/resources/nexus_repository_gitlfs_hosted/resource.tf new file mode 100644 index 00000000..24a5d5a1 --- /dev/null +++ b/examples/resources/nexus_repository_gitlfs_hosted/resource.tf @@ -0,0 +1,10 @@ +resource "nexus_repository_gitlfs_hosted" "internal" { + name = "gitlfs-internal" + online = true + + storage { + blob_store_name = "default" + strict_content_type_validation = false + write_policy = "ALLOW" + } +} diff --git a/internal/acceptance/template-strings-repository-gitlfs.go b/internal/acceptance/template-strings-repository-gitlfs.go new file mode 100644 index 00000000..1ea12ab7 --- /dev/null +++ b/internal/acceptance/template-strings-repository-gitlfs.go @@ -0,0 +1,7 @@ +package acceptance + +const ( + TemplateStringRepositoryGitlfsHosted = ` +resource "nexus_repository_gitlfs_hosted" "acceptance" { +` + TemplateStringHostedRepository +) diff --git a/internal/provider/main.go b/internal/provider/main.go index 4303ae72..b017591f 100644 --- a/internal/provider/main.go +++ b/internal/provider/main.go @@ -34,6 +34,7 @@ func Provider() *schema.Provider { "nexus_repository_docker_group": repository.DataSourceRepositoryDockerGroup(), "nexus_repository_docker_hosted": repository.DataSourceRepositoryDockerHosted(), "nexus_repository_docker_proxy": repository.DataSourceRepositoryDockerProxy(), + "nexus_repository_gitlfs_hosted": repository.DataSourceRepositoryGitlfsHosted(), "nexus_repository_list": repository.DataSourceRepositoryList(), "nexus_repository_maven_group": repository.DataSourceRepositoryMavenGroup(), "nexus_repository_maven_hosted": repository.DataSourceRepositoryMavenHosted(), @@ -92,6 +93,7 @@ func Provider() *schema.Provider { "nexus_repository_docker_group": repository.ResourceRepositoryDockerGroup(), "nexus_repository_docker_hosted": repository.ResourceRepositoryDockerHosted(), "nexus_repository_docker_proxy": repository.ResourceRepositoryDockerProxy(), + "nexus_repository_gitlfs_hosted": repository.ResourceRepositoryGitlfsHosted(), "nexus_repository_maven_group": repository.ResourceRepositoryMavenGroup(), "nexus_repository_maven_hosted": repository.ResourceRepositoryMavenHosted(), "nexus_repository_maven_proxy": repository.ResourceRepositoryMavenProxy(), diff --git a/internal/services/repository/data_source_repository_gitlfs_hosted.go b/internal/services/repository/data_source_repository_gitlfs_hosted.go new file mode 100644 index 00000000..425a767f --- /dev/null +++ b/internal/services/repository/data_source_repository_gitlfs_hosted.go @@ -0,0 +1,31 @@ +package repository + +import ( + "github.com/datadrivers/terraform-provider-nexus/internal/schema/common" + "github.com/datadrivers/terraform-provider-nexus/internal/schema/repository" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceRepositoryGitlfsHosted() *schema.Resource { + return &schema.Resource{ + Description: "Use this data source to get an existing hosted yum repository.", + + Read: dataSourceRepositoryGitlfsHostedRead, + Schema: map[string]*schema.Schema{ + // Common schemas + "id": common.DataSourceID, + "name": repository.DataSourceName, + "online": repository.DataSourceOnline, + // Hosted schemas + "cleanup": repository.DataSourceCleanup, + "component": repository.DataSourceComponent, + "storage": repository.DataSourceHostedStorage, + }, + } +} + +func dataSourceRepositoryGitlfsHostedRead(d *schema.ResourceData, m interface{}) error { + d.SetId(d.Get("name").(string)) + + return resourceGitlfsHostedRepositoryRead(d, m) +} diff --git a/internal/services/repository/data_source_repository_gitlfs_hosted_test.go b/internal/services/repository/data_source_repository_gitlfs_hosted_test.go new file mode 100644 index 00000000..5926e13d --- /dev/null +++ b/internal/services/repository/data_source_repository_gitlfs_hosted_test.go @@ -0,0 +1,50 @@ +package repository_test + +import ( + "fmt" + "strconv" + "testing" + + "github.com/datadrivers/go-nexus-client/nexus3/schema/repository" + "github.com/datadrivers/terraform-provider-nexus/internal/acceptance" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccDataSourceRepositoryGitlfsHostedConfig() string { + return ` +data "nexus_repository_gitlfs_hosted" "acceptance" { + name = nexus_repository_gitlfs_hosted.acceptance.id +}` +} + +func TestAccDataSourceRepositoryGitlfsHosted(t *testing.T) { + repoUsingDefaults := repository.GitLfsHostedRepository{ + Name: fmt.Sprintf("acceptance-%s", acctest.RandString(10)), + Online: true, + Storage: repository.HostedStorage{ + BlobStoreName: "default", + StrictContentTypeValidation: false, + }, + } + dataSourceName := "data.nexus_repository_gitlfs_hosted.acceptance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.AccPreCheck(t) }, + Providers: acceptance.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccResourceRepositoryGitlfsHostedConfig(repoUsingDefaults) + testAccDataSourceRepositoryGitlfsHostedConfig(), + Check: resource.ComposeTestCheckFunc( + resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "id", repoUsingDefaults.Name), + resource.TestCheckResourceAttr(dataSourceName, "name", repoUsingDefaults.Name), + resource.TestCheckResourceAttr(dataSourceName, "online", strconv.FormatBool(repoUsingDefaults.Online)), + resource.TestCheckResourceAttr(dataSourceName, "storage.0.blob_store_name", repoUsingDefaults.Storage.BlobStoreName), + resource.TestCheckResourceAttr(dataSourceName, "storage.0.strict_content_type_validation", strconv.FormatBool(repoUsingDefaults.Storage.StrictContentTypeValidation)), + ), + ), + }, + }, + }) +} diff --git a/internal/services/repository/resource_repository_gitlfs_hosted.go b/internal/services/repository/resource_repository_gitlfs_hosted.go new file mode 100644 index 00000000..31f13c21 --- /dev/null +++ b/internal/services/repository/resource_repository_gitlfs_hosted.go @@ -0,0 +1,154 @@ +package repository + +import ( + nexus "github.com/datadrivers/go-nexus-client/nexus3" + "github.com/datadrivers/go-nexus-client/nexus3/schema/repository" + "github.com/datadrivers/terraform-provider-nexus/internal/schema/common" + repositorySchema "github.com/datadrivers/terraform-provider-nexus/internal/schema/repository" + "github.com/datadrivers/terraform-provider-nexus/internal/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceRepositoryGitlfsHosted() *schema.Resource { + return &schema.Resource{ + Description: "Use this resource to create a hosted gitlfs repository.", + + Create: resourceGitlfsHostedRepositoryCreate, + Delete: resourceGitlfsHostedRepositoryDelete, + Exists: resourceGitlfsHostedRepositoryExists, + Read: resourceGitlfsHostedRepositoryRead, + Update: resourceGitlfsHostedRepositoryUpdate, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + // Common schemas + "id": common.ResourceID, + "name": repositorySchema.ResourceName, + "online": repositorySchema.ResourceOnline, + // Hosted schemas + "cleanup": repositorySchema.ResourceCleanup, + "component": repositorySchema.ResourceComponent, + "storage": repositorySchema.ResourceHostedStorage, + }, + } +} + +func getGitlfsHostedRepositoryFromResourceData(resourceData *schema.ResourceData) repository.GitLfsHostedRepository { + storageConfig := resourceData.Get("storage").([]interface{})[0].(map[string]interface{}) + writePolicy := repository.StorageWritePolicy(storageConfig["write_policy"].(string)) + + repo := repository.GitLfsHostedRepository{ + Name: resourceData.Get("name").(string), + Online: resourceData.Get("online").(bool), + Storage: repository.HostedStorage{ + BlobStoreName: storageConfig["blob_store_name"].(string), + StrictContentTypeValidation: storageConfig["strict_content_type_validation"].(bool), + WritePolicy: &writePolicy, + }, + } + + cleanupList := resourceData.Get("cleanup").([]interface{}) + if len(cleanupList) > 0 && cleanupList[0] != nil { + cleanupConfig := cleanupList[0].(map[string]interface{}) + if len(cleanupConfig) > 0 { + policy_names, ok := cleanupConfig["policy_names"] + if ok { + repo.Cleanup = &repository.Cleanup{ + PolicyNames: tools.InterfaceSliceToStringSlice(policy_names.(*schema.Set).List()), + } + } + } + } + + componentList := resourceData.Get("component").([]interface{}) + if len(componentList) > 0 && componentList[0] != nil { + componentConfig := componentList[0].(map[string]interface{}) + if len(componentConfig) > 0 { + repo.Component = &repository.Component{ + ProprietaryComponents: componentConfig["proprietary_components"].(bool), + } + } + } + + return repo +} + +func setGitlfsHostedRepositoryToResourceData(repo *repository.GitLfsHostedRepository, resourceData *schema.ResourceData) error { + resourceData.SetId(repo.Name) + resourceData.Set("name", repo.Name) + resourceData.Set("online", repo.Online) + + if err := resourceData.Set("storage", flattenHostedStorage(&repo.Storage)); err != nil { + return err + } + + if repo.Cleanup != nil { + if err := resourceData.Set("cleanup", flattenCleanup(repo.Cleanup)); err != nil { + return err + } + } + + if repo.Component != nil { + if err := resourceData.Set("component", flattenComponent(repo.Component)); err != nil { + return err + } + } + + return nil +} + +func resourceGitlfsHostedRepositoryCreate(resourceData *schema.ResourceData, m interface{}) error { + client := m.(*nexus.NexusClient) + + repo := getGitlfsHostedRepositoryFromResourceData(resourceData) + + if err := client.Repository.GitLfs.Hosted.Create(repo); err != nil { + return err + } + resourceData.SetId(repo.Name) + + return resourceGitlfsHostedRepositoryRead(resourceData, m) +} + +func resourceGitlfsHostedRepositoryRead(resourceData *schema.ResourceData, m interface{}) error { + client := m.(*nexus.NexusClient) + + repo, err := client.Repository.GitLfs.Hosted.Get(resourceData.Id()) + if err != nil { + return err + } + + if repo == nil { + resourceData.SetId("") + return nil + } + + return setGitlfsHostedRepositoryToResourceData(repo, resourceData) +} + +func resourceGitlfsHostedRepositoryUpdate(resourceData *schema.ResourceData, m interface{}) error { + client := m.(*nexus.NexusClient) + + repoName := resourceData.Id() + repo := getGitlfsHostedRepositoryFromResourceData(resourceData) + + if err := client.Repository.GitLfs.Hosted.Update(repoName, repo); err != nil { + return err + } + + return resourceGitlfsHostedRepositoryRead(resourceData, m) +} + +func resourceGitlfsHostedRepositoryDelete(resourceData *schema.ResourceData, m interface{}) error { + client := m.(*nexus.NexusClient) + return client.Repository.GitLfs.Hosted.Delete(resourceData.Id()) +} + +func resourceGitlfsHostedRepositoryExists(resourceData *schema.ResourceData, m interface{}) (bool, error) { + client := m.(*nexus.NexusClient) + + repo, err := client.Repository.GitLfs.Hosted.Get(resourceData.Id()) + return repo != nil, err +} diff --git a/internal/services/repository/resource_repository_gitlfs_hosted_test.go b/internal/services/repository/resource_repository_gitlfs_hosted_test.go new file mode 100644 index 00000000..f5b8fe00 --- /dev/null +++ b/internal/services/repository/resource_repository_gitlfs_hosted_test.go @@ -0,0 +1,82 @@ +package repository_test + +import ( + "bytes" + "fmt" + "strconv" + "testing" + "text/template" + + "github.com/datadrivers/go-nexus-client/nexus3/schema/repository" + "github.com/datadrivers/terraform-provider-nexus/internal/acceptance" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccResourceRepositoryGitlfsHosted() repository.GitLfsHostedRepository { + writePolicy := repository.StorageWritePolicyAllow + + return repository.GitLfsHostedRepository{ + Name: fmt.Sprintf("test-repo-%s", acctest.RandString(10)), + Online: true, + Storage: repository.HostedStorage{ + BlobStoreName: "default", + StrictContentTypeValidation: true, + WritePolicy: &writePolicy, + }, + Cleanup: &repository.Cleanup{ + PolicyNames: []string{"cleanup-weekly"}, + }, + Component: &repository.Component{ + ProprietaryComponents: true, + }, + } +} + +func testAccResourceRepositoryGitlfsHostedConfig(repo repository.GitLfsHostedRepository) string { + buf := &bytes.Buffer{} + resourceRepositoryGitlfsHostedTemplate := template.Must(template.New("GitlfsHostedRepository").Funcs(acceptance.TemplateFuncMap).Parse(acceptance.TemplateStringRepositoryGitlfsHosted)) + if err := resourceRepositoryGitlfsHostedTemplate.Execute(buf, repo); err != nil { + panic(err) + } + return buf.String() +} + +func TestAccResourceRepositoryGitlfsHosted(t *testing.T) { + repo := testAccResourceRepositoryGitlfsHosted() + resourceName := "nexus_repository_gitlfs_hosted.acceptance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.AccPreCheck(t) }, + Providers: acceptance.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccResourceRepositoryGitlfsHostedConfig(repo), + Check: resource.ComposeTestCheckFunc( + resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", repo.Name), + resource.TestCheckResourceAttr(resourceName, "name", repo.Name), + resource.TestCheckResourceAttr(resourceName, "online", strconv.FormatBool(repo.Online)), + ), + resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "storage.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage.0.blob_store_name", repo.Storage.BlobStoreName), + resource.TestCheckResourceAttr(resourceName, "storage.0.strict_content_type_validation", strconv.FormatBool(repo.Storage.StrictContentTypeValidation)), + resource.TestCheckResourceAttr(resourceName, "storage.0.write_policy", string(*repo.Storage.WritePolicy)), + resource.TestCheckResourceAttr(resourceName, "cleanup.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cleanup.0.policy_names.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cleanup.0.policy_names.0", repo.Cleanup.PolicyNames[0]), + resource.TestCheckResourceAttr(resourceName, "component.#", "1"), + resource.TestCheckResourceAttr(resourceName, "component.0.proprietary_components", strconv.FormatBool(repo.Component.ProprietaryComponents)), + ), + ), + }, + { + ResourceName: resourceName, + ImportStateId: repo.Name, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +}