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

Add networking port extra DHCP opts Update call #804

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions acceptance/openstack/networking/v2/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/acceptance/tools"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity"
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
Expand Down Expand Up @@ -336,3 +337,52 @@ func WaitForPortToCreate(client *gophercloud.ServiceClient, portID string, secs
return false, nil
})
}

// PortWithDHCPOpts represents a port with extra DHCP options configuration.
type PortWithDHCPOpts struct {
ports.Port
extradhcpopts.ExtraDHCPOptsExt
}

// CreatePortWithDHCPOpts will create a port with DHCP options on the specified subnet.
// An error will be returned if the port could not be created.
func CreatePortWithDHCPOpts(t *testing.T, client *gophercloud.ServiceClient, networkID, subnetID string) (*PortWithDHCPOpts, error) {
portName := tools.RandomString("TESTACC-", 8)

t.Logf("Attempting to create port: %s", portName)

portCreateOpts := ports.CreateOpts{
NetworkID: networkID,
Name: portName,
AdminStateUp: gophercloud.Enabled,
FixedIPs: []ports.IP{ports.IP{SubnetID: subnetID}},
}
createOpts := extradhcpopts.CreateOptsExt{
CreateOptsBuilder: portCreateOpts,
ExtraDHCPOpts: []extradhcpopts.ExtraDHCPOpts{
{
OptName: "test_option_1",
OptValue: "test_value_1",
},
},
}
port := &PortWithDHCPOpts{}

err := ports.Create(client, createOpts).ExtractInto(port)
if err != nil {
return nil, err
}

if err := WaitForPortToCreate(client, port.ID, 60); err != nil {
return nil, err
}

err = ports.Get(client, port.ID).ExtractInto(port)
if err != nil {
return port, err
}

t.Logf("Successfully created port: %s", portName)

return port, nil
}
54 changes: 54 additions & 0 deletions acceptance/openstack/networking/v2/ports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/gophercloud/gophercloud/acceptance/clients"
extensions "github.com/gophercloud/gophercloud/acceptance/openstack/networking/v2/extensions"
"github.com/gophercloud/gophercloud/acceptance/tools"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
)
Expand Down Expand Up @@ -388,3 +389,56 @@ func TestPortsPortSecurityCRUD(t *testing.T) {

tools.PrintResource(t, portWithExt)
}

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

// Create a Network
network, err := CreateNetwork(t, client)
if err != nil {
t.Fatalf("Unable to create a network: %v", err)
}
defer DeleteNetwork(t, client, network.ID)

// Create a Subnet
subnet, err := CreateSubnet(t, client, network.ID)
if err != nil {
t.Fatalf("Unable to create a subnet: %v", err)
}
defer DeleteSubnet(t, client, subnet.ID)

// Create a port with extra DHCP options.
port, err := CreatePortWithDHCPOpts(t, client, network.ID, subnet.ID)
if err != nil {
t.Fatalf("Unable to create a port: %v", err)
}
defer DeletePort(t, client, port.ID)

tools.PrintResource(t, port)

// Update the port with extra DHCP options.
newPortName := tools.RandomString("TESTACC-", 8)
portUpdateOpts := ports.UpdateOpts{
Name: newPortName,
}
updateOpts := extradhcpopts.UpdateOptsExt{
UpdateOptsBuilder: portUpdateOpts,
ExtraDHCPOpts: []extradhcpopts.ExtraDHCPOpts{
{
OptName: "test_option_2",
OptValue: "test_value_2",
},
},
}

newPort := &PortWithDHCPOpts{}
err = ports.Update(client, port.ID, updateOpts).ExtractInto(newPort)
if err != nil {
t.Fatalf("Could not update port: %v", err)
}

tools.PrintResource(t, newPort)
}
75 changes: 75 additions & 0 deletions openstack/networking/v2/extensions/extradhcpopts/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Package extradhcpopts allow to work with extra DHCP functionality of Neutron ports.

Example to Get a Port with DHCP opts

portID := "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2"
var s struct {
ports.Port
extradhcpopts.ExtraDHCPOptsExt
}

err := ports.Get(networkClient, portID).ExtractInto(&s)
if err != nil {
panic(err)
}

Example to Create a Port with DHCP opts

adminStateUp := true
portCreateOpts := ports.CreateOpts{
Name: "dhcp-conf-port",
AdminStateUp: &adminStateUp,
NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7",
FixedIPs: []ports.IP{
{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"},
},
}
createOpts := extradhcpopts.CreateOptsExt{
CreateOptsBuilder: portCreateOpts,
ExtraDHCPOpts: []extradhcpopts.ExtraDHCPOpts{
{
OptName: "optionA",
OptValue: "valueA",
},
},
}
var s struct {
ports.Port
extradhcpopts.ExtraDHCPOptsExt
}

err := ports.Create(networkClient, createOpts).ExtractInto(&s)
if err != nil {
panic(err)
}

Example to Update a Port with DHCP opts

portUpdateOpts := ports.UpdateOpts{
Name: "updated-dhcp-conf-port",
FixedIPs: []ports.IP{
{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"},
},
}
updateOpts := extradhcpopts.UpdateOptsExt{
UpdateOptsBuilder: portUpdateOpts,
ExtraDHCPOpts: []extradhcpopts.ExtraDHCPOpts{
{
OptName: "optionB",
OptValue: "valueB",
},
},
}
var s struct {
ports.Port
extradhcpopts.ExtraDHCPOptsExt
}
portID := "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2"

err := ports.Update(networkClient, portID, updateOpts).ExtractInto(&s)
if err != nil {
panic(err)
}
*/
package extradhcpopts
75 changes: 75 additions & 0 deletions openstack/networking/v2/extensions/extradhcpopts/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package extradhcpopts

import (
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
)

// CreateOptsExt adds port DHCP options to the base ports.CreateOpts.
type CreateOptsExt struct {
// CreateOptsBuilder is the interface options structs have to satisfy in order
// to be used in the main Create operation in this package.
ports.CreateOptsBuilder

// ExtraDHCPOpts field is a set of DHCP options for a single port.
ExtraDHCPOpts []ExtraDHCPOpts `json:"extra_dhcp_opts,omitempty"`
}

// ToPortCreateMap casts a CreateOptsExt struct to a map.
func (opts CreateOptsExt) ToPortCreateMap() (map[string]interface{}, error) {
base, err := opts.CreateOptsBuilder.ToPortCreateMap()
if err != nil {
return nil, err
}

port := base["port"].(map[string]interface{})

// Convert opts.DHCPOpts to a slice of maps.
if opts.ExtraDHCPOpts != nil {
extraDHCPOpts := make([]map[string]interface{}, len(opts.ExtraDHCPOpts))
for i, opt := range opts.ExtraDHCPOpts {
extraDHCPOptMap, err := opt.ToMap()
if err != nil {
return nil, err
}
extraDHCPOpts[i] = extraDHCPOptMap
}
port["extra_dhcp_opts"] = extraDHCPOpts
}

return base, nil
}

// UpdateOptsExt adds port DHCP options to the base ports.UpdateOpts
type UpdateOptsExt struct {
// UpdateOptsBuilder is the interface options structs have to satisfy in order
// to be used in the main Update operation in this package.
ports.UpdateOptsBuilder

// ExtraDHCPOpts field is a set of DHCP options for a single port.
ExtraDHCPOpts []ExtraDHCPOpts `json:"extra_dhcp_opts,omitempty"`
}

// ToPortUpdateMap casts an UpdateOpts struct to a map.
func (opts UpdateOptsExt) ToPortUpdateMap() (map[string]interface{}, error) {
base, err := opts.UpdateOptsBuilder.ToPortUpdateMap()
if err != nil {
return nil, err
}

port := base["port"].(map[string]interface{})

// Convert opts.ExtraDHCPOpts to a slice of maps.
if opts.ExtraDHCPOpts != nil {
extraDHCPOpts := make([]map[string]interface{}, len(opts.ExtraDHCPOpts))
for i, opt := range opts.ExtraDHCPOpts {
extraDHCPOptMap, err := opt.ToMap()
if err != nil {
return nil, err
}
extraDHCPOpts[i] = extraDHCPOptMap
}
port["extra_dhcp_opts"] = extraDHCPOpts
}

return base, nil
}
32 changes: 32 additions & 0 deletions openstack/networking/v2/extensions/extradhcpopts/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package extradhcpopts

import "github.com/gophercloud/gophercloud"

// ExtraDHCPOptsExt is a struct that contains different DHCP options for a single port.
type ExtraDHCPOptsExt struct {
ExtraDHCPOpts []ExtraDHCPOpts `json:"extra_dhcp_opts"`
}

// ExtraDHCPOpts represents a single set of extra DHCP options for a single port.
type ExtraDHCPOpts struct {
// Name is the name of a single DHCP option.
OptName string `json:"opt_name"`

// Value is the value of a single DHCP option.
OptValue string `json:"opt_value"`

// IPVersion is the IP protocol version of a single DHCP option.
// Valid value is 4 or 6. Default is 4.
IPVersion int `json:"ip_version,omitempty"`
}

// ToMap is a helper function to convert an individual DHCPOpts structure
// into a sub-map.
func (opts ExtraDHCPOpts) ToMap() (map[string]interface{}, error) {
b, err := gophercloud.BuildRequestBody(opts, "")
if err != nil {
return nil, err
}

return b, nil
}
Loading