Skip to content

Commit

Permalink
FFM-9085: Add a terraform resource to create a new target
Browse files Browse the repository at this point in the history
* Implement CRUD actions for creating a new target in terraform
* Add all the interfaces and implementations
* Add unit test
* Fix package path
* Add build script
  • Loading branch information
ribeirophillipe committed Aug 28, 2023
1 parent 98989f9 commit 1bf692a
Show file tree
Hide file tree
Showing 8 changed files with 436 additions and 13 deletions.
22 changes: 14 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,23 @@ default: testacc
test:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m

# build:
# go build -o ${BINARY}
build:
go build -o ${BINARY}

# install: build
# mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
# mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
install: build
mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}

# test:
# go test $(TEST) || exit 1
# echo $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4
test:
go test $(TEST) || exit 1
echo $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4

sweep:
@echo "WARNING: This will destroy infrastructure. Use only in development accounts."
go test $(SWEEP_DIR) -v -sweep=all $(SWEEPARGS) -timeout 60m

vendor:
go mod vendor

tidy:
go mod tidy
4 changes: 3 additions & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"

"github.com/harness/terraform-provider-harness/internal/service/platform/feature_flag"
"github.com/harness/terraform-provider-harness/internal/service/platform/feature_flag_target"
"github.com/harness/terraform-provider-harness/internal/service/platform/ff_api_key"
"github.com/harness/terraform-provider-harness/internal/service/platform/gitops/agent_yaml"
"github.com/harness/terraform-provider-harness/internal/service/platform/manual_freeze"
Expand Down Expand Up @@ -266,8 +267,9 @@ func Provider(version string) func() *schema.Provider {
"harness_platform_environment_group": pl_environment_group.ResourceEnvironmentGroup(),
"harness_platform_environment_clusters_mapping": pl_environment_clusters_mapping.ResourceEnvironmentClustersMapping(),
"harness_platform_environment_service_overrides": pl_environment_service_overrides.ResourceEnvironmentServiceOverrides(),
"harness_platform_service_overrides_v2": pl_service_overrides_v2.ResourceServiceOverrides(),
"harness_platform_feature_flag": feature_flag.ResourceFeatureFlag(),
"harness_platform_feature_flag_target": feature_flag_target.ResourceFeatureFlagTarget(),
"harness_platform_service_overrides_v2": pl_service_overrides_v2.ResourceServiceOverrides(),
"harness_platform_ff_api_key": ff_api_key.ResourceFFApiKey(),
"harness_platform_gitops_agent": gitops_agent.ResourceGitopsAgent(),
"harness_platform_gitops_applications": gitops_applications.ResourceGitopsApplication(),
Expand Down
3 changes: 2 additions & 1 deletion internal/service/cd/delegate/delegate_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/harness/harness-go-sdk/harness/cd/graphql"
"github.com/harness/harness-go-sdk/harness/delegate"
Expand Down Expand Up @@ -63,7 +64,7 @@ func deleteDelegate(t *testing.T, name string) {
cli, err := client.NewClientWithOpts(client.FromEnv)
require.NoError(t, err, "failed to create docker client: %s", err)

err = cli.ContainerStop(context.Background(), name, nil)
err = cli.ContainerStop(context.Background(), name, container.StopOptions{})
require.NoError(t, err, "failed to stop delegate container: %s", err)

err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package feature_flag

import (
"context"
"io/ioutil"
"io"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -209,7 +209,7 @@ func resourceFeatureFlagCreate(ctx context.Context, d *schema.ResourceData, meta
resp, httpResp, err = c.FeatureFlagsApi.GetFeatureFlag(ctx, id, c.AccountId, qp.OrganizationId, qp.ProjectId, readOpts)

if err != nil {
body, _ := ioutil.ReadAll(httpResp.Body)
body, _ := io.ReadAll(httpResp.Body)
return diag.Errorf("readstatus: %s, \nBody:%s", httpResp.Status, body)
//return helpers.HandleReadApiError(err, d, httpResp)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package feature_flag_target

import (
"context"
"io"
"net/http"
"time"

"github.com/antihax/optional"
"github.com/harness/harness-go-sdk/harness/nextgen"
"github.com/harness/terraform-provider-harness/helpers"
"github.com/harness/terraform-provider-harness/internal"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func ResourceFeatureFlagTarget() *schema.Resource {
resource := &schema.Resource{
Description: "Resource for managing Feature Flag Targets.",

ReadContext: resourceFeatureFlagTargetRead,
DeleteContext: resourceFeatureFlagTargetDelete,
CreateContext: resourceFeatureFlagTargetCreateOrUpdate,
UpdateContext: resourceFeatureFlagTargetUpdate,
Importer: helpers.ProjectResourceImporter,

Schema: map[string]*schema.Schema{
"identifier": {
Description: "Identifier of the Feature Flag Target",
Type: schema.TypeString,
Required: true,
ForceNew: false,
},
"org_id": {
Description: "Organization Identifier",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"project_id": {
Description: "Project Identifier",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"environment": {
Description: "Environment Identifier",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"account_id": {
Description: "Account Identifier",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"name": {
Description: "Target Name",
Type: schema.TypeString,
Required: true,
},
"attributes": {
Description: "Attributes",
Type: schema.TypeMap,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}

return resource
}

// FFTargetQueryParameters is the query parameters for the feature flag target
type FFTargetQueryParameters struct {
Identifier string
OrganizationID string
ProjectID string
AccountID string
Environment string
}

// FFTargetOpts is the options for the feature flag target
type FFTargetOpts struct {
Name string
Atributes map[string]interface{}
}

// resourceFeatureFlagTargetRead is the read function for the feature flag target
func resourceFeatureFlagTargetRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx)
id := d.Id()

if id == "" {
d.MarkNewResource()
return nil
}

qp := buildFFTargetQueryParameters(d)

resp, httpResp, err := c.TargetsApi.GetTarget(ctx, id, c.AccountId, qp.OrganizationID, qp.ProjectID, qp.Environment)

if err != nil {
return helpers.HandleReadApiError(err, d, httpResp)
}

readFeatureFlagTarget(d, &resp, *qp)

return nil
}

// resourceFeatureFlagTargetDelete is the delete function for the feature flag target
func resourceFeatureFlagTargetDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx)

id := d.Id()
if id == "" {
return nil
}

qp := buildFFTargetQueryParameters(d)

httpResp, err := c.TargetsApi.DeleteTarget(ctx, id, c.AccountId, qp.OrganizationID, qp.ProjectID, qp.Environment)
if err != nil {
return helpers.HandleApiError(err, d, httpResp)
}
return nil
}

// resourceFeatureFlagTargetCreateOrUpdate is the create function for the feature flag target
func resourceFeatureFlagTargetCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx)

var err error
var httpResp *http.Response
target := buildFFTargetCreate(d)
qp := buildFFTargetQueryParameters(d)
id := d.Id()

if id == "" {
httpResp, err = c.TargetsApi.CreateTarget(ctx, target, c.AccountId, qp.OrganizationID)
} else {
target, httpResp, err = c.TargetsApi.ModifyTarget(ctx, target, c.AccountId, qp.OrganizationID, qp.ProjectID, qp.Environment, id)
}

if err != nil {
return helpers.HandleApiError(err, d, httpResp)
}

readFeatureFlagTarget(d, &target, *qp)

return nil
}

// resourceFeatureFlagTargetUpdate is the update function for the feature flag target
func resourceFeatureFlagTargetUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx)

id := d.Id()
if id == "" {
id = d.Get("identifier").(string)
d.MarkNewResource()
}

qp := buildFFTargetQueryParameters(d)
opts := buildFFTargetPatchOpts(d)

var err error
var target nextgen.Target
var httpResp *http.Response

target, httpResp, err = c.TargetsApi.PatchTarget(ctx, c.AccountId, qp.OrganizationID, qp.ProjectID, qp.Environment, id, opts)
if err != nil {
body, _ := io.ReadAll(httpResp.Body)
return diag.Errorf("readstatus: %s, \nBody:%s", httpResp.Status, body)
}

readFeatureFlagTarget(d, &target, *qp)

return nil
}

// readFeatureFlagTarget is the read function for the feature flag target
func readFeatureFlagTarget(d *schema.ResourceData, flag *nextgen.Target, qp FFTargetQueryParameters) {
d.Set("identifier", qp.Identifier)
d.Set("org_id", qp.OrganizationID)
d.Set("project_id", qp.ProjectID)
d.Set("environment", qp.Environment)
d.Set("account_id", qp.AccountID)
d.Set("name", flag.Name)
d.Set("attributes", flag.Attributes)
}

// buildFFTargetQueryParameters is the query parameters for the feature flag target
func buildFFTargetQueryParameters(d *schema.ResourceData) *FFTargetQueryParameters {
return &FFTargetQueryParameters{
Identifier: d.Get("identifier").(string),
OrganizationID: d.Get("org_id").(string),
ProjectID: d.Get("project_id").(string),
AccountID: d.Get("account_id").(string),
Environment: d.Get("environment").(string),
}
}

// buildFFTargetCreateOpts
func buildFFTargetCreate(d *schema.ResourceData) nextgen.Target {
attribute := d.Get("attributes")
return nextgen.Target{
Account: d.Get("account_id").(string),
Attributes: &attribute,
Environment: d.Get("environment").(string),
Identifier: d.Get("identifier").(string),
Org: d.Get("org_id").(string),
Name: d.Get("name").(string),
Project: d.Get("project_id").(string),
CreatedAt: time.Now().Unix(),
}
}

// buildFFTargetPatchOpts is the options for the feature flag target
func buildFFTargetPatchOpts(d *schema.ResourceData) *nextgen.TargetsApiPatchTargetOpts {
opts := &FFTargetOpts{
Name: d.Get("name").(string),
Atributes: d.Get("attributes").(map[string]interface{}),
}

return &nextgen.TargetsApiPatchTargetOpts{
Body: optional.NewInterface(opts),
}
}
Loading

0 comments on commit 1bf692a

Please sign in to comment.