Adding support for create load balancer
diff --git a/rackspace/lb/lb/fixtures.go b/rackspace/lb/lb/fixtures.go
index 331d06e..36a5500 100644
--- a/rackspace/lb/lb/fixtures.go
+++ b/rackspace/lb/lb/fixtures.go
@@ -48,3 +48,89 @@
   `)
 	})
 }
+
+func mockCreateLBResponse(t *testing.T) {
+	th.Mux.HandleFunc("/loadbalancers", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+		th.TestJSONRequest(t, r, `
+{
+  "loadBalancer": {
+    "name": "a-new-loadbalancer",
+    "port": 80,
+    "protocol": "HTTP",
+    "virtualIps": [
+      {
+        "id": 2341
+      },
+      {
+        "id": 900001
+      }
+    ],
+    "nodes": [
+      {
+        "address": "10.1.1.1",
+        "port": 80,
+        "condition": "ENABLED"
+      }
+    ]
+  }
+}
+		`)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+  "loadBalancer": {
+    "name": "a-new-loadbalancer",
+    "id": 144,
+    "protocol": "HTTP",
+    "halfClosed": false,
+    "port": 83,
+    "algorithm": "RANDOM",
+    "status": "BUILD",
+    "timeout": 30,
+    "cluster": {
+      "name": "ztm-n01.staging1.lbaas.rackspace.net"
+    },
+    "nodes": [
+      {
+        "address": "10.1.1.1",
+        "id": 653,
+        "port": 80,
+        "status": "ONLINE",
+        "condition": "ENABLED",
+        "weight": 1
+      }
+    ],
+    "virtualIps": [
+      {
+        "address": "206.10.10.210",
+        "id": 39,
+        "type": "PUBLIC",
+        "ipVersion": "IPV4"
+      },
+      {
+        "address": "2001:4801:79f1:0002:711b:be4c:0000:0021",
+        "id": 900001,
+        "type": "PUBLIC",
+        "ipVersion": "IPV6"
+      }
+    ],
+    "created": {
+      "time": "2011-04-13T14:18:07Z"
+    },
+    "updated": {
+      "time": "2011-04-13T14:18:07Z"
+    },
+    "connectionLogging": {
+      "enabled": false
+    }
+  }
+}
+	`)
+	})
+}
diff --git a/rackspace/lb/lb/requests.go b/rackspace/lb/lb/requests.go
index 91262ac..2acab8a 100644
--- a/rackspace/lb/lb/requests.go
+++ b/rackspace/lb/lb/requests.go
@@ -1,6 +1,10 @@
 package lb
 
 import (
+	"errors"
+
+	"github.com/racker/perigee"
+
 	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/pagination"
 )
@@ -44,3 +48,180 @@
 		return LBPage{pagination.LinkedPageBase{PageResult: r}}
 	})
 }
+
+type enabledState *bool
+
+var (
+	iTrue  = true
+	iFalse = false
+
+	Enabled  enabledState = &iTrue
+	Disabled enabledState = &iFalse
+)
+
+// CreateOptsBuilder is the interface options structs have to satisfy in order
+// to be used in the main Create operation in this package. Since many
+// extensions decorate or modify the common logic, it is useful for them to
+// satisfy a basic interface in order for them to be used.
+type CreateOptsBuilder interface {
+	ToLBCreateMap() (map[string]interface{}, error)
+}
+
+// CreateOpts is the common options struct used in this package's Create
+// operation.
+type CreateOpts struct {
+	// Required - name of the load balancer to create. The name must be 128
+	// characters or fewer in length, and all UTF-8 characters are valid.
+	Name string
+
+	// Optional - nodes to be added.
+	Nodes []Node
+
+	// Required - protocol of the service that is being load balanced.
+	Protocol Protocol
+
+	// Optional - enables or disables Half-Closed support for the load balancer.
+	// Half-Closed support provides the ability for one end of the connection to
+	// terminate its output, while still receiving data from the other end. Only
+	// available for TCP/TCP_CLIENT_FIRST protocols.
+	HalfClosed enabledState
+
+	// Optional - the type of virtual IPs you want associated with the load
+	// balancer.
+	VIPs []VIP
+
+	// Optional - the access list management feature allows fine-grained network
+	// access controls to be applied to the load balancer virtual IP address.
+	AccessList string
+
+	// Optional - algorithm that defines how traffic should be directed between
+	// back-end nodes.
+	Algorithm Algorithm
+
+	// Optional - current connection logging configuration.
+	ConnectionLogging *ConnectionLogging
+
+	// Optional - specifies a limit on the number of connections per IP address
+	// to help mitigate malicious or abusive traffic to your applications.
+	//??? ConnThrottle string
+
+	//??? HealthMonitor string
+
+	// Optional - arbitrary information that can be associated with each LB.
+	Metadata map[string]interface{}
+
+	// Optional - port number for the service you are load balancing.
+	Port int
+
+	// Optional - the timeout value for the load balancer and communications with
+	// its nodes. Defaults to 30 seconds with a maximum of 120 seconds.
+	Timeout int
+
+	// Optional - specifies whether multiple requests from clients are directed
+	// to the same node.
+	//??? SessionPersistence
+
+	// Optional - enables or disables HTTP to HTTPS redirection for the load
+	// balancer. When enabled, any HTTP request returns status code 301 (Moved
+	// Permanently), and the requester is redirected to the requested URL via the
+	// HTTPS protocol on port 443. For example, http://example.com/page.html
+	// would be redirected to https://example.com/page.html. Only available for
+	// HTTPS protocol (port=443), or HTTP protocol with a properly configured SSL
+	// termination (secureTrafficOnly=true, securePort=443).
+	HTTPSRedirect enabledState
+}
+
+var (
+	errNameRequired    = errors.New("Name is a required attribute")
+	errTimeoutExceeded = errors.New("Timeout must be less than 120")
+)
+
+// ToLBCreateMap casts a CreateOpts struct to a map.
+func (opts CreateOpts) ToLBCreateMap() (map[string]interface{}, error) {
+	lb := make(map[string]interface{})
+
+	if opts.Name == "" {
+		return lb, errNameRequired
+	}
+	if opts.Timeout > 120 {
+		return lb, errTimeoutExceeded
+	}
+
+	lb["name"] = opts.Name
+
+	if len(opts.Nodes) > 0 {
+		nodes := []map[string]interface{}{}
+		for _, n := range opts.Nodes {
+			nodes = append(nodes, map[string]interface{}{
+				"address":   n.Address,
+				"port":      n.Port,
+				"condition": n.Condition,
+			})
+		}
+		lb["nodes"] = nodes
+	}
+
+	if opts.Protocol != "" {
+		lb["protocol"] = opts.Protocol
+	}
+	if opts.HalfClosed != nil {
+		lb["halfClosed"] = opts.HalfClosed
+	}
+
+	if len(opts.VIPs) > 0 {
+
+		lb["virtualIps"] = opts.VIPs
+	}
+
+	// if opts.AccessList != "" {
+	// 	lb["accessList"] = opts.AccessList
+	// }
+	if opts.Algorithm != "" {
+		lb["algorithm"] = opts.Algorithm
+	}
+	if opts.ConnectionLogging != nil {
+		lb["connectionLogging"] = &opts.ConnectionLogging
+	}
+	// if opts.ConnThrottle != "" {
+	// 	lb["connectionThrottle"] = opts.ConnThrottle
+	// }
+	// if opts.HealthMonitor != "" {
+	// 	lb["healthMonitor"] = opts.HealthMonitor
+	// }
+	if len(opts.Metadata) != 0 {
+		lb["metadata"] = opts.Metadata
+	}
+	if opts.Port > 0 {
+		lb["port"] = opts.Port
+	}
+	if opts.Timeout > 0 {
+		lb["timeout"] = opts.Timeout
+	}
+	// if opts.SessionPersistence != "" {
+	// 	lb["sessionPersistence"] = opts.SessionPersistence
+	// }
+	if opts.HTTPSRedirect != nil {
+		lb["httpsRedirect"] = &opts.HTTPSRedirect
+	}
+
+	return map[string]interface{}{"loadBalancer": lb}, nil
+}
+
+func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
+	var res CreateResult
+
+	reqBody, err := opts.ToLBCreateMap()
+	if err != nil {
+		res.Err = err
+		return res
+	}
+
+	_, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
+		MoreHeaders: c.AuthenticatedHeaders(),
+		ReqBody:     &reqBody,
+		Results:     &res.Body,
+		OkCodes:     []int{200},
+	})
+
+	return res
+}
diff --git a/rackspace/lb/lb/requests_test.go b/rackspace/lb/lb/requests_test.go
index 922d102..fc5b068 100644
--- a/rackspace/lb/lb/requests_test.go
+++ b/rackspace/lb/lb/requests_test.go
@@ -51,3 +51,67 @@
 	th.AssertNoErr(t, err)
 	th.AssertEquals(t, 1, count)
 }
+
+func TestCreate(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	mockCreateLBResponse(t)
+
+	opts := CreateOpts{
+		Name:     "a-new-loadbalancer",
+		Port:     80,
+		Protocol: "HTTP",
+		VIPs: []VIP{
+			VIP{ID: 2341},
+			VIP{ID: 900001},
+		},
+		Nodes: []Node{
+			Node{Address: "10.1.1.1", Port: 80, Condition: "ENABLED"},
+		},
+	}
+
+	lb, err := Create(client.ServiceClient(), opts).Extract()
+	th.AssertNoErr(t, err)
+
+	expected := &LoadBalancer{
+		Name:       "a-new-loadbalancer",
+		ID:         144,
+		Protocol:   "HTTP",
+		HalfClosed: false,
+		Port:       83,
+		Algorithm:  RAND,
+		Status:     BUILD,
+		Timeout:    30,
+		Cluster:    Cluster{Name: "ztm-n01.staging1.lbaas.rackspace.net"},
+		Nodes: []Node{
+			Node{
+				Address:   "10.1.1.1",
+				ID:        653,
+				Port:      80,
+				Status:    "ONLINE",
+				Condition: "ENABLED",
+				Weight:    1,
+			},
+		},
+		VIPs: []VIP{
+			VIP{
+				ID:      39,
+				Address: "206.10.10.210",
+				Type:    "PUBLIC",
+				Version: "IPV4",
+			},
+			VIP{
+				ID:      900001,
+				Address: "2001:4801:79f1:0002:711b:be4c:0000:0021",
+				Type:    "PUBLIC",
+				Version: "IPV6",
+			},
+		},
+		Created:           Datetime{Time: "2011-04-13T14:18:07Z"},
+		Updated:           Datetime{Time: "2011-04-13T14:18:07Z"},
+		ConnectionLogging: ConnectionLogging{Enabled: false},
+	}
+
+	th.AssertDeepEquals(t, expected, lb)
+}
diff --git a/rackspace/lb/lb/results.go b/rackspace/lb/lb/results.go
index b1e9792..7b2d4a8 100644
--- a/rackspace/lb/lb/results.go
+++ b/rackspace/lb/lb/results.go
@@ -2,6 +2,8 @@
 
 import (
 	"github.com/mitchellh/mapstructure"
+
+	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/pagination"
 )
 
@@ -96,10 +98,10 @@
 }
 
 type VIP struct {
-	Address string
-	ID      int
-	Type    string
-	Version string `mapstructure:"ipVersion"`
+	Address string `json:"address,omitempty"`
+	ID      int    `json:"id,omitempty"`
+	Type    string `json:"type,omitempty"`
+	Version string `json:"ipVersion,omitempty" mapstructure:"ipVersion"`
 }
 
 type LoadBalancer struct {
@@ -132,6 +134,33 @@
 	Updated Datetime
 
 	Port int
+
+	HalfClosed bool
+
+	Timeout int
+
+	Cluster Cluster
+
+	Nodes []Node
+
+	ConnectionLogging ConnectionLogging
+}
+
+type ConnectionLogging struct {
+	Enabled bool
+}
+
+type Cluster struct {
+	Name string
+}
+
+type Node struct {
+	Address   string
+	ID        int
+	Port      int
+	Status    Status
+	Condition string
+	Weight    int
 }
 
 // LBPage is the page returned by a pager when traversing over a collection of
@@ -161,3 +190,26 @@
 
 	return resp.LBs, err
 }
+
+type commonResult struct {
+	gophercloud.Result
+}
+
+// Extract interprets any commonResult as a LB, if possible.
+func (r commonResult) Extract() (*LoadBalancer, error) {
+	if r.Err != nil {
+		return nil, r.Err
+	}
+
+	var response struct {
+		LB LoadBalancer `mapstructure:"loadBalancer"`
+	}
+
+	err := mapstructure.Decode(r.Body, &response)
+
+	return &response.LB, err
+}
+
+type CreateResult struct {
+	commonResult
+}