Skip to content

Commit 43b2301

Browse files
committed
neutron: add segments extension package
1 parent 611b2a4 commit 43b2301

File tree

7 files changed

+556
-0
lines changed

7 files changed

+556
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package segments
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/gophercloud/gophercloud/v2"
8+
"github.com/gophercloud/gophercloud/v2/internal/acceptance/tools"
9+
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/segments"
10+
th "github.com/gophercloud/gophercloud/v2/testhelper"
11+
)
12+
13+
func CreateSegment(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*segments.Segment, error) {
14+
name := tools.RandomString("TESTACC-SEGMENT-", 8)
15+
desc := "test segment description"
16+
17+
opts := segments.CreateOpts{
18+
NetworkID: networkID,
19+
NetworkType: "geneve",
20+
Name: name,
21+
Description: desc,
22+
}
23+
24+
segment, err := segments.Create(context.TODO(), client, opts).Extract()
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
tools.PrintResource(t, segment)
30+
31+
th.AssertEquals(t, segment.Name, name)
32+
th.AssertEquals(t, segment.Description, desc)
33+
th.AssertEquals(t, segment.NetworkType, "geneve")
34+
th.AssertEquals(t, segment.NetworkID, networkID)
35+
36+
return segment, nil
37+
}
38+
39+
func DeleteSegment(t *testing.T, client *gophercloud.ServiceClient, segmentID string) {
40+
t.Logf("Attempting to delete segment %s", segmentID)
41+
42+
err := segments.Delete(context.TODO(), client, segmentID).ExtractErr()
43+
if err != nil {
44+
t.Fatalf("Failed to delete segment %s: %v", segmentID, err)
45+
}
46+
47+
t.Logf("Deleted segment %s", segmentID)
48+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//go:build acceptance || networking || segments
2+
3+
package segments
4+
5+
import (
6+
"context"
7+
"testing"
8+
9+
"github.com/gophercloud/gophercloud/v2/internal/acceptance/clients"
10+
networking "github.com/gophercloud/gophercloud/v2/internal/acceptance/openstack/networking/v2"
11+
"github.com/gophercloud/gophercloud/v2/internal/acceptance/tools"
12+
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/segments"
13+
th "github.com/gophercloud/gophercloud/v2/testhelper"
14+
)
15+
16+
func TestSegmentCRUD(t *testing.T) {
17+
clients.RequireAdmin(t)
18+
19+
client, err := clients.NewNetworkV2Client()
20+
th.AssertNoErr(t, err)
21+
22+
// Skip these tests if we don't have the required extension
23+
networking.RequireNeutronExtension(t, client, "segment")
24+
25+
network, err := networking.CreateNetwork(t, client)
26+
th.AssertNoErr(t, err)
27+
defer networking.DeleteNetwork(t, client, network.ID)
28+
29+
segment, err := CreateSegment(t, client, network.ID)
30+
th.AssertNoErr(t, err)
31+
defer DeleteSegment(t, client, segment.ID)
32+
33+
// Get
34+
segGet, err := segments.Get(context.TODO(), client, segment.ID).Extract()
35+
th.AssertNoErr(t, err)
36+
th.AssertEquals(t, segment.ID, segGet.ID)
37+
38+
// Update
39+
newName := tools.RandomString("UPDATED-SEGMENT-", 8)
40+
newDesc := "updated description"
41+
updateOpts := segments.UpdateOpts{
42+
Name: &newName,
43+
Description: &newDesc,
44+
}
45+
segUpdated, err := segments.Update(context.TODO(), client, segment.ID, updateOpts).Extract()
46+
th.AssertNoErr(t, err)
47+
th.AssertEquals(t, newName, segUpdated.Name)
48+
th.AssertEquals(t, newDesc, segUpdated.Description)
49+
50+
// List
51+
allPages, err = segments.List(client, nil).AllPages(context.TODO())
52+
th.AssertNoErr(t, err)
53+
allSegments, err = segments.ExtractSegments(allPages)
54+
th.AssertNoErr(t, err)
55+
th.AssertIntGreaterOrEqual(t, len(allSegments), 1)
56+
t.Logf("Found %d segments", len(allSegments))
57+
tools.PrintResource(t, allSegments)
58+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package segments
2+
3+
import (
4+
"context"
5+
6+
"github.com/gophercloud/gophercloud/v2"
7+
"github.com/gophercloud/gophercloud/v2/pagination"
8+
)
9+
10+
// ListOpts allows filtering when listing segments.
11+
type ListOpts struct {
12+
Name string `q:"name"`
13+
Description string `q:"description"`
14+
NetworkID string `q:"network_id"`
15+
PhysicalNetwork string `q:"physical_network"`
16+
NetworkType string `q:"network_type"`
17+
SegmentationID int `q:"segmentation_id"`
18+
SortDir string `q:"sort_dir"`
19+
SortKey string `q:"sort_key"`
20+
Fields string `q:"fields"`
21+
}
22+
23+
// ListOptsBuilder interface for listing.
24+
type ListOptsBuilder interface {
25+
ToSegmentListQuery() (string, error)
26+
}
27+
28+
func (opts ListOpts) ToSegmentListQuery() (string, error) {
29+
q, err := gophercloud.BuildQueryString(opts)
30+
if err != nil {
31+
return "", err
32+
}
33+
return q.String(), nil
34+
}
35+
36+
// List all segments.
37+
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
38+
url := rootURL(c)
39+
if opts != nil {
40+
query, err := opts.ToSegmentListQuery()
41+
if err != nil {
42+
return pagination.Pager{Err: err}
43+
}
44+
url += query
45+
}
46+
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
47+
return SegmentPage{LinkedPageBase: pagination.LinkedPageBase{PageResult: r}}
48+
})
49+
}
50+
51+
// CreateOptsBuilder allows extensions to add additional parameters.
52+
type CreateOptsBuilder interface {
53+
ToSegmentCreateMap() (map[string]any, error)
54+
}
55+
56+
// CreateOpts contains the fields needed for creating a segment.
57+
type CreateOpts struct {
58+
Name string `json:"name,omitempty"`
59+
Description string `json:"description,omitempty"`
60+
NetworkID string `json:"network_id" required:"true"`
61+
NetworkType string `json:"network_type" required:"true"`
62+
PhysicalNetwork string `json:"physical_network,omitempty"`
63+
SegmentationID int `json:"segmentation_id,omitempty"`
64+
}
65+
66+
func (opts CreateOpts) ToSegmentCreateMap() (map[string]any, error) {
67+
return gophercloud.BuildRequestBody(opts, "segment")
68+
}
69+
70+
// Create a new segment.
71+
func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
72+
b, err := opts.ToSegmentCreateMap()
73+
if err != nil {
74+
r.Err = err
75+
return
76+
}
77+
resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil)
78+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
79+
return
80+
}
81+
82+
// Get retrieves a segment by ID.
83+
func Get(ctx context.Context, c *gophercloud.ServiceClient, id string) (r GetResult) {
84+
resp, err := c.Get(ctx, resourceURL(c, id), &r.Body, nil)
85+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
86+
return
87+
}
88+
89+
// Delete removes a segment by ID.
90+
func Delete(ctx context.Context, c *gophercloud.ServiceClient, id string) (r DeleteResult) {
91+
resp, err := c.Delete(ctx, resourceURL(c, id), nil)
92+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
93+
return
94+
}
95+
96+
// UpdateOpts contains fields to update a segment.
97+
type UpdateOpts struct {
98+
Name *string `json:"name,omitempty"`
99+
Description *string `json:"description,omitempty"`
100+
SegmentationID *int `json:"segmentation_id,omitempty"`
101+
}
102+
103+
// UpdateOptsBuilder is the interface for update options.
104+
type UpdateOptsBuilder interface {
105+
ToSegmentUpdateMap() (map[string]any, error)
106+
}
107+
108+
func (opts UpdateOpts) ToSegmentUpdateMap() (map[string]any, error) {
109+
return gophercloud.BuildRequestBody(opts, "segment")
110+
}
111+
112+
// Update a segment.
113+
func Update(ctx context.Context, c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
114+
b, err := opts.ToSegmentUpdateMap()
115+
if err != nil {
116+
r.Err = err
117+
return
118+
}
119+
resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
120+
OkCodes: []int{200},
121+
})
122+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
123+
return
124+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package segments
2+
3+
import (
4+
"time"
5+
6+
"github.com/gophercloud/gophercloud/v2"
7+
"github.com/gophercloud/gophercloud/v2/pagination"
8+
)
9+
10+
// Segment model
11+
type Segment struct {
12+
ID string `json:"id"`
13+
Name string `json:"name"`
14+
Description string `json:"description"`
15+
NetworkID string `json:"network_id"`
16+
NetworkType string `json:"network_type"`
17+
PhysicalNetwork string `json:"physical_network"`
18+
SegmentationID int `json:"segmentation_id"`
19+
RevisionNumber int `json:"revision_number"`
20+
CreatedAt time.Time `json:"created_at"`
21+
UpdatedAt time.Time `json:"updated_at"`
22+
}
23+
24+
// SegmentPage wraps a page of segments.
25+
type SegmentPage struct {
26+
pagination.LinkedPageBase
27+
}
28+
29+
func (r SegmentPage) IsEmpty() (bool, error) {
30+
if r.StatusCode == 204 {
31+
return true, nil
32+
}
33+
34+
is, err := ExtractSegments(r)
35+
return len(is) == 0, err
36+
}
37+
38+
func ExtractSegments(r pagination.Page) ([]Segment, error) {
39+
var s []Segment
40+
err := ExtractSegmentsInto(r, &s)
41+
return s, err
42+
}
43+
44+
// ExtractSegmentsInto extracts the elements into a slice of Segment structs.
45+
func ExtractSegmentsInto(r pagination.Page, v any) error {
46+
return r.(SegmentPage).Result.ExtractIntoSlicePtr(v, "segments")
47+
}
48+
49+
// Segment results
50+
type commonResult struct {
51+
gophercloud.Result
52+
}
53+
54+
func (r commonResult) Extract() (*Segment, error) {
55+
var s Segment
56+
err := r.ExtractIntoStructPtr(&s, "segment")
57+
return &s, err
58+
}
59+
60+
type GetResult struct {
61+
commonResult
62+
}
63+
64+
type CreateResult struct {
65+
commonResult
66+
}
67+
68+
type UpdateResult struct {
69+
commonResult
70+
}
71+
72+
type DeleteResult struct {
73+
gophercloud.ErrResult
74+
}

0 commit comments

Comments
 (0)