Skip to content

Commit

Permalink
fix renaming a relation identifier (#7)
Browse files Browse the repository at this point in the history
* fix renaming a relation identifier

* bump ver

* docs and lint
  • Loading branch information
hedwigz authored Sep 4, 2022
1 parent fc19404 commit ae1cd8b
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ HOSTNAME=github.com
NAMESPACE=port-labs
NAME=port-labs
BINARY=terraform-provider-${NAME}
VERSION=0.2.0
VERSION=0.3.1
OS=$(shell go env GOOS)
ARCH=$(shell go env GOARCH)
OS_ARCH=${OS}_${ARCH}
Expand Down
3 changes: 2 additions & 1 deletion docs/resources/blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ Required:
Optional:

- `identifier` (String) The identifier of the relation
- `many` (Boolean) Whether or not the relation is many
- `many` (Boolean) Unsupported ATM.
Whether or not the relation is many
- `required` (Boolean) Whether or not the relation is required


20 changes: 19 additions & 1 deletion port/cli/relation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (c *PortClient) CreateRelation(ctx context.Context, bpID string, r *Relatio
if err != nil {
return "", err
}
if !result["ok"].(bool) {
if resp.StatusCode() > 299 || resp.StatusCode() < 200 || !result["ok"].(bool) {
return "", fmt.Errorf("failed to create relation, got: %s", resp.Body())
}
return result["identifier"].(string), nil
Expand Down Expand Up @@ -53,3 +53,21 @@ func (c *PortClient) ReadRelations(ctx context.Context, blueprintID string) ([]*
}
return bpRelations, nil
}

func (c *PortClient) DeleteRelation(ctx context.Context, blueprintID, relationID string) error {
url := "v1/blueprints/{blueprint_identifier}/relations/{relation_identifier}"
result := map[string]interface{}{}
resp, err := c.Client.R().
SetContext(ctx).
SetResult(&result).
SetPathParam("blueprint_identifier", blueprintID).
SetPathParam("relation_identifier", relationID).
Delete(url)
if err != nil {
return err
}
if !result["ok"].(bool) {
return fmt.Errorf("failed to delete relation, got: %s", resp.Body())
}
return nil
}
96 changes: 90 additions & 6 deletions port/resource_port_blueprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package port
import (
"context"

"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
Expand All @@ -15,7 +16,7 @@ func newBlueprintResource() *schema.Resource {
return &schema.Resource{
Description: "Port blueprint",
CreateContext: createBlueprint,
UpdateContext: createBlueprint,
UpdateContext: updateBlueprint,
ReadContext: readBlueprint,
DeleteContext: deleteBlueprint,
Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -68,9 +69,15 @@ func newBlueprintResource() *schema.Resource {
Description: "Whether or not the relation is required",
},
"many": {
Type: schema.TypeBool,
Optional: true,
Description: "Whether or not the relation is many",
Type: schema.TypeBool,
Optional: true,
ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics {
if i.(bool) {
return diag.Errorf("Many relations are not supported")
}
return nil
},
Description: "Unsupported ATM.\nWhether or not the relation is many",
},
},
},
Expand Down Expand Up @@ -244,8 +251,7 @@ func deleteBlueprint(ctx context.Context, d *schema.ResourceData, m interface{})
return diags
}

func createRelations(ctx context.Context, d *schema.ResourceData, m interface{}) error {
c := m.(*cli.PortClient)
func getRelations(d *schema.ResourceData) (rel []*cli.Relation) {
relations, ok := d.GetOk("relations")
if !ok {
return nil
Expand All @@ -265,6 +271,18 @@ func createRelations(ctx context.Context, d *schema.ResourceData, m interface{})
if req, ok := relation["required"]; ok {
r.Required = req.(bool)
}
if m, ok := relation["many"]; ok {
r.Many = m.(bool)
}
rel = append(rel, r)
}
return
}

func createRelations(ctx context.Context, d *schema.ResourceData, m interface{}) error {
c := m.(*cli.PortClient)
rels := getRelations(d)
for _, r := range rels {
_, err := c.CreateRelation(ctx, d.Id(), r)
if err != nil {
return err
Expand All @@ -273,6 +291,44 @@ func createRelations(ctx context.Context, d *schema.ResourceData, m interface{})
return nil
}

func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

// patchDeleteDeprecatedRelations deletes relations that are no longer present in the resource.
// This is necessary because we bundled relations inside the blueprint resource.
// In the future, the API of blueprints should support getting the relations and then we can delete this patch.
func patchDeleteDeprecatedRelations(ctx context.Context, d *schema.ResourceData, m interface{}) error {
c := m.(*cli.PortClient)
rels := getRelations(d)
ids := make([]string, len(rels))
for i, r := range rels {
ids[i] = r.Identifier
}
remoteRelations, err := c.ReadRelations(ctx, d.Id())
if err != nil {
return err
}
toDel := make([]*cli.Relation, 0)
for _, r := range remoteRelations {
if !contains(ids, r.Identifier) {
toDel = append(toDel, r)
}
}
for _, r := range toDel {
err := c.DeleteRelation(ctx, d.Id(), r.Identifier)
if err != nil {
return err
}
}
return nil
}

func createBlueprint(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
c := m.(*cli.PortClient)
Expand All @@ -297,6 +353,34 @@ func createBlueprint(ctx context.Context, d *schema.ResourceData, m interface{})
return diags
}

func updateBlueprint(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
c := m.(*cli.PortClient)
b, err := blueprintResourceToBody(d)
if err != nil {
return diag.FromErr(err)
}
var bp *cli.Blueprint
if d.Id() != "" {
bp, err = c.UpdateBlueprint(ctx, b, d.Id())
} else {
bp, err = c.CreateBlueprint(ctx, b)
}
if err != nil {
return diag.FromErr(err)
}
writeBlueprintComputedFieldsToResource(d, bp)
err = patchDeleteDeprecatedRelations(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
err = createRelations(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
return diags
}

func writeBlueprintComputedFieldsToResource(d *schema.ResourceData, b *cli.Blueprint) {
d.SetId(b.Identifier)
d.Set("created_at", b.CreatedAt.String())
Expand Down
86 changes: 86 additions & 0 deletions port/resource_port_blueprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,89 @@ func TestAccPortBlueprintUpdate(t *testing.T) {
},
})
}

func TestAccPortBlueprintUpdateRelation(t *testing.T) {
envID := genID()
vmID := genID()
var testAccActionConfigCreate = fmt.Sprintf(`
provider "port-labs" {}
resource "port-labs_blueprint" "Environment" {
title = "Environment"
icon = "Environment"
identifier = "%s"
properties {
identifier = "env_name"
type = "string"
title = "Name"
}
}
resource "port-labs_blueprint" "vm" {
title = "Virtual Machine"
icon = "Azure"
identifier = "%s"
properties {
identifier = "image"
type = "string"
title = "Image"
}
relations {
identifier = "vm-to-environment"
title = "Related Environment"
target = port-labs_blueprint.Environment.identifier
}
}
`, envID, vmID)
var testAccActionConfigUpdate = fmt.Sprintf(`
provider "port-labs" {}
resource "port-labs_blueprint" "Environment" {
title = "Environment"
icon = "Environment"
identifier = "%s"
properties {
identifier = "env_name"
type = "string"
title = "Name"
}
}
resource "port-labs_blueprint" "vm" {
title = "Virtual Machine"
icon = "Azure"
identifier = "%s"
properties {
identifier = "image"
type = "string"
title = "Image"
}
relations {
identifier = "environment"
title = "Related Environment"
target = port-labs_blueprint.Environment.identifier
}
}
`, envID, vmID)
resource.Test(t, resource.TestCase{
Providers: map[string]*schema.Provider{
"port-labs": Provider(),
},
Steps: []resource.TestStep{
{
Config: testAccActionConfigCreate,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.#", "1"),
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.0.title", "Related Environment"),
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.0.target", envID),
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.0.identifier", "vm-to-environment"),
),
},
{
Config: testAccActionConfigUpdate,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.#", "1"),
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.0.title", "Related Environment"),
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.0.target", envID),
resource.TestCheckResourceAttr("port-labs_blueprint.vm", "relations.0.identifier", "environment"),
),
},
},
})
}

0 comments on commit ae1cd8b

Please sign in to comment.