Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Google Container Registry feed #805

Merged
merged 8 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/resources/google_container_registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "octopusdeploy_google_container_registry Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
This resource manages a Google Container Registry feed in Octopus Deploy (alias of Docker Container Registry feed)
---

# octopusdeploy_google_container_registry (Resource)

This resource manages a Google Container Registry feed in Octopus Deploy (alias of Docker Container Registry feed)

## Example Usage

```terraform
resource "octopusdeploy_google_container_registry" "example" {
name = "Test Google Container Registry (OK to Delete)"
feed_uri = "https://google.docker.test"
registry_path = "testing/test-image"
password = "google authentication key file contents (json)"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `feed_uri` (String)
- `name` (String) The name of this resource.

### Optional

- `api_version` (String)
- `password` (String, Sensitive) The password associated with this resource.
- `registry_path` (String)
- `space_id` (String) The space ID associated with this Google container registry feed.
- `username` (String, Sensitive) The username associated with this resource.

### Read-Only

- `id` (String) The unique ID for this resource.

## Import

Import is supported using the following syntax:

```shell
terraform import [options] octopusdeploy_google_container_registry.<name> <feed-id>
```
4 changes: 2 additions & 2 deletions docs/resources/s3_feed.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
page_title: "octopusdeploy_s3_feed Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
This resource manages a OCI Registry feed in Octopus Deploy.
This resource manages a Amazon S3 Bucket feed in Octopus Deploy.
---

# octopusdeploy_s3_feed (Resource)

This resource manages a OCI Registry feed in Octopus Deploy.
This resource manages a Amazon S3 Bucket feed in Octopus Deploy.

## Example Usage

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import [options] octopusdeploy_google_container_registry.<name> <feed-id>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "octopusdeploy_google_container_registry" "example" {
name = "Test Google Container Registry (OK to Delete)"
feed_uri = "https://google.docker.test"
registry_path = "testing/test-image"
password = "google authentication key file contents (json)"
}
1 change: 1 addition & 0 deletions octopusdeploy_framework/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewMavenFeedResource,
NewOCIRegistryFeedResource,
NewS3FeedResource,
NewGoogleContainerRegistryFeedResource,
NewLifecycleResource,
NewEnvironmentResource,
NewStepTemplateResource,
Expand Down
176 changes: 176 additions & 0 deletions octopusdeploy_framework/resource_google_container_registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package octopusdeploy_framework

import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/path"

"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

type googleContainerRegistryFeedTypeResource struct {
*Config
}

func NewGoogleContainerRegistryFeedResource() resource.Resource {
return &googleContainerRegistryFeedTypeResource{}
}

var _ resource.ResourceWithImportState = &googleContainerRegistryFeedTypeResource{}

func (r *googleContainerRegistryFeedTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = util.GetTypeName("google_container_registry")
}

func (r *googleContainerRegistryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schemas.GoogleContainerRegistryFeedSchema{}.GetResourceSchema()
}

func (r *googleContainerRegistryFeedTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
r.Config = ResourceConfiguration(req, resp)
}

func (r *googleContainerRegistryFeedTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *schemas.GoogleContainerRegistryFeedTypeResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

dockerContainerRegistryFeed, err := createDockerContainerRegistryFeedResourceFromGoogleData(data)
if err != nil {
return
}

tflog.Info(ctx, fmt.Sprintf("creating Google Container Registry feed: %s", dockerContainerRegistryFeed.GetName()))

client := r.Config.Client
createdFeed, err := feeds.Add(client, dockerContainerRegistryFeed)
if err != nil {
resp.Diagnostics.AddError("unable to create Google Container Registry feed", err.Error())
return
}

updateGoogleDataFromDockerContainerRegistryFeed(data, data.SpaceID.ValueString(), createdFeed.(*feeds.DockerContainerRegistry))

tflog.Info(ctx, fmt.Sprintf("Google Container Registry feed created (%s)", data.ID))
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *googleContainerRegistryFeedTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *schemas.GoogleContainerRegistryFeedTypeResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Info(ctx, fmt.Sprintf("reading Google Container Registry feed (%s)", data.ID))

client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "google container registry feed"); err != nil {
resp.Diagnostics.AddError("unable to load Google Container Registry feed", err.Error())
}
return
}

dockerContainerRegistry := feed.(*feeds.DockerContainerRegistry)
updateGoogleDataFromDockerContainerRegistryFeed(data, data.SpaceID.ValueString(), dockerContainerRegistry)

tflog.Info(ctx, fmt.Sprintf("Google Container Registry feed read (%s)", dockerContainerRegistry.GetID()))
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *googleContainerRegistryFeedTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data, state *schemas.GoogleContainerRegistryFeedTypeResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Debug(ctx, fmt.Sprintf("updating Google Container Registry feed '%s'", data.ID.ValueString()))

feed, err := createDockerContainerRegistryFeedResourceFromGoogleData(data)
feed.ID = state.ID.ValueString()
if err != nil {
resp.Diagnostics.AddError("unable to load Google Container Registry feed", err.Error())
return
}

tflog.Info(ctx, fmt.Sprintf("updating Google Container Registry feed (%s)", data.ID))

client := r.Config.Client
updatedFeed, err := feeds.Update(client, feed)
if err != nil {
resp.Diagnostics.AddError("unable to update Google Container Registry feed", err.Error())
return
}

updateGoogleDataFromDockerContainerRegistryFeed(data, state.SpaceID.ValueString(), updatedFeed.(*feeds.DockerContainerRegistry))

tflog.Info(ctx, fmt.Sprintf("Google Container Registry feed updated (%s)", data.ID))

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *googleContainerRegistryFeedTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data schemas.GoogleContainerRegistryFeedTypeResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

if err := feeds.DeleteByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString()); err != nil {
resp.Diagnostics.AddError("unable to delete Google Container Registry feed", err.Error())
return
}
}

func createDockerContainerRegistryFeedResourceFromGoogleData(data *schemas.GoogleContainerRegistryFeedTypeResourceModel) (*feeds.DockerContainerRegistry, error) {
feed, err := feeds.NewDockerContainerRegistry(data.Name.ValueString())
if err != nil {
return nil, err
}

feed.ID = data.ID.ValueString()
feed.FeedURI = data.FeedUri.ValueString()
feed.PackageAcquisitionLocationOptions = nil
feed.Password = core.NewSensitiveValue(data.Password.ValueString())
feed.SpaceID = data.SpaceID.ValueString()
feed.Username = data.Username.ValueString()
feed.APIVersion = data.APIVersion.ValueString()
feed.RegistryPath = data.RegistryPath.ValueString()

return feed, nil
}

func updateGoogleDataFromDockerContainerRegistryFeed(data *schemas.GoogleContainerRegistryFeedTypeResourceModel, spaceId string, feed *feeds.DockerContainerRegistry) {
data.FeedUri = types.StringValue(feed.FeedURI)
data.Name = types.StringValue(feed.Name)
data.SpaceID = types.StringValue(spaceId)
if feed.APIVersion != "" {
data.APIVersion = types.StringValue(feed.APIVersion)
}
if feed.RegistryPath != "" {
data.RegistryPath = types.StringValue(feed.RegistryPath)
}
if feed.Username != "" {
data.Username = types.StringValue(feed.Username)
}

data.ID = types.StringValue(feed.ID)
}

func (*googleContainerRegistryFeedTypeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
135 changes: 135 additions & 0 deletions octopusdeploy_framework/resource_google_container_registry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package octopusdeploy_framework

import (
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"testing"
)

type googleFeedTestData struct {
name string
uri string
registryPath string
apiVersion string
username string
password string
}

func TestAccOctopusDeployGoogleFeed(t *testing.T) {
localName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
prefix := "octopusdeploy_google_container_registry." + localName
createData := googleFeedTestData{
name: acctest.RandStringFromCharSet(20, acctest.CharSetAlpha),
uri: "https://cloud.artifact.google.test",
registryPath: acctest.RandStringFromCharSet(10, acctest.CharSetAlpha),
apiVersion: acctest.RandStringFromCharSet(8, acctest.CharSetAlpha),
username: acctest.RandStringFromCharSet(16, acctest.CharSetAlpha),
password: acctest.RandStringFromCharSet(300, acctest.CharSetAlpha),
}
updateData := googleFeedTestData{
name: createData.name + "-updated",
uri: "https://testcloud.artifact.google.updated",
registryPath: createData.registryPath + "-updated",
apiVersion: createData.apiVersion + "-updated",
username: createData.username + "-updated",
password: createData.password + "-updated",
}
withMinimumData := googleFeedTestData{
name: "Google Registry Minimum",
uri: "https://testcloud.artifact.google.minimum",
}

resource.Test(t, resource.TestCase{
CheckDestroy: func(s *terraform.State) error { return testGoogleFeedCheckDestroy(s) },
PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
Config: testGoogleFeedBasic(createData, localName),
Check: testAssertGoogleFeedAttributes(createData, prefix),
},
{
Config: testGoogleFeedBasic(updateData, localName),
Check: testAssertGoogleFeedAttributes(updateData, prefix),
},
{
Config: testGoogleFeedWithMinimumData(withMinimumData, localName),
Check: testAssertGoogleFeedMinimumAttributes(withMinimumData, prefix),
},
},
})
}

func testGoogleFeedBasic(data googleFeedTestData, localName string) string {
return fmt.Sprintf(`
resource "octopusdeploy_google_container_registry" "%s" {
name = "%s"
feed_uri = "%s"
registry_path = "%s"
api_version = "%s"
username = "%s"
password = "%s"
}
`,
localName,
data.name,
data.uri,
data.registryPath,
data.apiVersion,
data.username,
data.password,
)
}

func testGoogleFeedWithMinimumData(data googleFeedTestData, localName string) string {
return fmt.Sprintf(`
resource "octopusdeploy_google_container_registry" "%s" {
name = "%s"
feed_uri = "%s"
}
`,
localName,
data.name,
data.uri,
)
}

func testAssertGoogleFeedAttributes(expected googleFeedTestData, prefix string) resource.TestCheckFunc {
return resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(prefix, "name", expected.name),
resource.TestCheckResourceAttr(prefix, "feed_uri", expected.uri),
resource.TestCheckResourceAttr(prefix, "registry_path", expected.registryPath),
resource.TestCheckResourceAttr(prefix, "api_version", expected.apiVersion),
resource.TestCheckResourceAttr(prefix, "username", expected.username),
resource.TestCheckResourceAttr(prefix, "password", expected.password),
)
}

func testAssertGoogleFeedMinimumAttributes(expected googleFeedTestData, prefix string) resource.TestCheckFunc {
return resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(prefix, "name", expected.name),
resource.TestCheckResourceAttr(prefix, "feed_uri", expected.uri),
resource.TestCheckNoResourceAttr(prefix, "registry_path"),
resource.TestCheckNoResourceAttr(prefix, "api_version"),
resource.TestCheckNoResourceAttr(prefix, "username"),
resource.TestCheckNoResourceAttr(prefix, "password"),
)
}

func testGoogleFeedCheckDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "octopusdeploy_google_container_registry_feed" {
continue
}

feed, err := feeds.GetByID(octoClient, octoClient.GetSpaceID(), rs.Primary.ID)
if err == nil && feed != nil {
return fmt.Errorf("google container registry feed (%s) still exists", rs.Primary.ID)
}
}

return nil
}
Loading
Loading