diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31258383..89ca7086 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,7 @@ on: - 'README.md' branches: - main + - feature/add-exit-network-attribute # Ensures only 1 action runs per PR and previous is canceled on new trigger concurrency: diff --git a/.github/workflows/smoketests.yml b/.github/workflows/smoketests.yml index 3525f2f7..ee4ebfd5 100644 --- a/.github/workflows/smoketests.yml +++ b/.github/workflows/smoketests.yml @@ -4,8 +4,8 @@ name: Smoke Tests permissions: read-all on: -# schedule: -# - cron: "0 */3 * * *" + schedule: + - cron: "0 */3 * * *" workflow_dispatch: {} jobs: diff --git a/docs/data-sources/remote_network.md b/docs/data-sources/remote_network.md index 744050d9..a8370f8e 100644 --- a/docs/data-sources/remote_network.md +++ b/docs/data-sources/remote_network.md @@ -35,3 +35,4 @@ data "twingate_remote_network" "foo" { ### Read-Only - `location` (String) The location of the Remote Network. Must be one of the following: AWS, AZURE, GOOGLE_CLOUD, ON_PREMISE, OTHER. +- `type` (String) The type of the Remote Network. Must be one of the following: REGULAR, EXIT. diff --git a/docs/data-sources/remote_networks.md b/docs/data-sources/remote_networks.md index e1c93496..27a81c36 100644 --- a/docs/data-sources/remote_networks.md +++ b/docs/data-sources/remote_networks.md @@ -51,3 +51,4 @@ Read-Only: - `id` (String) The ID of the Remote Network. - `location` (String) The location of the Remote Network. Must be one of the following: AWS, AZURE, GOOGLE_CLOUD, ON_PREMISE, OTHER. +- `type` (String) The type of the Remote Network. Must be one of the following: REGULAR, EXIT. diff --git a/docs/resources/remote_network.md b/docs/resources/remote_network.md index f4867240..fa9d3513 100644 --- a/docs/resources/remote_network.md +++ b/docs/resources/remote_network.md @@ -32,8 +32,8 @@ resource "twingate_remote_network" "aws_network" { ### Optional -- `exit_node` (Boolean) TODO - `location` (String) The location of the Remote Network. Must be one of the following: AWS, AZURE, GOOGLE_CLOUD, ON_PREMISE, OTHER. +- `type` (String) The type of the Remote Network. Must be one of the following: REGULAR, EXIT. Defaults to REGULAR. ### Read-Only diff --git a/twingate/internal/attr/remote-network.go b/twingate/internal/attr/remote-network.go index 282ac2c1..63e2cf9a 100644 --- a/twingate/internal/attr/remote-network.go +++ b/twingate/internal/attr/remote-network.go @@ -3,5 +3,4 @@ package attr const ( Location = "location" RemoteNetworks = "remote_networks" - ExitNode = "exit_node" ) diff --git a/twingate/internal/client/query/remote-network-by-id-read.go b/twingate/internal/client/query/remote-network-by-id-read.go index 1dd7cfaa..dba40154 100644 --- a/twingate/internal/client/query/remote-network-by-id-read.go +++ b/twingate/internal/client/query/remote-network-by-id-read.go @@ -14,7 +14,8 @@ func (r ReadRemoteNetworkByID) IsEmpty() bool { type gqlRemoteNetwork struct { IDName - Location string + Location string + NetworkType string } func (g gqlRemoteNetwork) ToModel() *model.RemoteNetwork { @@ -22,6 +23,7 @@ func (g gqlRemoteNetwork) ToModel() *model.RemoteNetwork { ID: string(g.ID), Name: g.Name, Location: g.Location, + Type: g.NetworkType, } } diff --git a/twingate/internal/client/remote-network.go b/twingate/internal/client/remote-network.go index c2415527..ebf4a614 100644 --- a/twingate/internal/client/remote-network.go +++ b/twingate/internal/client/remote-network.go @@ -12,14 +12,6 @@ type ( RemoteNetworkType string ) -func convertNetworkType(exitNodeNetwork bool) RemoteNetworkType { - if exitNodeNetwork { - return RemoteNetworkType("EXIT") - } - - return RemoteNetworkType("REGULAR") -} - func (client *Client) CreateRemoteNetwork(ctx context.Context, req *model.RemoteNetwork) (*model.RemoteNetwork, error) { opr := resourceRemoteNetwork.create() @@ -31,7 +23,7 @@ func (client *Client) CreateRemoteNetwork(ctx context.Context, req *model.Remote gqlVar(req.Name, "name"), gqlVar(true, "isActive"), gqlVar(RemoteNetworkLocation(req.Location), "location"), - gqlVar(convertNetworkType(req.ExitNode), "networkType"), + gqlVar(RemoteNetworkType(req.Type), "networkType"), ) response := query.CreateRemoteNetwork{} diff --git a/twingate/internal/model/remote-network.go b/twingate/internal/model/remote-network.go index cc6da950..af94efa9 100644 --- a/twingate/internal/model/remote-network.go +++ b/twingate/internal/model/remote-network.go @@ -8,6 +8,9 @@ const ( LocationGoogleCloud = "GOOGLE_CLOUD" LocationOnPremise = "ON_PREMISE" LocationOther = "OTHER" + + NetworkTypeRegular = "REGULAR" + NetworkTypeExit = "EXIT" ) var Locations = []string{LocationAWS, LocationAzure, LocationGoogleCloud, LocationOnPremise, LocationOther} //nolint @@ -16,7 +19,7 @@ type RemoteNetwork struct { ID string Name string Location string - ExitNode bool + Type string } func (n RemoteNetwork) GetName() string { diff --git a/twingate/internal/provider/datasource/converter.go b/twingate/internal/provider/datasource/converter.go index b72f39be..fad526ca 100644 --- a/twingate/internal/provider/datasource/converter.go +++ b/twingate/internal/provider/datasource/converter.go @@ -84,6 +84,7 @@ func convertRemoteNetworksToTerraform(networks []*model.RemoteNetwork) []remoteN ID: types.StringValue(network.ID), Name: types.StringValue(network.Name), Location: types.StringValue(network.Location), + Type: types.StringValue(network.Type), } }) } diff --git a/twingate/internal/provider/datasource/remote-network.go b/twingate/internal/provider/datasource/remote-network.go index db3bba60..12d375bf 100644 --- a/twingate/internal/provider/datasource/remote-network.go +++ b/twingate/internal/provider/datasource/remote-network.go @@ -31,6 +31,7 @@ type remoteNetworkModel struct { ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` Location types.String `tfsdk:"location"` + Type types.String `tfsdk:"type"` } func (d *remoteNetwork) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { @@ -81,6 +82,10 @@ func (d *remoteNetwork) Schema(ctx context.Context, req datasource.SchemaRequest Computed: true, Description: fmt.Sprintf("The location of the Remote Network. Must be one of the following: %s.", strings.Join(model.Locations, ", ")), }, + attr.Type: schema.StringAttribute{ + Computed: true, + Description: fmt.Sprintf("The type of the Remote Network. Must be one of the following: %s.", strings.Join([]string{model.NetworkTypeRegular, model.NetworkTypeExit}, ", ")), + }, }, } } @@ -105,6 +110,7 @@ func (d *remoteNetwork) Read(ctx context.Context, req datasource.ReadRequest, re data.ID = types.StringValue(network.ID) data.Name = types.StringValue(network.Name) data.Location = types.StringValue(network.Location) + data.Type = types.StringValue(network.Type) // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) diff --git a/twingate/internal/provider/datasource/remote-networks.go b/twingate/internal/provider/datasource/remote-networks.go index 3ef12936..b5b7f981 100644 --- a/twingate/internal/provider/datasource/remote-networks.go +++ b/twingate/internal/provider/datasource/remote-networks.go @@ -111,6 +111,10 @@ func (d *remoteNetworks) Schema(ctx context.Context, req datasource.SchemaReques Computed: true, Description: fmt.Sprintf("The location of the Remote Network. Must be one of the following: %s.", strings.Join(model.Locations, ", ")), }, + attr.Type: schema.StringAttribute{ + Computed: true, + Description: fmt.Sprintf("The type of the Remote Network. Must be one of the following: %s.", strings.Join([]string{model.NetworkTypeRegular, model.NetworkTypeExit}, ", ")), + }, }, }, }, diff --git a/twingate/internal/provider/resource/remote-network.go b/twingate/internal/provider/resource/remote-network.go index dc737001..2db6534f 100644 --- a/twingate/internal/provider/resource/remote-network.go +++ b/twingate/internal/provider/resource/remote-network.go @@ -6,7 +6,6 @@ import ( "fmt" "strings" - "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/attr" "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/client" "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/model" @@ -15,9 +14,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -38,7 +37,7 @@ type remoteNetworkModel struct { ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` Location types.String `tfsdk:"location"` - ExitNode types.Bool `tfsdk:"exit_node"` + Type types.String `tfsdk:"type"` } func (r *remoteNetwork) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -73,12 +72,15 @@ func (r *remoteNetwork) Schema(_ context.Context, _ resource.SchemaRequest, resp stringvalidator.OneOf(model.Locations...), }, }, - attr.ExitNode: schema.BoolAttribute{ + attr.Type: schema.StringAttribute{ Optional: true, Computed: true, - Description: "TODO", - Default: booldefault.StaticBool(false), - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: fmt.Sprintf("The type of the Remote Network. Must be one of the following: %s. Defaults to %s.", strings.Join([]string{model.NetworkTypeRegular, model.NetworkTypeExit}, ", "), model.NetworkTypeRegular), + Default: stringdefault.StaticString(model.NetworkTypeRegular), + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + Validators: []validator.String{ + stringvalidator.OneOf(model.NetworkTypeRegular, model.NetworkTypeExit), + }, }, // computed attr.ID: schema.StringAttribute{ @@ -107,7 +109,7 @@ func (r *remoteNetwork) Create(ctx context.Context, req resource.CreateRequest, network, err := r.client.CreateRemoteNetwork(ctx, &model.RemoteNetwork{ Name: plan.Name.ValueString(), Location: location, - ExitNode: plan.ExitNode.ValueBool(), + Type: plan.Type.ValueString(), }) r.helper(ctx, network, &plan, &resp.State, &resp.Diagnostics, err, operationCreate) @@ -182,6 +184,7 @@ func (r *remoteNetwork) helper(ctx context.Context, network *model.RemoteNetwork state.ID = types.StringValue(network.ID) state.Name = types.StringValue(network.Name) state.Location = types.StringValue(network.Location) + state.Type = types.StringValue(network.Type) // Set refreshed state diags := respState.Set(ctx, state) diff --git a/twingate/internal/test/acctests/resource/remote-network_test.go b/twingate/internal/test/acctests/resource/remote-network_test.go index 507b76ea..555bb073 100644 --- a/twingate/internal/test/acctests/resource/remote-network_test.go +++ b/twingate/internal/test/acctests/resource/remote-network_test.go @@ -190,15 +190,15 @@ func TestAccTwingateRemoteNetworkCreateExitNode(t *testing.T) { CheckDestroy: acctests.CheckTwingateRemoteNetworkDestroy, Steps: []sdk.TestStep{ { - Config: terraformResourceRemoteNetworkExitNode(terraformResourceName, name, true), + Config: terraformResourceRemoteNetworkExitNode(terraformResourceName, name, model.NetworkTypeExit), Check: acctests.ComposeTestCheckFunc( acctests.CheckTwingateResourceExists(theResource), sdk.TestCheckResourceAttr(theResource, attr.Name, name), - sdk.TestCheckResourceAttr(theResource, attr.ExitNode, "true"), + sdk.TestCheckResourceAttr(theResource, attr.Type, model.NetworkTypeExit), ), }, { - Config: terraformResourceRemoteNetworkExitNode(terraformResourceName, name, false), + Config: terraformResourceRemoteNetworkExitNode(terraformResourceName, name, model.NetworkTypeRegular), ConfigPlanChecks: sdk.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(theResource, plancheck.ResourceActionReplace), @@ -210,11 +210,11 @@ func TestAccTwingateRemoteNetworkCreateExitNode(t *testing.T) { }) } -func terraformResourceRemoteNetworkExitNode(terraformResourceName, name string, exitNode bool) string { +func terraformResourceRemoteNetworkExitNode(terraformResourceName, name, networkType string) string { return fmt.Sprintf(` resource "twingate_remote_network" "%s" { name = "%s" - exit_node = %v + type = "%s" } - `, terraformResourceName, name, exitNode) + `, terraformResourceName, name, networkType) } diff --git a/twingate/internal/test/client/remote-network_test.go b/twingate/internal/test/client/remote-network_test.go index 9845e33d..291c4f95 100644 --- a/twingate/internal/test/client/remote-network_test.go +++ b/twingate/internal/test/client/remote-network_test.go @@ -15,6 +15,7 @@ func TestClientRemoteNetworkCreateOk(t *testing.T) { ID: "test-id", Name: "test", Location: model.LocationOther, + Type: model.NetworkTypeRegular, } jsonResponse := `{ @@ -23,7 +24,8 @@ func TestClientRemoteNetworkCreateOk(t *testing.T) { "entity": { "id": "test-id", "name": "test", - "location": "OTHER" + "location": "OTHER", + "networkType": "REGULAR" }, "ok": true, "error": null @@ -39,6 +41,7 @@ func TestClientRemoteNetworkCreateOk(t *testing.T) { remoteNetwork, err := client.CreateRemoteNetwork(context.Background(), &model.RemoteNetwork{ Name: "test", Location: model.LocationOther, + Type: model.NetworkTypeRegular, }) assert.NoError(t, err) @@ -429,16 +432,19 @@ func TestClientNetworkReadAllOk(t *testing.T) { ID: "network1", Name: "tf-acc-network1", Location: model.LocationAzure, + Type: model.NetworkTypeRegular, }, { ID: "network2", Name: "network2", Location: model.LocationAWS, + Type: model.NetworkTypeRegular, }, { ID: "network3", Name: "tf-acc-network3", Location: model.LocationGoogleCloud, + Type: model.NetworkTypeExit, }, } @@ -454,14 +460,16 @@ func TestClientNetworkReadAllOk(t *testing.T) { "node": { "id": "network1", "name": "tf-acc-network1", - "location": "AZURE" + "location": "AZURE", + "networkType": "REGULAR" } }, { "node": { "id": "network2", "name": "network2", - "location": "AWS" + "location": "AWS", + "networkType": "REGULAR" } } ] @@ -480,7 +488,8 @@ func TestClientNetworkReadAllOk(t *testing.T) { "node": { "id": "network3", "name": "tf-acc-network3", - "location": "GOOGLE_CLOUD" + "location": "GOOGLE_CLOUD", + "networkType": "EXIT" } } ] @@ -595,6 +604,7 @@ func TestClientReadRemoteNetworkWithIDOk(t *testing.T) { ID: "network1", Name: "tf-acc-network1", Location: model.LocationOther, + Type: model.NetworkTypeRegular, } jsonResponse := `{ @@ -602,7 +612,8 @@ func TestClientReadRemoteNetworkWithIDOk(t *testing.T) { "remoteNetwork": { "id": "network1", "name": "tf-acc-network1", - "location": "OTHER" + "location": "OTHER", + "networkType": "REGULAR" } } }` @@ -626,6 +637,7 @@ func TestClientReadRemoteNetworkWithNameOk(t *testing.T) { ID: "network1", Name: "tf-acc-network1", Location: model.LocationAWS, + Type: model.NetworkTypeRegular, } jsonResponse := `{ @@ -636,14 +648,16 @@ func TestClientReadRemoteNetworkWithNameOk(t *testing.T) { "node": { "id": "network1", "name": "tf-acc-network1", - "location": "AWS" + "location": "AWS", + "networkType": "REGULAR" } }, { "node": { "id": "network2", "name": "tf-acc-network1", - "location": "AZURE" + "location": "AZURE", + "networkType": "REGULAR" } } ]