Skip to content

Commit 7dd55c3

Browse files
authored
Add support of FlavorProfile for Octavia
1 parent 84073f4 commit 7dd55c3

14 files changed

Lines changed: 837 additions & 19 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//go:build acceptance || networking || loadbalancer || flavorprofiles
2+
// +build acceptance networking loadbalancer flavorprofiles
3+
4+
package v2
5+
6+
import (
7+
"testing"
8+
9+
"github.com/gophercloud/gophercloud/internal/acceptance/clients"
10+
"github.com/gophercloud/gophercloud/internal/acceptance/tools"
11+
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavorprofiles"
12+
13+
th "github.com/gophercloud/gophercloud/testhelper"
14+
)
15+
16+
func TestFlavorProfilesList(t *testing.T) {
17+
client, err := clients.NewLoadBalancerV2Client()
18+
th.AssertNoErr(t, err)
19+
20+
allPages, err := flavorprofiles.List(client, nil).AllPages()
21+
th.AssertNoErr(t, err)
22+
23+
allFlavorProfiles, err := flavorprofiles.ExtractFlavorProfiles(allPages)
24+
th.AssertNoErr(t, err)
25+
26+
for _, flavorprofile := range allFlavorProfiles {
27+
tools.PrintResource(t, flavorprofile)
28+
}
29+
}
30+
31+
func TestFlavorProfilesCRUD(t *testing.T) {
32+
lbClient, err := clients.NewLoadBalancerV2Client()
33+
th.AssertNoErr(t, err)
34+
35+
flavorProfile, err := CreateFlavorProfile(t, lbClient)
36+
th.AssertNoErr(t, err)
37+
defer DeleteFlavorProfile(t, lbClient, flavorProfile)
38+
39+
tools.PrintResource(t, flavorProfile)
40+
41+
th.AssertEquals(t, "amphora", flavorProfile.ProviderName)
42+
43+
flavorProfileUpdateOpts := flavorprofiles.UpdateOpts{
44+
Name: tools.RandomString("TESTACCTUP-", 8),
45+
}
46+
47+
flavorProfileUpdated, err := flavorprofiles.Update(lbClient, flavorProfile.ID, flavorProfileUpdateOpts).Extract()
48+
th.AssertNoErr(t, err)
49+
50+
th.AssertEquals(t, flavorProfileUpdateOpts.Name, flavorProfileUpdated.Name)
51+
52+
t.Logf("Successfully updated flavorprofile %s", flavorProfileUpdated.Name)
53+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//go:build acceptance || networking || loadbalancer || flavors
2+
// +build acceptance networking loadbalancer flavors
3+
4+
package v2
5+
6+
import (
7+
"testing"
8+
9+
"github.com/gophercloud/gophercloud/internal/acceptance/clients"
10+
"github.com/gophercloud/gophercloud/internal/acceptance/tools"
11+
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavors"
12+
th "github.com/gophercloud/gophercloud/testhelper"
13+
)
14+
15+
func TestFlavorsList(t *testing.T) {
16+
client, err := clients.NewLoadBalancerV2Client()
17+
if err != nil {
18+
t.Fatalf("Unable to create a loadbalancer client: %v", err)
19+
}
20+
21+
allPages, err := flavors.List(client, nil).AllPages()
22+
if err != nil {
23+
t.Fatalf("Unable to list flavors: %v", err)
24+
}
25+
26+
allFlavors, err := flavors.ExtractFlavors(allPages)
27+
if err != nil {
28+
t.Fatalf("Unable to extract flavors: %v", err)
29+
}
30+
31+
for _, flavor := range allFlavors {
32+
tools.PrintResource(t, flavor)
33+
}
34+
}
35+
36+
func TestFlavorsCRUD(t *testing.T) {
37+
lbClient, err := clients.NewLoadBalancerV2Client()
38+
th.AssertNoErr(t, err)
39+
40+
flavorProfile, err := CreateFlavorProfile(t, lbClient)
41+
th.AssertNoErr(t, err)
42+
defer DeleteFlavorProfile(t, lbClient, flavorProfile)
43+
44+
tools.PrintResource(t, flavorProfile)
45+
46+
th.AssertEquals(t, "amphora", flavorProfile.ProviderName)
47+
48+
flavor, err := CreateFlavor(t, lbClient, flavorProfile)
49+
th.AssertNoErr(t, err)
50+
defer DeleteFlavor(t, lbClient, flavor)
51+
52+
tools.PrintResource(t, flavor)
53+
54+
th.AssertEquals(t, flavor.FlavorProfileId, flavorProfile.ID)
55+
56+
flavorUpdateOpts := flavors.UpdateOpts{
57+
Name: tools.RandomString("TESTACCTUP-", 8),
58+
}
59+
60+
flavorUpdated, err := flavors.Update(lbClient, flavor.ID, flavorUpdateOpts).Extract()
61+
th.AssertNoErr(t, err)
62+
63+
th.AssertEquals(t, flavorUpdateOpts.Name, flavorUpdated.Name)
64+
65+
t.Logf("Successfully updated flavor %s", flavorUpdated.Name)
66+
}

internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"github.com/gophercloud/gophercloud"
99
"github.com/gophercloud/gophercloud/internal/acceptance/clients"
1010
"github.com/gophercloud/gophercloud/internal/acceptance/tools"
11+
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavorprofiles"
12+
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavors"
1113
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/l7policies"
1214
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners"
1315
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
@@ -676,3 +678,72 @@ func WaitForLoadBalancerState(client *gophercloud.ServiceClient, lbID, status st
676678
return false, nil
677679
})
678680
}
681+
682+
func CreateFlavorProfile(t *testing.T, client *gophercloud.ServiceClient) (*flavorprofiles.FlavorProfile, error) {
683+
flavorProfileName := tools.RandomString("TESTACCT-", 8)
684+
flavorProfileDriver := "amphora"
685+
flavorProfileData := "{\"loadbalancer_topology\": \"SINGLE\"}"
686+
687+
createOpts := flavorprofiles.CreateOpts{
688+
Name: flavorProfileName,
689+
ProviderName: flavorProfileDriver,
690+
FlavorData: flavorProfileData,
691+
}
692+
693+
flavorProfile, err := flavorprofiles.Create(client, createOpts).Extract()
694+
if err != nil {
695+
return flavorProfile, err
696+
}
697+
698+
t.Logf("Successfully created flavorprofile %s", flavorProfileName)
699+
700+
th.AssertEquals(t, flavorProfileName, flavorProfile.Name)
701+
th.AssertEquals(t, flavorProfileDriver, flavorProfile.ProviderName)
702+
th.AssertEquals(t, flavorProfileData, flavorProfile.FlavorData)
703+
704+
return flavorProfile, nil
705+
}
706+
707+
func DeleteFlavorProfile(t *testing.T, client *gophercloud.ServiceClient, flavorProfile *flavorprofiles.FlavorProfile) {
708+
err := flavorprofiles.Delete(client, flavorProfile.ID).ExtractErr()
709+
if err != nil {
710+
t.Fatalf("Unable to delete flavorprofile: %v", err)
711+
}
712+
713+
t.Logf("Successfully deleted flavorprofile %s", flavorProfile.Name)
714+
}
715+
716+
func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient, flavorProfile *flavorprofiles.FlavorProfile) (*flavors.Flavor, error) {
717+
flavorName := tools.RandomString("TESTACCT-", 8)
718+
description := tools.RandomString("TESTACCT-desc-", 32)
719+
720+
createOpts := flavors.CreateOpts{
721+
Name: flavorName,
722+
Description: description,
723+
FlavorProfileId: flavorProfile.ID,
724+
Enabled: true,
725+
}
726+
727+
flavor, err := flavors.Create(client, createOpts).Extract()
728+
if err != nil {
729+
return flavor, err
730+
}
731+
732+
t.Logf("Successfully created flavor %s with flavorprofile %s", flavor.Name, flavorProfile.Name)
733+
734+
th.AssertEquals(t, flavorName, flavor.Name)
735+
th.AssertEquals(t, description, flavor.Description)
736+
th.AssertEquals(t, flavorProfile.ID, flavor.FlavorProfileId)
737+
th.AssertEquals(t, true, flavor.Enabled)
738+
739+
return flavor, nil
740+
}
741+
742+
func DeleteFlavor(t *testing.T, client *gophercloud.ServiceClient, flavor *flavors.Flavor) {
743+
err := flavors.Delete(client, flavor.ID).ExtractErr()
744+
if err != nil {
745+
t.Fatalf("Unable to delete flavor: %v", err)
746+
}
747+
748+
t.Logf("Successfully deleted flavor %s", flavor.Name)
749+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
Package flavorprofiles provides information and interaction
3+
with FlavorProfiles for the OpenStack Load-balancing service.
4+
5+
Example to List FlavorProfiles
6+
7+
listOpts := flavorprofiles.ListOpts{}
8+
9+
allPages, err := flavorprofiles.List(octaviaClient, listOpts).AllPages()
10+
if err != nil {
11+
panic(err)
12+
}
13+
14+
allFlavorProfiles, err := flavorprofiles.ExtractFlavorProfiles(allPages)
15+
if err != nil {
16+
panic(err)
17+
}
18+
19+
for _, flavorProfile := range allFlavorProfiles {
20+
fmt.Printf("%+v\n", flavorProfile)
21+
}
22+
23+
Example to Create a FlavorProfile
24+
25+
createOpts := flavorprofiles.CreateOpts{
26+
Name: "amphora-single",
27+
ProviderName: "amphora",
28+
FlavorData: "{\"loadbalancer_topology\": \"SINGLE\"}",
29+
}
30+
31+
flavorProfile, err := flavorprofiles.Create(octaviaClient, createOpts).Extract()
32+
if err != nil {
33+
panic(err)
34+
}
35+
36+
Example to Update a FlavorProfile
37+
38+
flavorProfileID := "dd6a26af-8085-4047-a62b-3080f4c76521"
39+
40+
updateOpts := flavorprofiles.UpdateOpts{
41+
Name: "amphora-single-updated",
42+
}
43+
44+
flavorProfile, err := flavorprofiles.Update(octaviaClient, flavorProfileID, updateOpts).Extract()
45+
if err != nil {
46+
panic(err)
47+
}
48+
49+
Example to Delete a FlavorProfile
50+
51+
flavorProfileID := "dd6a26af-8085-4047-a62b-3080f4c76521"
52+
err := flavorprofiles.Delete(octaviaClient, flavorProfileID).ExtractErr()
53+
if err != nil {
54+
panic(err)
55+
}
56+
*/
57+
package flavorprofiles
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package flavorprofiles
2+
3+
import (
4+
"github.com/gophercloud/gophercloud"
5+
"github.com/gophercloud/gophercloud/pagination"
6+
)
7+
8+
// ListOptsBuilder allows extensions to add additional parameters to the
9+
// List request.
10+
type ListOptsBuilder interface {
11+
ToFlavorProfileListQuery() (string, error)
12+
}
13+
14+
// ListOpts allows to manage the output of the request.
15+
type ListOpts struct {
16+
// The fields that you want the server to return
17+
Fields []string `q:"fields"`
18+
}
19+
20+
// ToFlavorProfileListQuery formats a ListOpts into a query string.
21+
func (opts ListOpts) ToFlavorProfileListQuery() (string, error) {
22+
q, err := gophercloud.BuildQueryString(opts)
23+
return q.String(), err
24+
}
25+
26+
// List returns a Pager which allows you to iterate over a collection of
27+
// FlavorProfiles. It accepts a ListOpts struct, which allows you to filter
28+
// and sort the returned collection for greater efficiency.
29+
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
30+
url := rootURL(c)
31+
if opts != nil {
32+
query, err := opts.ToFlavorProfileListQuery()
33+
if err != nil {
34+
return pagination.Pager{Err: err}
35+
}
36+
url += query
37+
}
38+
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
39+
return FlavorProfilePage{pagination.LinkedPageBase{PageResult: r}}
40+
})
41+
}
42+
43+
// CreateOptsBuilder allows extensions to add additional parameters to the
44+
// Create request.
45+
type CreateOptsBuilder interface {
46+
ToFlavorProfileCreateMap() (map[string]interface{}, error)
47+
}
48+
49+
// CreateOpts is the common options struct used in this package's Create
50+
// operation.
51+
type CreateOpts struct {
52+
// Human-readable name for the Loadbalancer. Does not have to be unique.
53+
Name string `json:"name" required:"true"`
54+
55+
// Providing the name of the provider supported by the Octavia installation.
56+
ProviderName string `json:"provider_name" required:"true"`
57+
58+
// Providing the json string containing the flavor metadata.
59+
FlavorData string `json:"flavor_data" required:"true"`
60+
}
61+
62+
// ToFlavorProfileCreateMap builds a request body from CreateOpts.
63+
func (opts CreateOpts) ToFlavorProfileCreateMap() (map[string]interface{}, error) {
64+
return gophercloud.BuildRequestBody(opts, "flavorprofile")
65+
}
66+
67+
// Create is and operation which add a new FlavorProfile into the database.
68+
// CreateResult will be returned.
69+
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
70+
b, err := opts.ToFlavorProfileCreateMap()
71+
if err != nil {
72+
r.Err = err
73+
return
74+
}
75+
resp, err := c.Post(rootURL(c), b, &r.Body, nil)
76+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
77+
return
78+
}
79+
80+
// Get retrieves a particular FlavorProfile based on its unique ID.
81+
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
82+
resp, err := c.Get(resourceURL(c, id), &r.Body, nil)
83+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
84+
return
85+
}
86+
87+
// UpdateOptsBuilder allows extensions to add additional parameters to the
88+
// Update request.
89+
type UpdateOptsBuilder interface {
90+
ToFlavorProfileUpdateMap() (map[string]interface{}, error)
91+
}
92+
93+
// UpdateOpts is the common options struct used in this package's Update
94+
// operation.
95+
type UpdateOpts struct {
96+
// Human-readable name for the Loadbalancer. Does not have to be unique.
97+
Name string `json:"name,omitempty"`
98+
99+
// Providing the name of the provider supported by the Octavia installation.
100+
ProviderName string `json:"provider_name,omitempty"`
101+
102+
// Providing the json string containing the flavor metadata.
103+
FlavorData string `json:"flavor_data,omitempty"`
104+
}
105+
106+
// ToFlavorProfileUpdateMap builds a request body from UpdateOpts.
107+
func (opts UpdateOpts) ToFlavorProfileUpdateMap() (map[string]interface{}, error) {
108+
b, err := gophercloud.BuildRequestBody(opts, "flavorprofile")
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
return b, nil
114+
}
115+
116+
// Update is an operation which modifies the attributes of the specified
117+
// FlavorProfile.
118+
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) {
119+
b, err := opts.ToFlavorProfileUpdateMap()
120+
if err != nil {
121+
r.Err = err
122+
return
123+
}
124+
resp, err := c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
125+
OkCodes: []int{200, 202},
126+
})
127+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
128+
return
129+
}
130+
131+
// Delete will permanently delete a particular FlavorProfile based on its
132+
// unique ID.
133+
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
134+
resp, err := c.Delete(resourceURL(c, id), nil)
135+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
136+
return
137+
}

0 commit comments

Comments
 (0)