Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions apiClient/guardrail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package apiClient

func (client *Client) CreateGuardrail(input map[string]interface{}) (*Guardrail, error) {
query := createGuardrailMutation()
responseData := &GuardrailResponse{}
variables := map[string]interface{}{
"input": input,
}

// execute api call
if err := client.doRequest(query, variables, responseData); err != nil {
return nil, client.handleCreateError(err, input, "guardrail")
}
return &responseData.Guardrail, nil
}

func (client *Client) ReadGuardrail(id string) (*Guardrail, error) {
query := readGuardrailQuery(id)
responseData := &GuardrailResponse{}

// execute api call
if err := client.doRequest(query, nil, responseData); err != nil {
return nil, client.handleReadError(err, id, "guardrail")
}
return &responseData.Guardrail, nil
}

func (client *Client) UpdateGuardrail(input map[string]interface{}) (*Guardrail, error) {
query := updateGuardrailMutation()
responseData := &GuardrailResponse{}
variables := map[string]interface{}{
"input": input,
}
// execute api call
if err := client.doRequest(query, variables, responseData); err != nil {
return nil, client.handleUpdateError(err, input, "guardrail")
}
return &responseData.Guardrail, nil
}
63 changes: 63 additions & 0 deletions apiClient/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,66 @@ func (client *Client) GetTurbotWorkspaceVersion() (*semver.Version, error) {
}
return version, nil
}

// guardrail

func createGuardrailMutation() string {
return `mutation CreateGuardrail($input: CreateGuardrailInput!) {
guardrail: createGuardrail(input: $input) {
title
description
tags
turbot {
id
akas
title
}
}
}`
}

func readGuardrailQuery(id string) string {
return fmt.Sprintf(`{
guardrail: guardrail(id: "%s") {
description
turbot {
id
akas
title
tags
}
accounts {
items {
turbot {
id
akas
}
}
}
targets {
items {
uri
}
}
controlTypes {
items {
uri
}
}
}
}`, id)
}

func updateGuardrailMutation() string {
return `mutation UpdateGuardrail($input: UpdateGuardrailInput!) {
guardrail: updateGuardrail(input: $input) {
description
tags
turbot {
id
akas
title
}
}
}`
}
32 changes: 32 additions & 0 deletions apiClient/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,3 +520,35 @@ type TurbotWatchMetadata struct {
ResourceId string
FavoriteId string
}

// Guardrail

type GuardrailResponse struct {
Guardrail Guardrail
}

type Guardrail struct {
Description string
Turbot TurbotResourceMetadata
Accounts struct {
Items []Account
}
ControlTypes struct {
Items []ControlType
}
Targets struct {
Items []Target
}
}

type Account struct {
Turbot TurbotResourceMetadata
}

type ControlType struct {
Uri string
}

type Target struct {
Uri string
}
9 changes: 8 additions & 1 deletion errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package errors

import (
"fmt"
"github.com/pkg/errors"
"net/http"
"regexp"
"strconv"
"strings"

"github.com/pkg/errors"
)

func NotFoundError(err error) bool {
Expand All @@ -21,6 +22,12 @@ func FailedValidationError(err error) bool {
return expectedErr.Match([]byte(err.Error()))
}

func ForbiddenError(err error) bool {
forbiddenErr := "(?i)graphql: Forbidden: Insufficient permissions for resource(?i)"
expectedErr := regexp.MustCompile(forbiddenErr)
return expectedErr.Match([]byte(err.Error()))
}

func ExtractErrorCode(err error) (int, error) {
// error returned from machinebox/graphql is of graphql type
// errorNon200Template = "graphql: server returned a non-200 status code: 503"
Expand Down
1 change: 1 addition & 0 deletions turbot/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func Provider() terraform.ResourceProvider {
"turbot_google_directory": resourceGoogleDirectory(),
"turbot_grant": resourceTurbotGrant(),
"turbot_grant_activation": resourceTurbotGrantActivation(),
"turbot_guardrail": resourceTurbotGuardrail(),
"turbot_ldap_directory": resourceTurbotLdapDirectory(),
"turbot_local_directory": resourceTurbotLocalDirectory(),
"turbot_local_directory_user": resourceTurbotLocalDirectoryUser(),
Expand Down
181 changes: 181 additions & 0 deletions turbot/resource_turbot_guardrail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package turbot

import (
"github.com/hashicorp/terraform/helper/schema"
"github.com/turbot/terraform-provider-turbot/apiClient"
"github.com/turbot/terraform-provider-turbot/errors"
)

// properties which must be passed to a create/update call
var guardrailProperties = map[string]string{
"title": "title",
"description": "description",
"targets": "targets",
"controls": "controlTypes",
"akas": "akas",
"tags": "tags",
}

func getGuardrailUpdateProperties() map[string]string {
excludedProperties := []string{"controls"}

// Remove the excluded properties from guardrailProperties
for _, key := range excludedProperties {
delete(guardrailProperties, key)
}

return guardrailProperties
}

func resourceTurbotGuardrail() *schema.Resource {
return &schema.Resource{
Create: resourceTurbotGuardrailCreate,
Read: resourceTurbotGuardrailRead,
Update: resourceTurbotGuardrailUpdate,
Delete: resourceTurbotGuardrailDelete,
Exists: resourceTurbotGuardrailExists,
Importer: &schema.ResourceImporter{
State: resourceTurbotGuardrailImport,
},
Schema: map[string]*schema.Schema{
"title": {
Description: "The title of the guardrail.",
Type: schema.TypeString,
Required: true,
},
"description": {
Description: "The description of the guardrail.",
Type: schema.TypeString,
Optional: true,
},
"targets": {
Description: "The targets where the guardrail will be applied.",
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"controls": {
Description: "The control types associated with the guardrail.",
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"tags": {
Description: "The tags for the guardrail.",
Type: schema.TypeMap,
Optional: true,
},
"akas": {
Description: "The akas of the guardrail.",
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
DiffSuppressFunc: suppressIfAkaRemoved(),
},
},
}
}

func resourceTurbotGuardrailExists(d *schema.ResourceData, meta interface{}) (b bool, e error) {
client := meta.(*apiClient.Client)
id := d.Id()
return client.ResourceExists(id)
}

func resourceTurbotGuardrailCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*apiClient.Client)
// build map of folder properties
input := mapFromResourceDataWithPropertyMap(d, guardrailProperties)

guardrail, err := client.CreateGuardrail(input)
if err != nil {
return err
}

// assign the id
d.SetId(guardrail.Turbot.Id)

// TODO Remove Read call once schema changes are In.
return resourceTurbotGuardrailRead(d, meta)
}

func resourceTurbotGuardrailUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*apiClient.Client)
id := d.Id()

// build map of folder properties
input := mapFromResourceDataWithPropertyMap(d, getGuardrailUpdateProperties())
input["id"] = id

_, err := client.UpdateGuardrail(input)
if err != nil {
return err
}
// set 'Read' Properties
// TODO Remove Read call once schema changes are In.
return resourceTurbotGuardrailRead(d, meta)
}

func resourceTurbotGuardrailRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*apiClient.Client)
id := d.Id()

guardrail, err := client.ReadGuardrail(id)
if err != nil {
if errors.NotFoundError(err) {
// folder was not found - clear id
d.SetId("")
}
return err
}

d.Set("title", guardrail.Turbot.Title)
d.Set("description", guardrail.Description)
d.Set("akas", guardrail.Turbot.Akas)
d.Set("tags", guardrail.Turbot.Tags)

if len(guardrail.Targets.Items) > 0 {
targets := []string{}
for _, target := range guardrail.Targets.Items {
targets = append(targets, target.Uri)
}
d.Set("targets", targets)
}

if len(guardrail.ControlTypes.Items) > 0 {
controls := []string{}
for _, control := range guardrail.ControlTypes.Items {
controls = append(controls, control.Uri)
}
d.Set("controls", controls)
}

return nil
}

func resourceTurbotGuardrailDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*apiClient.Client)
id := d.Id()
err := client.DeleteResource(id)
if err != nil {
return err
}

// clear the id to show we have deleted
d.SetId("")

return nil
}

func resourceTurbotGuardrailImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
if err := resourceTurbotGuardrailRead(d, meta); err != nil {
return nil, err
}
return []*schema.ResourceData{d}, nil
}
Loading