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

Add VPNaaS Service #162

Merged
merged 1 commit into from
Jul 15, 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
1 change: 1 addition & 0 deletions huaweicloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ func Provider() terraform.ResourceProvider {
"huaweicloud_dis_stream_v2": resourceDisStreamV2(),
"huaweicloud_cs_cluster_v1": resourceCsClusterV1(),
"huaweicloud_cs_peering_connect_v1": resourceCsPeeringConnectV1(),
"huaweicloud_vpnaas_service_v2": resourceVpnServiceV2(),
},

ConfigureFunc: configureProvider,
Expand Down
295 changes: 295 additions & 0 deletions huaweicloud/resource_huaweicloud_vpnaas_service_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
package huaweicloud

import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/huaweicloud/golangsdk"
"github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services"
)

func resourceVpnServiceV2() *schema.Resource {
return &schema.Resource{
Create: resourceVpnServiceV2Create,
Read: resourceVpnServiceV2Read,
Update: resourceVpnServiceV2Update,
Delete: resourceVpnServiceV2Delete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * time.Minute),
Update: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(10 * time.Minute),
},

Schema: map[string]*schema.Schema{
"region": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Optional: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
"admin_state_up": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"tenant_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
"subnet_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"router_id": {
Type: schema.TypeString,
Required: true,
Computed: false,
ForceNew: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"external_v6_ip": {
Type: schema.TypeString,
Computed: true,
},
"external_v4_ip": {
Type: schema.TypeString,
Computed: true,
},
"value_specs": {
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
},
},
}
}

func resourceVpnServiceV2Create(d *schema.ResourceData, meta interface{}) error {

config := meta.(*Config)
networkingClient, err := config.networkingV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud networking client: %s", err)
}

var createOpts services.CreateOptsBuilder

adminStateUp := d.Get("admin_state_up").(bool)
createOpts = VpnServiceCreateOpts{
services.CreateOpts{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
AdminStateUp: &adminStateUp,
TenantID: d.Get("tenant_id").(string),
SubnetID: d.Get("subnet_id").(string),
RouterID: d.Get("router_id").(string),
},
MapValueSpecs(d),
}

log.Printf("[DEBUG] Create service: %#v", createOpts)

service, err := services.Create(networkingClient, createOpts).Extract()
if err != nil {
return err
}

stateConf := &resource.StateChangeConf{
Pending: []string{"NOT_CREATED"},
Target: []string{"PENDING_CREATE"},
Refresh: waitForServiceCreation(networkingClient, service.ID),
Timeout: d.Timeout(schema.TimeoutCreate),
Delay: 0,
MinTimeout: 2 * time.Second,
}
_, err = stateConf.WaitForState()

if err != nil {
return err
}

log.Printf("[DEBUG] Service created: %#v", service)

d.SetId(service.ID)

return resourceVpnServiceV2Read(d, meta)
}

func resourceVpnServiceV2Read(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Retrieve information about service: %s", d.Id())

config := meta.(*Config)
networkingClient, err := config.networkingV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud networking client: %s", err)
}

service, err := services.Get(networkingClient, d.Id()).Extract()
if err != nil {
return CheckDeleted(d, err, "service")
}

log.Printf("[DEBUG] Read HuaweiCloud Service %s: %#v", d.Id(), service)

d.Set("name", service.Name)
d.Set("description", service.Description)
d.Set("subnet_id", service.SubnetID)
d.Set("admin_state_up", service.AdminStateUp)
d.Set("tenant_id", service.TenantID)
d.Set("router_id", service.RouterID)
d.Set("status", service.Status)
d.Set("external_v6_ip", service.ExternalV6IP)
d.Set("external_v4_ip", service.ExternalV4IP)
d.Set("region", GetRegion(d, config))

return nil
}

func resourceVpnServiceV2Update(d *schema.ResourceData, meta interface{}) error {

config := meta.(*Config)
networkingClient, err := config.networkingV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud networking client: %s", err)
}

opts := services.UpdateOpts{}

var hasChange bool

if d.HasChange("name") {
name := d.Get("name").(string)
opts.Name = &name
hasChange = true
}

if d.HasChange("description") {
description := d.Get("description").(string)
opts.Description = &description
hasChange = true
}

if d.HasChange("admin_state_up") {
adminStateUp := d.Get("admin_state_up").(bool)
opts.AdminStateUp = &adminStateUp
hasChange = true
}

var updateOpts services.UpdateOptsBuilder
updateOpts = opts

log.Printf("[DEBUG] Updating service with id %s: %#v", d.Id(), updateOpts)

if hasChange {
service, err := services.Update(networkingClient, d.Id(), updateOpts).Extract()
if err != nil {
return err
}
stateConf := &resource.StateChangeConf{
Pending: []string{"PENDING_UPDATE"},
Target: []string{"UPDATED"},
Refresh: waitForServiceUpdate(networkingClient, service.ID),
Timeout: d.Timeout(schema.TimeoutCreate),
Delay: 0,
MinTimeout: 2 * time.Second,
}
_, err = stateConf.WaitForState()

if err != nil {
return err
}

log.Printf("[DEBUG] Updated service with id %s", d.Id())
}

return resourceVpnServiceV2Read(d, meta)
}

func resourceVpnServiceV2Delete(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Destroy service: %s", d.Id())

config := meta.(*Config)
networkingClient, err := config.networkingV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud networking client: %s", err)
}

err = services.Delete(networkingClient, d.Id()).Err

if err != nil {
return err
}

stateConf := &resource.StateChangeConf{
Pending: []string{"DELETING"},
Target: []string{"DELETED"},
Refresh: waitForServiceDeletion(networkingClient, d.Id()),
Timeout: d.Timeout(schema.TimeoutDelete),
Delay: 0,
MinTimeout: 2 * time.Second,
}

_, err = stateConf.WaitForState()

return err
}

func waitForServiceDeletion(networkingClient *golangsdk.ServiceClient, id string) resource.StateRefreshFunc {

return func() (interface{}, string, error) {
serv, err := services.Get(networkingClient, id).Extract()
log.Printf("[DEBUG] Got service %s => %#v", id, serv)

if err != nil {
if _, ok := err.(golangsdk.ErrDefault404); ok {
log.Printf("[DEBUG] Service %s is actually deleted", id)
return "", "DELETED", nil
}
return nil, "", fmt.Errorf("Unexpected error: %s", err)
}

log.Printf("[DEBUG] Service %s deletion is pending", id)
return serv, "DELETING", nil
}
}

func waitForServiceCreation(networkingClient *golangsdk.ServiceClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
service, err := services.Get(networkingClient, id).Extract()
if err != nil {
return "", "NOT_CREATED", nil
}
return service, "PENDING_CREATE", nil
}
}

func waitForServiceUpdate(networkingClient *golangsdk.ServiceClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
service, err := services.Get(networkingClient, id).Extract()
if err != nil {
return "", "PENDING_UPDATE", nil
}
return service, "UPDATED", nil
}
}
94 changes: 94 additions & 0 deletions huaweicloud/resource_huaweicloud_vpnaas_service_v2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package huaweicloud

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/huaweicloud/golangsdk"
"github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services"
"strconv"
)

func TestAccVpnServiceV2_basic(t *testing.T) {
var service services.Service
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVpnServiceV2Destroy,
Steps: []resource.TestStep{
{
Config: testAccVpnServiceV2_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckVpnServiceV2Exists(
"huaweicloud_vpnaas_service_v2.service_1", &service),
resource.TestCheckResourceAttrPtr("huaweicloud_vpnaas_service_v2.service_1", "router_id", &service.RouterID),
resource.TestCheckResourceAttr("huaweicloud_vpnaas_service_v2.service_1", "admin_state_up", strconv.FormatBool(service.AdminStateUp)),
),
},
},
})
}

func testAccCheckVpnServiceV2Destroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud networking client: %s", err)
}
for _, rs := range s.RootModule().Resources {
if rs.Type != "huaweicloud_vpnaas_service" {
continue
}
_, err = services.Get(networkingClient, rs.Primary.ID).Extract()
if err == nil {
return fmt.Errorf("Service (%s) still exists.", rs.Primary.ID)
}
if _, ok := err.(golangsdk.ErrDefault404); !ok {
return err
}
}
return nil
}

func testAccCheckVpnServiceV2Exists(n string, serv *services.Service) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

config := testAccProvider.Meta().(*Config)
networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud networking client: %s", err)
}

var found *services.Service

found, err = services.Get(networkingClient, rs.Primary.ID).Extract()
if err != nil {
return err
}
*serv = *found

return nil
}
}

var testAccVpnServiceV2_basic = fmt.Sprintf(`
resource "huaweicloud_networking_router_v2" "router_1" {
name = "router_1"
admin_state_up = "true"
external_network_id = "%s"
}
resource "huaweicloud_vpnaas_service_v2" "service_1" {
router_id = "${huaweicloud_networking_router_v2.router_1.id}"
admin_state_up = "false"
}
`, OS_EXTGW_ID)
Loading