Skip to content
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
98 changes: 89 additions & 9 deletions net.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,24 @@ type Tunnel struct {
UsePmtu string `json:"usePmtu,omitempty"`
}

// Vxlans contains a list of vlxan profiles on the BIG-IP system.
type Vxlans struct {
Vxlans []Vxlan `json:"items"`
}

// Vxlan is the structure for the VXLAN profile on the bigip.
// https://devcentral.f5.com/wiki/iControlREST.APIRef_tm_net_tunnels_vxlan.ashx
type Vxlan struct {
Name string `json:"name,omitempty"`
AppService string `json:"appService,omitempty"`
DefaultsFrom string `json:"defaultsFrom,omitempty"`
Description string `json:"description,omitempty"`
EncapsulationType string `json:"encapsulationType,omitempty"`
FloodingType string `json:"floodingType,omitempty"`
Partition string `json:"partition,omitempty"`
Port int `json:"port,omitempty"`
}

const (
uriNet = "net"
uriInterface = "interface"
Expand All @@ -205,6 +223,21 @@ const (
uriRouteDomain = "route-domain"
)

// formatResourceID takes the resource name to
// ensure theres a partition for the Resource ID
func formatResourceID(name string) string {
// If the name specifies the partition already, then
// just hand it back.
regex := regexp.MustCompile(`^~([a-zA-Z0-9-.]+)~`)
if regex.MatchString(name) {
return name
}

// Otherwise, tack on the Common partition
// for best practices with the resource_id.
return "~Common~" + name
}

// Interfaces returns a list of interfaces.
func (b *BigIP) Interfaces() (*Interfaces, error) {
var interfaces Interfaces
Expand Down Expand Up @@ -494,15 +527,7 @@ func (b *BigIP) Tunnels() (*Tunnels, error) {
// GetTunnel fetches the tunnel by it's name.
func (b *BigIP) GetTunnel(name string) (*Tunnel, error) {
var tunnel Tunnel
values := []string{}
regex := regexp.MustCompile(`^(\/.+\/)?(.+)`)
match := regex.FindStringSubmatch(name)
if match[1] == "" {
values = append(values, "~Common~")
}
values = append(values, name)
// Join the strings into one.
result := strings.Join(values, "")
result := formatResourceID(name)
err, ok := b.getForEntity(&tunnel, uriNet, uriTunnels, uriTunnel, result)
if err != nil {
return nil, err
Expand All @@ -514,6 +539,11 @@ func (b *BigIP) GetTunnel(name string) (*Tunnel, error) {
return &tunnel, nil
}

// AddTunnel adds a new tunnel to the BIG-IP system from a config.
func (b *BigIP) AddTunnel(config *Tunnel) error {
return b.post(config, uriNet, uriTunnels, uriTunnel)
}

// CreateTunnel adds a new tunnel to the BIG-IP system.
func (b *BigIP) CreateTunnel(name, profile string) error {
config := &Tunnel{
Expand All @@ -533,3 +563,53 @@ func (b *BigIP) DeleteTunnel(name string) error {
func (b *BigIP) ModifyTunnel(name string, config *Tunnel) error {
return b.put(config, uriNet, uriTunnels, uriTunnel, name)
}

// Vxlans returns a list of vxlan profiles.
func (b *BigIP) Vxlans() ([]Vxlan, error) {
var vxlans Vxlans
err, _ := b.getForEntity(&vxlans, uriNet, uriTunnels, uriVxlan)
if err != nil {
return nil, err
}

return vxlans.Vxlans, nil
}

// GetVxlan fetches the vxlan profile by it's name.
func (b *BigIP) GetVxlan(name string) (*Vxlan, error) {
var vxlan Vxlan
result := formatResourceID(name)
err, ok := b.getForEntity(&vxlan, uriNet, uriTunnels, uriVxlan, result)
if err != nil {
return nil, err
}
if !ok {
return nil, nil
}

return &vxlan, nil
}

// AddVxlan adds a new vxlan profile to the BIG-IP system.
func (b *BigIP) AddVxlan(config *Vxlan) error {
return b.post(config, uriNet, uriTunnels, uriVxlan)
}

// CreateVxlan adds a new vxlan profile to the BIG-IP system.
func (b *BigIP) CreateVxlan(name string) error {
config := &Vxlan{
Name: name,
}

return b.post(config, uriNet, uriTunnels, uriVxlan)
}

// DeleteVxlan removes a vxlan profile.
func (b *BigIP) DeleteVxlan(name string) error {
return b.delete(uriNet, uriTunnels, uriVxlan, name)
}

// ModifyVxlan allows you to change any attribute of a vxlan profile.
func (b *BigIP) ModifyVxlan(name string, config *Vxlan) error {
return b.put(config, uriNet, uriTunnels, uriVxlan, name)
}
147 changes: 147 additions & 0 deletions net_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,33 @@ func (s *NetTestSuite) TestCreateTunnel() {
assertRestCall(s, "POST", "/mgmt/tm/net/tunnels/tunnel", `{"name":"some-foo-tunnel", "profile":"/Common/some-foo-profile"}`)
}

func (s *NetTestSuite) TestAddTunnel() {
someTunnel := Tunnel{
Name: "foo-tunnel",
AppService: "foo-appservice",
AutoLasthop: "foo-lasthop",
Description: "foo-desc",
IdleTimeout: 123,
IfIndex: 456,
Key: 789,
LocalAddress: "foo-local-address",
Mode: "foo-mode",
Mtu: 1440,
Partition: "foo-partition",
Profile: "foo-profile",
RemoteAddress: "foo-remoteaddr",
SecondaryAddress: "foo-secondaddr",
Tos: "foo-tos",
TrafficGroup: "foo-tg",
Transparent: "foo-transparent",
UsePmtu: "foo-pmtu",
}
err := s.Client.AddTunnel(&someTunnel)

assert.Nil(s.T(), err)
assertRestCall(s, "POST", "/mgmt/tm/net/tunnels/tunnel", `{"appService":"foo-appservice", "autoLasthop":"foo-lasthop", "description":"foo-desc", "idleTimeout":123, "ifIndex":456, "key":789, "localAddress":"foo-local-address", "mode":"foo-mode", "mtu":1440, "name":"foo-tunnel", "partition":"foo-partition", "profile":"foo-profile", "remoteAddress":"foo-remoteaddr", "secondaryAddress":"foo-secondaddr", "tos":"foo-tos", "trafficGroup":"foo-tg", "transparent":"foo-transparent", "usePmtu":"foo-pmtu"}`)
}

func (s *NetTestSuite) TestDeleteTunnel() {
err := s.Client.DeleteTunnel("some-foo-tunnel")

Expand All @@ -509,3 +536,123 @@ func (s *NetTestSuite) TestModifyTunnel() {
assert.Nil(s.T(), err)
assertRestCall(s, "PUT", "/mgmt/tm/net/tunnels/tunnel/some-foo-tunnel", `{"transparent":"enabled"}`)
}

var goodVxlansRespnse = `{
"items": [
{
"defaultsFrom": "/Common/vxlan",
"defaultsFromReference": {
"link": "https://localhost/mgmt/tm/net/tunnels/vxlan/~Common~vxlan?ver=13.1.1.2"
},
"encapsulationType": "vxlan",
"floodingType": "multipoint",
"fullPath": "/Common/vxlan-foo",
"generation": 1,
"kind": "tm:net:tunnels:vxlan:vxlanstate",
"name": "vxlan-foo",
"partition": "foo",
"port": 4789,
"selfLink": "https://localhost/mgmt/tm/net/tunnels/vxlan/~foo~vxlan-foo?ver=13.1.1.2"
},
{
"defaultsFrom": "/Common/vxlan",
"defaultsFromReference": {
"link": "https://localhost/mgmt/tm/net/tunnels/vxlan/~Common~vxlan?ver=13.1.1.2"
},
"encapsulationType": "vxlan",
"floodingType": "none",
"fullPath": "/Common/vxlan-bar",
"generation": 1,
"kind": "tm:net:tunnels:vxlan:vxlanstate",
"name": "vxlan-bar",
"partition": "bar",
"port": 4789,
"selfLink": "https://localhost/mgmt/tm/net/tunnels/vxlan/~bar~vxlan-bar?ver=13.1.1.2"
}
],
"kind": "tm:net:tunnels:vxlan:vxlancollectionstate",
"selfLink": "https://localhost/mgmt/tm/net/tunnels/vxlan?ver=13.1.1.2"
}`

var goodVxlanRespnse = `{
"defaultsFrom": "/Common/vxlan",
"defaultsFromReference": {
"link": "https://localhost/mgmt/tm/net/tunnels/vxlan/~Common~vxlan?ver=13.1.1.2"
},
"encapsulationType": "vxlan",
"floodingType": "multipoint",
"fullPath": "/Common/vxlan-foo",
"generation": 1,
"kind": "tm:net:tunnels:vxlan:vxlanstate",
"name": "vxlan-foo",
"partition": "foo",
"port": 4789,
"selfLink": "https://localhost/mgmt/tm/net/tunnels/vxlan/~foo~vxlan-foo?ver=13.1.1.2"
}`

func (s *NetTestSuite) TestVxlans() {
s.ResponseFunc = func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(goodVxlansRespnse))
}

vxlans, err := s.Client.Vxlans()

assert.Nil(s.T(), err)
assertRestCall(s, "GET", "/mgmt/tm/net/tunnels/vxlan", "")
assert.Equal(s.T(), 2, len(vxlans))
assert.Equal(s.T(), "vxlan-foo", vxlans[0].Name)
assert.Equal(s.T(), "vxlan-bar", vxlans[1].Name)
}

func (s *NetTestSuite) TestGetVxlan() {
s.ResponseFunc = func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(goodVxlanRespnse))
}

vxlan, err := s.Client.GetVxlan("~foo~vxlan-foo")

assert.Nil(s.T(), err)
assertRestCall(s, "GET", "/mgmt/tm/net/tunnels/vxlan/~foo~vxlan-foo", "")
assert.Equal(s.T(), "vxlan-foo", vxlan.Name)
assert.Equal(s.T(), 4789, vxlan.Port)
}

func (s *NetTestSuite) TestCreateVxlan() {
err := s.Client.CreateVxlan("some-foo-vxlan")

assert.Nil(s.T(), err)
assertRestCall(s, "POST", "/mgmt/tm/net/tunnels/vxlan", `{"name":"some-foo-vxlan"}`)
}

func (s *NetTestSuite) TestAddVxlan() {
someVxlan := Vxlan{
Name: "foo-vxlan",
AppService: "foo-appservice",
Description: "foo-desc",
DefaultsFrom: "foo-base-profile",
EncapsulationType: "foo-encap",
FloodingType: "foo-ft",
Partition: "foo-partition",
Port: 123,
}
err := s.Client.AddVxlan(&someVxlan)

assert.Nil(s.T(), err)
assertRestCall(s, "POST", "/mgmt/tm/net/tunnels/vxlan", `{"appService":"foo-appservice", "defaultsFrom":"foo-base-profile", "description":"foo-desc", "encapsulationType":"foo-encap", "floodingType":"foo-ft", "name":"foo-vxlan", "partition":"foo-partition", "port":123}`)
}

func (s *NetTestSuite) TestDeleteVxlan() {
err := s.Client.DeleteVxlan("some-foo-vxlan")

assert.Nil(s.T(), err)
assertRestCall(s, "DELETE", "/mgmt/tm/net/tunnels/vxlan/some-foo-vxlan", "")
}

func (s *NetTestSuite) TestModifyVxlan() {
vxlan := &Vxlan{Port: 456}

err := s.Client.ModifyVxlan("some-foo-vxlan", vxlan)

assert.Nil(s.T(), err)
assertRestCall(s, "PUT", "/mgmt/tm/net/tunnels/vxlan/some-foo-vxlan", `{"port":456}`)
}