From 85e76265de8b6ccc44854bee8beab50118a91a34 Mon Sep 17 00:00:00 2001 From: anton-sidelnikov Date: Thu, 3 Oct 2024 12:54:01 +0200 Subject: [PATCH] [Feat.] Enterprise VPN Connection Monitoring and EVPN Tags --- acceptance/openstack/evpn/connection_test.go | 78 ++++++++++++++++++- .../evpn/v5/connection-monitoring/Create.go | 50 ++++++++++++ .../evpn/v5/connection-monitoring/Delete.go | 10 +++ .../evpn/v5/connection-monitoring/Get.go | 17 ++++ .../evpn/v5/connection-monitoring/List.go | 28 +++++++ openstack/evpn/v5/quota/Get.go | 40 ++++++++++ openstack/evpn/v5/tags/Create.go | 28 +++++++ openstack/evpn/v5/tags/Delete.go | 18 +++++ openstack/evpn/v5/tags/List.go | 24 ++++++ 9 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 openstack/evpn/v5/connection-monitoring/Create.go create mode 100644 openstack/evpn/v5/connection-monitoring/Delete.go create mode 100644 openstack/evpn/v5/connection-monitoring/Get.go create mode 100644 openstack/evpn/v5/connection-monitoring/List.go create mode 100644 openstack/evpn/v5/quota/Get.go create mode 100644 openstack/evpn/v5/tags/Create.go create mode 100644 openstack/evpn/v5/tags/Delete.go create mode 100644 openstack/evpn/v5/tags/List.go diff --git a/acceptance/openstack/evpn/connection_test.go b/acceptance/openstack/evpn/connection_test.go index a1593089b..0f7076171 100644 --- a/acceptance/openstack/evpn/connection_test.go +++ b/acceptance/openstack/evpn/connection_test.go @@ -12,8 +12,11 @@ import ( "github.com/opentelekomcloud/gophertelekomcloud/openstack/common/pointerto" "github.com/opentelekomcloud/gophertelekomcloud/openstack/common/tags" "github.com/opentelekomcloud/gophertelekomcloud/openstack/evpn/v5/connection" + cm "github.com/opentelekomcloud/gophertelekomcloud/openstack/evpn/v5/connection-monitoring" cgw "github.com/opentelekomcloud/gophertelekomcloud/openstack/evpn/v5/customer-gateway" "github.com/opentelekomcloud/gophertelekomcloud/openstack/evpn/v5/gateway" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/evpn/v5/quota" + vpntags "github.com/opentelekomcloud/gophertelekomcloud/openstack/evpn/v5/tags" "github.com/opentelekomcloud/gophertelekomcloud/openstack/networking/v1/eips" "github.com/opentelekomcloud/gophertelekomcloud/openstack/networking/v2/subnets" th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" @@ -73,7 +76,6 @@ func TestConnectionLifecycle(t *testing.T) { t.Logf("Attempting to DELETE Enterprise VPN Connection: %s", gw.ID) th.AssertNoErr(t, connection.Delete(client, conn.ID)) th.AssertNoErr(t, WaitForConnectionDeleted(client, conn.ID, 800)) - }) t.Logf("Attempting to GET Enterprise VPN Connection: %s", conn.ID) @@ -106,6 +108,52 @@ func TestConnectionLifecycle(t *testing.T) { }) th.AssertNoErr(t, err) th.AssertEquals(t, 1, len(connList)) + + t.Logf("Attempting to CREATE Enterprise VPN Connection Monitoring") + monitoring, err := cm.Create(client, cm.CreateOpts{ConnectionID: conn.ID}) + th.AssertNoErr(t, err) + th.AssertNoErr(t, WaitForConnectionMonitoringActive(client, monitoring.ID, 800)) + th.AssertEquals(t, conn.ID, monitoring.ConnectionId) + + t.Cleanup(func() { + t.Logf("Attempting to DELETE Enterprise VPN Connection Monitoring: %s", monitoring.ID) + th.AssertNoErr(t, cm.Delete(client, monitoring.ID)) + th.AssertNoErr(t, WaitForConnectionMonitoringDeleted(client, monitoring.ID, 800)) + }) + + t.Logf("Attempting to GET Enterprise VPN Connection Monitor: %s", monitoring.ID) + monitor, err := cm.Get(client, monitoring.ID) + th.AssertNoErr(t, err) + th.AssertEquals(t, "ACTIVE", monitor.Status) + + t.Logf("Attempting to LIST Enterprise VPN Connection Monitor: %s", monitoring.ID) + monitorList, err := cm.List(client, cm.ListOpts{ConnectionId: conn.ID}) + th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(monitorList)) + + t.Logf("Attempting to GET Enterprise VPN Quotas: %s", monitoring.ID) + quotas, err := quota.Get(client) + th.AssertNoErr(t, err) + th.AssertEquals(t, 3, len(quotas.Resources)) + + extraTag := []tags.ResourceTag{ + { + Key: "One", + Value: "gopher", + }, + } + t.Logf("Attempting to CREATE Enterprise VPN Connection Tag: %s", extraTag) + err = vpntags.Create(client, "vpn-connection", conn.ID, vpntags.TagsOpts{Tags: extraTag}) + th.AssertNoErr(t, err) + + t.Cleanup(func() { + t.Logf("Attempting to DELETE Enterprise VPN Connection Tag: %s", extraTag) + th.AssertNoErr(t, vpntags.Delete(client, "vpn-connection", conn.ID, vpntags.TagsOpts{Tags: extraTag})) + }) + t.Logf("Attempting to LIST Enterprise VPN Connection Tags: %s", conn.ID) + tagList, err := vpntags.List(client, "vpn-connection", conn.ID) + th.AssertNoErr(t, err) + th.AssertEquals(t, 2, len(tagList)) } func createEvpnCustomerGateway(t *testing.T, client *golangsdk.ServiceClient) *cgw.CustomerGateway { @@ -132,6 +180,7 @@ func createEvpnCustomerGateway(t *testing.T, client *golangsdk.ServiceClient) *c }) return gw } + func createEvpnGateway(t *testing.T, subnet *subnets.Subnet, vpcId string, client *golangsdk.ServiceClient) *gateway.Gateway { clientNetV1, err := clients.NewNetworkV1Client() th.AssertNoErr(t, err) @@ -210,3 +259,30 @@ func WaitForConnectionActive(c *golangsdk.ServiceClient, id string, secs int) er return false, nil }) } + +func WaitForConnectionMonitoringDeleted(c *golangsdk.ServiceClient, id string, secs int) error { + return golangsdk.WaitFor(secs, func() (bool, error) { + _, err := cm.Get(c, id) + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + return true, nil + } + return false, fmt.Errorf("error retriving connection status: %w", err) + } + return false, nil + }) +} + +func WaitForConnectionMonitoringActive(c *golangsdk.ServiceClient, id string, secs int) error { + return golangsdk.WaitFor(secs, func() (bool, error) { + current, err := cm.Get(c, id) + if err != nil { + return false, err + } + + if current.Status == "ACTIVE" { + return true, nil + } + return false, nil + }) +} diff --git a/openstack/evpn/v5/connection-monitoring/Create.go b/openstack/evpn/v5/connection-monitoring/Create.go new file mode 100644 index 000000000..6e19f496e --- /dev/null +++ b/openstack/evpn/v5/connection-monitoring/Create.go @@ -0,0 +1,50 @@ +package connection_monitoring + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +type CreateOpts struct { + // Specifies the ID of the VPN connection to be monitored. + ConnectionID string `json:"vpn_connection_id" required:"true"` +} + +func Create(client *golangsdk.ServiceClient, opts CreateOpts) (*Monitor, error) { + b, err := build.RequestBody(opts, "connection_monitor") + if err != nil { + return nil, err + } + + raw, err := client.Post(client.ServiceURL("connection-monitors"), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{202, 201}, + }) + if err != nil { + return nil, err + } + + var res Monitor + return &res, extract.IntoStructPtr(raw.Body, &res, "connection_monitor") +} + +type Monitor struct { + // Specifies the ID of a VPN connection monitor. + ID string `json:"id"` + // Specifies the ID of the VPN connection to be monitored. + ConnectionId string `json:"vpn_connection_id"` + // Specifies the type of objects to be monitored. + Type string `json:"type"` + // Specifies the source address to be monitored. + SourceIp string `json:"source_ip"` + // Specifies the destination address to be monitored. + DestinationIp string `json:"destination_ip"` + // Specifies the protocol used by NQA. + ProtoType string `json:"proto_type"` + // Specifies the status of the VPN connection monitor. + // Value range: + // ACTIVE: normal + // PENDING_CREATE: creating + // PENDING_DELETE: deleting + Status string `json:"status"` +} diff --git a/openstack/evpn/v5/connection-monitoring/Delete.go b/openstack/evpn/v5/connection-monitoring/Delete.go new file mode 100644 index 000000000..05b6dbd49 --- /dev/null +++ b/openstack/evpn/v5/connection-monitoring/Delete.go @@ -0,0 +1,10 @@ +package connection_monitoring + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +) + +func Delete(client *golangsdk.ServiceClient, id string) (err error) { + _, err = client.Delete(client.ServiceURL("connection-monitors", id), nil) + return +} diff --git a/openstack/evpn/v5/connection-monitoring/Get.go b/openstack/evpn/v5/connection-monitoring/Get.go new file mode 100644 index 000000000..a0e8db8ef --- /dev/null +++ b/openstack/evpn/v5/connection-monitoring/Get.go @@ -0,0 +1,17 @@ +package connection_monitoring + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +func Get(client *golangsdk.ServiceClient, monitorId string) (*Monitor, error) { + raw, err := client.Get(client.ServiceURL("connection-monitors", monitorId), nil, nil) + if err != nil { + return nil, err + } + + var res Monitor + err = extract.IntoStructPtr(raw.Body, &res, "connection_monitor") + return &res, err +} diff --git a/openstack/evpn/v5/connection-monitoring/List.go b/openstack/evpn/v5/connection-monitoring/List.go new file mode 100644 index 000000000..cc1b5174f --- /dev/null +++ b/openstack/evpn/v5/connection-monitoring/List.go @@ -0,0 +1,28 @@ +package connection_monitoring + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +type ListOpts struct { + // Specifies a VPN connection ID. + ConnectionId string `q:"vpn_connection_id"` +} + +func List(client *golangsdk.ServiceClient, opts ListOpts) ([]Monitor, error) { + url, err := golangsdk.NewURLBuilder(). + WithEndpoints("connection-monitors").WithQueryParams(&opts).Build() + if err != nil { + return nil, err + } + + raw, err := client.Get(client.ServiceURL(url.String()), nil, nil) + if err != nil { + return nil, err + } + + var res []Monitor + err = extract.IntoSlicePtr(raw.Body, &res, "connection_monitors") + return res, err +} diff --git a/openstack/evpn/v5/quota/Get.go b/openstack/evpn/v5/quota/Get.go new file mode 100644 index 000000000..4248f38c0 --- /dev/null +++ b/openstack/evpn/v5/quota/Get.go @@ -0,0 +1,40 @@ +package quota + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +func Get(client *golangsdk.ServiceClient) (*Quota, error) { + url, err := golangsdk.NewURLBuilder(). + WithEndpoints("vpn", "quotas").Build() + if err != nil { + return nil, err + } + + raw, err := client.Get(client.ServiceURL(url.String()), nil, nil) + if err != nil { + return nil, err + } + + var res Quota + err = extract.IntoStructPtr(raw.Body, &res, "quotas") + return &res, err +} + +type Quota struct { + Resources []Info `json:"resources"` +} + +type Info struct { + // Specifies a resource type. + // Value range: + // customer_gateway: customer gateway + // vpn_connection: Enterprise Edition VPN connection + // vpn_gateway: Enterprise Edition VPN gateway + Type string `json:"type"` + // Specifies the quota upper limit. + Quota int `json:"quota"` + // Specifies the number of resources in use. + Used int `json:"used"` +} diff --git a/openstack/evpn/v5/tags/Create.go b/openstack/evpn/v5/tags/Create.go new file mode 100644 index 000000000..eda6f9c02 --- /dev/null +++ b/openstack/evpn/v5/tags/Create.go @@ -0,0 +1,28 @@ +package tags + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/common/tags" +) + +type TagsOpts struct { + // Specifies a tag list. + // A maximum of 20 tags can be specified. + Tags []tags.ResourceTag `json:"tags" required:"true"` +} + +// Create creates tags +// resourceType Specifies the resource type. +// The value can be vpn-gateway, customer-gateway, or vpn-connection. +func Create(client *golangsdk.ServiceClient, resourceType, resourceId string, opts TagsOpts) error { + b, err := build.RequestBody(opts, "") + if err != nil { + return err + } + _, err = client.Post(client.ServiceURL(resourceType, resourceId, "tags", "create"), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{204}, + MoreHeaders: map[string]string{"Content-Type": "application/json", "X-Language": "en-us"}, + }) + return err +} diff --git a/openstack/evpn/v5/tags/Delete.go b/openstack/evpn/v5/tags/Delete.go new file mode 100644 index 000000000..852704481 --- /dev/null +++ b/openstack/evpn/v5/tags/Delete.go @@ -0,0 +1,18 @@ +package tags + +import ( + "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) + +func Delete(client *golangsdk.ServiceClient, resourceType, resourceId string, opts TagsOpts) error { + b, err := build.RequestBody(opts, "") + if err != nil { + return err + } + _, err = client.Post(client.ServiceURL(resourceType, resourceId, "tags", "delete"), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{204}, + MoreHeaders: map[string]string{"Content-Type": "application/json", "X-Language": "en-us"}, + }) + return err +} diff --git a/openstack/evpn/v5/tags/List.go b/openstack/evpn/v5/tags/List.go new file mode 100644 index 000000000..7d59beea0 --- /dev/null +++ b/openstack/evpn/v5/tags/List.go @@ -0,0 +1,24 @@ +package tags + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/common/tags" +) + +func List(client *golangsdk.ServiceClient, resourceType, resourceId string) ([]tags.ResourceTag, error) { + url, err := golangsdk.NewURLBuilder(). + WithEndpoints(resourceType, resourceId, "tags").Build() + if err != nil { + return nil, err + } + + raw, err := client.Get(client.ServiceURL(url.String()), nil, nil) + if err != nil { + return nil, err + } + + var res []tags.ResourceTag + err = extract.IntoSlicePtr(raw.Body, &res, "tags") + return res, err +}