Skip to content

Commit 571ecb5

Browse files
Gianluca Cannataaculnaig
authored andcommitted
Revert "remove VPC subnets and routes API endpoints"
This reverts commit 2eb2952.
1 parent a47ddde commit 571ecb5

File tree

3 files changed

+339
-0
lines changed

3 files changed

+339
-0
lines changed

doc/vpc.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ VPC (Virtual Private Cloud) is the product umbrella containing networking-relate
77
The VPC methods provide a unified namespace for all VPC-related features:
88

99
- **Networks** - Private networks for instances to connect to
10+
- **Subnets** - Subnets within private networks
1011
- **Firewalls** - Firewall rules for network security
1112
- **Load Balancers** - Load balancer configuration
1213
- **Reserved IPs** - Reserved IP address management
@@ -178,6 +179,114 @@ fmt.Printf("Result: %s\n", resp.Result)
178179

179180
---
180181

182+
## VPC Subnets
183+
184+
Subnets within private networks.
185+
186+
### ListVPCSubnets
187+
188+
Lists all subnets for a private network.
189+
190+
```go
191+
subnets, err := client.ListVPCSubnets("network-id")
192+
if err != nil {
193+
log.Fatal(err)
194+
}
195+
196+
for _, subnet := range subnets {
197+
fmt.Printf("Subnet: %s (ID: %s)\n", subnet.Name, subnet.ID)
198+
}
199+
```
200+
201+
### GetVPCSubnet
202+
203+
Gets a specific subnet by ID.
204+
205+
```go
206+
subnet, err := client.GetVPCSubnet("network-id", "subnet-id")
207+
if err != nil {
208+
log.Fatal(err)
209+
}
210+
211+
fmt.Printf("Subnet: %s, Status: %s\n", subnet.Name, subnet.Status)
212+
```
213+
214+
### FindVPCSubnet
215+
216+
Finds a subnet by either part of the ID or part of the name.
217+
218+
```go
219+
subnet, err := client.FindVPCSubnet("my-subnet", "network-id")
220+
if err != nil {
221+
log.Fatal(err)
222+
}
223+
224+
fmt.Printf("Found: %s\n", subnet.Name)
225+
```
226+
227+
### CreateVPCSubnet
228+
229+
Creates a new subnet for a private network.
230+
231+
```go
232+
config := civogo.SubnetConfig{
233+
Name: "my-subnet",
234+
}
235+
236+
subnet, err := client.CreateVPCSubnet("network-id", config)
237+
if err != nil {
238+
log.Fatal(err)
239+
}
240+
241+
fmt.Printf("Created subnet: %s\n", subnet.ID)
242+
```
243+
244+
### AttachVPCSubnetToInstance
245+
246+
Attaches a subnet to an instance by creating a route.
247+
248+
```go
249+
route := &civogo.CreateRoute{
250+
ResourceID: "instance-id",
251+
ResourceType: "instance",
252+
}
253+
254+
result, err := client.AttachVPCSubnetToInstance("network-id", "subnet-id", route)
255+
if err != nil {
256+
log.Fatal(err)
257+
}
258+
259+
fmt.Printf("Route created: %s\n", result.ID)
260+
```
261+
262+
### DetachVPCSubnetFromInstance
263+
264+
Detaches a subnet from an instance.
265+
266+
```go
267+
resp, err := client.DetachVPCSubnetFromInstance("network-id", "subnet-id")
268+
if err != nil {
269+
log.Fatal(err)
270+
}
271+
272+
fmt.Printf("Result: %s\n", resp.Result)
273+
```
274+
275+
### DeleteVPCSubnet
276+
277+
Deletes a subnet.
278+
279+
```go
280+
resp, err := client.DeleteVPCSubnet("network-id", "subnet-id")
281+
if err != nil {
282+
log.Fatal(err)
283+
}
284+
285+
fmt.Printf("Result: %s\n", resp.Result)
286+
```
287+
288+
---
289+
181290
## VPC Firewalls
182291

183292
Firewall management for network security.

vpc.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,121 @@ func (c *Client) UpdateVPCNetwork(id string, nc NetworkConfig) (*NetworkResult,
173173
return result, nil
174174
}
175175

176+
// =============================================================================
177+
// VPC Subnets - /v2/vpc/networks/{network_id}/subnets
178+
// =============================================================================
179+
180+
// GetVPCSubnet gets a subnet with ID using VPC API path
181+
func (c *Client) GetVPCSubnet(networkID, subnetID string) (*Subnet, error) {
182+
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/vpc/networks/%s/subnets/%s", networkID, subnetID))
183+
if err != nil {
184+
return nil, decodeError(err)
185+
}
186+
187+
subnet := Subnet{}
188+
err = json.NewDecoder(bytes.NewReader(resp)).Decode(&subnet)
189+
return &subnet, err
190+
}
191+
192+
// ListVPCSubnets lists all subnets for a private network using VPC API path
193+
func (c *Client) ListVPCSubnets(networkID string) ([]Subnet, error) {
194+
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/vpc/networks/%s/subnets", networkID))
195+
if err != nil {
196+
return nil, decodeError(err)
197+
}
198+
199+
subnets := make([]Subnet, 0)
200+
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&subnets); err != nil {
201+
return nil, err
202+
}
203+
204+
return subnets, nil
205+
}
206+
207+
// CreateVPCSubnet creates a new subnet for a private network using VPC API path
208+
func (c *Client) CreateVPCSubnet(networkID string, subnet SubnetConfig) (*Subnet, error) {
209+
body, err := c.SendPostRequest(fmt.Sprintf("/v2/vpc/networks/%s/subnets", networkID), subnet)
210+
if err != nil {
211+
return nil, decodeError(err)
212+
}
213+
214+
var result = &Subnet{}
215+
if err := json.NewDecoder(bytes.NewReader(body)).Decode(result); err != nil {
216+
return nil, err
217+
}
218+
219+
return result, nil
220+
}
221+
222+
// FindVPCSubnet finds a subnet by either part of the ID or part of the name using VPC API path
223+
func (c *Client) FindVPCSubnet(search, networkID string) (*Subnet, error) {
224+
subnets, err := c.ListVPCSubnets(networkID)
225+
if err != nil {
226+
return nil, decodeError(err)
227+
}
228+
229+
exactMatch := false
230+
partialMatchesCount := 0
231+
result := Subnet{}
232+
233+
for _, value := range subnets {
234+
if value.Name == search || value.ID == search {
235+
exactMatch = true
236+
result = value
237+
} else if strings.Contains(value.Name, search) || strings.Contains(value.ID, search) {
238+
if !exactMatch {
239+
result = value
240+
partialMatchesCount++
241+
}
242+
}
243+
}
244+
245+
if exactMatch || partialMatchesCount == 1 {
246+
return &result, nil
247+
} else if partialMatchesCount > 1 {
248+
err := fmt.Errorf("unable to find %s because there were multiple matches", search)
249+
return nil, MultipleMatchesError.wrap(err)
250+
} else {
251+
err := fmt.Errorf("unable to find %s, zero matches", search)
252+
return nil, ZeroMatchesError.wrap(err)
253+
}
254+
}
255+
256+
// AttachVPCSubnetToInstance attaches a subnet to an instance using VPC API path
257+
func (c *Client) AttachVPCSubnetToInstance(networkID, subnetID string, route *CreateRoute) (*Route, error) {
258+
resp, err := c.SendPostRequest(fmt.Sprintf("/v2/vpc/networks/%s/subnets/%s/routes", networkID, subnetID), route)
259+
if err != nil {
260+
return nil, decodeError(err)
261+
}
262+
263+
var result = &Route{}
264+
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(result); err != nil {
265+
return nil, err
266+
}
267+
268+
return result, nil
269+
}
270+
271+
// DetachVPCSubnetFromInstance detaches a subnet from an instance using VPC API path
272+
func (c *Client) DetachVPCSubnetFromInstance(networkID, subnetID string) (*SimpleResponse, error) {
273+
resp, err := c.SendDeleteRequest(fmt.Sprintf("/v2/vpc/networks/%s/subnets/%s/routes", networkID, subnetID))
274+
if err != nil {
275+
return nil, decodeError(err)
276+
}
277+
278+
return c.DecodeSimpleResponse(resp)
279+
}
280+
281+
// DeleteVPCSubnet deletes a subnet using VPC API path
282+
func (c *Client) DeleteVPCSubnet(networkID, subnetID string) (*SimpleResponse, error) {
283+
resp, err := c.SendDeleteRequest(fmt.Sprintf("/v2/vpc/networks/%s/subnets/%s", networkID, subnetID))
284+
if err != nil {
285+
return nil, decodeError(err)
286+
}
287+
288+
return c.DecodeSimpleResponse(resp)
289+
}
290+
176291
// =============================================================================
177292
// VPC Firewalls - /v2/vpc/firewalls
178293
// =============================================================================

vpc_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,121 @@ func TestDeleteVPCNetwork(t *testing.T) {
262262
}
263263
}
264264

265+
// =============================================================================
266+
// VPC Subnets Tests
267+
// =============================================================================
268+
269+
func TestGetVPCSubnet(t *testing.T) {
270+
client, server, _ := NewClientForTesting(map[string]string{
271+
"/v2/vpc/networks/12345/subnets/6789": `{"network_id": "12345", "id": "6789", "name": "test-subnet"}`,
272+
})
273+
defer server.Close()
274+
275+
got, err := client.GetVPCSubnet("12345", "6789")
276+
if err != nil {
277+
t.Errorf("Request returned an error: %s", err)
278+
return
279+
}
280+
if got.Name != "test-subnet" {
281+
t.Errorf("Expected %s, got %s", "test-subnet", got.Name)
282+
}
283+
}
284+
285+
func TestFindVPCSubnet(t *testing.T) {
286+
client, server, _ := NewClientForTesting(map[string]string{
287+
"/v2/vpc/networks/12345/subnets": `[
288+
{
289+
"id": "6789",
290+
"name": "test-subnet",
291+
"network_id": "12345"
292+
},
293+
{
294+
"id": "67890",
295+
"name": "test-subnet-2",
296+
"network_id": "12345"
297+
}
298+
]`,
299+
})
300+
defer server.Close()
301+
302+
got, _ := client.FindVPCSubnet("6789", "12345")
303+
if got.ID != "6789" {
304+
t.Errorf("Expected %s, got %s", "6789", got.ID)
305+
}
306+
307+
got, _ = client.FindVPCSubnet("test-subnet-2", "12345")
308+
if got.ID != "67890" {
309+
t.Errorf("Expected %s, got %s", "67890", got.ID)
310+
}
311+
}
312+
313+
func TestCreateVPCSubnet(t *testing.T) {
314+
client, server, _ := NewClientForTesting(map[string]string{
315+
"/v2/vpc/networks/12345/subnets": `{"id": "76cc107f-fbef-4e2b-b97f-f5d34f4075d3","network_id": "12345","name": "test-subnet","status": "success"}`,
316+
})
317+
defer server.Close()
318+
319+
subnet := SubnetConfig{
320+
Name: "test-subnet",
321+
}
322+
323+
got, err := client.CreateVPCSubnet("12345", subnet)
324+
if err != nil {
325+
t.Errorf("Request returned an error: %s", err)
326+
return
327+
}
328+
329+
expected := &Subnet{
330+
ID: "76cc107f-fbef-4e2b-b97f-f5d34f4075d3",
331+
Name: "test-subnet",
332+
NetworkID: "12345",
333+
Status: "success",
334+
}
335+
336+
if !reflect.DeepEqual(got, expected) {
337+
t.Errorf("Expected %+v, got %+v", expected, got)
338+
}
339+
}
340+
341+
func TestListVPCSubnets(t *testing.T) {
342+
client, server, _ := NewClientForTesting(map[string]string{
343+
"/v2/vpc/networks/12345/subnets": `[{
344+
"id": "6789",
345+
"name": "test-subnet",
346+
"network_id": "12345"
347+
}]`,
348+
})
349+
defer server.Close()
350+
got, err := client.ListVPCSubnets("12345")
351+
352+
if err != nil {
353+
t.Errorf("Request returned an error: %s", err)
354+
return
355+
}
356+
expected := []Subnet{{ID: "6789", Name: "test-subnet", NetworkID: "12345"}}
357+
if !reflect.DeepEqual(got, expected) {
358+
t.Errorf("Expected %+v, got %+v", expected, got)
359+
}
360+
}
361+
362+
func TestDeleteVPCSubnet(t *testing.T) {
363+
client, server, _ := NewClientForTesting(map[string]string{
364+
"/v2/vpc/networks/12345/subnets/6789": `{"result": "success"}`,
365+
})
366+
defer server.Close()
367+
368+
got, err := client.DeleteVPCSubnet("12345", "6789")
369+
if err != nil {
370+
t.Errorf("Request returned an error: %s", err)
371+
return
372+
}
373+
374+
expected := &SimpleResponse{Result: "success"}
375+
if !reflect.DeepEqual(got, expected) {
376+
t.Errorf("Expected %+v, got %+v", expected, got)
377+
}
378+
}
379+
265380
// =============================================================================
266381
// VPC Firewalls Tests
267382
// =============================================================================

0 commit comments

Comments
 (0)