diff --git a/Makefile b/Makefile index 9f8b04fc..f2bf5e91 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ BIN_NAME=terraform-provider-instaclustr # for VERSION, don't add prefix "v", e.g., use "1.9.8" instead of "v1.9.8" as it could break circleCI stuff -VERSION=1.13.2 +VERSION=1.14.0 INSTALL_FOLDER=$(HOME)/.terraform.d/plugins/terraform.instaclustr.com/instaclustr/instaclustr/$(VERSION)/darwin_amd64 diff --git a/README.md b/README.md index 21044c94..8732f49c 100644 --- a/README.md +++ b/README.md @@ -325,7 +325,7 @@ Unit tests are within `instaclustr` folder with `_unit_test` suffix, and used to #### Acceptance Testing -Acceptance tests are within `acc_test` folder, and used to run end-to-end testing. We recommend using CircleCI to run your acceptance tests, however you can run them locally. Acceptance tests require end to end interaction with the instaclustr platform and will create real (paid) infrastructure. If you wish to perform local testing you must set the variables below and run: ```make testacc``` +Acceptance tests are within `acc_test` folder, and used to run end-to-end testing. We recommend using CircleCI to run your acceptance tests, however you can run them locally. Acceptance tests require end to end interaction with the Instaclustr platform and will create real (paid) infrastructure. If you wish to perform local testing you must set the variables below and run: ```make testacc``` Variable | Command | Description diff --git a/acc_test/data/valid_with_vpc_peering.tf b/acc_test/data/valid_with_vpc_peering.tf index ab2d83d0..5835db3a 100644 --- a/acc_test/data/valid_with_vpc_peering.tf +++ b/acc_test/data/valid_with_vpc_peering.tf @@ -35,5 +35,19 @@ resource "instaclustr_vpc_peering" "valid_with_vpc_peering" { cluster_id = "${instaclustr_cluster.valid_with_vpc_peering.cluster_id}" peer_vpc_id = "vpc-12345678" peer_account_id = "494111121110" - peer_subnet = "10.128.176.0/20" + peer_subnets = toset(["10.128.176.0/20", "10.129.176.0/20"]) +} + +resource "instaclustr_vpc_peering" "valid_with_vpc_peering_single_subnet" { + cluster_id = "${instaclustr_cluster.valid_with_vpc_peering.cluster_id}" + peer_vpc_id = "vpc-12345679" + peer_account_id = "494111121110" + peer_subnets = toset(["10.130.176.0/20"]) +} + +resource "instaclustr_vpc_peering" "valid_with_vpc_peering_legacy" { + cluster_id = "${instaclustr_cluster.valid_with_vpc_peering.cluster_id}" + peer_vpc_id = "vpc-12345680" + peer_account_id = "494111121110" + peer_subnet = "10.131.176.0/20" } \ No newline at end of file diff --git a/docs/resources/vpc_peering.md b/docs/resources/vpc_peering.md index df043a30..59ef5107 100644 --- a/docs/resources/vpc_peering.md +++ b/docs/resources/vpc_peering.md @@ -16,10 +16,30 @@ Property | Description | Default `cluster_id`|The ID of an existing Instaclustr managed cluster|Required `peer_vpc_id`|The ID of the VPC with which you are creating the VPC peering connection|Required `peer_account_id`|The account ID of the owner of the accepter VPC|Required -`peer_subnet`|The subnet for the VPC|Required +`peer_subnets`|A set of one or more peer subnets (in IPv4 CIDR format) for the VPC|Required `peer_region`| The Region code for the accepter VPC, if the accepter VPC is located in a Region other than the Region in which you make the request. | Not Required `aws_vpc_connection_id`| The ID of the VPC peering connection. | Computed +#### Example +``` +resource "instaclustr_vpc_peering" "example_vpc_peering" { + cluster_id = "${instaclustr_cluster.example.cluster_id}" + peer_vpc_id = "vpc-123456" + peer_account_id = "1234567890" + peer_subnets = toset(["10.0.0.0/20", "10.0.32.0/20"]) +} +``` + +#### Legacy format +The legacy VPC peering connection type only supports a single IPv4 CIDR for the peer subnet field. To maintain backwards compatibility this resource definition is still available; however we recommend against using it for new plans. +Property | Description | Default +---------|-------------|-------- +`cluster_id`|The ID of an existing Instaclustr managed cluster|Required +`peer_vpc_id`|The ID of the VPC with which you are creating the VPC peering connection|Required +`peer_account_id`|The account ID of the owner of the accepter VPC|Required +`peer_subnet`|The peer subnet (in IPv4 CIDR format) for the VPC|Required +`peer_region`| The Region code for the accepter VPC, if the accepter VPC is located in a Region other than the Region in which you make the request. | Not Required +`aws_vpc_connection_id`| The ID of the VPC peering connection. | Computed #### Example ``` diff --git a/examples/main.tf b/examples/main.tf index 6c590a0b..1aa299dd 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -100,7 +100,7 @@ resource "instaclustr_vpc_peering" "example_vpc_peering" { cluster_id = "${instaclustr_cluster.example.id}" peer_vpc_id = "vpc-123456" peer_account_id = "1234567890" - peer_subnet = "10.0.0.0/20" + peer_subnets = toset(["10.0.0.0/20", "10.0.32.0/20"]) } // Updating the kafka-schema-registry and the kafka-rest-proxy bundle user passwords at the cluster creation time diff --git a/instaclustr/resource_cluster_unit_test.go b/instaclustr/resource_cluster_unit_test.go index 31de2397..f71b57ff 100644 --- a/instaclustr/resource_cluster_unit_test.go +++ b/instaclustr/resource_cluster_unit_test.go @@ -488,6 +488,68 @@ func TestDoClusterResizeCA(t *testing.T) { } } +func TestCreateVpcPeeringRequest(t *testing.T) { + resourceSchema := map[string]*schema.Schema{ + "peer_vpc_id": { + Type: schema.TypeString, + }, + "peer_account_id": { + Type: schema.TypeString, + }, + "peer_subnets": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "peer_region": { + Type: schema.TypeString, + }, + } + + peerSubnets := schema.NewSet(schema.HashString, []interface{}{"10.20.0.0/16", "10.21.0.0/16"}) + resourceDataMap := map[string]interface{}{ + "peer_vpc_id": "vpc-12345678", + "peer_account_id": "494111121110", + "peer_subnets": peerSubnets.List(), + "peer_region": "", + } + resourceLocalData := schema.TestResourceDataRaw(t, resourceSchema, resourceDataMap) + + if _, err := createVpcPeeringRequest(resourceLocalData); err != nil { + t.Fatalf("Expected nil error but got %v", err) + } +} + +func TestCreateVpcPeeringRequestLegacy(t *testing.T) { + resourceSchema := map[string]*schema.Schema{ + "peer_vpc_id": { + Type: schema.TypeString, + }, + "peer_account_id": { + Type: schema.TypeString, + }, + "peer_subnet": { + Type: schema.TypeString, + }, + "peer_region": { + Type: schema.TypeString, + }, + } + + resourceDataMap := map[string]interface{}{ + "peer_vpc_id": "vpc-12345678", + "peer_account_id": "494111121110", + "peer_subnet": "10.20.0.0/16", + "peer_region": "", + } + resourceLocalData := schema.TestResourceDataRaw(t, resourceSchema, resourceDataMap) + + if _, err := createVpcPeeringRequest(resourceLocalData); err != nil { + t.Fatalf("Expected nil error but got %v", err) + } +} + type MockApiClient struct { cluster Cluster err error diff --git a/instaclustr/resource_vpc_peering.go b/instaclustr/resource_vpc_peering.go index 2c047829..fa51d3fa 100644 --- a/instaclustr/resource_vpc_peering.go +++ b/instaclustr/resource_vpc_peering.go @@ -48,8 +48,18 @@ func resourceVpcPeering() *schema.Resource { }, "peer_subnet": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"peer_subnets"}, + }, + + "peer_subnets": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + ConflictsWith: []string{"peer_subnet"}, }, "peer_region": { @@ -91,15 +101,13 @@ func resourceVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error { timePassed += ClusterReadInterval } - createData := CreateVPCPeeringRequest{ - PeerVpcID: d.Get("peer_vpc_id").(string), - PeerAccountID: d.Get("peer_account_id").(string), - PeerSubnet: d.Get("peer_subnet").(string), - PeerRegion: d.Get("peer_region").(string), + createData, err := createVpcPeeringRequest(d) + if err != nil { + return fmt.Errorf("[Error] Error creating VPC peering request: %s", err) } var jsonStr []byte - jsonStr, err := json.Marshal(createData) + jsonStr, err = json.Marshal(createData) if err != nil { return fmt.Errorf("[Error] Error creating VPC peering request: %s", err) } @@ -144,7 +152,11 @@ func resourceVpcPeeringRead(d *schema.ResourceData, meta interface{}) error { d.Set("peer_vpc_id", vpcPeering.PeerVpcID) d.Set("peer_account_id", vpcPeering.PeerAccountID) d.Set("aws_vpc_connection_id", vpcPeering.AWSVpcConnectionID) - d.Set("peer_subnet", vpcPeering.PeerSubnet) + if len(vpcPeering.PeerSubnet) == 0 { + d.Set("peer_subnets", vpcPeering.PeerSubnets) + } else if len(vpcPeering.PeerSubnets) == 0 { + d.Set("peer_subnet", vpcPeering.PeerSubnet) + } d.Set("peer_region", vpcPeering.PeerRegion) log.Printf("[INFO] Fetched VPC peering %s info from the remote server.", vpcPeering.ID) @@ -187,3 +199,19 @@ func resourceVpcPeeringStateImport(d *schema.ResourceData, meta interface{}) ([] d.Set("vpc_peering_id", idParts[1]) return []*schema.ResourceData{d}, nil } + +func createVpcPeeringRequest(d *schema.ResourceData) (CreateVPCPeeringRequest, error) { + result := CreateVPCPeeringRequest{ + PeerVpcID: d.Get("peer_vpc_id").(string), + PeerAccountID: d.Get("peer_account_id").(string), + PeerRegion: d.Get("peer_region").(string), + } + if _, isSet := d.GetOk("peer_subnet"); isSet { + result.PeerSubnet = d.Get("peer_subnet").(string) + } else if _, isSet := d.GetOk("peer_subnets"); isSet { + result.PeerSubnets = d.Get("peer_subnets").(*schema.Set).List() + } else { + return result, fmt.Errorf("[Error] Error creating peering request - at least one subnet must be specified") + } + return result, nil +} diff --git a/instaclustr/structs.go b/instaclustr/structs.go index fe0be206..59fa49d2 100644 --- a/instaclustr/structs.go +++ b/instaclustr/structs.go @@ -155,27 +155,24 @@ type Node struct { } type CreateVPCPeeringRequest struct { - PeerVpcID string `json:"peerVpcId"` - PeerAccountID string `json:"peerAccountId"` - PeerSubnet string `json:"peerSubnet"` - PeerRegion string `json:"peerRegion,omitempty"` + PeerVpcID string `json:"peerVpcId"` + PeerAccountID string `json:"peerAccountId"` + PeerSubnet string `json:"peerSubnet"` + PeerSubnets []interface{} `json:"peerSubnets"` + PeerRegion string `json:"peerRegion,omitempty"` } type VPCPeering struct { - ID string `json:"id"` - AWSVpcConnectionID string `json:"aws_vpc_connection_id"` - ClusterDataCentre string `json:"clusterDataCentre"` - VpcID string `json:"vpcId"` - PeerVpcID string `json:"peerVpcId"` - PeerAccountID string `json:"peerAccountId"` - PeerSubnet string `json:"peerSubnet"` - StatusCode string `json:"statusCode"` - PeerRegion string `json:"peerRegion"` -} - -type VPCPeeringSubnet struct { - Network string `json:"network"` - PrefixLength string `json:"prefixLength"` + ID string `json:"id"` + AWSVpcConnectionID string `json:"aws_vpc_connection_id"` + ClusterDataCentre string `json:"clusterDataCentre"` + VpcID string `json:"vpcId"` + PeerVpcID string `json:"peerVpcId"` + PeerAccountID string `json:"peerAccountId"` + PeerSubnet string `json:"peerSubnet"` + PeerSubnets []interface{} `json:"peerSubnets"` + StatusCode string `json:"statusCode"` + PeerRegion string `json:"peerRegion"` } type ResizeClusterRequest struct { @@ -198,10 +195,10 @@ type UpdateBundleUserRequest struct { } type CreateKafkaUserRequest struct { - Username string `json:"username"` - Password string `json:"password"` - InitialPermissions string `json:"initial-permissions"` - Options KafkaUserCreateOptions `json:"options,omitempty"` + Username string `json:"username"` + Password string `json:"password"` + InitialPermissions string `json:"initial-permissions"` + Options KafkaUserCreateOptions `json:"options,omitempty"` } type KafkaUserCreateOptions struct { @@ -210,9 +207,9 @@ type KafkaUserCreateOptions struct { } type UpdateKafkaUserRequest struct { - Username string `json:"username"` - Password string `json:"password"` - Options KafkaUserResetPasswordOptions `json:"options,omitempty"` + Username string `json:"username"` + Password string `json:"password"` + Options KafkaUserResetPasswordOptions `json:"options,omitempty"` } type KafkaUserResetPasswordOptions struct {