Skip to content

Network peering #43

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

Merged
merged 8 commits into from
Oct 1, 2019
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
2 changes: 1 addition & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ websitefmtcheck:

lint:
@echo "==> Checking source code against linters..."
@GOGC=30 golangci-lint run ./$(PKG_NAME)
@GOGC=30 golangci-lint run ./$(PKG_NAME) --deadline=30m

tools:
GO111MODULE=off go get -u github.com/client9/misspell/cmd/misspell
Expand Down
2 changes: 1 addition & 1 deletion mongodbatlas/resource_mongodbatlas_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func testAccMongoDBAtlasClusterConfigAWS(projectID, name, backupEnabled string)
resource "mongodbatlas_cluster" "test" {
project_id = "%s"
name = "%s"
disk_size_gb = 40
disk_size_gb = 100
num_shards = 1

replication_factor = 3
Expand Down
47 changes: 42 additions & 5 deletions mongodbatlas/resource_mongodbatlas_network_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"net/http"
"reflect"
"strings"
"time"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
matlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas"
Expand Down Expand Up @@ -221,14 +223,22 @@ func resourceMongoDBAtlasNetworkContainerUpdate(d *schema.ResourceData, meta int
func resourceMongoDBAtlasNetworkContainerDelete(d *schema.ResourceData, meta interface{}) error {
//Get client connection.
conn := meta.(*matlas.Client)
ids := decodeStateID(d.Id())
projectID := ids["project_id"]
containerID := ids["container_id"]

_, err := conn.Containers.Delete(context.Background(), projectID, containerID)
stateConf := &resource.StateChangeConf{
Pending: []string{"provisioned_container"},
Target: []string{"deleted"},
Refresh: resourceNetworkContainerRefreshFunc(d, conn),
Timeout: 1 * time.Hour,
MinTimeout: 10 * time.Second,
Delay: 2 * time.Minute,
}

// Wait, catching any errors
_, err := stateConf.WaitForState()
if err != nil {
return fmt.Errorf(errorContainerDelete, containerID, err)
return fmt.Errorf(errorContainerDelete, decodeStateID(d.Id())["container_id"], err)
}

return nil
}

Expand Down Expand Up @@ -267,3 +277,30 @@ func resourceMongoDBAtlasNetworkContainerImportState(d *schema.ResourceData, met
}
return []*schema.ResourceData{d}, nil
}

func resourceNetworkContainerRefreshFunc(d *schema.ResourceData, client *matlas.Client) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
ids := decodeStateID(d.Id())
projectID := ids["project_id"]
containerID := ids["container_id"]

var err error
container, res, err := client.Containers.Get(context.Background(), projectID, containerID)
if err != nil {
if res.StatusCode == 404 {
return 42, "deleted", nil
}
return nil, "", err
}
if *container.Provisioned && err == nil {
return nil, "provisioned_container", nil
}

_, err = client.Containers.Delete(context.Background(), projectID, containerID)
if err != nil {
return nil, "provisioned_container", nil
}

return 42, "deleted", nil
}
}
107 changes: 77 additions & 30 deletions mongodbatlas/resource_mongodbatlas_network_peering.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ func resourceMongoDBAtlasNetworkPeering() *schema.Resource {
Optional: true,
Computed: true,
},
"atlas_gcp_project_id": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"atlas_vpc_name": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"error_message": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -238,15 +248,10 @@ func resourceMongoDBAtlasNetworkPeeringCreate(d *schema.ResourceData, meta inter
return fmt.Errorf(errorPeersCreate, err)
}

d.SetId(encodeStateID(map[string]string{
"project_id": projectID,
"peer_id": peer.ID,
}))

stateConf := &resource.StateChangeConf{
Pending: []string{"INITIATING", "FINALIZING", "ADDING_PEER", "WAITING_FOR_USER"},
Target: []string{"AVAILABLE", "PENDING_ACCEPTANCE"},
Refresh: resourceNetworkPeeringRefreshFunc(peer.ID, projectID, conn),
Refresh: resourceNetworkPeeringRefreshFunc(peer.ID, projectID, peerRequest.ContainerID, conn),
Timeout: 1 * time.Hour,
MinTimeout: 10 * time.Second,
Delay: 30 * time.Second,
Expand All @@ -258,6 +263,13 @@ func resourceMongoDBAtlasNetworkPeeringCreate(d *schema.ResourceData, meta inter
return fmt.Errorf(errorPeersCreate, err)
}

// container := cont.(matlas.Container)
d.SetId(encodeStateID(map[string]string{
"project_id": projectID,
"peer_id": peer.ID,
"provider_name": providerName,
}))

return resourceMongoDBAtlasNetworkPeeringRead(d, meta)
}

Expand All @@ -267,11 +279,11 @@ func resourceMongoDBAtlasNetworkPeeringRead(d *schema.ResourceData, meta interfa
ids := decodeStateID(d.Id())
projectID := ids["project_id"]
peerID := ids["peer_id"]
providerName := ids["provider_name"]

peer, resp, err := conn.Peers.Get(context.Background(), projectID, peerID)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {

return nil
}
return fmt.Errorf(errorPeersRead, peerID, err)
Expand Down Expand Up @@ -336,6 +348,23 @@ func resourceMongoDBAtlasNetworkPeeringRead(d *schema.ResourceData, meta interfa
if err := d.Set("peer_id", peer.ID); err != nil {
return fmt.Errorf("error setting `peer_id` for Network Peering Connection (%s): %s", peerID, err)
}

// If provider name is GCP we need to get the parameters to configure the the reciprocal connection
// between Mongo and Google
container := &matlas.Container{}
if strings.ToUpper(providerName) == "GCP" {
container, _, err = conn.Containers.Get(context.Background(), projectID, peer.ContainerID)
if err != nil {
return err
}
}
if err := d.Set("atlas_gcp_project_id", container.GCPProjectID); err != nil {
return fmt.Errorf("error setting `atlas_gcp_project_id` for Network Peering Connection (%s): %s", peerID, err)
}
if err := d.Set("atlas_vpc_name", container.NetworkName); err != nil {
return fmt.Errorf("error setting `atlas_vpc_name` for Network Peering Connection (%s): %s", peerID, err)
}

return nil
}

Expand Down Expand Up @@ -404,7 +433,7 @@ func resourceMongoDBAtlasNetworkPeeringUpdate(d *schema.ResourceData, meta inter
stateConf := &resource.StateChangeConf{
Pending: []string{"INITIATING", "FINALIZING", "ADDING_PEER", "WAITING_FOR_USER"},
Target: []string{"AVAILABLE", "PENDING_ACCEPTANCE"},
Refresh: resourceNetworkPeeringRefreshFunc(peerID, projectID, conn),
Refresh: resourceNetworkPeeringRefreshFunc(peerID, projectID, "", conn),
Timeout: d.Timeout(schema.TimeoutCreate),
MinTimeout: 30 * time.Second,
Delay: 1 * time.Minute,
Expand Down Expand Up @@ -437,10 +466,10 @@ func resourceMongoDBAtlasNetworkPeeringDelete(d *schema.ResourceData, meta inter
stateConf := &resource.StateChangeConf{
Pending: []string{"AVAILABLE", "INITIATING", "PENDING_ACCEPTANCE", "FINALIZING", "ADDING_PEER", "WAITING_FOR_USER", "TERMINATING", "DELETING"},
Target: []string{"DELETED"},
Refresh: resourceNetworkPeeringRefreshFunc(peerID, projectID, conn),
Refresh: resourceNetworkPeeringRefreshFunc(peerID, projectID, "", conn),
Timeout: 1 * time.Hour,
MinTimeout: 30 * time.Second,
Delay: 1 * time.Minute, // Wait 30 secs before starting
Delay: 10 * time.Second, // Wait 10 secs before starting
}

// Wait, catching any errors
Expand All @@ -454,52 +483,55 @@ func resourceMongoDBAtlasNetworkPeeringDelete(d *schema.ResourceData, meta inter
func resourceMongoDBAtlasNetworkPeeringImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
conn := meta.(*matlas.Client)

parts := strings.SplitN(d.Id(), "-", 2)
if len(parts) != 2 {
return nil, errors.New("import format error: to import a peer, use the format {project_id}-{peer_id}")
parts := strings.SplitN(d.Id(), "-", 3)
if len(parts) != 3 {
return nil, errors.New("import format error: to import a peer, use the format {project_id}-{peer_id}-{provider_name}")
}

projectID := parts[0]
peerID := parts[1]
providerName := parts[2]

peer, _, err := conn.Peers.Get(context.Background(), projectID, peerID)
if err != nil {
return nil, fmt.Errorf("couldn't import peer %s in project %s, error: %s", peerID, projectID, err)
}

d.SetId(encodeStateID(map[string]string{
"project_id": projectID,
"peer_id": peer.ID,
}))

if err := d.Set("project_id", projectID); err != nil {
log.Printf("[WARN] Error setting project_id for (%s): %s", peerID, err)
}

if err := d.Set("container_id", peer.ContainerID); err != nil {
log.Printf("[WARN] Error setting container_id for (%s): %s", peerID, err)
}

//Check wich provider is using.
provider := "AWS"
if peer.VNetName != "" {
provider = "AZURE"
} else if peer.NetworkName != "" {
provider = "GCP"
}
if providerName != provider {
providerName = provider
}

if err := d.Set("provider_name", provider); err != nil {
if err := d.Set("project_id", projectID); err != nil {
log.Printf("[WARN] Error setting project_id for (%s): %s", peerID, err)
}
if err := d.Set("container_id", peer.ContainerID); err != nil {
log.Printf("[WARN] Error setting container_id for (%s): %s", peerID, err)
}
if err := d.Set("provider_name", providerName); err != nil {
log.Printf("[WARN] Error setting provider_name for (%s): %s", peerID, err)
}

d.SetId(encodeStateID(map[string]string{
"project_id": projectID,
"peer_id": peer.ID,
"provider_name": providerName,
}))

return []*schema.ResourceData{d}, nil
}

func resourceNetworkPeeringRefreshFunc(peerID, projectID string, client *matlas.Client) resource.StateRefreshFunc {
func resourceNetworkPeeringRefreshFunc(peerID, projectID, containerID string, client *matlas.Client) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
c, resp, err := client.Peers.Get(context.Background(), projectID, peerID)
if err != nil {
if resp.StatusCode == 404 {
if resp != nil && resp.StatusCode == 404 {
return 42, "DELETED", nil
}
log.Printf("error reading MongoDB Network Peering Connection %s: %s", peerID, err)
Expand All @@ -511,9 +543,24 @@ func resourceNetworkPeeringRefreshFunc(peerID, projectID string, client *matlas.
if len(c.StatusName) > 0 {
status = c.StatusName
}

log.Printf("[DEBUG] status for MongoDB Network Peering Connection: %s: %s", peerID, status)

/* We need to get the provisioned status from Mongo container that contains the peering connection
* to validate if it has changed to true. This means that the reciprocal connection in Mongo side
* is right, and the Mongo parameters used on the Google side to configure the reciprocal connection
* are now available. */
if status == "WAITING_FOR_USER" {
container, _, err := client.Containers.Get(context.Background(), projectID, containerID)

if err != nil {
return nil, "", fmt.Errorf(errorContainerRead, containerID, err)
}

if *container.Provisioned {
return container, "PENDING_ACCEPTANCE", nil
}
}

return c, status, nil
}
}
20 changes: 10 additions & 10 deletions mongodbatlas/resource_mongodbatlas_network_peering_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func TestAccResourceMongoDBAtlasNetworkPeering_basicAWS(t *testing.T) {
}

func TestAccResourceMongoDBAtlasNetworkPeering_basicAzure(t *testing.T) {
t.Skip()
var peer matlas.Peer

resourceName := "mongodbatlas_network_peering.test"
Expand Down Expand Up @@ -85,7 +86,7 @@ func TestAccResourceMongoDBAtlasNetworkPeering_basicAzure(t *testing.T) {
ImportStateIdFunc: testAccCheckMongoDBAtlasNetworkPeeringImportStateIDFunc(resourceName),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"region_name", "atlas_cidr_block"},
ImportStateVerifyIgnore: []string{"atlas_cidr_block"},
},
},
})
Expand Down Expand Up @@ -113,15 +114,14 @@ func TestAccResourceMongoDBAtlasNetworkPeering_basicGCP(t *testing.T) {
resource.TestCheckResourceAttrSet(resourceName, "project_id"),
resource.TestCheckResourceAttrSet(resourceName, "container_id"),
resource.TestCheckResourceAttr(resourceName, "provider_name", providerName),
resource.TestCheckResourceAttr(resourceName, "azure_directory_id", gcpProjectID),
resource.TestCheckResourceAttr(resourceName, "gcp_project_id", gcpProjectID),
),
},
{
ResourceName: resourceName,
ImportStateIdFunc: testAccCheckMongoDBAtlasNetworkPeeringImportStateIDFunc(resourceName),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"region_name"},
ResourceName: resourceName,
ImportStateIdFunc: testAccCheckMongoDBAtlasNetworkPeeringImportStateIDFunc(resourceName),
ImportState: true,
ImportStateVerify: true,
},
},
})
Expand All @@ -133,7 +133,7 @@ func testAccCheckMongoDBAtlasNetworkPeeringImportStateIDFunc(resourceName string
if !ok {
return "", fmt.Errorf("Not found: %s", resourceName)
}
return fmt.Sprintf("%s-%s", rs.Primary.Attributes["project_id"], rs.Primary.Attributes["peer_id"]), nil
return fmt.Sprintf("%s-%s-%s", rs.Primary.Attributes["project_id"], rs.Primary.Attributes["peer_id"], rs.Primary.Attributes["provider_name"]), nil
}
}

Expand Down Expand Up @@ -236,7 +236,7 @@ func testAccMongoDBAtlasNetworkPeeringConfigGCP(projectID, providerName, gcpProj
return fmt.Sprintf(`
resource "mongodbatlas_network_container" "test" {
project_id = "%[1]s"
atlas_cidr_block = "192.168.208.0/21"
atlas_cidr_block = "192.168.192.0/18"
provider_name = "%[2]s"
}

Expand All @@ -245,7 +245,7 @@ func testAccMongoDBAtlasNetworkPeeringConfigGCP(projectID, providerName, gcpProj
container_id = mongodbatlas_network_container.test.container_id
provider_name = "%[2]s"
gcp_project_id = "%[3]s"
network_name = "mongodbatlas_network_container.test.network_name"
network_name = "myNetworkName"
}
`, projectID, providerName, gcpProjectID)
}
Loading