diff --git a/device.go b/device.go index 7675a7e..68f9306 100644 --- a/device.go +++ b/device.go @@ -46,11 +46,53 @@ type Devices struct { Devices []Device `json:"items"` } +// UnicastAddress is an abstraction and used by Device +type UnicastAddress struct { + EffectiveIP string `json:"effectiveIp"` + EffectivePort int `json:"effectivePort"` + IP string `json:"ip"` + Port int `json:"port"` +} + +// Device represents an individual bigip as viewed from the cluster +// see: https://devcentral.f5.com/Wiki/iControlREST.APIRef_tm_cm_device.ashx type Device struct { - ConfigsyncIp string `json:"configsyncIp,omitempty"` - Name string `json:"name,omitempty"` - MirrorIp string `json:"mirrorIp,omitempty"` - MirrorSecondaryIp string `json:"mirrorSecondaryIp,omitempty"` + ConfigsyncIp string `json:"configsyncIp,omitempty"` + Name string `json:"name,omitempty"` + MirrorIp string `json:"mirrorIp,omitempty"` + MirrorSecondaryIp string `json:"mirrorSecondaryIp,omitempty"` + ActiveModules []string `json:"activeModules,omitempty"` + AppService string `json:"appService,omitempty"` + BaseMac string `json:"baseMac,omitempty"` + Build string `json:"build,omitempty"` + Cert string `json:"cert,omitempty"` + ChassisID string `json:"chassisId,omitempty"` + ChassisType string `json:"chassisType,omitempty"` + Comment string `json:"comment,omitempty"` + ConfigsyncIP string `json:"configsyncIp,omitempty"` + Contact string `json:"contact,omitempty"` + Description string `json:"description,omitempty"` + Edition string `json:"edition,omitempty"` + FailoverState string `json:"failoverState,omitempty"` + HaCapacity int `json:"haCapacity,omitempty"` + Hostname string `json:"hostname,omitempty"` + InactiveModules string `json:"inactiveModules,omitempty"` + Key string `json:"key,omitempty"` + Location string `json:"location,omitempty"` + ManagementIP string `json:"managementIp,omitempty"` + MarketingName string `json:"marketingName,omitempty"` + MulticastInterface string `json:"multicastInterface,omitempty"` + MulticastIP string `json:"multicastIp,omitempty"` + MulticastPort int `json:"multicastPort,omitempty"` + OptionalModules []string `json:"optionalModules,omitempty"` + Partition string `json:"partition,omitempty"` + PlatformID string `json:"platformId,omitempty"` + Product string `json:"product,omitempty"` + SelfDevice string `json:"selfDevice,omitempty"` + TimeLimitedModules []string `json:"timeLimitedModules,omitempty"` + TimeZone string `json:"timeZone,omitempty"` + Version string `json:"version,omitempty"` + UnicastAddress []UnicastAddress } type Devicegroups struct { @@ -260,6 +302,18 @@ func (b *BigIP) Devices(name string) (*Device, error) { return &device, nil } +// GetDevices returns a list of the bigip's in the cluster. +func (b *BigIP) GetDevices() ([]Device, error) { + var devices Devices + err, _ := b.getForEntity(&devices, uriCm, uriDiv) + + if err != nil { + return nil, err + } + + return devices.Devices, nil +} + func (b *BigIP) CreateDevicegroup(p *Devicegroup) error { return b.post(p, uriCm, uriDG) } diff --git a/device_test.go b/device_test.go new file mode 100644 index 0000000..3937f5b --- /dev/null +++ b/device_test.go @@ -0,0 +1,189 @@ +package bigip + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "io/ioutil" +) + +var goodDeviceResponse = `{ + "items": [ + { + "activeModules": [ + "APM, Base, VE GBB (500 CCU, 2500 Access Sessions)|XFLGBEL-BRZXIDZ|Anti-Virus Checks|Base Endpoint Security Checks|Firewall Checks|Network Access|Secure Virtual Keyboard|APM, Web Application|Machine Certificate Checks|Protected Workspace|Remote Desktop|App Tunnel" + ], + "baseMac": "aa:aa:aa:aa:aa:aa", + "build": "0.0.4", + "cert": "/Common/dtdi.crt", + "certReference": { + "link": "https://localhost/mgmt/tm/cm/cert/~Common~dtdi.crt?ver=13.1.1.2" + }, + "chassisId": "foo", + "chassisType": "individual", + "configsyncIp": "10.1.1.10", + "edition": "Point Release 2", + "failoverState": "active", + "fullPath": "/Common/foo.f5.com", + "generation": 1, + "haCapacity": 0, + "hostname": "foo.f5.com", + "key": "/Common/dtdi.key", + "keyReference": { + "link": "https://localhost/mgmt/tm/cm/key/~Common~dtdi.key?ver=13.1.1.2" + }, + "kind": "tm:cm:device:devicestate", + "managementIp": "172.16.1.10", + "marketingName": "BIG-IP Virtual Edition", + "mirrorIp": "10.1.1.10", + "mirrorSecondaryIp": "any6", + "multicastIp": "any6", + "multicastPort": 0, + "name": "foo.f5.com", + "optionalModules": [ + "Advanced Protocols, VE", + "URL Filtering, VE-25M-1G, 500 Sessions, 3Yr" + ], + "partition": "Common", + "platformId": "foo", + "product": "BIG-IP", + "selfDevice": "true", + "selfLink": "https://localhost/mgmt/tm/cm/device/~Common~foo.f5.com?ver=13.1.1.2", + "timeZone": "Europe/Rome", + "unicastAddress": [ + { + "effectiveIp": "management-ip", + "effectivePort": 123, + "ip": "management-ip", + "port": 123 + }, + { + "effectiveIp": "10.1.1.10", + "effectivePort": 456, + "ip": "10.1.1.10", + "port": 456 + } + ], + "version": "13.1.1.2" + }, + { + "activeModules": [ + "APM, Base, VE GBB (500 CCU, 2500 Access Sessions)|UEMOINR-IPCMIEL|Anti-Virus Checks|Base Endpoint Security Checks|Firewall Checks|Network Access|Secure Virtual Keyboard|APM, Web Application|Machine Certificate Checks|Protected Workspace|Remote Desktop|App Tunnel" + ], + "baseMac": "bb:bb:bb:bb:bb:bb", + "build": "0.0.4", + "chassisId": "bar", + "chassisType": "individual", + "configsyncIp": "10.1.1.11", + "edition": "Point Release 2", + "failoverState": "standby", + "fullPath": "/Common/bar.f5.com", + "generation": 2, + "haCapacity": 0, + "hostname": "bar.f5.com", + "kind": "tm:cm:device:devicestate", + "managementIp": "172.16.1.11", + "marketingName": "BIG-IP Virtual Edition", + "mirrorIp": "10.1.1.11", + "mirrorSecondaryIp": "any6", + "multicastIp": "any6", + "multicastPort": 0, + "name": "bar.f5.com", + "optionalModules": [ + "Advanced Protocols, VE", + "URL Filtering, VE-25M-1G, 500 Sessions, 3Yr" + ], + "partition": "Common", + "platformId": "Z100", + "product": "BIG-IP", + "selfDevice": "false", + "selfLink": "https://localhost/mgmt/tm/cm/device/~Common~bar.f5.com?ver=13.1.1.2", + "timeZone": "Europe/Rome", + "unicastAddress": [ + { + "effectiveIp": "management-ip", + "effectivePort": 123, + "ip": "management-ip", + "port": 123 + }, + { + "effectiveIp": "10.1.1.11", + "effectivePort": 456, + "ip": "10.1.1.11", + "port": 456 + } + ], + "version": "13.1.1.2" + } + ], + "kind": "tm:cm:device:devicecollectionstate", + "selfLink": "https://localhost/mgmt/tm/cm/device?ver=13.1.1.2" +}` + +// assertDeviceRestCall verifies that the DeviceTestSuite receives an +// http request with a matching method, URI, and body. +func assertDeviceRestCall(s *DeviceTestSuite, method, path, body string) { + assert.Equal(s.T(), method, s.LastRequest.Method) + assert.Equal(s.T(), path, s.LastRequest.URL.Path) + if body != "" { + assert.JSONEq(s.T(), body, s.LastRequestBody) + } +} + +// Setup the TestSuite + +type DeviceTestSuite struct { + suite.Suite + Client *BigIP + Server *httptest.Server + LastRequest *http.Request + LastRequestBody string + ResponseFunc func(http.ResponseWriter, *http.Request) +} + +func (s *DeviceTestSuite) SetupSuite() { + s.Server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, _ := ioutil.ReadAll(r.Body) + s.LastRequestBody = string(body) + s.LastRequest = r + if s.ResponseFunc != nil { + s.ResponseFunc(w, r) + } + })) + + s.Client = NewSession(s.Server.URL, "", "", nil) +} + +func (s *DeviceTestSuite) TearDownSuite() { + s.Server.Close() +} + +func (s *DeviceTestSuite) SetupTest() { + s.ResponseFunc = nil + s.LastRequest = nil +} + +func TestDeviceSuite(t *testing.T) { + suite.Run(t, new(DeviceTestSuite)) +} + +func (s *DeviceTestSuite) TestGetDevices() { + s.ResponseFunc = func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(goodDeviceResponse)) + } + + devices, err := s.Client.GetDevices() + + assert.Nil(s.T(), err) + assertDeviceRestCall(s, "GET", "/mgmt/tm/cm/device", "") + assert.Equal(s.T(), 2, len(devices)) + + assert.Equal(s.T(), "foo.f5.com", devices[0].Name) + assert.Equal(s.T(), "bar.f5.com", devices[1].Name) + + assert.Equal(s.T(), "active", devices[0].FailoverState) + assert.Equal(s.T(), "standby", devices[1].FailoverState) +}