Use a Concat method to aggregate Collection pages.
diff --git a/collections.go b/collections.go
index 82e6c7a..0a800a0 100644
--- a/collections.go
+++ b/collections.go
@@ -21,6 +21,10 @@
 	// Pager returns one of the concrete Pager implementations from this package, or a custom one.
 	// The style of Pager returned determines how the collection is paged.
 	Pager() Pager
+
+	// Concat the contents of another collection on to the end of this one.
+	// Return a new collection that contains elements from both.
+	Concat(Collection) Collection
 }
 
 // EachPage iterates through a Collection one page at a time.
@@ -50,7 +54,19 @@
 // AllPages consolidates all pages reachable from a provided starting point into a single mega-Page.
 // Use this only when you know that the full set will always fit within memory.
 func AllPages(first Collection) (Collection, error) {
-	return first, nil
+	megaPage := first
+	isFirst := true
+
+	err := EachPage(first, func(page Collection) bool {
+		if isFirst {
+			isFirst = false
+		} else {
+			megaPage = megaPage.Concat(page)
+		}
+		return true
+	})
+
+	return megaPage, err
 }
 
 // Pager describes a specific paging idiom for a Page resource.
diff --git a/collections_test.go b/collections_test.go
index 4c8674d..4b0fdc5 100644
--- a/collections_test.go
+++ b/collections_test.go
@@ -20,6 +20,10 @@
 	return SinglePager{}
 }
 
+func (c SinglePageCollection) Concat(other Collection) Collection {
+	panic("Concat should never be called on a single-paged collection.")
+}
+
 func AsSingleInts(c Collection) []int {
 	return c.(SinglePageCollection).results
 }
@@ -68,6 +72,17 @@
 	results []int
 }
 
+func (c LinkedCollection) Pager() Pager {
+	return NewLinkPager(c)
+}
+
+func (c LinkedCollection) Concat(other Collection) Collection {
+	return LinkedCollection{
+		service: c.service,
+		results: append(c.results, AsLinkedInts(other)...),
+	}
+}
+
 func (c LinkedCollection) Links() PaginationLinks {
 	return c.PaginationLinks
 }
@@ -77,7 +92,6 @@
 }
 
 func (c LinkedCollection) Interpret(response interface{}) (LinkCollection, error) {
-	fmt.Printf("Interpreting result: %#v\n", response)
 	casted, ok := response.([]interface{})
 	if ok {
 		asInts := make([]int, len(casted))
@@ -102,20 +116,11 @@
 			service:         c.service,
 			results:         asInts,
 		}
-		if nextURL != nil {
-			fmt.Printf("Returning result: %s\n", *nextURL)
-		} else {
-			fmt.Printf("No next link")
-		}
 		return result, nil
 	}
 	return nil, errors.New("Wat")
 }
 
-func (c LinkedCollection) Pager() Pager {
-	return NewLinkPager(c)
-}
-
 func AsLinkedInts(results Collection) []int {
 	return results.(LinkedCollection).results
 }
@@ -196,3 +201,28 @@
 		t.Errorf("Expected 3 calls, but was %d", callCount)
 	}
 }
+
+func TestAllLinked(t *testing.T) {
+	testhelper.SetupHTTP()
+	defer testhelper.TeardownHTTP()
+
+	setupLinkedResponses(t)
+	lc := createLinked()
+
+	all, err := AllPages(lc)
+	if err != nil {
+		t.Fatalf("Unexpected error collection all linked pages: %v", err)
+	}
+
+	actual := AsLinkedInts(all)
+	expected := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
+
+	if !reflect.DeepEqual(expected, actual) {
+		t.Errorf("Expected %v, but was %v", expected, actual)
+	}
+
+	original := []int{1, 2, 3}
+	if !reflect.DeepEqual(AsLinkedInts(lc), original) {
+		t.Errorf("AllPages modified the original page, and now it contains: %v", lc)
+	}
+}
diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go
index d3068df..e972404 100644
--- a/openstack/identity/v3/endpoints/results.go
+++ b/openstack/identity/v3/endpoints/results.go
@@ -30,6 +30,14 @@
 	return gophercloud.NewLinkPager(list)
 }
 
+// Concat adds the contents of another Collection to this one.
+func (list EndpointList) Concat(other gophercloud.Collection) gophercloud.Collection {
+	return EndpointList{
+		client:    list.client,
+		Endpoints: append(list.Endpoints, AsEndpoints(other)...),
+	}
+}
+
 // Service returns the ServiceClient used to acquire this list.
 func (list EndpointList) Service() *gophercloud.ServiceClient {
 	return list.client
diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go
index c6ce1b9..88510b4 100644
--- a/openstack/identity/v3/services/results.go
+++ b/openstack/identity/v3/services/results.go
@@ -19,8 +19,8 @@
 type ServiceList struct {
 	gophercloud.PaginationLinks `json:"links"`
 
-	client *gophercloud.ServiceClient
-	Page   []Service `json:"services"`
+	client   *gophercloud.ServiceClient
+	Services []Service `json:"services"`
 }
 
 // Pager indicates that the ServiceList is paginated by next and previous links.
@@ -28,6 +28,14 @@
 	return gophercloud.NewLinkPager(list)
 }
 
+// Concat returns a new collection that's the result of appending a new collection at the end of this one.
+func (list ServiceList) Concat(other gophercloud.Collection) gophercloud.Collection {
+	return ServiceList{
+		client:   list.client,
+		Services: append(list.Services, AsServices(other)...),
+	}
+}
+
 // Service returns the ServiceClient used to acquire this list.
 func (list ServiceList) Service() *gophercloud.ServiceClient {
 	return list.client
@@ -56,5 +64,5 @@
 // AsServices extracts a slice of Services from a Collection acquired from List.
 // It panics if the Collection does not actually contain Services.
 func AsServices(results gophercloud.Collection) []Service {
-	return results.(*ServiceList).Page
+	return results.(*ServiceList).Services
 }