Skip to content

Commit

Permalink
support force deleting a blueprint
Browse files Browse the repository at this point in the history
  • Loading branch information
Tankilevitch committed Jan 22, 2024
1 parent 1947767 commit d69e61e
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 23 deletions.
2 changes: 0 additions & 2 deletions docs/resources/port_action.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,5 +429,3 @@ Optional:
- `agent` (Boolean) Use the agent to invoke the action
- `method` (String) The HTTP method to invoke the action
- `synchronized` (Boolean) Synchronize the action


2 changes: 0 additions & 2 deletions docs/resources/port_action_permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,5 +222,3 @@ Optional:
- `roles` (List of String) The roles with execution permission
- `teams` (List of String) The teams with execution permission
- `users` (List of String) The users with execution permission


2 changes: 0 additions & 2 deletions docs/resources/port_aggregation_properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,5 +645,3 @@ Optional:

- `average_of` (String) The time periods to calculate the average of, e.g. hour, day, week, month
- `measure_time_by` (String) The property name on which to calculate the the time periods, e.g. $createdAt, $updated_at or any other date property


15 changes: 13 additions & 2 deletions docs/resources/port_blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ description: |-
}
}
```
Force Deleting a Blueprint
There could be cases where a blueprint will be managed by Terraform, but entities will get created from other sources such as the PORT UI or different integrations.
In this case, when trying to delete the blueprint, Terraform will fail because it will try to delete the entities that were created outside of Terraform.
To overcome this behavior, you can set the environment variable PORT_FORCE_DELETE_ENTITIES to true.
This will trigger a migration that will delete all the entities in the blueprint and then delete the blueprint itself.
---

# port_blueprint (Resource)
Expand Down Expand Up @@ -212,6 +217,14 @@ resource "port_blueprint" "microservice" {
```

## Force Deleting a Blueprint

There could be cases where a blueprint will be managed by Terraform, but entities will get created from other sources such as the PORT UI or different integrations.
In this case, when trying to delete the blueprint, Terraform will fail because it will try to delete the entities that were created outside of Terraform.

To overcome this behavior, you can set the environment variable `PORT_FORCE_DELETE_ENTITIES` to `true`.
This will trigger a migration that will delete all the entities in the blueprint and then delete the blueprint itself.



<!-- schema generated by tfplugindocs -->
Expand Down Expand Up @@ -444,5 +457,3 @@ Required:
Optional:

- `agent` (Boolean) The agent of the webhook changelog destination


2 changes: 0 additions & 2 deletions docs/resources/port_entity.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,3 @@ Optional:

- `many_relations` (Map of List of String) The many relation of the entity
- `single_relations` (Map of String) The single relation of the entity


198 changes: 194 additions & 4 deletions docs/resources/port_scorecard.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,204 @@
page_title: "port_scorecard Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
scorecard resource
Scorecard
This resource allows you to manage a scorecard.
See the Port documentation https://docs.getport.io/promote-scorecards/ for more information about scorecards.
Example Usage
Create a parent blueprint with a child blueprint and an aggregation property to count the parent kids:
```hcl
resource "portblueprint" "microservice" {
title = "microservice"
icon = "Terraform"
identifier = "microservice"
properties = {
stringprops = {
"author" = {
title = "Author"
}
"url" = {
title = "URL"
}
}
booleanprops = {
"required" = {
type = "boolean"
}
}
numberprops = {
"sum" = {
type = "number"
}
}
}
}
resource "portscorecard" "readiness" {
identifier = "Readiness"
title = "Readiness"
blueprint = portblueprint.microservice.identifier
rules = [
{
identifier = "hasOwner"
title = "Has Owner"
level = "Gold"
query = {
combinator = "and"
conditions = [
jsonencode({
property = "$team"
operator = "isNotEmpty"
}),
jsonencode({
property = "author",
operator : "=",
value : "myValue"
})
]
}
},
{
identifier = "hasUrl"
title = "Has URL"
level = "Silver"
query = {
combinator = "and"
conditions = [jsonencode({
property = "url"
operator = "isNotEmpty"
})]
}
},
{
identifier = "checkSumIfRequired"
title = "Check Sum If Required"
level = "Bronze"
query = {
combinator = "or"
conditions = [
jsonencode({
property = "required"
operator : "="
value : false
}),
jsonencode({
property = "sum"
operator : ">"
value : 2
})
]
}
}
]
dependson = [
portblueprint.microservice
]
}
```
---

# port_scorecard (Resource)

scorecard resource
# Scorecard

This resource allows you to manage a scorecard.

See the [Port documentation](https://docs.getport.io/promote-scorecards/) for more information about scorecards.

## Example Usage

Create a parent blueprint with a child blueprint and an aggregation property to count the parent kids:

```hcl
resource "port_blueprint" "microservice" {
title = "microservice"
icon = "Terraform"
identifier = "microservice"
properties = {
string_props = {
"author" = {
title = "Author"
}
"url" = {
title = "URL"
}
}
boolean_props = {
"required" = {
type = "boolean"
}
}
number_props = {
"sum" = {
type = "number"
}
}
}
}
resource "port_scorecard" "readiness" {
identifier = "Readiness"
title = "Readiness"
blueprint = port_blueprint.microservice.identifier
rules = [
{
identifier = "hasOwner"
title = "Has Owner"
level = "Gold"
query = {
combinator = "and"
conditions = [
jsonencode({
property = "$team"
operator = "isNotEmpty"
}),
jsonencode({
property = "author",
operator : "=",
value : "myValue"
})
]
}
},
{
identifier = "hasUrl"
title = "Has URL"
level = "Silver"
query = {
combinator = "and"
conditions = [jsonencode({
property = "url"
operator = "isNotEmpty"
})]
}
},
{
identifier = "checkSumIfRequired"
title = "Check Sum If Required"
level = "Bronze"
query = {
combinator = "or"
conditions = [
jsonencode({
property = "required"
operator : "="
value : false
}),
jsonencode({
property = "sum"
operator : ">"
value : 2
})
]
}
}
]
depends_on = [
port_blueprint.microservice
]
}
```



Expand Down Expand Up @@ -47,5 +239,3 @@ Required:

- `combinator` (String) The combinator of the query
- `conditions` (List of String) The conditions of the query. Each condition object should be encoded to a string


2 changes: 0 additions & 2 deletions docs/resources/port_team.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,3 @@ Team resource
- `id` (String) The ID of this resource.
- `provider_name` (String) The provider of the team
- `updated_at` (String) The last update date of the team


2 changes: 0 additions & 2 deletions docs/resources/port_webhook.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,3 @@ Optional:
- `signature_algorithm` (String) The signature algorithm of the webhook
- `signature_header_name` (String) The signature header name of the webhook
- `signature_prefix` (String) The signature prefix of the webhook


23 changes: 23 additions & 0 deletions internal/cli/blueprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,26 @@ func (c *PortClient) DeleteBlueprint(ctx context.Context, id string) error {
}
return nil
}

func (c *PortClient) DeleteBlueprintWithAllEntities(ctx context.Context, id string) (*string, error) {
url := "v1/blueprints/{identifier}/all-entities?delete_blueprint=true"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetPathParam("identifier", id).
Delete(url)
if err != nil {
return nil, err
}
var pb PortBody
err = json.Unmarshal(resp.Body(), &pb)
if err != nil {
return nil, err
}
if !pb.OK {
return nil, fmt.Errorf("failed to trigger blueprint deletion with all entities, got: %s", resp.Body())
}

return &pb.MigrationId, nil

}
24 changes: 24 additions & 0 deletions internal/cli/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cli

import (
"context"
"fmt"
)

func (c *PortClient) GetMigration(ctx context.Context, id string) (*Migration, error) {
pb := &PortBody{}
url := "v1/migrations/{identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetResult(pb).
SetPathParam("identifier", id).
Get(url)
if err != nil {
return nil, err
}
if !pb.OK {
return nil, fmt.Errorf("failed to read migration, got: %s", resp.Body())
}
return &pb.Migration, nil
}
15 changes: 15 additions & 0 deletions internal/cli/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,19 @@ type (
Users []string `json:"users,omitempty"`
Provider string `json:"provider,omitempty"`
}

Migration struct {
Meta
Id string `json:"id,omitempty"`
Actor string `json:"actor,omitempty"`
SourceBlueprint string `json:"sourceBlueprint,omitempty"`
Mapping any `json:"mapping,omitempty"`
Status string `json:"status,omitempty"`
DeleteBlueprint bool `json:"deleteBlueprint,omitempty"`
DeleteEntities bool `json:"deleteEntities,omitempty"`
FailureCount int `json:"failureCount,omitempty"`
SuccessCount int `json:"successCount,omitempty"`
}
)

type PortBody struct {
Expand All @@ -306,6 +319,8 @@ type PortBody struct {
Integration Webhook `json:"integration"`
Scorecard Scorecard `json:"Scorecard"`
Team Team `json:"team"`
MigrationId string `json:"migrationId"`
Migration Migration `json:"migration"`
}

type TeamUserBody struct {
Expand Down
15 changes: 15 additions & 0 deletions internal/consts/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package consts

const (
Failure = "FAILURE"
Cancelled = "CANCELLED"
Completed = "COMPLETED"
Running = "RUNNING"
Pending = "PENDING"
Initializing = "INITIALIZING"
PendingCancellation = "PENDING_CANCELLATION"
)

func IsTerminalStatus(status string) bool {
return status == Failure || status == Cancelled || status == Completed
}
Loading

0 comments on commit d69e61e

Please sign in to comment.