Add nodes :joy:
diff --git a/rackspace/lb/v1/nodes/fixtures.go b/rackspace/lb/v1/nodes/fixtures.go
index 77be3b6..65eefe0 100644
--- a/rackspace/lb/v1/nodes/fixtures.go
+++ b/rackspace/lb/v1/nodes/fixtures.go
@@ -49,8 +49,8 @@
 	})
 }
 
-func mockCreateResponse(t *testing.T) {
-	th.Mux.HandleFunc("/loadbalancers", func(w http.ResponseWriter, r *http.Request) {
+func mockCreateResponse(t *testing.T, lbID int) {
+	th.Mux.HandleFunc(_rootURL(lbID), func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "POST")
 		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
 
diff --git a/rackspace/lb/v1/nodes/requests.go b/rackspace/lb/v1/nodes/requests.go
index 6e723d2..338c250 100644
--- a/rackspace/lb/v1/nodes/requests.go
+++ b/rackspace/lb/v1/nodes/requests.go
@@ -3,19 +3,89 @@
 import (
 	"fmt"
 
+	"github.com/racker/perigee"
 	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/pagination"
 )
 
 func List(client *gophercloud.ServiceClient, loadBalancerID int, limit *int) pagination.Pager {
 	url := rootURL(client, loadBalancerID)
-
 	if limit != nil {
 		url += fmt.Sprintf("?limit=%d", limit)
 	}
 
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return NodePage{pagination.SinglePageBase(r)}
+	})
+}
+
+type CreateOptsBuilder interface {
+	ToNodeCreateMap() (map[string]interface{}, error)
+}
+
+type CreateOpts []CreateOpt
+
+type CreateOpt struct {
+	// Required
+	Address   string
+	Port      int
+	Condition Condition
+	Type      Type
+}
+
+func (opts CreateOpts) ToNodeCreateMap() (map[string]interface{}, error) {
+	type nodeMap map[string]interface{}
+	nodes := []nodeMap{}
+
+	for k, v := range opts {
+		if v.Address == "" {
+			return nodeMap{}, fmt.Errorf("ID is a required attribute, none provided for %d CreateOpt element", k)
+		}
+
+		node := make(map[string]interface{})
+		node["address"] = v.Address
+
+		if v.Port > 0 {
+			node["port"] = v.Port
+		}
+		if v.Condition != "" {
+			node["condition"] = v.Condition
+		}
+		if v.Type != "" {
+			node["type"] = v.Type
+		}
+
+		nodes = append(nodes, node)
 	}
-	return pagination.NewPager(client, url, createPageFn)
+
+	return nodeMap{"nodes": nodes}, nil
+}
+
+func Create(client *gophercloud.ServiceClient, loadBalancerID int, opts CreateOptsBuilder) CreateResult {
+	var res CreateResult
+
+	reqBody, err := opts.ToNodeCreateMap()
+	if err != nil {
+		res.Err = err
+		return res
+	}
+
+	resp, err := perigee.Request("POST", rootURL(client, loadBalancerID), perigee.Options{
+		MoreHeaders: client.AuthenticatedHeaders(),
+		ReqBody:     &reqBody,
+		Results:     &res.Body,
+		OkCodes:     []int{200},
+	})
+	if err != nil {
+		res.Err = err
+		return res
+	}
+
+	pr, err := pagination.PageResultFrom(resp.HttpResponse)
+	if err != nil {
+		res.Err = err
+		return res
+	}
+
+	return CreateResult{pagination.SinglePageBase(pr)}
 }
diff --git a/rackspace/lb/v1/nodes/requests_test.go b/rackspace/lb/v1/nodes/requests_test.go
index 0509670..8e4813f 100644
--- a/rackspace/lb/v1/nodes/requests_test.go
+++ b/rackspace/lb/v1/nodes/requests_test.go
@@ -55,3 +55,53 @@
 	th.AssertNoErr(t, err)
 	th.AssertEquals(t, 1, count)
 }
+
+func TestCreate(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	mockCreateResponse(t, lbID)
+
+	opts := CreateOpts{
+		CreateOpt{
+			Address:   "10.2.2.3",
+			Port:      80,
+			Condition: ENABLED,
+			Type:      PRIMARY,
+		},
+		CreateOpt{
+			Address:   "10.2.2.4",
+			Port:      81,
+			Condition: ENABLED,
+			Type:      SECONDARY,
+		},
+	}
+
+	page := Create(client.ServiceClient(), lbID, opts)
+
+	actual, err := page.ExtractNodes()
+	th.AssertNoErr(t, err)
+
+	expected := []Node{
+		Node{
+			ID:        185,
+			Address:   "10.2.2.3",
+			Port:      80,
+			Condition: ENABLED,
+			Status:    ONLINE,
+			Weight:    1,
+			Type:      PRIMARY,
+		},
+		Node{
+			ID:        186,
+			Address:   "10.2.2.4",
+			Port:      81,
+			Condition: ENABLED,
+			Status:    ONLINE,
+			Weight:    1,
+			Type:      SECONDARY,
+		},
+	}
+
+	th.CheckDeepEquals(t, expected, actual)
+}
diff --git a/rackspace/lb/v1/nodes/results.go b/rackspace/lb/v1/nodes/results.go
index 98cb741..399f5c9 100644
--- a/rackspace/lb/v1/nodes/results.go
+++ b/rackspace/lb/v1/nodes/results.go
@@ -98,15 +98,31 @@
 	return len(is) == 0, nil
 }
 
-// ExtractNodes accepts a Page struct, specifically a NodePage struct, and
-// extracts the elements into a slice of Node structs. In other words, a
-// generic collection is mapped into a relevant slice.
-func ExtractNodes(page pagination.Page) ([]Node, error) {
+func commonExtractNodes(body interface{}) ([]Node, error) {
 	var resp struct {
 		Nodes []Node `mapstructure:"nodes" json:"nodes"`
 	}
 
-	err := mapstructure.Decode(page.(NodePage).Body, &resp)
+	err := mapstructure.Decode(body, &resp)
 
 	return resp.Nodes, err
 }
+
+// ExtractNodes accepts a Page struct, specifically a NodePage struct, and
+// extracts the elements into a slice of Node structs. In other words, a
+// generic collection is mapped into a relevant slice.
+func ExtractNodes(page pagination.Page) ([]Node, error) {
+	return commonExtractNodes(page.(NodePage).Body)
+}
+
+// CreateResult represents the result of a create operation. Since multiple
+// nodes can be added in one operation, this result represents multiple nodes -
+// and should be treated as a typical pagination Page. Use ExtractNodes to get
+// out a slice of Node structs.
+type CreateResult struct {
+	pagination.SinglePageBase
+}
+
+func (res CreateResult) ExtractNodes() ([]Node, error) {
+	return commonExtractNodes(res.Body)
+}