diff --git a/novaclient/tests/v1_1/test_availability_zone.py b/novaclient/tests/v1_1/test_availability_zone.py
index fe9e885f4..b248b6f0e 100644
--- a/novaclient/tests/v1_1/test_availability_zone.py
+++ b/novaclient/tests/v1_1/test_availability_zone.py
@@ -19,33 +19,43 @@ import six
 from novaclient.tests import utils
 from novaclient.tests.v1_1 import fakes
 from novaclient.v1_1 import availability_zones
-from novaclient.v1_1 import shell
-
-
-cs = fakes.FakeClient()
 
 
 class AvailabilityZoneTest(utils.TestCase):
+    # NOTE(cyeoh): import shell here so the V3 version of
+    # this class can inherit off the v3 version of shell
+    from novaclient.v1_1 import shell  # noqa
+
+    def setUp(self):
+        super(AvailabilityZoneTest, self).setUp()
+        self.cs = self._get_fake_client()
+        self.availability_zone_type = self._get_availability_zone_type()
+
+    def _get_fake_client(self):
+        return fakes.FakeClient()
+
+    def _get_availability_zone_type(self):
+        return availability_zones.AvailabilityZone
 
     def _assertZone(self, zone, name, status):
         self.assertEqual(zone.zoneName, name)
         self.assertEqual(zone.zoneState, status)
 
     def test_list_availability_zone(self):
-        zones = cs.availability_zones.list(detailed=False)
-        cs.assert_called('GET', '/os-availability-zone')
+        zones = self.cs.availability_zones.list(detailed=False)
+        self.cs.assert_called('GET', '/os-availability-zone')
 
         for zone in zones:
             self.assertTrue(isinstance(zone,
-                                       availability_zones.AvailabilityZone))
+                                       self.availability_zone_type))
 
         self.assertEqual(2, len(zones))
 
         l0 = [six.u('zone-1'), six.u('available')]
         l1 = [six.u('zone-2'), six.u('not available')]
 
-        z0 = shell._treeizeAvailabilityZone(zones[0])
-        z1 = shell._treeizeAvailabilityZone(zones[1])
+        z0 = self.shell._treeizeAvailabilityZone(zones[0])
+        z1 = self.shell._treeizeAvailabilityZone(zones[1])
 
         self.assertEqual((len(z0), len(z1)), (1, 1))
 
@@ -53,12 +63,12 @@ class AvailabilityZoneTest(utils.TestCase):
         self._assertZone(z1[0], l1[0], l1[1])
 
     def test_detail_availability_zone(self):
-        zones = cs.availability_zones.list(detailed=True)
-        cs.assert_called('GET', '/os-availability-zone/detail')
+        zones = self.cs.availability_zones.list(detailed=True)
+        self.cs.assert_called('GET', '/os-availability-zone/detail')
 
         for zone in zones:
             self.assertTrue(isinstance(zone,
-                                       availability_zones.AvailabilityZone))
+                                       self.availability_zone_type))
 
         self.assertEqual(3, len(zones))
 
@@ -75,9 +85,9 @@ class AvailabilityZoneTest(utils.TestCase):
              six.u('enabled XXX 2012-12-26 14:45:24')]
         l8 = [six.u('zone-2'), six.u('not available')]
 
-        z0 = shell._treeizeAvailabilityZone(zones[0])
-        z1 = shell._treeizeAvailabilityZone(zones[1])
-        z2 = shell._treeizeAvailabilityZone(zones[2])
+        z0 = self.shell._treeizeAvailabilityZone(zones[0])
+        z1 = self.shell._treeizeAvailabilityZone(zones[1])
+        z2 = self.shell._treeizeAvailabilityZone(zones[2])
 
         self.assertEqual((len(z0), len(z1), len(z2)), (3, 5, 1))
 
diff --git a/novaclient/tests/v3/fakes.py b/novaclient/tests/v3/fakes.py
index c2fd0c8cf..e1f5dbb2c 100644
--- a/novaclient/tests/v3/fakes.py
+++ b/novaclient/tests/v3/fakes.py
@@ -14,6 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from datetime import datetime
+
 from novaclient.openstack.common import strutils
 from novaclient.tests import fakes
 from novaclient.tests.v1_1 import fakes as fakes_v1_1
@@ -228,3 +230,44 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
 
     def delete_servers_1234_os_server_password(self, **kw):
         return (202, {}, None)
+
+    #
+    # Availability Zones
+    #
+    def get_os_availability_zone(self, **kw):
+        return (200, {}, {"availability_zone_info": [
+                              {"zone_name": "zone-1",
+                               "zone_state": {"available": True},
+                               "hosts": None},
+                              {"zone_name": "zone-2",
+                               "zone_state": {"available": False},
+                               "hosts": None}]})
+
+    def get_os_availability_zone_detail(self, **kw):
+        return (200, {}, {"availability_zone_info": [
+                              {"zone_name": "zone-1",
+                               "zone_state": {"available": True},
+                               "hosts": {
+                                   "fake_host-1": {
+                                       "nova-compute": {"active": True,
+                                           "available": True,
+                                           "updated_at":
+                                   datetime(2012, 12, 26, 14, 45, 25, 0)}}}},
+                              {"zone_name": "internal",
+                               "zone_state": {"available": True},
+                               "hosts": {
+                                   "fake_host-1": {
+                                       "nova-sched": {
+                                           "active": True,
+                                           "available": True,
+                                           "updated_at":
+                                   datetime(2012, 12, 26, 14, 45, 25, 0)}},
+                                   "fake_host-2": {
+                                       "nova-network": {
+                                           "active": True,
+                                           "available": False,
+                                           "updated_at":
+                                   datetime(2012, 12, 26, 14, 45, 24, 0)}}}},
+                              {"zone_name": "zone-2",
+                               "zone_state": {"available": False},
+                               "hosts": None}]})
diff --git a/novaclient/tests/v3/test_availability_zone.py b/novaclient/tests/v3/test_availability_zone.py
new file mode 100644
index 000000000..004ba95fa
--- /dev/null
+++ b/novaclient/tests/v3/test_availability_zone.py
@@ -0,0 +1,38 @@
+# Copyright 2011 OpenStack Foundation
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from novaclient.tests.v1_1 import test_availability_zone
+from novaclient.tests.v3 import fakes
+from novaclient.v3 import availability_zones
+
+
+class AvailabilityZoneTest(test_availability_zone.AvailabilityZoneTest):
+    from novaclient.v3 import shell  # noqa
+
+    def setUp(self):
+        super(AvailabilityZoneTest, self).setUp()
+        self.cs = self._get_fake_client()
+        self.availability_zone_type = self._get_availability_zone_type()
+
+    def _assertZone(self, zone, name, status):
+        self.assertEqual(zone.zone_name, name)
+        self.assertEqual(zone.zone_state, status)
+
+    def _get_fake_client(self):
+        return fakes.FakeClient()
+
+    def _get_availability_zone_type(self):
+        return availability_zones.AvailabilityZone
diff --git a/novaclient/v1_1/availability_zones.py b/novaclient/v1_1/availability_zones.py
index 41362aa25..bf5903785 100644
--- a/novaclient/v1_1/availability_zones.py
+++ b/novaclient/v1_1/availability_zones.py
@@ -36,6 +36,7 @@ class AvailabilityZoneManager(base.ManagerWithFind):
     Manage :class:`AvailabilityZone` resources.
     """
     resource_class = AvailabilityZone
+    return_parameter_name = "availabilityZoneInfo"
 
     def list(self, detailed=True):
         """
@@ -45,6 +46,7 @@ class AvailabilityZoneManager(base.ManagerWithFind):
         """
         if detailed is True:
             return self._list("/os-availability-zone/detail",
-                              "availabilityZoneInfo")
+                              self.return_parameter_name)
         else:
-            return self._list("/os-availability-zone", "availabilityZoneInfo")
+            return self._list("/os-availability-zone",
+                              self.return_parameter_name)
diff --git a/novaclient/v3/availability_zones.py b/novaclient/v3/availability_zones.py
new file mode 100644
index 000000000..bd2a9d239
--- /dev/null
+++ b/novaclient/v3/availability_zones.py
@@ -0,0 +1,33 @@
+# Copyright 2011 OpenStack Foundation
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+"""
+Availability Zone interface.
+"""
+
+from novaclient.v1_1 import availability_zones
+
+
+class AvailabilityZone(availability_zones.AvailabilityZone):
+    pass
+
+
+class AvailabilityZoneManager(availability_zones.AvailabilityZoneManager):
+    """
+    Manage :class:`AvailabilityZone` resources.
+    """
+    resource_class = AvailabilityZone
+    return_parameter_name = 'availability_zone_info'
diff --git a/novaclient/v3/client.py b/novaclient/v3/client.py
index 4cbf8d3e7..8bfb2bb09 100644
--- a/novaclient/v3/client.py
+++ b/novaclient/v3/client.py
@@ -16,6 +16,7 @@
 
 from novaclient import client
 from novaclient.v3 import agents
+from novaclient.v3 import availability_zones
 from novaclient.v3 import flavor_access
 from novaclient.v3 import flavors
 from novaclient.v3 import hosts
@@ -56,6 +57,8 @@ class Client(object):
         self.os_cache = os_cache or not no_cache
         #TODO(bnemec): Add back in v3 extensions
         self.agents = agents.AgentsManager(self)
+        self.availability_zones = \
+            availability_zones.AvailabilityZoneManager(self)
         self.hosts = hosts.HostManager(self)
         self.flavors = flavors.FlavorManager(self)
         self.flavor_access = flavor_access.FlavorAccessManager(self)
diff --git a/novaclient/v3/shell.py b/novaclient/v3/shell.py
index 52aa45936..8638224dc 100644
--- a/novaclient/v3/shell.py
+++ b/novaclient/v3/shell.py
@@ -32,8 +32,8 @@ from novaclient.openstack.common import strutils
 from novaclient.openstack.common import timeutils
 from novaclient.openstack.common import uuidutils
 from novaclient import utils
-from novaclient.v1_1 import availability_zones
 from novaclient.v1_1 import quotas
+from novaclient.v3 import availability_zones
 from novaclient.v3 import servers
 
 
@@ -1433,7 +1433,7 @@ def _translate_volume_snapshot_keys(collection):
 
 def _translate_availability_zone_keys(collection):
     _translate_keys(collection,
-                    [('zoneName', 'name'), ('zoneState', 'status')])
+                    [('zone_name', 'name'), ('zone_state', 'status')])
 
 
 @utils.arg('--all-tenants',
@@ -3161,40 +3161,40 @@ def _treeizeAvailabilityZone(zone):
     result = []
 
     # Zone tree view item
-    az.zoneName = zone.zoneName
-    az.zoneState = ('available'
-                    if zone.zoneState['available'] else 'not available')
-    az._info['zoneName'] = az.zoneName
-    az._info['zoneState'] = az.zoneState
+    az.zone_name = zone.zone_name
+    az.zone_state = ('available'
+                    if zone.zone_state['available'] else 'not available')
+    az._info['zone_name'] = az.zone_name
+    az._info['zone_state'] = az.zone_state
     result.append(az)
 
     if zone.hosts is not None:
-        for (host, services) in zone.hosts.items():
+        zone_hosts = sorted(zone.hosts.items(), key=lambda x: x[0])
+        for (host, services) in zone_hosts:
             # Host tree view item
             az = AvailabilityZone(zone.manager,
                                   copy.deepcopy(zone._info), zone._loaded)
-            az.zoneName = '|- %s' % host
-            az.zoneState = ''
-            az._info['zoneName'] = az.zoneName
-            az._info['zoneState'] = az.zoneState
+            az.zone_name = '|- %s' % host
+            az.zone_state = ''
+            az._info['zone_name'] = az.zone_name
+            az._info['zone_state'] = az.zone_state
             result.append(az)
 
             for (svc, state) in services.items():
                 # Service tree view item
                 az = AvailabilityZone(zone.manager,
                                       copy.deepcopy(zone._info), zone._loaded)
-                az.zoneName = '| |- %s' % svc
-                az.zoneState = '%s %s %s' % (
+                az.zone_name = '| |- %s' % svc
+                az.zone_state = '%s %s %s' % (
                                'enabled' if state['active'] else 'disabled',
                                ':-)' if state['available'] else 'XXX',
                                state['updated_at'])
-                az._info['zoneName'] = az.zoneName
-                az._info['zoneState'] = az.zoneState
+                az._info['zone_name'] = az.zone_name
+                az._info['zone_state'] = az.zone_state
                 result.append(az)
     return result
 
 
-@utils.service_type('compute')
 def do_availability_zone_list(cs, _args):
     """List all the availability zones."""
     try: