Skip to content

Commit

Permalink
Merge pull request #66 from port-labs/PORT-4423-support-webhook-in-te…
Browse files Browse the repository at this point in the history
…rraform-and-pulumi

Port 4423 support webhook in terraform and pulumi
  • Loading branch information
MPTG94 authored Aug 14, 2023
2 parents 2730797 + b7bef3b commit 5780f46
Show file tree
Hide file tree
Showing 12 changed files with 940 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
@talsabagport @danielsinai @dvirsegev @matarpeles
@talsabagport @danielsinai @dvirsegev @matarpeles @pazhersh @MPTG94
1 change: 0 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ description: |-
### Optional

- `base_url` (String) Base URL for Port-labs (environment: `PORT_BASE_URL`)
- `token` (String, Sensitive) Token for Port-labs
77 changes: 77 additions & 0 deletions docs/resources/port_webhook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port_webhook Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
Webhook resource
---

# port_webhook (Resource)

Webhook resource



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

### Optional

- `description` (String) The description of the webhook
- `enabled` (Boolean) Whether the webhook is enabled
- `icon` (String) The icon of the webhook
- `identifier` (String) The identifier of the webhook
- `mappings` (Attributes List) The mappings of the webhook (see [below for nested schema](#nestedatt--mappings))
- `security` (Attributes) The security of the webhook (see [below for nested schema](#nestedatt--security))
- `title` (String) The title of the webhook

### Read-Only

- `created_at` (String) The creation date of the webhook
- `created_by` (String) The creator of the webhook
- `id` (String) The ID of this resource.
- `updated_at` (String) The last update date of the webhook
- `updated_by` (String) The last updater of the webhook

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

Required:

- `blueprint` (String) The blueprint of the mapping
- `entity` (Attributes) The entity of the mapping (see [below for nested schema](#nestedatt--mappings--entity))

Optional:

- `filter` (String) The filter of the mapping
- `items_to_parse` (String) The items to parser of the mapping

<a id="nestedatt--mappings--entity"></a>
### Nested Schema for `mappings.entity`

Required:

- `identifier` (String) The identifier of the entity

Optional:

- `icon` (String) The icon of the entity
- `properties` (Map of String) The properties of the entity
- `relations` (Map of String) The relations of the entity
- `team` (String) The team of the entity
- `title` (String) The title of the entity



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

Optional:

- `request_identifier_path` (String) The request identifier path of the webhook
- `secret` (String) The secret of the webhook
- `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


44 changes: 40 additions & 4 deletions internal/cli/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,49 @@ type (
Required *bool `json:"required,omitempty"`
Many *bool `json:"many,omitempty"`
}

Webhook struct {
Meta
Identifier string `json:"identifier,omitempty"`
Title *string `json:"title,omitempty"`
Icon *string `json:"icon,omitempty"`
Description *string `json:"description,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
Security *Security `json:"security,omitempty"`
Mappings []Mappings `json:"mappings,omitempty"`
}

Security struct {
Secret *string `json:"secret,omitempty"`
SignatureHeaderName *string `json:"signatureHeaderName,omitempty"`
SignatureAlgorithm *string `json:"signatureAlgorithm,omitempty"`
SignaturePrefix *string `json:"signaturePrefix,omitempty"`
RequestIdentifierPath *string `json:"requestIdentifierPath,omitempty"`
}

EntityProperty struct {
Identifier string `json:"identifier,omitempty"`
Title *string `json:"title,omitempty"`
Icon *string `json:"icon,omitempty"`
Team *string `json:"team,omitempty"`
Properties map[string]string `json:"properties,omitempty"`
Relations map[string]string `json:"relations,omitempty"`
}

Mappings struct {
Blueprint string `json:"blueprint,omitempty"`
Filter *string `json:"filter,omitempty"`
ItemsToParse *string `json:"items_to_parse,omitempty"`
Entity *EntityProperty `json:"entity,omitempty"`
}
)

type PortBody struct {
OK bool `json:"ok"`
Entity Entity `json:"entity"`
Blueprint Blueprint `json:"blueprint"`
Action Action `json:"action"`
OK bool `json:"ok"`
Entity Entity `json:"entity"`
Blueprint Blueprint `json:"blueprint"`
Action Action `json:"action"`
Integration Webhook `json:"integration"`
}

type PortProviderModel struct {
Expand Down
87 changes: 87 additions & 0 deletions internal/cli/webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cli

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

func (c *PortClient) ReadWebhook(ctx context.Context, webhookID string) (*Webhook, int, error) {
pb := &PortBody{}
url := "v1/webhooks/{webhook_identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetResult(pb).
SetPathParam("webhook_identifier", webhookID).
Get(url)
if err != nil {
return nil, resp.StatusCode(), err
}
if !pb.OK {
return nil, resp.StatusCode(), fmt.Errorf("failed to read webhook, got: %s", resp.Body())
}
return &pb.Integration, resp.StatusCode(), nil
}

func (c *PortClient) CreateWebhook(ctx context.Context, webhook *Webhook) (*Webhook, error) {
url := "v1/webhooks"
resp, err := c.Client.R().
SetBody(webhook).
SetContext(ctx).
Post(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 create webhook, got: %s", resp.Body())
}
return &pb.Integration, nil
}

func (c *PortClient) UpdateWebhook(ctx context.Context, webhookID string, webhook *Webhook) (*Webhook, error) {
url := "v1/webhooks/{webhook_identifier}"
resp, err := c.Client.R().
SetBody(webhook).
SetContext(ctx).
SetPathParam("webhook_identifier", webhookID).
Put(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 create webhook, got: %s", resp.Body())
}
return &pb.Integration, nil
}

func (c *PortClient) DeleteWebhook(ctx context.Context, webhookID string) error {
url := "v1/webhooks/{webhook_identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetPathParam("webhook_identifier", webhookID).
Delete(url)
if err != nil {
return err
}
responseBody := make(map[string]interface{})
err = json.Unmarshal(resp.Body(), &responseBody)
if err != nil {
return err
}
if !(responseBody["ok"].(bool)) {
return fmt.Errorf("failed to delete webhook. got:\n%s", string(resp.Body()))
}
return nil
}
44 changes: 44 additions & 0 deletions port/webhook/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package webhook

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

type SecurityModel struct {
Secret types.String `tfsdk:"secret"`
SignatureHeaderName types.String `tfsdk:"signature_header_name"`
SignatureAlgorithm types.String `tfsdk:"signature_algorithm"`
SignaturePrefix types.String `tfsdk:"signature_prefix"`
RequestIdentifierPath types.String `tfsdk:"request_identifier_path"`
}

type EntityModel struct {
Identifier types.String `tfsdk:"identifier"`
Title types.String `tfsdk:"title"`
Icon types.String `tfsdk:"icon"`
Team types.String `tfsdk:"team"`
Properties map[string]string `tfsdk:"properties"`
Relations map[string]string `tfsdk:"relations"`
}

type MappingsModel struct {
Blueprint types.String `tfsdk:"blueprint"`
Filter types.String `tfsdk:"filter"`
ItemsToParse types.String `tfsdk:"items_to_parse"`
Entity *EntityModel `tfsdk:"entity"`
}

type WebhookModel struct {
ID types.String `tfsdk:"id"`
Icon types.String `tfsdk:"icon"`
Identifier types.String `tfsdk:"identifier"`
Title types.String `tfsdk:"title"`
Description types.String `tfsdk:"description"`
Enabled types.Bool `tfsdk:"enabled"`
Security *SecurityModel `tfsdk:"security"`
Mappings []MappingsModel `tfsdk:"mappings"`
CreatedAt types.String `tfsdk:"created_at"`
CreatedBy types.String `tfsdk:"created_by"`
UpdatedAt types.String `tfsdk:"updated_at"`
UpdatedBy types.String `tfsdk:"updated_by"`
}
67 changes: 67 additions & 0 deletions port/webhook/refreshWebhookState.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package webhook

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/port-labs/terraform-provider-port-labs/internal/cli"
"github.com/port-labs/terraform-provider-port-labs/internal/flex"
)

func refreshWebhookState(ctx context.Context, state *WebhookModel, w *cli.Webhook) error {
state.ID = types.StringValue(w.Identifier)
state.Identifier = types.StringValue(w.Identifier)
state.CreatedAt = types.StringValue(w.CreatedAt.String())
state.CreatedBy = types.StringValue(w.CreatedBy)
state.UpdatedAt = types.StringValue(w.UpdatedAt.String())
state.UpdatedBy = types.StringValue(w.UpdatedBy)
state.Icon = flex.GoStringToFramework(w.Icon)
state.Title = flex.GoStringToFramework(w.Title)
state.Description = flex.GoStringToFramework(w.Description)
state.Enabled = flex.GoBoolToFramework(w.Enabled)

if w.Security.RequestIdentifierPath != nil || w.Security.Secret != nil || w.Security.SignatureHeaderName != nil || w.Security.SignatureAlgorithm != nil || w.Security.SignaturePrefix != nil {
state.Security = &SecurityModel{
Secret: flex.GoStringToFramework(w.Security.Secret),
SignatureHeaderName: flex.GoStringToFramework(w.Security.SignatureHeaderName),
SignatureAlgorithm: flex.GoStringToFramework(w.Security.SignatureAlgorithm),
SignaturePrefix: flex.GoStringToFramework(w.Security.SignaturePrefix),
RequestIdentifierPath: flex.GoStringToFramework(w.Security.RequestIdentifierPath),
}
}

if len(w.Mappings) > 0 {
state.Mappings = []MappingsModel{}
for _, v := range w.Mappings {
mapping := &MappingsModel{
Blueprint: types.StringValue(v.Blueprint),
Entity: &EntityModel{
Identifier: types.StringValue(v.Entity.Identifier),
},
}

mapping.Filter = flex.GoStringToFramework(v.Filter)
mapping.ItemsToParse = flex.GoStringToFramework(v.ItemsToParse)
mapping.Entity.Icon = flex.GoStringToFramework(v.Entity.Icon)
mapping.Entity.Title = flex.GoStringToFramework(v.Entity.Title)
mapping.Entity.Team = flex.GoStringToFramework(v.Entity.Team)

if v.Entity.Properties != nil {
mapping.Entity.Properties = map[string]string{}
for k, v := range v.Entity.Properties {
mapping.Entity.Properties[k] = v
}
}

if v.Entity.Relations != nil {
mapping.Entity.Relations = map[string]string{}
for k, v := range v.Entity.Relations {
mapping.Entity.Relations[k] = v
}
}
state.Mappings = append(state.Mappings, *mapping)
}
}

return nil
}
Loading

0 comments on commit 5780f46

Please sign in to comment.