Skip to content

Commit

Permalink
IaC for Integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
erikzaadi committed Jun 4, 2024
1 parent 8d84407 commit 078bc8a
Show file tree
Hide file tree
Showing 15 changed files with 782 additions and 7 deletions.
2 changes: 1 addition & 1 deletion docs/resources/port_blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ resource "port_blueprint" "microservice" {
There could be cases where a blueprint will be managed by Terraform, but entities will get created from other sources (e.g. Port UI, API or other supported integrations).
In this case, when trying to delete the blueprint, Terraform will fail because it will try to delete the blueprint without deleting the entities first as they are not managed by Terraform.

To overcome this behavior, you can set the argument `force_delete_entities=true`.
To overcome this behavior, you can set the argument `force_delete_entities=true`.
On the blueprint destroy it will trigger a migration that will delete all the entities in the blueprint and then delete the blueprint itself.

```hcl
Expand Down
124 changes: 124 additions & 0 deletions docs/resources/port_integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port_integration Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
Integration resource
Docs about integration and be found here https://docs.getport.io/integrations-index/.
```hcl
resource "portintegration" "mycustomintegration" {
installationid = "my-custom-integration-id"
title = "My Custom Integration"
version = "1.33.7"
config = jsonencode({
createMissingRelatedEntitiesboolean = true
deleteDependentEntities = true,
resources = [{
kind = "my-custom-kind"
selector = {
query = ".title"
}
port = {
entity = {
mappings = [{
identifier = "'my-identifier'"
title = ".title"
blueprint = "'my-blueprint'"
properties = {
my_property = 123
}
relations = {}
}]
}
}
}]
})
}
```
NOTICE:
The following config properties (selector.query|entity.mappings.*) are jq expressions, which means that you need to input either a valid jq expression (E.g .title), or if you want a string value, a qouted escaped string val (E.g 'my-string').
---

# port_integration (Resource)

# Integration resource

Docs about integration and be found [here](https://docs.getport.io/integrations-index/).


```hcl
resource "port_integration" "my_custom_integration" {
installation_id = "my-custom-integration-id"
title = "My Custom Integration"
version = "1.33.7"
config = jsonencode({
createMissingRelatedEntitiesboolean = true
deleteDependentEntities = true,
resources = [{
kind = "my-custom-kind"
selector = {
query = ".title"
}
port = {
entity = {
mappings = [{
identifier = "'my-identifier'"
title = ".title"
blueprint = "'my-blueprint'"
properties = {
my_property = 123
}
relations = {}
}]
}
}
}]
})
}
```

### NOTICE:

The following config properties (`selector.query|entity.mappings.*`) are jq expressions, which means that you need to input either a valid jq expression (E.g `.title`), or if you want a string value, a qouted escaped string val (E.g `'my-string'`).



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

### Required

- `installation_id` (String)

### Optional

- `config` (String) Integration Config Raw JSON string (use `jsonencode`)
- `installation_app_type` (String)
- `kafka_changelog_destination` (Object) The changelog destination of the blueprint (just an empty `{}`) (see [below for nested schema](#nestedatt--kafka_changelog_destination))
- `title` (String)
- `version` (String)
- `webhook_changelog_destination` (Attributes) The webhook changelog destination of the integration (see [below for nested schema](#nestedatt--webhook_changelog_destination))

### Read-Only

- `id` (String) The ID of this resource.

<a id="nestedatt--kafka_changelog_destination"></a>
### Nested Schema for `kafka_changelog_destination`

Optional:



<a id="nestedatt--webhook_changelog_destination"></a>
### Nested Schema for `webhook_changelog_destination`

Required:

- `url` (String) The url of the webhook changelog destination

Optional:

- `agent` (Boolean) The agent of the webhook changelog destination
5 changes: 3 additions & 2 deletions examples/provider.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ terraform {
}
}
provider "port" {
client_id = "" # or set the environment variable PORT_CLIENT_ID
secret = "" # or set the environment variable PORT_CLIENT_SECRET
client_id = "60EsooJtOqimlekxrNh7nfr2iOgTcyLZ" # or set the environment variable PORT_CLIENT_ID
secret = "35D7Hw4ZpjdHW0u1lNS0cE5UXvevhlGQWeXuwkIX91s6UjgLzO44GSBG9yNBdehr" # or set the environment variable PORT_CLIENT_SECRET
base_url = "http://localhost:3000"
}
29 changes: 29 additions & 0 deletions examples/resources/port_integration/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
resource "port_integration" "my_custom_integration" {
installation_id = "my-custom-integration-id"
title = "My Custom Integration"
version = "1.33.7"
installation_app_type = "WEBHOOK"
config = jsonencode({
createMissingRelatedEntitiesboolean = true
deleteDependentEntities = true
resources = [{
kind = "my-custom-kind"
selector = {
query = ".title"
}
port = {
entity = {
mappings = [{
identifier = "'my-identifier'"
title = ".title"
blueprint = "'my-blueprint'"
properties = {
my_property = 123
}
relations = {}
}]
}
}
}]
})
}
1 change: 1 addition & 0 deletions examples/resources/port_integration/provider.tf
96 changes: 96 additions & 0 deletions internal/cli/integration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package cli

import (
"context"
"encoding/json"
"fmt"
)

type PortBodyForIntegration struct {
OK bool `json:"ok"`
Integration Integration `json:"integration"`
}

func (c *PortClient) GetIntegration(ctx context.Context, id string) (*Integration, error) {
pb := &PortBodyForIntegration{}
url := "v1/integration/{identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetResult(pb).
SetPathParam("identifier", id).
SetQueryParam("byField", "installationId").
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.Integration, nil
}

func (c *PortClient) UpdateIntegration(ctx context.Context, id string, integration *Integration) (*Integration, error) {
url := "v1/integration/{identifier}"

resp, err := c.Client.R().
SetBody(integration).
SetContext(ctx).
SetPathParam("identifier", id).
Patch(url)
if err != nil {
return nil, err
}
var pppb PortBodyForIntegration
err = json.Unmarshal(resp.Body(), &pppb)
if err != nil {
return nil, err
}
if !pppb.OK {
return nil, fmt.Errorf("failed to update integration, got: %s", resp.Body())
}
return &pppb.Integration, nil
}

func (c *PortClient) CreateIntegration(ctx context.Context, integration *Integration) (*Integration, error) {
url := "v1/integration"

resp, err := c.Client.R().
SetBody(integration).
SetContext(ctx).
Post(url)
if err != nil {
return nil, err
}

var pppb PortBodyForIntegration
err = json.Unmarshal(resp.Body(), &pppb)
if err != nil {
return nil, err
}
if !pppb.OK {
return nil, fmt.Errorf("failed to create integration, got: %s", resp.Body())
}

return &pppb.Integration, nil
}

func (c *PortClient) DeleteIntegration(ctx context.Context, id string) (int, error) {
url := "v1/integration/{identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetPathParam("identifier", id).
Delete(url)
if err != nil {
return resp.StatusCode(), err
}
var pb PortBodyForIntegration
err = json.Unmarshal(resp.Body(), &pb)
if err != nil {
return resp.StatusCode(), err
}
if !pb.OK {
return resp.StatusCode(), fmt.Errorf("failed to delete integration, got: %s", resp.Body())
}
return resp.StatusCode(), nil
}
11 changes: 10 additions & 1 deletion internal/cli/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ type PortBody struct {
BlueprintPermissions Blueprint `json:"blueprint_permissions"`
Action Action `json:"action"`
ActionPermissions ActionPermissions `json:"permissions"`
Integration Webhook `json:"integration"`
Webhook Webhook `json:"integration"`
Scorecard Scorecard `json:"Scorecard"`
Team Team `json:"team"`
Page Page `json:"page"`
Expand Down Expand Up @@ -440,3 +440,12 @@ type PortProviderModel struct {
type PortBodyDelete struct {
Ok bool `json:"ok"`
}

type Integration struct {
Title string `json:"title"`
InstallationId string `json:"installationId,omitempty"`
InstallationAppType *string `json:"installationAppType,omitempty"`
Version string `json:"version,omitempty"`
Config *map[string]any `json:"config,omitempty"`
ChangelogDestination *ChangelogDestination `json:"changelogDestination,omitempty"`
}
8 changes: 5 additions & 3 deletions internal/cli/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (c *PortClient) ReadWebhook(ctx context.Context, webhookID string) (*Webhoo
if !pb.OK {
return nil, resp.StatusCode(), fmt.Errorf("failed to read webhook, got: %s", resp.Body())
}
return &pb.Integration, resp.StatusCode(), nil
return &pb.Webhook, resp.StatusCode(), nil
}

func (c *PortClient) CreateWebhook(ctx context.Context, webhook *Webhook) (*Webhook, error) {
Expand All @@ -41,7 +41,8 @@ func (c *PortClient) CreateWebhook(ctx context.Context, webhook *Webhook) (*Webh
if !pb.OK {
return nil, fmt.Errorf("failed to create webhook, got: %s", resp.Body())
}
return &pb.Integration, nil

return &pb.Webhook, nil
}

func (c *PortClient) UpdateWebhook(ctx context.Context, webhookID string, webhook *Webhook) (*Webhook, error) {
Expand All @@ -62,7 +63,8 @@ func (c *PortClient) UpdateWebhook(ctx context.Context, webhookID string, webhoo
if !pb.OK {
return nil, fmt.Errorf("failed to create webhook, got: %s", resp.Body())
}
return &pb.Integration, nil

return &pb.Webhook, nil
}

func (c *PortClient) DeleteWebhook(ctx context.Context, webhookID string) error {
Expand Down
47 changes: 47 additions & 0 deletions port/integration/integrationToPortBody.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package integration

import (
"github.com/port-labs/terraform-provider-port-labs/v2/internal/cli"
"github.com/port-labs/terraform-provider-port-labs/v2/internal/consts"
"github.com/port-labs/terraform-provider-port-labs/v2/internal/utils"
)

func integrationToPortBody(state *IntegrationModel) (*cli.Integration, error) {
if state == nil {
return nil, nil
}

integration := &cli.Integration{
InstallationId: state.InstallationId.ValueString(),
Version: state.Version.ValueString(),
Title: state.Title.ValueString(),
}

if !state.InstallationAppType.IsNull() {
installationAppType := state.InstallationAppType.ValueString()
integration.InstallationAppType = &installationAppType
}

if !state.Config.IsNull() {
configStr := state.Config.ValueString()
config, err := utils.TerraformJsonStringToGoObject(&configStr)
if err != nil {
return nil, err
}
integration.Config = config
}
if !state.KafkaChangelogDestination.IsNull() {
integration.ChangelogDestination = &cli.ChangelogDestination{
Type: consts.Kafka,
}
}
if state.WebhookChangelogDestination != nil {
integration.ChangelogDestination = &cli.ChangelogDestination{
Type: consts.Webhook,
Url: state.WebhookChangelogDestination.Url.ValueString(),
Agent: state.WebhookChangelogDestination.Agent.ValueBoolPointer(),
}
}

return integration, nil
}
19 changes: 19 additions & 0 deletions port/integration/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package integration

import "github.com/hashicorp/terraform-plugin-framework/types"

type WebhookChangelogDestinationModel struct {
Url types.String `tfsdk:"url"`
Agent types.Bool `tfsdk:"agent"`
}

type IntegrationModel struct {
ID types.String `tfsdk:"id"`
InstallationId types.String `tfsdk:"installation_id"`
InstallationAppType types.String `tfsdk:"installation_app_type"`
Title types.String `tfsdk:"title"`
Version types.String `tfsdk:"version"`
Config types.String `tfsdk:"config"`
KafkaChangelogDestination types.Object `tfsdk:"kafka_changelog_destination"`
WebhookChangelogDestination *WebhookChangelogDestinationModel `tfsdk:"webhook_changelog_destination"`
}
Loading

0 comments on commit 078bc8a

Please sign in to comment.