Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: added support for exit networks #616

Closed
Closed
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
37 changes: 37 additions & 0 deletions docs/data-sources/exit_network.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "twingate_exit_network Data Source - terraform-provider-twingate"
subcategory: ""
description: |-
TODO: Exit Networks behave similarly to Remote Networks. For more information, see Twingate's documentation https://www.twingate.com/docs/exit-networks.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexb-twingate please check which doc description should we set for ExitNetworks

---

# twingate_exit_network (Data Source)

TODO: Exit Networks behave similarly to Remote Networks. For more information, see Twingate's [documentation](https://www.twingate.com/docs/exit-networks).

## Example Usage

```terraform
data "twingate_exit_network" "foo" {
id = "<your exit network's id>"
}

# OR

data "twingate_exit_network" "foo" {
name = "<your exit network's name>"
}
```

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

### Optional

- `id` (String) The ID of the Exit Network
- `name` (String) The name of the Exit Network

### Read-Only

- `location` (String) The location of the Exit Network. Must be one of the following: AWS, AZURE, GOOGLE_CLOUD, ON_PREMISE, OTHER.
53 changes: 53 additions & 0 deletions docs/data-sources/exit_networks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "twingate_exit_networks Data Source - terraform-provider-twingate"
subcategory: ""
description: |-
TODO: Exit Networks behave similarly to Remote Networks. For more information, see Twingate's documentation https://www.twingate.com/docs/exit-networks.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexb-twingate please check which doc description should we set for ExitNetworks

---

# twingate_exit_networks (Data Source)

TODO: Exit Networks behave similarly to Remote Networks. For more information, see Twingate's [documentation](https://www.twingate.com/docs/exit-networks).

## Example Usage

```terraform
data "twingate_exit_networks" "all" {
name = "<your exit network's name>"
# name_regexp = "<regular expression of exit network name>"
# name_contains = "<a string in the exit network name>"
# name_exclude = "<your exit network's name to exclude>"
# name_prefix = "<prefix of exit network name>"
# name_suffix = "<suffix of exit network name>"
}
```

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

### Optional

- `name` (String) Returns only exit networks that exactly match this name. If no options are passed it will return all exit networks. Only one option can be used at a time.
- `name_contains` (String) Match when the value exist in the name of the exit network.
- `name_exclude` (String) Match when the exact value does not exist in the name of the exit network.
- `name_prefix` (String) The name of the exit network must start with the value.
- `name_regexp` (String) The regular expression match of the name of the exit network.
- `name_suffix` (String) The name of the exit network must end with the value.

### Read-Only

- `exit_networks` (Attributes List) List of Exit Networks (see [below for nested schema](#nestedatt--exit_networks))
- `id` (String) The ID of this resource.

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

Optional:

- `name` (String) The name of the Exit Network.

Read-Only:

- `id` (String) The ID of the Exit Network.
- `location` (String) The location of the Exit Network. Must be one of the following: AWS, AZURE, GOOGLE_CLOUD, ON_PREMISE, OTHER.
39 changes: 39 additions & 0 deletions docs/resources/exit_network.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "twingate_exit_network Resource - terraform-provider-twingate"
subcategory: ""
description: |-
TODO: Exit Networks behave similarly to Remote Networks. For more information, see Twingate's documentation https://www.twingate.com/docs/exit-networks.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexb-twingate please check which doc description should we set for ExitNetworks

---

# twingate_exit_network (Resource)

TODO: Exit Networks behave similarly to Remote Networks. For more information, see Twingate's [documentation](https://www.twingate.com/docs/exit-networks).

## Example Usage

```terraform
provider "twingate" {
api_token = "1234567890abcdef"
network = "mynetwork"
}

resource "twingate_exit_network" "aws_network" {
name = "aws_exit_network"
}
```

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

### Required

- `name` (String) The name of the Exit Network

### Optional

- `location` (String) The location of the Exit Network. Must be one of the following: AWS, AZURE, GOOGLE_CLOUD, ON_PREMISE, OTHER.

### Read-Only

- `id` (String) The ID of the Exit Network
9 changes: 9 additions & 0 deletions examples/data-sources/twingate_exit_network/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data "twingate_exit_network" "foo" {
id = "<your exit network's id>"
}

# OR

data "twingate_exit_network" "foo" {
name = "<your exit network's name>"
}
8 changes: 8 additions & 0 deletions examples/data-sources/twingate_exit_networks/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
data "twingate_exit_networks" "all" {
name = "<your exit network's name>"
# name_regexp = "<regular expression of exit network name>"
# name_contains = "<a string in the exit network name>"
# name_exclude = "<your exit network's name to exclude>"
# name_prefix = "<prefix of exit network name>"
# name_suffix = "<suffix of exit network name>"
}
8 changes: 8 additions & 0 deletions examples/resources/twingate_exit_network/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
provider "twingate" {
api_token = "1234567890abcdef"
network = "mynetwork"
}

resource "twingate_exit_network" "aws_network" {
name = "aws_exit_network"
}
5 changes: 5 additions & 0 deletions twingate/internal/attr/exit-network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package attr

const (
ExitNetworks = "exit_networks"
)
1 change: 1 addition & 0 deletions twingate/internal/attr/remote-network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package attr
const (
Location = "location"
RemoteNetworks = "remote_networks"
ExitNode = "exit_node"
)
1 change: 1 addition & 0 deletions twingate/internal/client/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
resourceConnectorToken resource = "connector token"
resourceGroup resource = "group"
resourceRemoteNetwork resource = "remote network"
resourceExitNetwork resource = "exit network"
resourceResource resource = "resource"
resourceResourceAccess resource = "resource access"
resourceSecurityPolicy resource = "security policy"
Expand Down
4 changes: 3 additions & 1 deletion twingate/internal/client/query/remote-network-by-id-read.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ func (r ReadRemoteNetworkByID) IsEmpty() bool {

type gqlRemoteNetwork struct {
IDName
Location string
Location string
NetworkType string
}

func (g gqlRemoteNetwork) ToModel() *model.RemoteNetwork {
return &model.RemoteNetwork{
ID: string(g.ID),
Name: g.Name,
Location: g.Location,
ExitNode: g.NetworkType == model.NetworkTypeExit,
}
}

Expand Down
2 changes: 1 addition & 1 deletion twingate/internal/client/query/remote-network-create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package query
import "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/model"

type CreateRemoteNetwork struct {
RemoteNetworkEntityResponse `graphql:"remoteNetworkCreate(name: $name, isActive: $isActive, location: $location)"`
RemoteNetworkEntityResponse `graphql:"remoteNetworkCreate(name: $name, isActive: $isActive, location: $location, networkType: $networkType)"`
}

func (q CreateRemoteNetwork) IsEmpty() bool {
Expand Down
22 changes: 20 additions & 2 deletions twingate/internal/client/query/remote-networks-read.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,30 @@ func (r RemoteNetworks) ToModel() []*model.RemoteNetwork {
})
}

type RemoteNetworkType string

func ConvertNetworkType(exitNodeNetwork bool) RemoteNetworkType {
if exitNodeNetwork {
return model.NetworkTypeExit
}

return model.NetworkTypeRegular
}

type RemoteNetworkTypeFilterOperatorInput struct {
In []RemoteNetworkType `json:"in"`
}

type RemoteNetworkFilterInput struct {
Name *StringFilterOperationInput `json:"name"`
Name *StringFilterOperationInput `json:"name"`
NetworkType *RemoteNetworkTypeFilterOperatorInput `json:"networkType"`
}

func NewRemoteNetworkFilterInput(name, filter string) *RemoteNetworkFilterInput {
func NewRemoteNetworkFilterInput(name, filter string, exitNode bool) *RemoteNetworkFilterInput {
return &RemoteNetworkFilterInput{
Name: NewStringFilterOperationInput(name, filter),
NetworkType: &RemoteNetworkTypeFilterOperatorInput{
In: []RemoteNetworkType{ConvertNetworkType(exitNode)},
},
}
}
49 changes: 35 additions & 14 deletions twingate/internal/client/remote-network.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ import (

type RemoteNetworkLocation string

func resolveNetworkResource(exitNode bool) resource {
if exitNode {
return resourceExitNetwork
}

return resourceRemoteNetwork
}

func (client *Client) CreateRemoteNetwork(ctx context.Context, req *model.RemoteNetwork) (*model.RemoteNetwork, error) {
opr := resourceRemoteNetwork.create()
opr := resolveNetworkResource(req.ExitNode).create()

if req.Name == "" {
return nil, opr.apiError(ErrGraphqlNetworkNameIsEmpty)
Expand All @@ -20,6 +28,7 @@ func (client *Client) CreateRemoteNetwork(ctx context.Context, req *model.Remote
gqlVar(req.Name, "name"),
gqlVar(true, "isActive"),
gqlVar(RemoteNetworkLocation(req.Location), "location"),
gqlVar(query.ConvertNetworkType(req.ExitNode), "networkType"),
)

response := query.CreateRemoteNetwork{}
Expand All @@ -30,11 +39,11 @@ func (client *Client) CreateRemoteNetwork(ctx context.Context, req *model.Remote
return response.ToModel(), nil
}

func (client *Client) ReadRemoteNetworks(ctx context.Context, name, filter string) ([]*model.RemoteNetwork, error) {
opr := resourceRemoteNetwork.read()
func (client *Client) ReadRemoteNetworks(ctx context.Context, name, filter string, exitNode bool) ([]*model.RemoteNetwork, error) {
opr := resolveNetworkResource(exitNode).read()

variables := newVars(
gqlNullable(query.NewRemoteNetworkFilterInput(name, filter), "filter"),
gqlNullable(query.NewRemoteNetworkFilterInput(name, filter, exitNode), "filter"),
cursor(query.CursorRemoteNetworks),
pageLimit(client.pageLimit),
)
Expand Down Expand Up @@ -64,17 +73,17 @@ func (client *Client) readRemoteNetworksAfter(ctx context.Context, variables map
return &response.PaginatedResource, nil
}

func (client *Client) ReadRemoteNetwork(ctx context.Context, remoteNetworkID, remoteNetworkName string) (*model.RemoteNetwork, error) {
func (client *Client) ReadRemoteNetwork(ctx context.Context, remoteNetworkID, remoteNetworkName string, exitNode bool) (*model.RemoteNetwork, error) {
switch {
case remoteNetworkID != "":
return client.ReadRemoteNetworkByID(ctx, remoteNetworkID)
return client.ReadRemoteNetworkByID(ctx, remoteNetworkID, exitNode)
default:
return client.ReadRemoteNetworkByName(ctx, remoteNetworkName)
return client.ReadRemoteNetworkByName(ctx, remoteNetworkName, exitNode)
}
}

func (client *Client) ReadRemoteNetworkByID(ctx context.Context, remoteNetworkID string) (*model.RemoteNetwork, error) {
opr := resourceRemoteNetwork.read()
func (client *Client) ReadRemoteNetworkByID(ctx context.Context, remoteNetworkID string, exitNode bool) (*model.RemoteNetwork, error) {
opr := resolveNetworkResource(exitNode).read()

if remoteNetworkID == "" {
return nil, opr.apiError(ErrGraphqlNetworkIDIsEmpty)
Expand All @@ -86,11 +95,17 @@ func (client *Client) ReadRemoteNetworkByID(ctx context.Context, remoteNetworkID
return nil, err
}

return response.ToModel(), nil
network := response.ToModel()

if network.ExitNode != exitNode {
return nil, opr.apiError(ErrGraphqlResultIsEmpty, attr{id: remoteNetworkID})
}

return network, nil
}

func (client *Client) ReadRemoteNetworkByName(ctx context.Context, remoteNetworkName string) (*model.RemoteNetwork, error) {
opr := resourceRemoteNetwork.read()
func (client *Client) ReadRemoteNetworkByName(ctx context.Context, remoteNetworkName string, exitNode bool) (*model.RemoteNetwork, error) {
opr := resolveNetworkResource(exitNode).read()

if remoteNetworkName == "" {
return nil, opr.apiError(ErrGraphqlNetworkNameIsEmpty)
Expand All @@ -102,11 +117,17 @@ func (client *Client) ReadRemoteNetworkByName(ctx context.Context, remoteNetwork
return nil, err
}

return response.RemoteNetworks.Edges[0].Node.ToModel(), nil
network := response.RemoteNetworks.Edges[0].Node.ToModel()

if network.ExitNode != exitNode {
return nil, opr.apiError(ErrGraphqlResultIsEmpty, attr{name: remoteNetworkName})
}

return network, nil
}

func (client *Client) UpdateRemoteNetwork(ctx context.Context, req *model.RemoteNetwork) (*model.RemoteNetwork, error) {
opr := resourceRemoteNetwork.update()
opr := resolveNetworkResource(req.ExitNode).update()

variables := newVars(
gqlID(req.ID),
Expand Down
4 changes: 4 additions & 0 deletions twingate/internal/model/remote-network.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const (
LocationGoogleCloud = "GOOGLE_CLOUD"
LocationOnPremise = "ON_PREMISE"
LocationOther = "OTHER"

NetworkTypeExit = "EXIT"
NetworkTypeRegular = "REGULAR"
)

var Locations = []string{LocationAWS, LocationAzure, LocationGoogleCloud, LocationOnPremise, LocationOther} //nolint
Expand All @@ -16,6 +19,7 @@ type RemoteNetwork struct {
ID string
Name string
Location string
ExitNode bool
}

func (n RemoteNetwork) GetName() string {
Expand Down
2 changes: 2 additions & 0 deletions twingate/internal/provider/datasource/all-datasources.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ const (
TwingateGroup = "twingate_group"
TwingateGroups = "twingate_groups"
TwingateRemoteNetwork = "twingate_remote_network"
TwingateExitNetwork = "twingate_exit_network"
TwingateRemoteNetworks = "twingate_remote_networks"
TwingateExitNetworks = "twingate_exit_networks"
TwingateUser = "twingate_user"
TwingateUsers = "twingate_users"
TwingateConnector = "twingate_connector"
Expand Down
10 changes: 10 additions & 0 deletions twingate/internal/provider/datasource/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ func convertRemoteNetworksToTerraform(networks []*model.RemoteNetwork) []remoteN
})
}

func convertExitNetworksToTerraform(networks []*model.RemoteNetwork) []exitNetworkModel {
return utils.Map(networks, func(network *model.RemoteNetwork) exitNetworkModel {
return exitNetworkModel{
ID: types.StringValue(network.ID),
Name: types.StringValue(network.Name),
Location: types.StringValue(network.Location),
}
})
}

func convertDomainsToTerraform(domains []string) *domainsModel {
return &domainsModel{
Domains: utils.MakeStringSet(domains),
Expand Down
Loading
Loading