Setting up initial LBaaS structure + tests :zap:
diff --git a/openstack/networking/v2/extensions/lbaas/members/doc.go b/openstack/networking/v2/extensions/lbaas/members/doc.go
new file mode 100644
index 0000000..acb4272
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/members/doc.go
@@ -0,0 +1 @@
+package members
diff --git a/openstack/networking/v2/extensions/lbaas/members/requests.go b/openstack/networking/v2/extensions/lbaas/members/requests.go
new file mode 100644
index 0000000..acb4272
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/members/requests.go
@@ -0,0 +1 @@
+package members
diff --git a/openstack/networking/v2/extensions/lbaas/members/requests_test.go b/openstack/networking/v2/extensions/lbaas/members/requests_test.go
new file mode 100644
index 0000000..acb4272
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/members/requests_test.go
@@ -0,0 +1 @@
+package members
diff --git a/openstack/networking/v2/extensions/lbaas/members/results.go b/openstack/networking/v2/extensions/lbaas/members/results.go
new file mode 100644
index 0000000..acb4272
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/members/results.go
@@ -0,0 +1 @@
+package members
diff --git a/openstack/networking/v2/extensions/lbaas/members/urls.go b/openstack/networking/v2/extensions/lbaas/members/urls.go
new file mode 100644
index 0000000..acb4272
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/members/urls.go
@@ -0,0 +1 @@
+package members
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/doc.go b/openstack/networking/v2/extensions/lbaas/monitors/doc.go
new file mode 100644
index 0000000..99fa30a
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/monitors/doc.go
@@ -0,0 +1 @@
+package monitors
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/requests.go b/openstack/networking/v2/extensions/lbaas/monitors/requests.go
new file mode 100644
index 0000000..99fa30a
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/monitors/requests.go
@@ -0,0 +1 @@
+package monitors
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go b/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go
new file mode 100644
index 0000000..99fa30a
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go
@@ -0,0 +1 @@
+package monitors
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/results.go b/openstack/networking/v2/extensions/lbaas/monitors/results.go
new file mode 100644
index 0000000..99fa30a
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/monitors/results.go
@@ -0,0 +1 @@
+package monitors
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/urls.go b/openstack/networking/v2/extensions/lbaas/monitors/urls.go
new file mode 100644
index 0000000..99fa30a
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/monitors/urls.go
@@ -0,0 +1 @@
+package monitors
diff --git a/openstack/networking/v2/extensions/lbaas/pools/doc.go b/openstack/networking/v2/extensions/lbaas/pools/doc.go
new file mode 100644
index 0000000..058ebec
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/pools/doc.go
@@ -0,0 +1 @@
+package pools
diff --git a/openstack/networking/v2/extensions/lbaas/pools/requests.go b/openstack/networking/v2/extensions/lbaas/pools/requests.go
new file mode 100644
index 0000000..058ebec
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/pools/requests.go
@@ -0,0 +1 @@
+package pools
diff --git a/openstack/networking/v2/extensions/lbaas/pools/requests_test.go b/openstack/networking/v2/extensions/lbaas/pools/requests_test.go
new file mode 100644
index 0000000..058ebec
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/pools/requests_test.go
@@ -0,0 +1 @@
+package pools
diff --git a/openstack/networking/v2/extensions/lbaas/pools/results.go b/openstack/networking/v2/extensions/lbaas/pools/results.go
new file mode 100644
index 0000000..058ebec
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/pools/results.go
@@ -0,0 +1 @@
+package pools
diff --git a/openstack/networking/v2/extensions/lbaas/pools/urls.go b/openstack/networking/v2/extensions/lbaas/pools/urls.go
new file mode 100644
index 0000000..058ebec
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/pools/urls.go
@@ -0,0 +1 @@
+package pools
diff --git a/openstack/networking/v2/extensions/lbaas/vips/doc.go b/openstack/networking/v2/extensions/lbaas/vips/doc.go
new file mode 100644
index 0000000..5320e81
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/vips/doc.go
@@ -0,0 +1 @@
+package vips
diff --git a/openstack/networking/v2/extensions/lbaas/vips/requests.go b/openstack/networking/v2/extensions/lbaas/vips/requests.go
new file mode 100644
index 0000000..bcc0b58
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/vips/requests.go
@@ -0,0 +1,93 @@
+package vips
+
+import (
+	"strconv"
+
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/openstack/utils"
+	"github.com/rackspace/gophercloud/pagination"
+)
+
+// ListOpts allows the filtering and sorting of paginated collections through
+// the API. Filtering is achieved by passing in struct field values that map to
+// the floating IP attributes you want to see returned. SortKey allows you to
+// sort by a particular network attribute. SortDir sets the direction, and is
+// either `asc' or `desc'. Marker and Limit are used for pagination.
+type ListOpts struct {
+	ID              string
+	Name            string
+	AdminStateUp    *bool
+	Status          string
+	TenantID        string
+	SubnetID        string
+	Address         string
+	PortID          string
+	Protocol        string
+	ProtocolPort    int
+	ConnectionLimit int
+	Limit           int
+	Marker          string
+	SortKey         string
+	SortDir         string
+}
+
+// List returns a Pager which allows you to iterate over a collection of
+// routers. It accepts a ListOpts struct, which allows you to filter and sort
+// the returned collection for greater efficiency.
+//
+// Default policy settings return only those routers that are owned by the
+// tenant who submits the request, unless an admin user submits the request.
+func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
+	q := make(map[string]string)
+	if opts.ID != "" {
+		q["id"] = opts.ID
+	}
+	if opts.Name != "" {
+		q["name"] = opts.Name
+	}
+	if opts.AdminStateUp != nil {
+		q["admin_state_up"] = strconv.FormatBool(*opts.AdminStateUp)
+	}
+	if opts.Status != "" {
+		q["status"] = opts.Status
+	}
+	if opts.TenantID != "" {
+		q["tenant_id"] = opts.TenantID
+	}
+	if opts.SubnetID != "" {
+		q["subnet_id"] = opts.SubnetID
+	}
+	if opts.Address != "" {
+		q["address"] = opts.Address
+	}
+	if opts.PortID != "" {
+		q["port_id"] = opts.PortID
+	}
+	if opts.Protocol != "" {
+		q["protocol"] = opts.Protocol
+	}
+	if opts.ProtocolPort != 0 {
+		q["protocol_port"] = strconv.Itoa(opts.ProtocolPort)
+	}
+	if opts.ConnectionLimit != 0 {
+		q["connection_limit"] = strconv.Itoa(opts.ConnectionLimit)
+	}
+	if opts.Marker != "" {
+		q["marker"] = opts.Marker
+	}
+	if opts.Limit != 0 {
+		q["limit"] = strconv.Itoa(opts.Limit)
+	}
+	if opts.SortKey != "" {
+		q["sort_key"] = opts.SortKey
+	}
+	if opts.SortDir != "" {
+		q["sort_dir"] = opts.SortDir
+	}
+
+	u := rootURL(c) + utils.BuildQuery(q)
+
+	return pagination.NewPager(c, u, func(r pagination.LastHTTPResponse) pagination.Page {
+		return VIPPage{pagination.LinkedPageBase{LastHTTPResponse: r}}
+	})
+}
diff --git a/openstack/networking/v2/extensions/lbaas/vips/requests_test.go b/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
new file mode 100644
index 0000000..ccb3d02
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
@@ -0,0 +1,132 @@
+package vips
+
+import (
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
+	th "github.com/rackspace/gophercloud/testhelper"
+)
+
+const tokenID = "123"
+
+func serviceClient() *gophercloud.ServiceClient {
+	return &gophercloud.ServiceClient{
+		Provider: &gophercloud.ProviderClient{TokenID: tokenID},
+		Endpoint: th.Endpoint(),
+	}
+}
+
+func TestURLs(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.AssertEquals(t, th.Endpoint()+"v2.0/lb/vips", rootURL(serviceClient()))
+	th.AssertEquals(t, th.Endpoint()+"v2.0/lb/vips/foo", resourceURL(serviceClient(), "foo"))
+}
+
+func TestList(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/v2.0/lb/vips", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+  "vips":[
+         {
+           "id": "db902c0c-d5ff-4753-b465-668ad9656918",
+           "tenant_id": "310df60f-2a10-4ee5-9554-98393092194c",
+           "name": "web_vip",
+           "description": "lb config for the web tier",
+           "subnet_id": "96a4386a-f8c3-42ed-afce-d7954eee77b3",
+           "address" : "10.30.176.47",
+           "port_id" : "cd1f7a47-4fa6-449c-9ee7-632838aedfea",
+           "protocol": "HTTP",
+           "protocol_port": 80,
+           "pool_id" : "cfc6589d-f949-4c66-99d2-c2da56ef3764",
+           "admin_state_up": true,
+           "status": "ACTIVE"
+         },
+         {
+           "id": "36e08a3e-a78f-4b40-a229-1e7e23eee1ab",
+           "tenant_id": "310df60f-2a10-4ee5-9554-98393092194c",
+           "name": "db_vip",
+					 "description": "lb config for the db tier",
+           "subnet_id": "9cedb85d-0759-4898-8a4b-fa5a5ea10086",
+           "address" : "10.30.176.48",
+           "port_id" : "cd1f7a47-4fa6-449c-9ee7-632838aedfea",
+           "protocol": "TCP",
+           "protocol_port": 3306,
+           "pool_id" : "41efe233-7591-43c5-9cf7-923964759f9e",
+           "session_persistence" : {"type" : "SOURCE_IP"},
+           "connection_limit" : 2000,
+           "admin_state_up": true,
+           "status": "INACTIVE"
+         }
+      ]
+}
+			`)
+	})
+
+	count := 0
+
+	List(serviceClient(), ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+		count++
+		actual, err := ExtractVIPs(page)
+		if err != nil {
+			t.Errorf("Failed to extract LBs: %v", err)
+			return false, err
+		}
+
+		expected := []VirtualIP{
+			VirtualIP{
+				ID:           "db902c0c-d5ff-4753-b465-668ad9656918",
+				TenantID:     "310df60f-2a10-4ee5-9554-98393092194c",
+				Name:         "web_vip",
+				Description:  "lb config for the web tier",
+				SubnetID:     "96a4386a-f8c3-42ed-afce-d7954eee77b3",
+				Address:      "10.30.176.47",
+				PortID:       "cd1f7a47-4fa6-449c-9ee7-632838aedfea",
+				Protocol:     "HTTP",
+				ProtocolPort: 80,
+				PoolID:       "cfc6589d-f949-4c66-99d2-c2da56ef3764",
+				Persistence:  SessionPersistence{},
+				ConnLimit:    0,
+				AdminStateUp: true,
+				Status:       "ACTIVE",
+			},
+			VirtualIP{
+				ID:           "36e08a3e-a78f-4b40-a229-1e7e23eee1ab",
+				TenantID:     "310df60f-2a10-4ee5-9554-98393092194c",
+				Name:         "db_vip",
+				Description:  "lb config for the db tier",
+				SubnetID:     "9cedb85d-0759-4898-8a4b-fa5a5ea10086",
+				Address:      "10.30.176.48",
+				PortID:       "cd1f7a47-4fa6-449c-9ee7-632838aedfea",
+				Protocol:     "TCP",
+				ProtocolPort: 3306,
+				PoolID:       "41efe233-7591-43c5-9cf7-923964759f9e",
+				Persistence:  SessionPersistence{Type: "SOURCE_IP"},
+				ConnLimit:    2000,
+				AdminStateUp: true,
+				Status:       "INACTIVE",
+			},
+		}
+
+		th.CheckDeepEquals(t, expected, actual)
+
+		return true, nil
+	})
+
+	if count != 1 {
+		t.Errorf("Expected 1 page, got %d", count)
+	}
+}
diff --git a/openstack/networking/v2/extensions/lbaas/vips/results.go b/openstack/networking/v2/extensions/lbaas/vips/results.go
new file mode 100644
index 0000000..35a7bc1
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/vips/results.go
@@ -0,0 +1,140 @@
+package vips
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/rackspace/gophercloud/pagination"
+)
+
+// SessionPersistence represents the session persistence feature of the load
+// balancing service. It attempts to force connections or requests in the same
+// session to be processed by the same member as long as it is ative. Three
+// types of persistence are supported:
+//
+// SOURCE_IP:   With this mode, all connections originating from the same source
+//              IP address, will be handled by the same member of the pool.
+// HTTP_COOKIE: With this persistence mode, the load balancing function will
+//              create a cookie on the first request from a client. Subsequent
+//              requests containing the same cookie value will be handled by
+//              the same member of the pool.
+// APP_COOKIE:  With this persistence mode, the load balancing function will
+//              rely on a cookie established by the backend application. All
+//              requests carrying the same cookie value will be handled by the
+//              same member of the pool.
+type SessionPersistence struct {
+	// The type of persistence mode
+	Type string
+}
+
+// VirtualIP is the primary load balancing configuration object that specifies
+// the virtual IP address and port on which client traffic is received, as well
+// as other details such as the load balancing method to be use, protocol, etc.
+// This entity is sometimes known in LB products under the name of a "virtual
+// server", a "vserver" or a "listener".
+type VirtualIP struct {
+	// The unique ID for the VIP.
+	ID string `mapstructure:"id" json:"id"`
+
+	// Owner of the VIP. Only an admin user can specify a tenant ID other than its own.
+	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+
+	// Human-readable name for the VIP. Does not have to be unique.
+	Name string `mapstructure:"name" json:"name"`
+
+	// Human-readable description for the VIP.
+	Description string `mapstructure:"description" json:"description"`
+
+	// The ID of the subnet on which to allocate the VIP address.
+	SubnetID string `mapstructure:"subnet_id" json:"subnet_id"`
+
+	// The IP address of the VIP.
+	Address string `mapstructure:"address" json:"address"`
+
+	// The protocol of the VIP address. A valid value is TCP, HTTP, or HTTPS.
+	Protocol string `mapstructure:"protocol" json:"protocol"`
+
+	// The port on which to listen to client traffic that is associated with the
+	// VIP address. A valid value is from 0 to 65535.
+	ProtocolPort int `mapstructure:"protocol_port" json:"protocol_port"`
+
+	// The ID of the pool with which the VIP is associated.
+	PoolID string `mapstructure:"pool_id" json:"pool_id"`
+
+	// The ID of the port which belongs to the load balancer
+	PortID string `mapstructure:"port_id" json:"port_id"`
+
+	// Indicates whether connections in the same session will be processed by the
+	// same pool member or not.
+	Persistence SessionPersistence `mapstructure:"session_persistence" json:"session_persistence"`
+
+	// The maximum number of connections allowed for the VIP. Default is -1,
+	// meaning no limit.
+	ConnLimit int `mapstructure:"connection_limit" json:"connection_limit"`
+
+	// The administrative state of the VIP. A valid value is true (UP) or false (DOWN).
+	AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+
+	// The status of the VIP. Indicates whether the VIP is operational.
+	Status string `mapstructure:"status" json:"status"`
+}
+
+// VIPPage is the page returned by a pager when traversing over a
+// collection of routers.
+type VIPPage struct {
+	pagination.LinkedPageBase
+}
+
+// NextPageURL is invoked when a paginated collection of routers has reached
+// the end of a page and the pager seeks to traverse over a new one. In order
+// to do this, it needs to construct the next page's URL.
+func (p VIPPage) NextPageURL() (string, error) {
+	type link struct {
+		Href string `mapstructure:"href"`
+		Rel  string `mapstructure:"rel"`
+	}
+	type resp struct {
+		Links []link `mapstructure:"vips_links"`
+	}
+
+	var r resp
+	err := mapstructure.Decode(p.Body, &r)
+	if err != nil {
+		return "", err
+	}
+
+	var url string
+	for _, l := range r.Links {
+		if l.Rel == "next" {
+			url = l.Href
+		}
+	}
+	if url == "" {
+		return "", nil
+	}
+
+	return url, nil
+}
+
+// IsEmpty checks whether a RouterPage struct is empty.
+func (p VIPPage) IsEmpty() (bool, error) {
+	is, err := ExtractVIPs(p)
+	if err != nil {
+		return true, nil
+	}
+	return len(is) == 0, nil
+}
+
+// ExtractVIPs accepts a Page struct, specifically a VIPPage struct,
+// and extracts the elements into a slice of VirtualIP structs. In other words,
+// a generic collection is mapped into a relevant slice.
+func ExtractVIPs(page pagination.Page) ([]VirtualIP, error) {
+	var resp struct {
+		VIPs []VirtualIP `mapstructure:"vips" json:"vips"`
+	}
+
+	err := mapstructure.Decode(page.(VIPPage).Body, &resp)
+	if err != nil {
+		return nil, err
+	}
+
+	return resp.VIPs, nil
+}
diff --git a/openstack/networking/v2/extensions/lbaas/vips/urls.go b/openstack/networking/v2/extensions/lbaas/vips/urls.go
new file mode 100644
index 0000000..570db6d
--- /dev/null
+++ b/openstack/networking/v2/extensions/lbaas/vips/urls.go
@@ -0,0 +1,17 @@
+package vips
+
+import "github.com/rackspace/gophercloud"
+
+const (
+	version      = "v2.0"
+	rootPath     = "lb"
+	resourcePath = "vips"
+)
+
+func rootURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL(version, rootPath, resourcePath)
+}
+
+func resourceURL(c *gophercloud.ServiceClient, id string) string {
+	return c.ServiceURL(version, rootPath, resourcePath, id)
+}