From 8bf3e9a711c574e3703cf583e3c0b6f08d06b256 Mon Sep 17 00:00:00 2001 From: Zhenguo Niu Date: Mon, 15 Jul 2019 16:23:45 +0800 Subject: [PATCH] Add VPNaaS Service --- huaweicloud/provider.go | 1 + .../resource_huaweicloud_vpnaas_service_v2.go | 295 ++++++++++++++++++ ...urce_huaweicloud_vpnaas_service_v2_test.go | 94 ++++++ huaweicloud/types.go | 7 + .../v2/extensions/vpnaas/services/doc.go | 68 ++++ .../v2/extensions/vpnaas/services/requests.go | 150 +++++++++ .../v2/extensions/vpnaas/services/results.go | 121 +++++++ .../v2/extensions/vpnaas/services/urls.go | 16 + vendor/modules.txt | 1 + .../docs/r/vpnaas_service_v2.html.markdown | 72 +++++ website/huaweicloud.erb | 9 + 11 files changed, 834 insertions(+) create mode 100644 huaweicloud/resource_huaweicloud_vpnaas_service_v2.go create mode 100644 huaweicloud/resource_huaweicloud_vpnaas_service_v2_test.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/doc.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/requests.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/results.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/urls.go create mode 100644 website/docs/r/vpnaas_service_v2.html.markdown diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 5b70b7a649..2f4b9b77eb 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -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, diff --git a/huaweicloud/resource_huaweicloud_vpnaas_service_v2.go b/huaweicloud/resource_huaweicloud_vpnaas_service_v2.go new file mode 100644 index 0000000000..f2a08fd3b6 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_vpnaas_service_v2.go @@ -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 + } +} diff --git a/huaweicloud/resource_huaweicloud_vpnaas_service_v2_test.go b/huaweicloud/resource_huaweicloud_vpnaas_service_v2_test.go new file mode 100644 index 0000000000..47218ef47b --- /dev/null +++ b/huaweicloud/resource_huaweicloud_vpnaas_service_v2_test.go @@ -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) diff --git a/huaweicloud/types.go b/huaweicloud/types.go index a42e61d4d3..5bb630136d 100644 --- a/huaweicloud/types.go +++ b/huaweicloud/types.go @@ -21,6 +21,7 @@ import ( "github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/fwaas_v2/rules" "github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/layer3/floatingips" "github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/layer3/routers" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services" "github.com/huaweicloud/golangsdk/openstack/networking/v2/networks" "github.com/huaweicloud/golangsdk/openstack/networking/v2/ports" "github.com/huaweicloud/golangsdk/openstack/networking/v2/subnets" @@ -358,3 +359,9 @@ type EIPCreateOpts struct { eips.ApplyOpts ValueSpecs map[string]string `json:"value_specs,omitempty"` } + +// VpnServiceCreateOpts represents the attributes used when creating a new VPN service. +type VpnServiceCreateOpts struct { + services.CreateOpts + ValueSpecs map[string]string `json:"value_specs,omitempty"` +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/doc.go b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/doc.go new file mode 100644 index 0000000000..b0a13a05d7 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/doc.go @@ -0,0 +1,68 @@ +/* +Package services allows management and retrieval of VPN services in the +OpenStack Networking Service. + +Example to List Services + + listOpts := services.ListOpts{ + TenantID: "966b3c7d36a24facaf20b7e458bf2192", + } + + allPages, err := services.List(networkClient, listOpts).AllPages() + if err != nil { + panic(err) + } + + allPolicies, err := services.ExtractServices(allPages) + if err != nil { + panic(err) + } + + for _, service := range allServices { + fmt.Printf("%+v\n", service) + } + +Example to Create a Service + + createOpts := services.CreateOpts{ + Name: "vpnservice1", + Description: "A service", + RouterID: "2512e759-e8d7-4eea-a0af-4a85927a2e59", + AdminStateUp: golangsdk.Enabled, + } + + service, err := services.Create(networkClient, createOpts).Extract() + if err != nil { + panic(err) + } + +Example to Update a Service + + serviceID := "38aee955-6283-4279-b091-8b9c828000ec" + + updateOpts := services.UpdateOpts{ + Description: "New Description", + } + + service, err := services.Update(networkClient, serviceID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to Delete a Service + + serviceID := "38aee955-6283-4279-b091-8b9c828000ec" + err := services.Delete(networkClient, serviceID).ExtractErr() + if err != nil { + panic(err) + } + +Example to Show the details of a specific Service by ID + + service, err := services.Get(client, "f2b08c1e-aa81-4668-8ae1-1401bcb0576c").Extract() + if err != nil { + panic(err) + } + +*/ +package services diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/requests.go new file mode 100644 index 0000000000..f1ef0d0134 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/requests.go @@ -0,0 +1,150 @@ +package services + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToServiceCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains all the values needed to create a new VPN service +type CreateOpts struct { + // TenantID specifies a tenant to own the VPN service. The caller must have + // an admin role in order to set this. Otherwise, this field is left unset + // and the caller will be the owner. + TenantID string `json:"tenant_id,omitempty"` + + // SubnetID is the ID of the subnet. + SubnetID string `json:"subnet_id,omitempty"` + + // RouterID is the ID of the router. + RouterID string `json:"router_id" required:"true"` + + // Description is the human readable description of the service. + Description string `json:"description,omitempty"` + + // AdminStateUp is the administrative state of the resource, which is up (true) or down (false). + AdminStateUp *bool `json:"admin_state_up"` + + // Name is the human readable name of the service. + Name string `json:"name,omitempty"` + + // The ID of the flavor. + FlavorID string `json:"flavor_id,omitempty"` +} + +// ToServiceCreateMap casts a CreateOpts struct to a map. +func (opts CreateOpts) ToServiceCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "vpnservice") +} + +// Create accepts a CreateOpts struct and uses the values to create a new +// VPN service. +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToServiceCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) + return +} + +// Delete will permanently delete a particular VPN service based on its +// unique ID. +func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = c.Delete(resourceURL(c, id), nil) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToServiceUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts contains the values used when updating a VPN service +type UpdateOpts struct { + // Name is the human readable name of the service. + Name *string `json:"name,omitempty"` + + // Description is the human readable description of the service. + Description *string `json:"description,omitempty"` + + // AdminStateUp is the administrative state of the resource, which is up (true) or down (false). + AdminStateUp *bool `json:"admin_state_up,omitempty"` +} + +// ToServiceUpdateMap casts aa UodateOpts struct to a map. +func (opts UpdateOpts) ToServiceUpdateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "vpnservice") +} + +// Update allows VPN services to be updated. +func Update(c *golangsdk.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToServiceUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// ListOptsBuilder allows extensions to add additional parameters to the +// List request. +type ListOptsBuilder interface { + ToServiceListQuery() (string, error) +} + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the VPN service attributes you want to see returned. +type ListOpts struct { + TenantID string `q:"tenant_id"` + Name string `q:"name"` + Description string `q:"description"` + AdminStateUp *bool `q:"admin_state_up"` + Status string `q:"status"` + SubnetID string `q:"subnet_id"` + RouterID string `q:"router_id"` + ProjectID string `q:"project_id"` + ExternalV6IP string `q:"external_v6_ip"` + ExternalV4IP string `q:"external_v4_ip"` + FlavorID string `q:"flavor_id"` +} + +// ToServiceListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToServiceListQuery() (string, error) { + q, err := golangsdk.BuildQueryString(opts) + return q.String(), err +} + +// List returns a Pager which allows you to iterate over a collection of +// VPN services. It accepts a ListOpts struct, which allows you to filter +// and sort the returned collection for greater efficiency. +func List(c *golangsdk.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := rootURL(c) + if opts != nil { + query, err := opts.ToServiceListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return ServicePage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Get retrieves a particular VPN service based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) + return +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/results.go new file mode 100644 index 0000000000..d41d70b7c6 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/results.go @@ -0,0 +1,121 @@ +package services + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// Service is a VPN Service +type Service struct { + // TenantID is the ID of the project. + TenantID string `json:"tenant_id"` + + // ProjectID is the ID of the project. + ProjectID string `json:"project_id"` + + // SubnetID is the ID of the subnet. + SubnetID string `json:"subnet_id"` + + // RouterID is the ID of the router. + RouterID string `json:"router_id"` + + // Description is a human-readable description for the resource. + // Default is an empty string + Description string `json:"description"` + + // AdminStateUp is the administrative state of the resource, which is up (true) or down (false). + AdminStateUp bool `json:"admin_state_up"` + + // Name is the human readable name of the service. + Name string `json:"name"` + + // Status indicates whether IPsec VPN service is currently operational. + // Values are ACTIVE, DOWN, BUILD, ERROR, PENDING_CREATE, PENDING_UPDATE, or PENDING_DELETE. + Status string `json:"status"` + + // ID is the unique ID of the VPN service. + ID string `json:"id"` + + // ExternalV6IP is the read-only external (public) IPv6 address that is used for the VPN service. + ExternalV6IP string `json:"external_v6_ip"` + + // ExternalV4IP is the read-only external (public) IPv4 address that is used for the VPN service. + ExternalV4IP string `json:"external_v4_ip"` + + // FlavorID is the ID of the flavor. + FlavorID string `json:"flavor_id"` +} + +type commonResult struct { + golangsdk.Result +} + +// ServicePage is the page returned by a pager when traversing over a +// collection of VPN services. +type ServicePage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of VPN services has +// reached the end of a page and the pager seeks to traverse over a new one. +// In order to do this, it needs to construct the next page's URL. +func (r ServicePage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"vpnservices_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a ServicePage struct is empty. +func (r ServicePage) IsEmpty() (bool, error) { + is, err := ExtractServices(r) + return len(is) == 0, err +} + +// ExtractServices accepts a Page struct, specifically a Service struct, +// and extracts the elements into a slice of Service structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractServices(r pagination.Page) ([]Service, error) { + var s struct { + Services []Service `json:"vpnservices"` + } + err := (r.(ServicePage)).ExtractInto(&s) + return s.Services, err +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Service. +type GetResult struct { + commonResult +} + +// Extract is a function that accepts a result and extracts a VPN service. +func (r commonResult) Extract() (*Service, error) { + var s struct { + Service *Service `json:"vpnservice"` + } + err := r.ExtractInto(&s) + return s.Service, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Service. +type CreateResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its +// ExtractErr method to determine if the operation succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} + +// UpdateResult represents the result of an update operation. Call its Extract +// method to interpret it as a service. +type UpdateResult struct { + commonResult +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/urls.go new file mode 100644 index 0000000000..ef17a34aed --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services/urls.go @@ -0,0 +1,16 @@ +package services + +import "github.com/huaweicloud/golangsdk" + +const ( + rootPath = "vpn" + resourcePath = "vpnservices" +) + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(rootPath, resourcePath) +} + +func resourceURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(rootPath, resourcePath, id) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4113f14965..9debaea5a2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -256,6 +256,7 @@ github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/provider github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/security/groups github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/security/rules github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/snatrules +github.com/huaweicloud/golangsdk/openstack/networking/v2/extensions/vpnaas/services github.com/huaweicloud/golangsdk/openstack/networking/v2/networks github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings github.com/huaweicloud/golangsdk/openstack/networking/v2/ports diff --git a/website/docs/r/vpnaas_service_v2.html.markdown b/website/docs/r/vpnaas_service_v2.html.markdown new file mode 100644 index 0000000000..b78af3a420 --- /dev/null +++ b/website/docs/r/vpnaas_service_v2.html.markdown @@ -0,0 +1,72 @@ +--- +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_vpnaas_service_v2" +sidebar_current: "docs-huaweicloud-resource-vpnaas-service-v2" +description: |- + Manages a V2 VPN service resource within HuaweiCloud. +--- + +# huaweicloud\_vpnaas\_service_v2 + +Manages a V2 VPN service resource within HuaweiCloud. + +## Example Usage + +```hcl +resource "huaweicloud_vpnaas_service_v2" "service_1" { + name = "my_service" + router_id = "14a75700-fc03-4602-9294-26ee44f366b3" + admin_state_up = "true" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional) The region in which to obtain the V2 Networking client. + A Networking client is needed to create a VPN service. If omitted, the + `region` argument of the provider is used. Changing this creates a new + service. + +* `name` - (Optional) The name of the service. Changing this updates the name of + the existing service. + +* `tenant_id` - (Optional) The owner of the service. Required if admin wants to + create a service for another project. Changing this creates a new service. + +* `description` - (Optional) The human-readable description for the service. + Changing this updates the description of the existing service. + +* `admin_state_up` - (Optional) The administrative state of the resource. Can either be up(true) or down(false). + Changing this updates the administrative state of the existing service. + +* `subnet_id` - (Optional) SubnetID is the ID of the subnet. Default is null. + +* `router_id` - (Required) The ID of the router. Changing this creates a new service. + +* `value_specs` - (Optional) Map of additional options. + +## Attributes Reference + +The following attributes are exported: + +* `region` - See Argument Reference above. +* `name` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. +* `router_id` - See Argument Reference above. +* `admin_state_up` - See Argument Reference above. +* `subnet_id` - See Argument Reference above. +* `status` - Indicates whether IPsec VPN service is currently operational. Values are ACTIVE, DOWN, BUILD, ERROR, PENDING_CREATE, PENDING_UPDATE, or PENDING_DELETE. +* `external_v6_ip` - The read-only external (public) IPv6 address that is used for the VPN service. +* `external_v4_ip` - The read-only external (public) IPv4 address that is used for the VPN service. +* `description` - See Argument Reference above. +* `value_specs` - See Argument Reference above. + +## Import + +Services can be imported using the `id`, e.g. + +``` +$ terraform import huaweicloud_vpnaas_service_v2.service_1 832cb7f3-59fe-40cf-8f64-8350ffc03272 +``` diff --git a/website/huaweicloud.erb b/website/huaweicloud.erb index 9826ca0171..786c617740 100644 --- a/website/huaweicloud.erb +++ b/website/huaweicloud.erb @@ -585,6 +585,15 @@ + > + VPNaaS Resources + + + > Cloud Stream Resources