Verify "get a server" API response attributes

Now most attributes of Nova v2/v3 APIs are not checked in Tempest,
and this patch adds some tests which check these attributes to block
the backward incompatibility change in the future.

This patch adds the checks of "get a server" API responses.

The response body of v2 API is the following:
  {
    "server": {
      "id": "c2f2ebe8-5a25-442b-83d2-9f0926a7a88a",
      "name": "vm01-v3",
      "status": "ACTIVE",
      "image": {
        "id": "b62655db-2ff7-4d7f-8821-d0a468a25bec",
        "links": [{"href": "http://[..]", "rel": "bookmark"}]
      },
      "flavor": {
        "id": "42",
        "links": [{"href": "http://[..]", "rel": "bookmark"}]
      },
      "user_id": "832ebd066fb0427ea77c4aab6bab5ec1",
      "tenant_id": "b8d8f3df596b482e93c4225b1d72d2c2",
      "created": "2014-03-13T00:40:21Z",
      "updated": "2014-03-13T00:40:31Z",
      "metadata": {},
      "links": [
        {"href": "http://[..]", "rel": "self"},
        {"href": "http://[..]", "rel": "bookmark"}
      ],
      "addresses": {
        "private": [{
          "OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:5f:c3:0f",
          "version": 4, "addr": "10.0.0.5", "OS-EXT-IPS:type": "fixed"
        }]
      },
      "key_name": null,
      "hostId": "6efdef81d6341b7fac789263e366cdf3ed5136f5894db8a2b79d1bc7",
      "progress": 0,
      "OS-SRV-USG:launched_at": "2014-03-13T00:40:31.000000",
      "OS-SRV-USG:terminated_at": null,
      "OS-EXT-AZ:availability_zone": "nova",

      "OS-EXT-STS:task_state": null,
      "OS-EXT-STS:vm_state": "active",
      "OS-EXT-STS:power_state": 1,

      "OS-EXT-SRV-ATTR:host": "localhost-dev",
      "OS-EXT-SRV-ATTR:instance_name": "instance-0000004a",
      "OS-EXT-SRV-ATTR:hypervisor_hostname": "localhost-dev",

      "os-extended-volumes:volumes_attached": [],
      "accessIPv4": "",
      "accessIPv6": "",
      "config_drive": "",
      "OS-DCF:diskConfig": "MANUAL"
    }
  }

The one of v3 API is the following:
  {
    "server": {
      "id": "c2f2ebe8-5a25-442b-83d2-9f0926a7a88a",
      "name": "vm01-v3",
      "status": "ACTIVE",
      "image": {
        "id": "b62655db-2ff7-4d7f-8821-d0a468a25bec",
        "links": [{"href": "http://[..]", "rel": "bookmark"}]
      },
      "flavor": {
        "id": "42", "links": [{"href": "http://192.168.11.100:8774/flavors/42", "rel": "bookmark"}]
      },
      "user_id": "832ebd066fb0427ea77c4aab6bab5ec1",
      "tenant_id": "b8d8f3df596b482e93c4225b1d72d2c2",
      "created": "2014-03-13T00:40:21Z",
      "updated": "2014-03-13T00:40:31Z",
      "metadata": {},
      "links": [
        {"href": "http://[..]", "rel": "self"},
        {"href": "http://[..]", "rel": "bookmark"}
      ],
      "addresses": {
        "private": [{
          "version": 4, "type": "fixed",
          "addr": "10.0.0.5", "mac_addr": "fa:16:3e:5f:c3:0f"
        }]
      },
      "key_name": null,
      "host_id": "6efdef81d6341b7fac789263e366cdf3ed5136f5894db8a2b79d1bc7",
      "progress": 0,
      "os-server-usage:launched_at": "2014-03-13T00:40:31.000000",
      "os-server-usage:terminated_at": null,
      "os-extended-availability-zone:availability_zone": "nova",

      "os-extended-status:task_state": null,
      "os-extended-status:vm_state": "active",
      "os-extended-status:power_state": 1,
      "os-extended-status:locked_by": null,

      "os-extended-server-attributes:host": "localhost-dev",
      "os-extended-server-attributes:instance_name": "instance-0000004a",
      "os-extended-server-attributes:hypervisor_hostname": "localhost-dev",

      "os-extended-volumes:volumes_attached": [],
      "os-pci:pci_devices": [],
      "os-access-ips:access_ip_v4": "",
      "os-access-ips:access_ip_v6": "",
      "os-config-drive:config_drive": ""
    }
  }

Partially implements blueprint nova-api-attribute-test

Change-Id: I951eae22d694349ae734e1ea16f24f500af6a894
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/compute/servers.py
index 14e9ce9..d66fd03 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/compute/servers.py
@@ -48,7 +48,7 @@
     }
 }
 
-base_update_server = {
+base_update_get_server = {
     'status_code': [200],
     'response_body': {
         'type': 'object',
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index fe53abd..6ee6f19 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -46,7 +46,7 @@
     }
 }
 
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
 update_server['response_body']['properties']['server']['properties'].update({
     'hostId': {'type': 'string'},
     'OS-DCF:diskConfig': {'type': 'string'},
@@ -60,6 +60,39 @@
     'hostId'
 )
 
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'hostId': {'type': 'string'},
+
+    # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ"
+    # attributes.
+    'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+    'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+    'OS-EXT-AZ:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR"
+    # attributes.
+    'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+    'OS-EXT-STS:vm_state': {'type': 'string'},
+    'OS-EXT-STS:power_state': {'type': 'integer'},
+    'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+    'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+    'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'OS-DCF:diskConfig': {'type': 'string'},
+    'accessIPv4': parameter_types.access_ip_v4,
+    'accessIPv6': parameter_types.access_ip_v6,
+    'config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+    # NOTE: OS-SRV-USG, OS-EXT-AZ, OS-EXT-STS, OS-EXT-SRV-ATTR,
+    # os-extended-volumes, OS-DCF and accessIPv4/v6 are API
+    # extension, and some environments return a response without
+    # these attributes. So they are not 'required'.
+    'hostId'
+)
+
 list_virtual_interfaces = {
     'status_code': [200],
     'response_body': {
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/compute/v3/servers.py
index 4fb2d87..0e5bd77 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/compute/v3/servers.py
@@ -57,7 +57,7 @@
         ['type', 'mac_addr']
     )
 
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
 update_server['response_body']['properties']['server']['properties'].update({
     'addresses': addresses_v3,
     'host_id': {'type': 'string'},
@@ -71,6 +71,43 @@
     'host_id'
 )
 
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'host_id': {'type': 'string'},
+
+    # NOTE: Non-admin users also can see "os-server-usage" and
+    # "os-extended-availability-zone" attributes.
+    'os-server-usage:launched_at': {'type': ['string', 'null']},
+    'os-server-usage:terminated_at': {'type': ['string', 'null']},
+    'os-extended-availability-zone:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "os-extended-status" and
+    # "os-extended-server-attributes" attributes.
+    'os-extended-status:task_state': {'type': ['string', 'null']},
+    'os-extended-status:vm_state': {'type': 'string'},
+    'os-extended-status:power_state': {'type': 'integer'},
+    'os-extended-status:locked_by': {'type': ['string', 'null']},
+    'os-extended-server-attributes:host': {'type': ['string', 'null']},
+    'os-extended-server-attributes:instance_name': {'type': 'string'},
+    'os-extended-server-attributes:hypervisor_hostname': {
+        'type': ['string', 'null']
+    },
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'os-pci:pci_devices': {'type': 'array'},
+    'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
+    'os-access-ips:access_ip_v6': parameter_types.access_ip_v6,
+    'os-config-drive:config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+    # NOTE: os-server-usage, os-extended-availability-zone,
+    # os-extended-status, os-extended-server-attributes,
+    # os-extended-volumes, os-pci, os-access-ips and
+    # os-config-driveare API extension, and some environments
+    # return a response without these attributes. So they are not 'required'.
+    'host_id'
+)
+
 attach_detach_volume = {
     'status_code': [202]
 }
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 23c1e64..6fdb17b 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -134,6 +134,7 @@
         """Returns the details of an existing server."""
         resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
         return resp, body['server']
 
     def delete_server(self, server_id):
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 11258a6..d933998 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -136,6 +136,7 @@
         """Returns the details of an existing server."""
         resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
         return resp, body['server']
 
     def delete_server(self, server_id):