Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v1] Add support of Flavors and FlavorProfiles for Octavia #2887

Merged
merged 2 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//go:build acceptance || networking || loadbalancer || flavorprofiles
// +build acceptance networking loadbalancer flavorprofiles

package v2

import (
"testing"

"github.com/gophercloud/gophercloud/internal/acceptance/clients"
"github.com/gophercloud/gophercloud/internal/acceptance/tools"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavorprofiles"

th "github.com/gophercloud/gophercloud/testhelper"
)

func TestFlavorProfilesList(t *testing.T) {
client, err := clients.NewLoadBalancerV2Client()
th.AssertNoErr(t, err)

allPages, err := flavorprofiles.List(client, nil).AllPages()
th.AssertNoErr(t, err)

allFlavorProfiles, err := flavorprofiles.ExtractFlavorProfiles(allPages)
th.AssertNoErr(t, err)

for _, flavorprofile := range allFlavorProfiles {
tools.PrintResource(t, flavorprofile)
}
}

func TestFlavorProfilesCRUD(t *testing.T) {
lbClient, err := clients.NewLoadBalancerV2Client()
th.AssertNoErr(t, err)

flavorProfile, err := CreateFlavorProfile(t, lbClient)
th.AssertNoErr(t, err)
defer DeleteFlavorProfile(t, lbClient, flavorProfile)

tools.PrintResource(t, flavorProfile)

th.AssertEquals(t, "amphora", flavorProfile.ProviderName)

flavorProfileUpdateOpts := flavorprofiles.UpdateOpts{
Name: tools.RandomString("TESTACCTUP-", 8),
}

flavorProfileUpdated, err := flavorprofiles.Update(lbClient, flavorProfile.ID, flavorProfileUpdateOpts).Extract()
th.AssertNoErr(t, err)

th.AssertEquals(t, flavorProfileUpdateOpts.Name, flavorProfileUpdated.Name)

t.Logf("Successfully updated flavorprofile %s", flavorProfileUpdated.Name)
}
66 changes: 66 additions & 0 deletions internal/acceptance/openstack/loadbalancer/v2/flavors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//go:build acceptance || networking || loadbalancer || flavors
// +build acceptance networking loadbalancer flavors

package v2

import (
"testing"

"github.com/gophercloud/gophercloud/internal/acceptance/clients"
"github.com/gophercloud/gophercloud/internal/acceptance/tools"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavors"
th "github.com/gophercloud/gophercloud/testhelper"
)

func TestFlavorsList(t *testing.T) {
client, err := clients.NewLoadBalancerV2Client()
if err != nil {
t.Fatalf("Unable to create a loadbalancer client: %v", err)
}

allPages, err := flavors.List(client, nil).AllPages()
if err != nil {
t.Fatalf("Unable to list flavors: %v", err)
}

allFlavors, err := flavors.ExtractFlavors(allPages)
if err != nil {
t.Fatalf("Unable to extract flavors: %v", err)
}

for _, flavor := range allFlavors {
tools.PrintResource(t, flavor)
}
}

func TestFlavorsCRUD(t *testing.T) {
lbClient, err := clients.NewLoadBalancerV2Client()
th.AssertNoErr(t, err)

flavorProfile, err := CreateFlavorProfile(t, lbClient)
th.AssertNoErr(t, err)
defer DeleteFlavorProfile(t, lbClient, flavorProfile)

tools.PrintResource(t, flavorProfile)

th.AssertEquals(t, "amphora", flavorProfile.ProviderName)

flavor, err := CreateFlavor(t, lbClient, flavorProfile)
th.AssertNoErr(t, err)
defer DeleteFlavor(t, lbClient, flavor)

tools.PrintResource(t, flavor)

th.AssertEquals(t, flavor.FlavorProfileId, flavorProfile.ID)

flavorUpdateOpts := flavors.UpdateOpts{
Name: tools.RandomString("TESTACCTUP-", 8),
}

flavorUpdated, err := flavors.Update(lbClient, flavor.ID, flavorUpdateOpts).Extract()
th.AssertNoErr(t, err)

th.AssertEquals(t, flavorUpdateOpts.Name, flavorUpdated.Name)

t.Logf("Successfully updated flavor %s", flavorUpdated.Name)
}
71 changes: 71 additions & 0 deletions internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/internal/acceptance/clients"
"github.com/gophercloud/gophercloud/internal/acceptance/tools"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavorprofiles"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/flavors"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/l7policies"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
Expand Down Expand Up @@ -676,3 +678,72 @@ func WaitForLoadBalancerState(client *gophercloud.ServiceClient, lbID, status st
return false, nil
})
}

func CreateFlavorProfile(t *testing.T, client *gophercloud.ServiceClient) (*flavorprofiles.FlavorProfile, error) {
flavorProfileName := tools.RandomString("TESTACCT-", 8)
flavorProfileDriver := "amphora"
flavorProfileData := "{\"loadbalancer_topology\": \"SINGLE\"}"

createOpts := flavorprofiles.CreateOpts{
Name: flavorProfileName,
ProviderName: flavorProfileDriver,
FlavorData: flavorProfileData,
}

flavorProfile, err := flavorprofiles.Create(client, createOpts).Extract()
if err != nil {
return flavorProfile, err
}

t.Logf("Successfully created flavorprofile %s", flavorProfileName)

th.AssertEquals(t, flavorProfileName, flavorProfile.Name)
th.AssertEquals(t, flavorProfileDriver, flavorProfile.ProviderName)
th.AssertEquals(t, flavorProfileData, flavorProfile.FlavorData)

return flavorProfile, nil
}

func DeleteFlavorProfile(t *testing.T, client *gophercloud.ServiceClient, flavorProfile *flavorprofiles.FlavorProfile) {
err := flavorprofiles.Delete(client, flavorProfile.ID).ExtractErr()
if err != nil {
t.Fatalf("Unable to delete flavorprofile: %v", err)
}

t.Logf("Successfully deleted flavorprofile %s", flavorProfile.Name)
}

func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient, flavorProfile *flavorprofiles.FlavorProfile) (*flavors.Flavor, error) {
flavorName := tools.RandomString("TESTACCT-", 8)
description := tools.RandomString("TESTACCT-desc-", 32)

createOpts := flavors.CreateOpts{
Name: flavorName,
Description: description,
FlavorProfileId: flavorProfile.ID,
Enabled: true,
}

flavor, err := flavors.Create(client, createOpts).Extract()
if err != nil {
return flavor, err
}

t.Logf("Successfully created flavor %s with flavorprofile %s", flavor.Name, flavorProfile.Name)

th.AssertEquals(t, flavorName, flavor.Name)
th.AssertEquals(t, description, flavor.Description)
th.AssertEquals(t, flavorProfile.ID, flavor.FlavorProfileId)
th.AssertEquals(t, true, flavor.Enabled)

return flavor, nil
}

func DeleteFlavor(t *testing.T, client *gophercloud.ServiceClient, flavor *flavors.Flavor) {
err := flavors.Delete(client, flavor.ID).ExtractErr()
if err != nil {
t.Fatalf("Unable to delete flavor: %v", err)
}

t.Logf("Successfully deleted flavor %s", flavor.Name)
}
57 changes: 57 additions & 0 deletions openstack/loadbalancer/v2/flavorprofiles/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Package flavorprofiles provides information and interaction
with FlavorProfiles for the OpenStack Load-balancing service.

Example to List FlavorProfiles

listOpts := flavorprofiles.ListOpts{}

allPages, err := flavorprofiles.List(octaviaClient, listOpts).AllPages()
if err != nil {
panic(err)
}

allFlavorProfiles, err := flavorprofiles.ExtractFlavorProfiles(allPages)
if err != nil {
panic(err)
}

for _, flavorProfile := range allFlavorProfiles {
fmt.Printf("%+v\n", flavorProfile)
}

Example to Create a FlavorProfile

createOpts := flavorprofiles.CreateOpts{
Name: "amphora-single",
ProviderName: "amphora",
FlavorData: "{\"loadbalancer_topology\": \"SINGLE\"}",
}

flavorProfile, err := flavorprofiles.Create(octaviaClient, createOpts).Extract()
if err != nil {
panic(err)
}

Example to Update a FlavorProfile

flavorProfileID := "dd6a26af-8085-4047-a62b-3080f4c76521"

updateOpts := flavorprofiles.UpdateOpts{
Name: "amphora-single-updated",
}

flavorProfile, err := flavorprofiles.Update(octaviaClient, flavorProfileID, updateOpts).Extract()
if err != nil {
panic(err)
}

Example to Delete a FlavorProfile

flavorProfileID := "dd6a26af-8085-4047-a62b-3080f4c76521"
err := flavorprofiles.Delete(octaviaClient, flavorProfileID).ExtractErr()
if err != nil {
panic(err)
}
*/
package flavorprofiles
137 changes: 137 additions & 0 deletions openstack/loadbalancer/v2/flavorprofiles/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package flavorprofiles

import (
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
)

// ListOptsBuilder allows extensions to add additional parameters to the
// List request.
type ListOptsBuilder interface {
ToFlavorProfileListQuery() (string, error)
}

// ListOpts allows to manage the output of the request.
type ListOpts struct {
// The fields that you want the server to return
Fields []string `q:"fields"`
}

// ToFlavorProfileListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToFlavorProfileListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
return q.String(), err
}

// List returns a Pager which allows you to iterate over a collection of
// FlavorProfiles. It accepts a ListOpts struct, which allows you to filter
// and sort the returned collection for greater efficiency.
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := rootURL(c)
if opts != nil {
query, err := opts.ToFlavorProfileListQuery()
if err != nil {
return pagination.Pager{Err: err}
}
url += query
}
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
return FlavorProfilePage{pagination.LinkedPageBase{PageResult: r}}
})
}

// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface {
ToFlavorProfileCreateMap() (map[string]interface{}, error)
}

// CreateOpts is the common options struct used in this package's Create
// operation.
type CreateOpts struct {
// Human-readable name for the Loadbalancer. Does not have to be unique.
Name string `json:"name" required:"true"`

// Providing the name of the provider supported by the Octavia installation.
ProviderName string `json:"provider_name" required:"true"`

// Providing the json string containing the flavor metadata.
FlavorData string `json:"flavor_data" required:"true"`
}

// ToFlavorProfileCreateMap builds a request body from CreateOpts.
func (opts CreateOpts) ToFlavorProfileCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "flavorprofile")
}

// Create is and operation which add a new FlavorProfile into the database.
// CreateResult will be returned.
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToFlavorProfileCreateMap()
if err != nil {
r.Err = err
return
}
resp, err := c.Post(rootURL(c), b, &r.Body, nil)
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}

// Get retrieves a particular FlavorProfile based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
resp, err := c.Get(resourceURL(c, id), &r.Body, nil)
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}

// UpdateOptsBuilder allows extensions to add additional parameters to the
// Update request.
type UpdateOptsBuilder interface {
ToFlavorProfileUpdateMap() (map[string]interface{}, error)
}

// UpdateOpts is the common options struct used in this package's Update
// operation.
type UpdateOpts struct {
// Human-readable name for the Loadbalancer. Does not have to be unique.
Name string `json:"name,omitempty"`

// Providing the name of the provider supported by the Octavia installation.
ProviderName string `json:"provider_name,omitempty"`

// Providing the json string containing the flavor metadata.
FlavorData string `json:"flavor_data,omitempty"`
}

// ToFlavorProfileUpdateMap builds a request body from UpdateOpts.
func (opts UpdateOpts) ToFlavorProfileUpdateMap() (map[string]interface{}, error) {
b, err := gophercloud.BuildRequestBody(opts, "flavorprofile")
if err != nil {
return nil, err
}

return b, nil
}

// Update is an operation which modifies the attributes of the specified
// FlavorProfile.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) {
b, err := opts.ToFlavorProfileUpdateMap()
if err != nil {
r.Err = err
return
}
resp, err := c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 202},
})
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}

// Delete will permanently delete a particular FlavorProfile based on its
// unique ID.
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
resp, err := c.Delete(resourceURL(c, id), nil)
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}