diff --git a/port/resource_port_action.go b/port/resource_port_action.go index 5eeddec0..71e28826 100644 --- a/port/resource_port_action.go +++ b/port/resource_port_action.go @@ -3,7 +3,9 @@ package port import ( "context" "encoding/json" + "fmt" "strconv" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -211,13 +213,29 @@ func newActionResource() *schema.Resource { Description: "Whether the action requires approval or not", }, }, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, } } func readAction(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { var diags diag.Diagnostics c := m.(*cli.PortClient) - action, statusCode, err := c.ReadAction(ctx, d.Get("blueprint_identifier").(string), d.Id()) + id := d.Id() + actionIdentifier := id + blueprintIdentifier := d.Get("blueprint_identifier").(string) + if strings.Contains(id, ":") { + parts := strings.SplitN(id, ":", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return diag.FromErr(fmt.Errorf("unexpected format of ID (%s), expected blueprintId:entityId", id)) + } + + blueprintIdentifier = parts[0] + actionIdentifier = parts[1] + } + + action, statusCode, err := c.ReadAction(ctx, blueprintIdentifier, actionIdentifier) if err != nil { if statusCode == 404 { d.SetId("") @@ -226,12 +244,14 @@ func readAction(ctx context.Context, d *schema.ResourceData, m interface{}) diag return diag.FromErr(err) } - writeActionFieldsToResource(d, action) + writeActionFieldsToResource(d, action, blueprintIdentifier) return diags } -func writeActionFieldsToResource(d *schema.ResourceData, action *cli.Action) { +func writeActionFieldsToResource(d *schema.ResourceData, action *cli.Action, blueprintIdentifier string) { d.SetId(action.Identifier) + d.Set("blueprint_identifier", blueprintIdentifier) + d.Set("identifier", action.Identifier) d.Set("title", action.Title) d.Set("icon", action.Icon) d.Set("description", action.Description) @@ -426,7 +446,11 @@ func actionResourceToBody(d *schema.ResourceData) (*cli.Action, error) { func deleteAction(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { var diags diag.Diagnostics c := m.(*cli.PortClient) - err := c.DeleteAction(ctx, d.Get("blueprint_identifier").(string), d.Id()) + id := d.Id() + actionIdentifier := id + blueprintIdentifier := d.Get("blueprint_identifier").(string) + + err := c.DeleteAction(ctx, blueprintIdentifier, actionIdentifier) if err != nil { return diag.FromErr(err) } @@ -440,15 +464,21 @@ func createAction(ctx context.Context, d *schema.ResourceData, m interface{}) di if err != nil { return diag.FromErr(err) } + var a *cli.Action + + blueprintIdentifier := d.Get("blueprint_identifier").(string) + actionIdentifier := d.Id() if d.Id() != "" { - a, err = c.UpdateAction(ctx, d.Get("blueprint_identifier").(string), d.Id(), action) + a, err = c.UpdateAction(ctx, blueprintIdentifier, actionIdentifier, action) } else { a, err = c.CreateAction(ctx, d.Get("blueprint_identifier").(string), action) } + if err != nil { return diag.FromErr(err) } + d.SetId(a.Identifier) return diags } diff --git a/port/resource_port_action_test.go b/port/resource_port_action_test.go index 1d46faa9..8741dcbd 100644 --- a/port/resource_port_action_test.go +++ b/port/resource_port_action_test.go @@ -152,6 +152,82 @@ func TestAccPortAction(t *testing.T) { }) } +func TestActionImport(t *testing.T) { + blueprintIdentifier := genID() + actionIdentifier := genID() + var testAccActionConfigCreate = fmt.Sprintf(` + resource "port-labs_blueprint" "microservice" { + title = "TF test microservice" + icon = "Terraform" + identifier = "%s" + properties { + identifier = "text" + type = "string" + title = "text" + } + } + resource "port-labs_action" "restart_microservice" { + title = "Restart service" + icon = "Terraform" + identifier = "%s" + blueprint_identifier = port-labs_blueprint.microservice.identifier + trigger = "DAY-2" + invocation_method { + type = "KAFKA" + } + user_properties { + identifier = "reason" + type = "string" + title = "Reason" + default = "test" + } + user_properties { + identifier = "delay" + type = "number" + title = "Delay" + default = 3 + } + user_properties { + identifier = "clear_cache" + type = "boolean" + title = "Clear cache" + default = true + } + user_properties { + identifier = "services" + type = "array" + title = "Services" + default_items = ["api", "frontend"] + } + user_properties { + identifier = "config" + type = "object" + title = "Config" + default = jsonencode({"when":"immediate"}) + } + } + `, blueprintIdentifier, actionIdentifier) + 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_action.restart_microservice", "title", "Restart service"), + ), + }, + { + ResourceName: "port-labs_action.restart_microservice", + ImportState: true, + ImportStateVerify: true, + ImportStateId: fmt.Sprintf("%s:%s", blueprintIdentifier, actionIdentifier), + }, + }, + }) +} + func TestAccPortActionPropMeta(t *testing.T) { identifier := genID() actionIdentifier := genID() diff --git a/port/resource_port_blueprint.go b/port/resource_port_blueprint.go index d37b3546..99be51c0 100644 --- a/port/resource_port_blueprint.go +++ b/port/resource_port_blueprint.go @@ -342,7 +342,11 @@ func newBlueprintResource() *schema.Resource { Computed: true, }, }, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, } + } func readBlueprint(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { @@ -412,6 +416,7 @@ func writeBlueprintFieldsToResource(d *schema.ResourceData, b *cli.Blueprint) { d.SetId(b.Identifier) d.Set("title", b.Title) d.Set("icon", b.Icon) + d.Set("identifier", b.Identifier) d.Set("description", b.Description) d.Set("created_at", b.CreatedAt.String()) d.Set("created_by", b.CreatedBy) diff --git a/port/resource_port_blueprint_test.go b/port/resource_port_blueprint_test.go index a9909c1f..031d6c8f 100644 --- a/port/resource_port_blueprint_test.go +++ b/port/resource_port_blueprint_test.go @@ -149,6 +149,41 @@ func TestAccPortBlueprint(t *testing.T) { }) } +func TestAccPortBlueprintImport(t *testing.T) { + var testAccActionConfigCreate = ` + resource "port-labs_blueprint" "microservice" { + title = "microservice" + icon = "Terraform" + identifier = "import_microservice" + properties { + identifier = "bool" + type = "boolean" + title = "boolean" + } + } +` + 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.microservice", "title", "microservice"), + resource.TestCheckResourceAttr("port-labs_blueprint.microservice", "identifier", "import_microservice"), + ), + }, + { + ResourceName: "port-labs_blueprint.microservice", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"data_source"}, + }, + }, + }) +} + func TestAccBlueprintWithDefaultValue(t *testing.T) { identifier := genID() var testAccActionConfigCreate = fmt.Sprintf(` diff --git a/port/resource_port_entity.go b/port/resource_port_entity.go index 6d54a236..fa4ebc0c 100644 --- a/port/resource_port_entity.go +++ b/port/resource_port_entity.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "strconv" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -133,13 +134,19 @@ func newEntityResource() *schema.Resource { Computed: true, }, }, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, } } func deleteEntity(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { var diags diag.Diagnostics c := m.(*cli.PortClient) - err := c.DeleteEntity(ctx, d.Id(), d.Get("blueprint").(string)) + id := d.Id() + entityIdentifier := id + blueprintIdentifier := d.Get("blueprint").(string) + err := c.DeleteEntity(ctx, entityIdentifier, blueprintIdentifier) if err != nil { return diag.FromErr(err) } @@ -192,6 +199,7 @@ func entityResourceToBody(d *schema.ResourceData, bp *cli.Blueprint) (*cli.Entit if id != "" { e.Identifier = id } + e.Title = d.Get("title").(string) e.Blueprint = d.Get("blueprint").(string) @@ -250,20 +258,20 @@ func writeEntityComputedFieldsToResource(d *schema.ResourceData, e *cli.Entity) d.Set("updated_by", e.UpdatedBy) } -func writeEntityFieldsToResource(d *schema.ResourceData, e *cli.Entity) { +func writeEntityFieldsToResource(d *schema.ResourceData, e *cli.Entity, blueprintIdentifier string) { d.SetId(e.Identifier) d.Set("title", e.Title) + d.Set("blueprint", e.Blueprint) - team := d.Get("team") + entityTeams := e.Team + if len(entityTeams) > 0 { + team := d.Get("team") - if team != "" { - d.Set("team", e.Team[0]) - } - - teams := d.Get("teams").(*schema.Set) - - if len(teams.List()) > 0 { - d.Set("teams", e.Team) + if team != "" { + d.Set("team", e.Team[0]) + } else { + d.Set("teams", e.Team) + } } d.Set("created_at", e.CreatedAt.String()) @@ -351,7 +359,20 @@ func createEntity(ctx context.Context, d *schema.ResourceData, m interface{}) di func readEntity(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { var diags diag.Diagnostics c := m.(*cli.PortClient) - e, statusCode, err := c.ReadEntity(ctx, d.Id(), d.Get("blueprint").(string)) + id := d.Id() + blueprintIdentifier := d.Get("blueprint").(string) + entityIdentifier := d.Id() + + if strings.Contains(id, ":") { + parts := strings.SplitN(id, ":", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return diag.FromErr(fmt.Errorf("unexpected format of ID (%s), expected blueprintId:entityId", id)) + } + blueprintIdentifier = parts[0] + entityIdentifier = parts[1] + } + + e, statusCode, err := c.ReadEntity(ctx, entityIdentifier, blueprintIdentifier) if err != nil { if statusCode == 404 { d.SetId("") @@ -360,7 +381,7 @@ func readEntity(ctx context.Context, d *schema.ResourceData, m interface{}) diag return diag.FromErr(err) } - writeEntityFieldsToResource(d, e) + writeEntityFieldsToResource(d, e, blueprintIdentifier) if err != nil { return diag.FromErr(err) } diff --git a/port/resource_port_entity_test.go b/port/resource_port_entity_test.go index 5f8473a3..b127970f 100644 --- a/port/resource_port_entity_test.go +++ b/port/resource_port_entity_test.go @@ -228,6 +228,88 @@ func TestAccPortEntity(t *testing.T) { }) } +func TestAccPortEntityImport(t *testing.T) { + blueprintIdentifier := genID() + entityIdentifier := genID() + var testAccActionConfigCreate = fmt.Sprintf(` + resource "port-labs_blueprint" "microservice" { + title = "TF Provider Test" + icon = "Terraform" + identifier = "%s" + properties { + identifier = "text" + type = "string" + title = "text" + } + properties { + identifier = "bool" + type = "boolean" + title = "boolean" + } + properties { + identifier = "num" + type = "number" + title = "number" + } + properties { + identifier = "obj" + type = "object" + title = "object" + } + properties { + identifier = "arr" + type = "array" + title = "array" + } + } + resource "port-labs_entity" "microservice" { + title = "monolith" + blueprint = "${port-labs_blueprint.microservice.identifier}" + teams = ["Everyone"] + identifier = "%s" + properties { + name = "text" + value = "hedwig" + } + properties { + name = "bool" + value = "true" + } + properties { + name = "num" + value = 123 + } + properties { + name = "arr" + items = [1,2,3] + } + properties { + name = "obj" + value = jsonencode({"a":"b"}) + } + } +`, blueprintIdentifier, entityIdentifier) + 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_entity.microservice", "title", "monolith"), + ), + }, + { + ResourceName: "port-labs_entity.microservice", + ImportState: true, + ImportStateVerify: true, + ImportStateId: fmt.Sprintf("%s:%s", blueprintIdentifier, entityIdentifier), + ImportStateVerifyIgnore: []string{"identifier"}, + }, + }, + }) +} func TestAccPortEntitiesRelation(t *testing.T) { identifier1 := genID() identifier2 := genID()