Skip to content

Commit

Permalink
Blueprints resource (#2)
Browse files Browse the repository at this point in the history
* added blueprints resource
refactor http client

* added blueprints resource
refactor http client

* bump version

* fix tests collision

* support update blueprint and add test

* CR

* fix tests
  • Loading branch information
hedwigz authored Aug 16, 2022
1 parent 34cc173 commit c93b77a
Show file tree
Hide file tree
Showing 17 changed files with 1,039 additions and 127 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.0.16
VERSION=0.1.0
OS=$(shell go env GOOS)
ARCH=$(shell go env GOARCH)
OS_ARCH=${OS}_${ARCH}
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port Provider"
page_title: "port-labs Provider"
subcategory: ""
description: |-
---

# port Provider
# port-labs Provider



Expand Down
68 changes: 68 additions & 0 deletions docs/resources/blueprint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port-labs_blueprint Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
Port blueprint
---

# port-labs_blueprint (Resource)

Port blueprint



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

### Required

- `icon` (String) The icon of the blueprint
- `identifier` (String) The identifier of the blueprint
- `properties` (Block Set, Min: 1) The metadata of the entity (see [below for nested schema](#nestedblock--properties))
- `title` (String) The display name of the blueprint

### Optional

- `data_source` (String) The data source for entities of this blueprint
- `relations` (Block Set) The blueprints that are connected to this blueprint (see [below for nested schema](#nestedblock--relations))

### Read-Only

- `created_at` (String)
- `created_by` (String)
- `id` (String) The ID of this resource.
- `updated_at` (String)
- `updated_by` (String)

<a id="nestedblock--properties"></a>
### Nested Schema for `properties`

Required:

- `identifier` (String) The identifier of the property
- `title` (String) The name of this property
- `type` (String) The type of the property

Optional:

- `default` (String) The default value of the property
- `description` (String) The description of the property
- `format` (String) The format of the Property


<a id="nestedblock--relations"></a>
### Nested Schema for `relations`

Required:

- `target` (String) The id of the connected blueprint
- `title` (String) The display name of the relation

Optional:

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


12 changes: 7 additions & 5 deletions docs/resources/entity.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port-labs_entity Resource - terraform-provider-port"
page_title: "port-labs_entity Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
Port entity
Expand All @@ -10,8 +10,9 @@ description: |-

Port entity

<!-- schema generated by tfplugindocs -->


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

### Required
Expand All @@ -34,24 +35,25 @@ Port entity
- `updated_by` (String)

<a id="nestedblock--properties"></a>

### Nested Schema for `properties`

Required:

- `name` (String) The name of this property
- `type` (String) The type of the properrty
- `type` (String) The type of the property

Optional:

- `items` (List of String) The list of items, in case the type of this property is a list
- `value` (String) The value for this property

<a id="nestedblock--relations"></a>

<a id="nestedblock--relations"></a>
### Nested Schema for `relations`

Required:

- `identifier` (String) The id of the connected entity
- `name` (String) The name of the relation


33 changes: 33 additions & 0 deletions examples/resources/port-labs_blueprint/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
resource "port-labs_blueprint" "environment" {
title = "Environment"
icon = "Environment"
identifier = "hedwig-env"
properties {
identifier = "name"
type = "string"
title = "name"
}
properties {
identifier = "docs-url"
type = "string"
title = "Docs URL"
format = "url"
}
}

resource "port-labs_blueprint" "vm" {
title = "VM"
icon = "GPU"
identifier = "hedwig-vm"
properties {
identifier = "name"
type = "string"
title = "Name"
}
relations {
identifier = "environment"
title = "Test Relation"
required = "true"
target = port-labs_blueprint.environment.identifier
}
}
File renamed without changes.
88 changes: 88 additions & 0 deletions port/cli/blueprint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cli

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

func (c *PortClient) ReadBlueprint(ctx context.Context, id string) (*Blueprint, error) {
pb := &PortBody{}
url := "v0.1/blueprints/{identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetQueryParam("exclude_mirror_properties", "true").
SetResult(pb).
SetPathParam("identifier", id).
Get(url)
if err != nil {
return nil, err
}
if !pb.OK {
return nil, fmt.Errorf("failed to read blueprint, got: %s", resp.Body())
}
return &pb.Blueprint, nil
}

func (c *PortClient) CreateBlueprint(ctx context.Context, b *Blueprint) (*Blueprint, error) {
url := "v0.1/blueprints"
resp, err := c.Client.R().
SetBody(b).
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 blueprint, got: %s", resp.Body())
}
return &pb.Blueprint, nil
}

func (c *PortClient) UpdateBlueprint(ctx context.Context, b *Blueprint, id string) (*Blueprint, error) {
url := "v0.1/blueprints/{identifier}"
resp, err := c.Client.R().
SetBody(b).
SetContext(ctx).
SetPathParam("identifier", id).
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 blueprint, got: %s", resp.Body())
}
return &pb.Blueprint, nil
}

func (c *PortClient) DeleteBlueprint(ctx context.Context, id string) error {
url := "v0.1/blueprints/{identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetPathParam("identifier", id).
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 blueprint. got:\n%s", string(resp.Body()))
}
return nil
}
79 changes: 79 additions & 0 deletions port/cli/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cli

import (
"context"
"encoding/json"
"strings"

"github.com/go-resty/resty/v2"
)

type (
Option func(*PortClient)
PortClient struct {
Client *resty.Client
ClientID string
}
)

func New(baseURL string, opts ...Option) (*PortClient, error) {
c := &PortClient{
Client: resty.New().
SetBaseURL(baseURL).
SetRetryCount(5).
SetRetryWaitTime(300).
// retry when create permission fails because scopes are created async-ly and sometimes (mainly in tests) the scope doesn't exist yet.
AddRetryCondition(func(r *resty.Response, err error) bool {
if err != nil {
return true
}
if !strings.Contains(r.Request.URL, "/permissions") {
return false
}
b := make(map[string]interface{})
err = json.Unmarshal(r.Body(), &b)
return err != nil || b["ok"] != true
}),
}
for _, opt := range opts {
opt(c)
}
return c, nil
}

func (c *PortClient) Authenticate(ctx context.Context, clientID, clientSecret string) (string, error) {
url := "v0.1/auth/access_token"
resp, err := c.Client.R().
SetContext(ctx).
SetQueryParam("client_id", clientID).
SetQueryParam("client_secret", clientSecret).
Get(url)
if err != nil {
return "", err
}
var tokenResp AccessTokenResponse
err = json.Unmarshal(resp.Body(), &tokenResp)
if err != nil {
return "", err
}
c.Client.SetAuthToken(tokenResp.AccessToken)
return tokenResp.AccessToken, nil
}

func WithHeader(key, val string) Option {
return func(pc *PortClient) {
pc.Client.SetHeader(key, val)
}
}

func WithClientID(clientID string) Option {
return func(pc *PortClient) {
pc.ClientID = clientID
}
}

func WithToken(token string) Option {
return func(pc *PortClient) {
pc.Client.SetAuthToken(token)
}
}
Loading

0 comments on commit c93b77a

Please sign in to comment.