From 35ec433f590e157f2826d9f4742b7699993927ef Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Thu, 29 Aug 2024 14:42:17 +0200 Subject: [PATCH] Implement PrivateNetworks API endpoint --- client.go | 2 + doc_test.go | 109 ++++++++++++++++++++++ privatenetworks.go | 164 +++++++++++++++++++++++++++++++++ privatenetworks_test.go | 199 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 474 insertions(+) create mode 100644 privatenetworks.go create mode 100644 privatenetworks_test.go diff --git a/client.go b/client.go index 2eaa07b..4cc4fbc 100644 --- a/client.go +++ b/client.go @@ -35,6 +35,7 @@ type Client struct { IPs *IPService LoadBalancers *LoadBalancerService ObjectStorages *ObjectStorageService + PrivateNetworks *PrivateNetworkService Servers *ServerService ServerDisks *ServerDisksService Networks *NetworkService @@ -60,6 +61,7 @@ func NewClient(project, apiKey, userAgent string) *Client { c.IPs = &IPService{client: c} c.LoadBalancers = &LoadBalancerService{client: c} c.ObjectStorages = &ObjectStorageService{client: c} + c.PrivateNetworks = &PrivateNetworkService{client: c} c.Servers = &ServerService{client: c} c.ServerDisks = &ServerDisksService{client: c} c.Networks = &NetworkService{client: c} diff --git a/doc_test.go b/doc_test.go index 800b416..15eabd2 100644 --- a/doc_test.go +++ b/doc_test.go @@ -412,6 +412,115 @@ func ExampleNetworkCircuitService_List() { } } +func ExamplePrivateNetworkService_Create() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + privnet, _ := client.PrivateNetworks.Create(context.Background(), "my-network") + + fmt.Printf("ID: %s - Name: %s - IPv6: %s\n", privnet.ID, privnet.Name, privnet.IPv6Aggregate) +} + +func ExamplePrivateNetworkService_Destroy() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + err := client.PrivateNetworks.Destroy(context.Background(), "pn-123ab") + + if err != nil { + fmt.Printf("Cannot remove private network. Error: %s", err) + } +} + +func ExamplePrivateNetworkService_Details() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + privnet, _ := client.PrivateNetworks.Details(context.Background(), "pn-123ab") + + fmt.Printf("ID: %s - Name: %s - IPv6: %s\n", privnet.ID, privnet.Name, privnet.IPv6Aggregate) +} + +func ExamplePrivateNetworkService_EstimatedCost() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + netCost, _ := client.PrivateNetworks.EstimatedCost(context.Background(), "pn-123ab") + + fmt.Printf("Price: %.2f%s - Discount: %.2f - Total: %.2f\n", netCost.Price, netCost.Currency, netCost.Discount, netCost.Total) +} + +func ExamplePrivateNetworkService_Edit() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + params := glesys.EditPrivateNetworkParams{ + ID: "pn-123ab", + Name: "new-network-name", + } + + privnet, _ := client.PrivateNetworks.Edit(context.Background(), params) + + fmt.Printf("ID: %s - Name: %s - IPv6: %s\n", privnet.ID, privnet.Name, privnet.IPv6Aggregate) +} + +func ExamplePrivateNetworkService_List() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + privnet, _ := client.PrivateNetworks.List(context.Background()) + + for _, net := range *privnet { + fmt.Printf("ID: %s - Name: %s - IPv6: %s\n", net.ID, net.Name, net.IPv6Aggregate) + } +} + +func ExamplePrivateNetworkService_CreateSegment() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + params := glesys.CreatePrivateNetworkSegmentParams{ + PrivateNetworkID: "pn-123ab", + Datacenter: "dc-fbg1", + Name: "kvm-segment", + Platform: "kvm", + IPv4Subnet: "192.168.0.0/24", + } + + segment, _ := client.PrivateNetworks.CreateSegment(context.Background(), params) + + fmt.Printf("ID: %s - Name: %s\nIPv6: %s\nIPv4: %s\nPlatform: %s\nDatacenter: %s\n", + segment.ID, segment.Name, segment.IPv6Subnet, segment.IPv4Subnet, segment.Platform, segment.Datacenter) +} + +func ExamplePrivateNetworkService_EditSegment() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + params := glesys.EditPrivateNetworkSegmentParams{ + ID: "6f5cb761-163e-4a5f-b9da-98acbe68e28d", + Name: "updated-name", + } + + segment, _ := client.PrivateNetworks.EditSegment(context.Background(), params) + + fmt.Printf("ID: %s - Name: %s\nIPv6: %s\nIPv4: %s\nPlatform: %s\nDatacenter: %s\n", + segment.ID, segment.Name, segment.IPv6Subnet, segment.IPv4Subnet, segment.Platform, segment.Datacenter) +} + +func ExamplePrivateNetworkService_ListSegments() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + segments, _ := client.PrivateNetworks.ListSegments(context.Background(), "pn-123ab") + + for _, s := range *segments { + fmt.Printf("ID: %s - Name: %s\nIPv6: %s\nIPv4: %s\nPlatform: %s\nDatacenter: %s\n", + s.ID, s.Name, s.IPv6Subnet, s.IPv4Subnet, s.Platform, s.Datacenter) + } +} + +func ExamplePrivateNetworkService_DestroySegment() { + client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") + + err := client.PrivateNetworks.DestroySegment(context.Background(), "6f5cb761-163e-4a5f-b9da-98acbe68e28d") + + if err != nil { + fmt.Printf("Cannot remove private network segment. Error: %s", err) + } +} + func ExampleServerService_Create() { client := glesys.NewClient("CL12345", "your-api-key", "my-application/0.0.1") diff --git a/privatenetworks.go b/privatenetworks.go new file mode 100644 index 0000000..0c01c50 --- /dev/null +++ b/privatenetworks.go @@ -0,0 +1,164 @@ +package glesys + +import ( + "context" +) + +// PrivateNetworkService provides functions to interact with PrivateNetworks +type PrivateNetworkService struct { + client clientInterface +} + +// PrivateNetwork represents a privatenetwork +type PrivateNetwork struct { + ID string `json:"id"` + IPv6Aggregate string `json:"ipv6aggregate"` + Name string `json:"name"` +} + +// PrivateNetworkBilling +type PrivateNetworkBilling struct { + Currency string `json:"currency"` + Price float64 `json:"price"` + Discount float64 `json:"discount"` // discount in $Currency + Total float64 `json:"total"` +} + +// EditPrivateNetworkParams is used when editing an existing private network +type EditPrivateNetworkParams struct { + ID string `json:"privatenetworkid"` + Name string `json:"name,omitempty"` +} + +// PrivateNetworkSegment represents a segment as part of a PrivateNetwork +type PrivateNetworkSegment struct { + ID string `json:"id"` + Name string `json:"name"` + IPv4Subnet string `json:"ipv4subnet"` + IPv6Subnet string `json:"ipv6subnet"` + Platform string `json:"platform"` + Datacenter string `json:"datacenter"` +} + +// CreatePrivateNetworkSegmentParams is used when creating Segments in a PrivateNetwork +type CreatePrivateNetworkSegmentParams struct { + PrivateNetworkID string `json:"privatenetworkid"` + Datacenter string `json:"datacenter"` + IPv4Subnet string `json:"ipv4subnet"` // x.y.z.a/netmask + Name string `json:"name"` + Platform string `json:"platform"` +} + +// EditPrivateNetworkSegmentParams is used when editing an existing segment +type EditPrivateNetworkSegmentParams struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` +} + +// Create creates a new PrivateNetwork +func (s *PrivateNetworkService) Create(context context.Context, name string) (*PrivateNetwork, error) { + data := struct { + Response struct { + PrivateNetwork PrivateNetwork + } + }{} + err := s.client.post(context, "privatenetwork/create", &data, name) + return &data.Response.PrivateNetwork, err +} + +// Details returns detailed information about a PrivateNetwork +func (s *PrivateNetworkService) Details(context context.Context, privateNetworkID string) (*PrivateNetwork, error) { + data := struct { + Response struct { + PrivateNetwork PrivateNetwork + } + }{} + err := s.client.post(context, "privatenetwork/details", &data, privateNetworkID) + return &data.Response.PrivateNetwork, err +} + +// List returns detailed information about a PrivateNetwork +func (s *PrivateNetworkService) List(context context.Context) (*[]PrivateNetwork, error) { + data := struct { + Response struct { + PrivateNetworks []PrivateNetwork + } + }{} + err := s.client.post(context, "privatenetwork/list", &data, nil) + return &data.Response.PrivateNetworks, err +} + +// Destroy deletes a PrivateNetwork +func (s *PrivateNetworkService) Destroy(context context.Context, privateNetworkID string) error { + return s.client.post(context, "privatenetwork/delete", nil, struct { + PrivateNetworkID string `json:"privatenetworkid"` + }{privateNetworkID}) +} + +// Edit modifies a PrivateNetwork +func (s *PrivateNetworkService) Edit(context context.Context, params EditPrivateNetworkParams) (*PrivateNetwork, error) { + data := struct { + Response struct { + PrivateNetwork PrivateNetwork + } + }{} + err := s.client.post(context, "privatenetwork/edit", &data, struct { + EditPrivateNetworkParams + }{params}) + return &data.Response.PrivateNetwork, err +} + +// EstimatedCost returns billing information about a PrivateNetwork +func (s *PrivateNetworkService) EstimatedCost(context context.Context, privateNetworkID string) (*PrivateNetworkBilling, error) { + data := struct { + Response struct { + Billing PrivateNetworkBilling + } + }{} + err := s.client.post(context, "privatenetwork/estimatedcost", &data, struct { + ID string `json:"privatenetworkid,omitempty"` + }{privateNetworkID}) + return &data.Response.Billing, err +} + +// Create creates a new PrivateNetworkSegment +func (s *PrivateNetworkService) CreateSegment(context context.Context, params CreatePrivateNetworkSegmentParams) (*PrivateNetworkSegment, error) { + data := struct { + Response struct { + PrivateNetworkSegment PrivateNetworkSegment + } + }{} + err := s.client.post(context, "privatenetwork/createsegment", &data, params) + return &data.Response.PrivateNetworkSegment, err +} + +// Edit modifies a new PrivateNetworkSegment +func (s *PrivateNetworkService) EditSegment(context context.Context, params EditPrivateNetworkSegmentParams) (*PrivateNetworkSegment, error) { + data := struct { + Response struct { + PrivateNetworkSegment PrivateNetworkSegment + } + }{} + err := s.client.post(context, "privatenetwork/editsegment", &data, params) + return &data.Response.PrivateNetworkSegment, err +} + +// ListSegments returns detailed information about a PrivateNetwork +func (s *PrivateNetworkService) ListSegments(context context.Context, privatenetworkid string) (*[]PrivateNetworkSegment, error) { + data := struct { + Response struct { + PrivateNetworkSegments []PrivateNetworkSegment + } + }{} + err := s.client.post(context, "privatenetwork/listsegments", &data, struct { + PrivateNetworkID string `json:"privatenetworkid"` + }{privatenetworkid}) + return &data.Response.PrivateNetworkSegments, err +} + +// DestroySegment deletes a PrivateNetworkSegment +func (s *PrivateNetworkService) DestroySegment(context context.Context, id string) error { + return s.client.post(context, "privatenetwork/deletesegment", nil, struct { + ID string `json:"id"` + }{id}) +} diff --git a/privatenetworks_test.go b/privatenetworks_test.go new file mode 100644 index 0000000..73b68d6 --- /dev/null +++ b/privatenetworks_test.go @@ -0,0 +1,199 @@ +package glesys + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPrivateNetworksCreate(t *testing.T) { + c := &mockClient{body: `{ "response": { "privatenetwork": + { "id": "pn-123ab", "name": "mynetwork", "ipv6aggregate": "fe00:123::/48"}}}`} + n := PrivateNetworkService{client: c} + + networkname := "mynetwork" + + net, _ := n.Create(context.Background(), networkname) + + assert.Equal(t, "POST", c.lastMethod, "method is used correct") + assert.Equal(t, "privatenetwork/create", c.lastPath, "path used is correct") + assert.Equal(t, "pn-123ab", net.ID, "ID is correct") + assert.Equal(t, "mynetwork", net.Name, "Name is correct") + assert.Equal(t, "fe00:123::/48", net.IPv6Aggregate, "IPv6Aggregate is correct") +} + +func TestPrivateNetworksDestroy(t *testing.T) { + c := &mockClient{} + n := PrivateNetworkService{client: c} + + n.Destroy(context.Background(), "pn-123ab") + + assert.Equal(t, "POST", c.lastMethod, "method used is correct") + assert.Equal(t, "privatenetwork/delete", c.lastPath, "path used is correct") +} + +func TestPrivateNetworksDetails(t *testing.T) { + c := &mockClient{body: `{ "response": { "privatenetwork": { + "id": "pn-123ab", + "name": "mynetwork", + "ipv6aggregate": "fe00:123::/48" + } } }`} + n := PrivateNetworkService{client: c} + + net, _ := n.Details(context.Background(), "pn-123ab") + + assert.Equal(t, "POST", c.lastMethod, "method used is correct") + assert.Equal(t, "privatenetwork/details", c.lastPath, "path used is correct") + assert.Equal(t, "mynetwork", net.Name, "Name is correct") + assert.Equal(t, "pn-123ab", net.ID, "ID is correct") + assert.Equal(t, "fe00:123::/48", net.IPv6Aggregate, "IPv6Aggregate is correct") +} + +func TestPrivateNetworksList(t *testing.T) { + c := &mockClient{body: `{ "response": { "privatenetworks": [{ + "id": "pn-123ab", + "name": "mynetwork", + "ipv6aggregate": "fe00:123::/48" + }, { + "id": "pn-456cd", + "name": "othernet", + "ipv6aggregate": "fe00:456::/48" } ] } }`} + + n := PrivateNetworkService{client: c} + + net, _ := n.List(context.Background()) + + assert.Equal(t, "POST", c.lastMethod, "method used is correct") + assert.Equal(t, "privatenetwork/list", c.lastPath, "path used is correct") + assert.Equal(t, "mynetwork", (*net)[0].Name, "Name is correct") + assert.Equal(t, "pn-123ab", (*net)[0].ID, "ID is correct") + assert.Equal(t, "fe00:123::/48", (*net)[0].IPv6Aggregate, "IPv6Aggregate is correct") + assert.Equal(t, "othernet", (*net)[1].Name, "Name is correct") + assert.Equal(t, "pn-456cd", (*net)[1].ID, "ID is correct") + assert.Equal(t, "fe00:456::/48", (*net)[1].IPv6Aggregate, "IPv6Aggregate is correct") +} + +func TestPrivateNetworksEdit(t *testing.T) { + c := &mockClient{body: `{ "response": { "privatenetwork": + { "name": "newnetwork-1", "id": "pn-123ab"}}}`} + + n := PrivateNetworkService{client: c} + + params := EditPrivateNetworkParams{ + Name: "newnetwork-1", + ID: "pn-123ab", + } + + net, _ := n.Edit(context.Background(), params) + + assert.Equal(t, "POST", c.lastMethod, "method is used correct") + assert.Equal(t, "privatenetwork/edit", c.lastPath, "path used is correct") + assert.Equal(t, "pn-123ab", net.ID, "ID is correct") + assert.Equal(t, "newnetwork-1", net.Name, "Name is correct") +} + +func TestPrivateNetworksEstimatedcost(t *testing.T) { + c := &mockClient{body: `{ "response": { "billing": + { "currency": "SEK", "price": 50.0, + "discount": 12.5, "total": 37.5}}}`} + + n := PrivateNetworkService{client: c} + + netid := "pn-123ab" + + net, _ := n.EstimatedCost(context.Background(), netid) + + assert.Equal(t, "POST", c.lastMethod, "method is used correct") + assert.Equal(t, "privatenetwork/estimatedcost", c.lastPath, "path used is correct") + assert.Equal(t, 50.0, net.Price, "Price is correct") + assert.Equal(t, 12.5, net.Discount, "Discount is correct") + assert.Equal(t, 37.5, net.Total, "Total price is correct") +} + +func TestPrivateNetworkSegmentsCreate(t *testing.T) { + c := &mockClient{body: `{ "response": { "privatenetworksegment": + { "id": "266979ab-1e05-4fbc-b9e0-577f31c0d2e9", + "name": "mysegment", "ipv6subnet": "fe00:123:0:/64", + "ipv4subnet": "10.0.0.0/24", "datacenter": "dc-fbg1", + "platform": "kvm"}}}`} + n := PrivateNetworkService{client: c} + + params := CreatePrivateNetworkSegmentParams{ + Name: "mysegment", + Platform: "kvm", + Datacenter: "dc-fbg1", + IPv4Subnet: "10.0.0.0/24", + } + + segment, _ := n.CreateSegment(context.Background(), params) + + assert.Equal(t, "POST", c.lastMethod, "method is used correct") + assert.Equal(t, "privatenetwork/createsegment", c.lastPath, "path used is correct") + assert.Equal(t, "266979ab-1e05-4fbc-b9e0-577f31c0d2e9", segment.ID, "ID is correct") + assert.Equal(t, "mysegment", segment.Name, "Name is correct") + assert.Equal(t, "fe00:123:0:/64", segment.IPv6Subnet, "IPv6Subnet is correct") + assert.Equal(t, "10.0.0.0/24", segment.IPv4Subnet, "IPv4Subnet is correct") +} + +func TestPrivateNetworkSegmentsDestroy(t *testing.T) { + c := &mockClient{} + n := PrivateNetworkService{client: c} + + n.DestroySegment(context.Background(), "pn-123ab") + + assert.Equal(t, "POST", c.lastMethod, "method used is correct") + assert.Equal(t, "privatenetwork/deletesegment", c.lastPath, "path used is correct") +} + +func TestPrivateNetworkSegmentsList(t *testing.T) { + c := &mockClient{body: ` + { "response": { "privatenetworksegments": [{ + "id": "fb34a19a-392a-43ec-ab3f-0c5b73ad1234", + "name": "mysegment", + "platform": "kvm", + "datacenter": "dc-fbg1", + "ipv4subnet": "10.0.0.0/24", + "ipv6subnet": "fe00:123:0:/64" + }, { + "id": "fb34a19a-392a-43ec-ab3f-0c5b73ad5678", + "name": "othersegment", + "platform": "kvm", + "datacenter": "dc-fbg1", + "ipv4subnet": "10.0.0.0/24", + "ipv6subnet": "fe00:456:1:/64" } ] } } + `} + + n := PrivateNetworkService{client: c} + + segments, _ := n.ListSegments(context.Background(), "pn-123ab") + + assert.Equal(t, "POST", c.lastMethod, "method used is correct") + assert.Equal(t, "privatenetwork/listsegments", c.lastPath, "path used is correct") + assert.Equal(t, "mysegment", (*segments)[0].Name, "Name is correct") + assert.Equal(t, "fb34a19a-392a-43ec-ab3f-0c5b73ad1234", (*segments)[0].ID, "ID is correct") + assert.Equal(t, "fe00:123:0:/64", (*segments)[0].IPv6Subnet, "IPv6Aggregate is correct") + assert.Equal(t, "othersegment", (*segments)[1].Name, "Name is correct") + assert.Equal(t, "fb34a19a-392a-43ec-ab3f-0c5b73ad5678", (*segments)[1].ID, "ID is correct") + assert.Equal(t, "kvm", (*segments)[1].Platform, "Platform is correct") + assert.Equal(t, "fe00:456:1:/64", (*segments)[1].IPv6Subnet, "IPv6Aggregate is correct") +} + +func TestPrivateNetworkSegmentsEdit(t *testing.T) { + c := &mockClient{body: `{ "response": { "privatenetworksegment": + { "name": "segmentname-2", "id": "fb34a19a-392a-43ec-ab3f-0c5b73ad1234"}}}`} + + n := PrivateNetworkService{client: c} + + params := EditPrivateNetworkSegmentParams{ + Name: "segmentname-2", + ID: "fb34a19a-392a-43ec-ab3f-0c5b73ad1234", + } + + segment, _ := n.EditSegment(context.Background(), params) + + assert.Equal(t, "POST", c.lastMethod, "method is used correct") + assert.Equal(t, "privatenetwork/editsegment", c.lastPath, "path used is correct") + assert.Equal(t, "fb34a19a-392a-43ec-ab3f-0c5b73ad1234", segment.ID, "ID is correct") + assert.Equal(t, "segmentname-2", segment.Name, "Name is correct") +}