Merge branch 'issue-21-list-addresses-by-network' of https://github.com/jrperritt/gophercloud into jrperritt-issue-21-list-addresses-by-network

Conflicts:
	.travis.yml
diff --git a/acceptance/02-list-servers.go b/acceptance/02-list-servers.go
index 77bf82f..db33203 100644
--- a/acceptance/02-list-servers.go
+++ b/acceptance/02-list-servers.go
@@ -1,9 +1,9 @@
 package main
 
 import (
+	"flag"
 	"fmt"
 	"github.com/rackspace/gophercloud"
-	"flag"
 )
 
 var quiet = flag.Bool("quiet", false, "Quiet mode, for acceptance testing.  $? still indicates errors though.")
@@ -26,19 +26,19 @@
 	}
 
 	if !*quiet {
-    fmt.Println("Id,Name")
+		fmt.Println("Id,Name")
 		for _, s := range servers {
-      if s.AccessIPv4 != "" {
-        panic("IPv4 not expected")
-      }
+			if s.AccessIPv4 != "" {
+				panic("IPv4 not expected")
+			}
 
-      if s.Status != "" {
-        panic("Status not expected")
-      }
+			if s.Status != "" {
+				panic("Status not expected")
+			}
 
-      if s.Progress != 0 {
-        panic("Progress not expected")
-      }
+			if s.Progress != 0 {
+				panic("Progress not expected")
+			}
 
 			fmt.Printf("%s,\"%s\"\n", s.Id, s.Name)
 		}
@@ -52,10 +52,9 @@
 	}
 
 	if !*quiet {
-    fmt.Println("Id,Name,AccessIPv4,Status,Progress")
+		fmt.Println("Id,Name,AccessIPv4,Status,Progress")
 		for _, s := range servers {
 			fmt.Printf("%s,\"%s\",%s,%s,%d\n", s.Id, s.Name, s.AccessIPv4, s.Status, s.Progress)
 		}
 	}
 }
-
diff --git a/acceptance/03-get-server-details.go b/acceptance/03-get-server-details.go
index 9d534ef..ca00e5e 100644
--- a/acceptance/03-get-server-details.go
+++ b/acceptance/03-get-server-details.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
@@ -16,8 +16,8 @@
 	withIdentity(false, func(auth gophercloud.AccessProvider) {
 		withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
 			var (
-				err error
-				serverId string
+				err              error
+				serverId         string
 				deleteAfterwards bool
 			)
 
@@ -40,7 +40,7 @@
 				panic(err)
 			}
 
-			configs := []string {
+			configs := []string{
 				"Access IPv4: %s\n",
 				"Access IPv6: %s\n",
 				"    Created: %s\n",
@@ -56,7 +56,7 @@
 				"    User ID: %s\n",
 			}
 
-			values := []string {
+			values := []string{
 				s.AccessIPv4,
 				s.AccessIPv6,
 				s.Created,
@@ -91,7 +91,7 @@
 func locateAServer(servers gophercloud.CloudServersProvider) (deleteAfter bool, id string, err error) {
 	ss, err := servers.ListServers()
 	if err != nil {
-		return false, "", err	
+		return false, "", err
 	}
 
 	if len(ss) > 0 {
diff --git a/acceptance/05-list-images.go b/acceptance/05-list-images.go
index 8120591..8cdd6c4 100644
--- a/acceptance/05-list-images.go
+++ b/acceptance/05-list-images.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
diff --git a/acceptance/06-list-flavors.go b/acceptance/06-list-flavors.go
index 5495a83..109d018 100644
--- a/acceptance/06-list-flavors.go
+++ b/acceptance/06-list-flavors.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
diff --git a/acceptance/08-reauthentication.go b/acceptance/08-reauthentication.go
index f383a30..1bcf4fc 100644
--- a/acceptance/08-reauthentication.go
+++ b/acceptance/08-reauthentication.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
diff --git a/acceptance/09-resize-server.go b/acceptance/09-resize-server.go
index b12ef4b..8582ad3 100644
--- a/acceptance/09-resize-server.go
+++ b/acceptance/09-resize-server.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 	"time"
 )
@@ -19,8 +19,8 @@
 			done := make(chan bool)
 			go resizeRejectTest(api, done)
 			go resizeAcceptTest(api, done)
-			_ = <- done
-			_ = <- done
+			_ = <-done
+			_ = <-done
 
 			if !*quiet {
 				fmt.Println("Done.")
diff --git a/acceptance/10-reboot-server.go b/acceptance/10-reboot-server.go
index 78ab357..eff9963 100644
--- a/acceptance/10-reboot-server.go
+++ b/acceptance/10-reboot-server.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
diff --git a/acceptance/11-rescue-unrescue-server.go b/acceptance/11-rescue-unrescue-server.go
index 4c4d481..657c7c8 100644
--- a/acceptance/11-rescue-unrescue-server.go
+++ b/acceptance/11-rescue-unrescue-server.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
diff --git a/acceptance/12-update-server.go b/acceptance/12-update-server.go
index 203b37d..8b9e73f 100644
--- a/acceptance/12-update-server.go
+++ b/acceptance/12-update-server.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
diff --git a/acceptance/13-rebuild-server.go b/acceptance/13-rebuild-server.go
index 12aed26..48745a6 100644
--- a/acceptance/13-rebuild-server.go
+++ b/acceptance/13-rebuild-server.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
@@ -22,8 +22,8 @@
 
 			log("Rebuilding server")
 			newDetails, err := servers.RebuildServer(id, gophercloud.NewServer{
-				Name: randomString("ACPTTEST", 32),
-				ImageRef: findAlternativeImage(),
+				Name:      randomString("ACPTTEST", 32),
+				ImageRef:  findAlternativeImage(),
 				FlavorRef: findAlternativeFlavor(),
 				AdminPass: randomString("", 16),
 			})
diff --git a/acceptance/14-list-addresses.go b/acceptance/14-list-addresses.go
index d1835e1..705d72d 100644
--- a/acceptance/14-list-addresses.go
+++ b/acceptance/14-list-addresses.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
@@ -11,33 +11,53 @@
 func main() {
 	flag.Parse()
 	withIdentity(false, func(acc gophercloud.AccessProvider) {
-		withServerApi(acc, func(servers gophercloud.CloudServersProvider) {
+		withServerApi(acc, func(api gophercloud.CloudServersProvider) {
 			log("Creating server")
-			id, err := createServer(servers, "", "", "", "")
+			id, err := createServer(api, "", "", "", "")
 			if err != nil {
 				panic(err)
 			}
-			waitForServerState(servers, id, "ACTIVE")
-			defer servers.DeleteServerById(id)
+			waitForServerState(api, id, "ACTIVE")
+			defer api.DeleteServerById(id)
 
-			log("Getting list of addresses...")
-			addresses, err := servers.ListAddresses(id)
-			if (err != nil) && (err != gophercloud.WarnUnauthoritative) {
-				panic(err)
-			}
-			if err == gophercloud.WarnUnauthoritative {
-				log("Uh oh -- got a response back, but it's not authoritative for some reason.")
-			}
-			for _, addr := range addresses.Public {
-				log("Address:", addr.Addr, "  IPv", addr.Version)
-			}
+			tryAllAddresses(id, api)
+			tryAddressesByNetwork("private", id, api)
 
 			log("Done")
 		})
 	})
 }
 
-func log(s... interface{}) {
+func tryAllAddresses(id string, api gophercloud.CloudServersProvider) {
+	log("Getting list of all addresses...")
+	addresses, err := api.ListAddresses(id)
+	if (err != nil) && (err != gophercloud.WarnUnauthoritative) {
+		panic(err)
+	}
+	if err == gophercloud.WarnUnauthoritative {
+		log("Uh oh -- got a response back, but it's not authoritative for some reason.")
+	}
+	if !*quiet {
+		fmt.Println("Addresses:")
+		fmt.Printf("%+v\n", addresses)
+	}
+}
+
+func tryAddressesByNetwork(networkLabel string, id string, api gophercloud.CloudServersProvider) {
+	log("Getting list of addresses on", networkLabel, "network...")
+	network, err := api.ListAddressesByNetwork(id, networkLabel)
+	if (err != nil) && (err != gophercloud.WarnUnauthoritative) {
+		panic(err)
+	}
+	if err == gophercloud.WarnUnauthoritative {
+		log("Uh oh -- got a response back, but it's not authoritative for some reason.")
+	}
+	for _, addr := range network[networkLabel] {
+		log("Address:", addr.Addr, "  IPv", addr.Version)
+	}
+}
+
+func log(s ...interface{}) {
 	if !*quiet {
 		fmt.Println(s...)
 	}
diff --git a/acceptance/17-create-delete-image.go b/acceptance/17-create-delete-image.go
index 1fae5ab..25d8c72 100644
--- a/acceptance/17-create-delete-image.go
+++ b/acceptance/17-create-delete-image.go
@@ -44,7 +44,7 @@
 }
 
 func log(s string) {
-        if !*quiet {
-                fmt.Println(s)
-        }
+	if !*quiet {
+		fmt.Println(s)
+	}
 }
diff --git a/acceptance/99-delete-server.go b/acceptance/99-delete-server.go
index f3639b9..55b8798 100644
--- a/acceptance/99-delete-server.go
+++ b/acceptance/99-delete-server.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"flag"
+	"fmt"
 	"github.com/rackspace/gophercloud"
 )
 
@@ -42,5 +42,5 @@
 				fmt.Printf("%d servers removed.\n", n)
 			}
 		})
-	})	
+	})
 }
diff --git a/context.go b/context.go
index 57f0801..a41cc6d 100644
--- a/context.go
+++ b/context.go
@@ -98,7 +98,7 @@
 		}
 	}
 	if strings.Contains(name, "://") {
-		p = Provider {
+		p = Provider{
 			AuthEndpoint: name,
 		}
 		return p, nil
diff --git a/interfaces.go b/interfaces.go
index e94f496..7a9c7eb 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -146,6 +146,10 @@
 	// this function might be more efficient.
 	ListAddresses(id string) (AddressSet, error)
 
+	// ListAddressesByNetwork yields the list of available addresses for a given server id and networkLabel.
+	// Example: ListAddressesByNetwork("234-4353-4jfrj-43j2s", "private")
+	ListAddressesByNetwork(id, networkLabel string) (NetworkAddress, error)
+
 	// Images
 
 	// ListImages yields the list of available operating system images.  This function
diff --git a/servers.go b/servers.go
index 6ca8d24..fc5925d 100644
--- a/servers.go
+++ b/servers.go
@@ -316,6 +316,32 @@
 }
 
 // See the CloudServersProvider interface for details.
+func (gsp *genericServersProvider) ListAddressesByNetwork(id, networkLabel string) (NetworkAddress, error) {
+	pas := make(NetworkAddress)
+	var statusCode int
+
+	err := gsp.context.WithReauth(gsp.access, func() error {
+		ep := fmt.Sprintf("%s/servers/%s/ips/%s", gsp.endpoint, id, networkLabel)
+		return perigee.Get(ep, perigee.Options{
+			Results: &pas,
+			MoreHeaders: map[string]string{
+				"X-Auth-Token": gsp.access.AuthToken(),
+			},
+			OkCodes:    []int{200, 203},
+			StatusCode: &statusCode,
+		})
+	})
+
+	if err != nil {
+		if statusCode == 203 {
+			err = WarnUnauthoritative
+		}
+	}
+
+	return pas, err
+}
+
+// See the CloudServersProvider interface for details.
 func (gsp *genericServersProvider) CreateImage(id string, ci CreateImage) (string, error) {
 	response, err := gsp.context.ResponseWithReauth(gsp.access, func() (*perigee.Response, error) {
 		ep := fmt.Sprintf("%s/servers/%s/action", gsp.endpoint, id)
@@ -366,6 +392,8 @@
 	Private []VersionedAddress `json:"private"`
 }
 
+type NetworkAddress map[string][]VersionedAddress
+
 // Server records represent (virtual) hardware instances (not configurations) accessible by the user.
 //
 // The AccessIPv4 / AccessIPv6 fields provides IP addresses for the server in the IPv4 or IPv6 format, respectively.