Merge branch 'x-new-api' into v0.2.0
diff --git a/acceptance/19-list-addresses-0.1.go b/acceptance/19-list-addresses-0.1.go
new file mode 100644
index 0000000..7df2ad5
--- /dev/null
+++ b/acceptance/19-list-addresses-0.1.go
@@ -0,0 +1,56 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"github.com/rackspace/gophercloud"
+)
+
+var quiet = flag.Bool("quiet", false, "Quiet mode, for acceptance testing.  $? still indicates errors though.")
+
+func main() {
+	flag.Parse()
+	withIdentity(false, func(acc gophercloud.AccessProvider) {
+		withServerApi(acc, func(api gophercloud.CloudServersProvider) {
+			log("Creating server")
+			id, err := createServer(api, "", "", "", "")
+			if err != nil {
+				panic(err)
+			}
+			waitForServerState(api, id, "ACTIVE")
+			defer api.DeleteServerById(id)
+
+			tryAllAddresses(id, api)
+
+			log("Done")
+		})
+	})
+}
+
+func tryAllAddresses(id string, api gophercloud.CloudServersProvider) {
+	log("Getting the server instance")
+	s, err := api.ServerById(id)
+	if err != nil {
+		panic(err)
+	}
+
+	log("Getting the complete set of pools")
+	ps, err := s.AllAddressPools()
+	if err != nil {
+		panic(err)
+	}
+
+	log("Listing IPs for each pool")
+	for k, v := range ps {
+		log(fmt.Sprintf("  Pool %s", k))
+		for _, a := range v {
+			log(fmt.Sprintf("    IP: %s, Version: %d", a.Addr, a.Version))
+		}
+	}
+}
+
+func log(s ...interface{}) {
+	if !*quiet {
+		fmt.Println(s...)
+	}
+}
diff --git a/osutil/auth.go b/osutil/auth.go
index 60a5f0b..409846c 100644
--- a/osutil/auth.go
+++ b/osutil/auth.go
@@ -44,7 +44,7 @@
 		return "", nilOptions, ErrNoUsername
 	}
 
-	if password == "" && apiKey == "" {
+	if password == "" {
 		return "", nilOptions, ErrNoPassword
 	}
 
diff --git a/servers.go b/servers.go
index fc5925d..92bb370 100644
--- a/servers.go
+++ b/servers.go
@@ -5,6 +5,7 @@
 
 import (
 	"fmt"
+	"github.com/mitchellh/mapstructure"
 	"github.com/racker/perigee"
 	"strings"
 )
@@ -55,6 +56,22 @@
 			},
 		})
 	})
+
+	// Compatibility with v0.0.x -- we "map" our public and private
+	// addresses into a legacy structure field for the benefit of
+	// earlier software.
+
+	if err != nil {
+		return ss, err
+	}
+
+	for _, s := range ss {
+		err = mapstructure.Decode(s.RawAddresses, &s.Addresses)
+		if err != nil {
+			return ss, err
+		}
+	}
+
 	return ss, err
 }
 
@@ -71,6 +88,17 @@
 			},
 		})
 	})
+
+	// Compatibility with v0.0.x -- we "map" our public and private
+	// addresses into a legacy structure field for the benefit of
+	// earlier software.
+
+	if err != nil {
+		return s, err
+	}
+
+	err = mapstructure.Decode(s.RawAddresses, &s.Addresses)
+
 	return s, err
 }
 
@@ -400,6 +428,8 @@
 //
 // Addresses provides addresses for any attached isolated networks.
 // The version field indicates whether the IP address is version 4 or 6.
+// Note: only public and private pools appear here.
+// To get the complete set, use the AllAddressPools() method instead.
 //
 // Created tells when the server entity was created.
 //
@@ -473,9 +503,9 @@
 // http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ch_extensions.html#ext_status
 // for more details.  It's too lengthy to include here.
 type Server struct {
-	AccessIPv4         string            `json:"accessIPv4"`
-	AccessIPv6         string            `json:"accessIPv6"`
-	Addresses          AddressSet        `json:"addresses"`
+	AccessIPv4         string `json:"accessIPv4"`
+	AccessIPv6         string `json:"accessIPv6"`
+	Addresses          AddressSet
 	Created            string            `json:"created"`
 	Flavor             FlavorLink        `json:"flavor"`
 	HostId             string            `json:"hostId"`
@@ -494,6 +524,24 @@
 	OsExtStsPowerState int               `json:"OS-EXT-STS:power_state"`
 	OsExtStsTaskState  string            `json:"OS-EXT-STS:task_state"`
 	OsExtStsVmState    string            `json:"OS-EXT-STS:vm_state"`
+
+	RawAddresses map[string]interface{} `json:"addresses"`
+}
+
+// AllAddressPools returns a complete set of address pools available on the server.
+// The name of each pool supported keys the map.
+// The value of the map contains the addresses provided in the corresponding pool.
+func (s *Server) AllAddressPools() (map[string][]VersionedAddress, error) {
+	pools := make(map[string][]VersionedAddress, 0)
+	for pool, subtree := range s.RawAddresses {
+		addresses := make([]VersionedAddress, 0)
+		err := mapstructure.Decode(subtree, &addresses)
+		if err != nil {
+			return nil, err
+		}
+		pools[pool] = addresses
+	}
+	return pools, nil
 }
 
 // NewServerSettings structures record those fields of the Server structure to change
@@ -547,20 +595,23 @@
 // The Id field contains the server's unique identifier.
 // The identifier's scope is best assumed to be bound by the user's account, unless other arrangements have been made with Rackspace.
 //
+// The SecurityGroup field allows the user to specify a security group at launch.
+//
 // Any Links provided are used to refer to the server specifically by URL.
 // These links are useful for making additional REST calls not explicitly supported by Gorax.
 type NewServer struct {
-	Name            string            `json:"name,omitempty"`
-	ImageRef        string            `json:"imageRef,omitempty"`
-	FlavorRef       string            `json:"flavorRef,omitempty"`
-	Metadata        map[string]string `json:"metadata,omitempty"`
-	Personality     []FileConfig      `json:"personality,omitempty"`
-	Networks        []NetworkConfig   `json:"networks,omitempty"`
-	AdminPass       string            `json:"adminPass,omitempty"`
-	KeyPairName     string            `json:"key_name,omitempty"`
-	Id              string            `json:"id,omitempty"`
-	Links           []Link            `json:"links,omitempty"`
-	OsDcfDiskConfig string            `json:"OS-DCF:diskConfig,omitempty"`
+	Name            string                   `json:"name,omitempty"`
+	ImageRef        string                   `json:"imageRef,omitempty"`
+	FlavorRef       string                   `json:"flavorRef,omitempty"`
+	Metadata        map[string]string        `json:"metadata,omitempty"`
+	Personality     []FileConfig             `json:"personality,omitempty"`
+	Networks        []NetworkConfig          `json:"networks,omitempty"`
+	AdminPass       string                   `json:"adminPass,omitempty"`
+	KeyPairName     string                   `json:"key_name,omitempty"`
+	Id              string                   `json:"id,omitempty"`
+	Links           []Link                   `json:"links,omitempty"`
+	OsDcfDiskConfig string                   `json:"OS-DCF:diskConfig,omitempty"`
+	SecurityGroup   []map[string]interface{} `json:"security_groups,omitempty"`
 }
 
 // ResizeRequest structures are used internally to encode to JSON the parameters required to resize a server instance.