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

Egress fw rules #18

Merged
merged 3 commits into from
Jan 9, 2024
Merged
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
6 changes: 6 additions & 0 deletions crusoe/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package crusoe
import (
"context"
"fmt"
"github.com/crusoecloud/terraform-provider-crusoe/internal/vpc_network"
"github.com/crusoecloud/terraform-provider-crusoe/internal/vpc_subnet"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
Expand Down Expand Up @@ -53,6 +55,8 @@ func (p *crusoeProvider) DataSources(_ context.Context) []func() datasource.Data
disk.NewDisksDataSource,
ib_network.NewIBNetworkDataSource,
project.NewProjectsDataSource,
vpc_network.NewVPCNetworksDataSource,
vpc_subnet.NewVPCSubnetsDataSource,
}
}

Expand All @@ -64,6 +68,8 @@ func (p *crusoeProvider) Resources(_ context.Context) []func() resource.Resource
firewall_rule.NewFirewallRuleResource,
ib_partition.NewIBPartitionResource,
project.NewProjectResource,
vpc_network.NewVPCNetworkResource,
vpc_subnet.NewVPCSubnetResource,
}
}

Expand Down
59 changes: 59 additions & 0 deletions examples/vpc-networks/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
terraform {
required_providers {
crusoe = {
source = "registry.terraform.io/crusoecloud/crusoe"
}
}
}

locals {
my_ssh_key = file("~/.ssh/id_ed25519.pub")
}

resource "crusoe_vpc_network" "my_vpc_network" {
name = "my-new-network"
cidr = "10.0.0.0/8"
}

resource "crusoe_vpc_subnet" "my_vpc_subnet" {
name = "my-new-subnet"
cidr = "10.0.0.0/16"
location = "us-northcentral1-a"
network = crusoe_vpc_network.my_vpc_network.id
}

// firewall rule
resource "crusoe_vpc_firewall_rule" "open_fw_rule" {
network = crusoe_vpc_network.my_vpc_network.id
name = "example-terraform-rule"
action = "allow"
direction = "ingress"
protocols = "tcp"
source = "0.0.0.0/0"
source_ports = "1-65535"
destination = crusoe_vpc_network.my_vpc_network.cidr
destination_ports = "1-65535"

// It is currently not possible for terraform to create subnets and firewall rules concurrently.
// This directive should be specified when creating firewall rules and subnets to avoid failures.
depends_on = [crusoe_vpc_subnet.my_vpc_subnet]
}

// Create a VM in the new subnet
resource "crusoe_compute_instance" "my_vm" {
name = "my-new-vm"
type = "a40.1x"
location = "us-northcentral1-a"

# specify the base image
image = "ubuntu20.04:latest"

ssh_key = local.my_ssh_key

network_interfaces = [
{
subnet = crusoe_vpc_subnet.my_vpc_subnet.id
}
]

}
4 changes: 2 additions & 2 deletions internal/firewall_rule/firewall_rule_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (r *firewallRuleResource) Schema(ctx context.Context, req resource.SchemaRe
"direction": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
Validators: []validator.String{validators.RegexValidator{RegexPattern: "^ingress"}}, // TODO: support egress once supported by API
Validators: []validator.String{validators.RegexValidator{RegexPattern: "^(ingress|egress)"}},
},
"protocols": schema.StringAttribute{
Required: true,
Expand Down Expand Up @@ -125,7 +125,7 @@ func (r *firewallRuleResource) Create(ctx context.Context, req resource.CreateRe
}

projectID := ""
if plan.ProjectID.ValueString() == ""{
if plan.ProjectID.ValueString() == "" {
project, err := common.GetFallbackProject(ctx, r.client, &resp.Diagnostics)
if err != nil {
resp.Diagnostics.AddError("Failed to create firewall rule",
Expand Down
2 changes: 2 additions & 0 deletions internal/vm/vm_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ func (r *vmResource) Schema(ctx context.Context, req resource.SchemaRequest, res
},
"subnet": schema.StringAttribute{
Computed: true,
Optional: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, // maintain across updates
},
"interface_type": schema.StringAttribute{
Expand Down Expand Up @@ -278,6 +279,7 @@ func (r *vmResource) Create(ctx context.Context, req resource.CreateRequest, res

for _, networkInterface := range tNetworkInterfaces {
newNetworkInterfaces = []swagger.NetworkInterface{{
Subnet: networkInterface.Subnet.ValueString(),
Ips: []swagger.IpAddresses{{
PublicIpv4: &swagger.PublicIpv4Address{
Type_: networkInterface.PublicIpv4.Type.ValueString(),
Expand Down
120 changes: 120 additions & 0 deletions internal/vpc_network/vpc_network_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package vpc_network

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

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"

swagger "github.com/crusoecloud/client-go/swagger/v1alpha5"
"github.com/crusoecloud/terraform-provider-crusoe/internal/common"
)

type vpcNetworksDataSource struct {
client *swagger.APIClient
}

type vpcNetworksDataSourceModel struct {
VPCNetworks []vpcNetworksModel `tfsdk:"vpc_networks"`
}

type vpcNetworksDataSourceFilter struct {

Check failure on line 23 in internal/vpc_network/vpc_network_data_source.go

View workflow job for this annotation

GitHub Actions / lint

`vpcNetworksDataSourceFilter` is unused (deadcode)
ProjectID *string `tfsdk:"project_id"`
}

type vpcNetworksModel struct {
ID string `tfsdk:"id"`
Name string `tfsdk:"name"`
CIDR string `tfsdk:"cidr"`
Gateway string `tfsdk:"gateway"`
Subnets []string `tfsdk:"subnets"`
}

func NewVPCNetworksDataSource() datasource.DataSource {
return &vpcNetworksDataSource{}
}

// Configure adds the provider configured client to the data source.
func (ds *vpcNetworksDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*swagger.APIClient)
if !ok {
resp.Diagnostics.AddError("Failed to initialize provider", common.ErrorMsgProviderInitFailed)

return
}

ds.client = client
}

//nolint:gocritic // Implements Terraform defined interface
func (ds *vpcNetworksDataSource) Metadata(ctx context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) {
response.TypeName = request.ProviderTypeName + "_vpc_networks"
}

//nolint:gocritic // Implements Terraform defined interface
func (ds *vpcNetworksDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) {
response.Schema = schema.Schema{Attributes: map[string]schema.Attribute{
"vpc_networks": schema.ListNestedAttribute{
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"name": schema.StringAttribute{
Required: true,
},
"cidr": schema.StringAttribute{
Required: true,
},
"gateway": schema.StringAttribute{
Required: true,
},
"subnets": schema.ListAttribute{
ElementType: types.StringType,
Optional: true,
},
},
},
},
}}
}

//nolint:gocritic // Implements Terraform defined interface
func (ds *vpcNetworksDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
projectID, err := common.GetFallbackProject(ctx, ds.client, &resp.Diagnostics)
if err != nil {
resp.Diagnostics.AddError("Failed to fetch VPC Networks",
fmt.Sprintf("No project was specified and it was not possible to determine which project to use: %v", err))

return
}

dataResp, httpResp, err := ds.client.VPCNetworksApi.ListVPCNetworks(ctx, projectID)
if err != nil {
resp.Diagnostics.AddError("Failed to Fetch VPC Networks", "Could not fetch VPC Network data at this time.")

return
}
defer httpResp.Body.Close()

var state vpcNetworksDataSourceModel
for i := range dataResp.Items {
state.VPCNetworks = append(state.VPCNetworks, vpcNetworksModel{
ID: dataResp.Items[i].Id,
Name: dataResp.Items[i].Name,
CIDR: dataResp.Items[i].Cidr,
Gateway: dataResp.Items[i].Gateway,
Subnets: dataResp.Items[i].Subnets,
})
}

diags := resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
}
Loading
Loading