Migrate RAPI QA to trunk.
[ganeti-local] / qa / qa_rapi.py
1 #
2
3 # Copyright (C) 2007, 2008 Google Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
19
20
21 """Remote API QA tests.
22
23 """
24
25 import urllib2
26
27 from ganeti import utils
28 from ganeti import constants
29 from ganeti import errors
30 from ganeti import serializer
31
32 import qa_config
33 import qa_utils
34 import qa_error
35
36 from qa_utils import AssertEqual, AssertNotEqual, AssertIn, StartSSH
37
38
39 # Create opener which doesn't try to look for proxies.
40 NoProxyOpener = urllib2.build_opener(urllib2.ProxyHandler({}))
41
42
43 INSTANCE_FIELDS = ("name", "os", "pnode", "snodes",
44                    "admin_state", "admin_ram",
45                    "disk_template", "ip", "mac", "bridge",
46                    "sda_size", "sdb_size", "vcpus",
47                    "oper_state", "status", "tags")
48
49 NODE_FIELDS = ("name", "dtotal", "dfree",
50                "mtotal", "mnode", "mfree",
51                "pinst_cnt", "sinst_cnt", "tags")
52
53 LIST_FIELDS = ("name", "uri")
54
55
56 def Enabled():
57   """Return whether remote API tests should be run.
58
59   """
60   return constants.RAPI_ENABLE and qa_config.TestEnabled('rapi')
61
62
63 def PrintRemoteAPIWarning():
64   """Print warning if remote API is not enabled.
65
66   """
67   if constants.RAPI_ENABLE or not qa_config.TestEnabled('rapi'):
68     return
69   msg = ("Remote API is not enabled in this Ganeti build. Please run"
70          " `configure [...] --enable-rapi'.")
71   print
72   print qa_utils.FormatWarning(msg)
73
74
75 def _DoTests(uris):
76   master = qa_config.GetMasterNode()
77   host = master["primary"]
78   port = qa_config.get("rapi-port", default=constants.RAPI_PORT)
79
80   for uri, verify in uris:
81     assert uri.startswith("/")
82
83     url = "http://%s:%s%s" % (host, port, uri)
84
85     print "Testing %s ..." % url
86
87     response = NoProxyOpener.open(url)
88
89     AssertEqual(response.info()["Content-type"], "application/json")
90
91     data = serializer.LoadJson(response.read())
92
93     if verify is not None:
94       if callable(verify):
95         verify(data)
96       else:
97         AssertEqual(data, verify)
98
99
100 @qa_utils.DefineHook('rapi-version')
101 def TestVersion():
102   """Testing remote API version.
103
104   """
105   _DoTests([
106     ("/version", constants.RAPI_VERSION),
107     ])
108
109
110 @qa_utils.DefineHook('rapi-empty-cluster')
111 def TestEmptyCluster():
112   """Testing remote API on an empty cluster.
113
114   """
115   master_name = qa_config.GetMasterNode()["primary"]
116
117   def _VerifyInfo(data):
118     AssertIn("name", data)
119     AssertIn("master", data)
120     AssertEqual(data["master"], master_name)
121
122   def _VerifyNodes(data):
123     master_entry = {
124       "name": master_name,
125       "uri": "/nodes/%s" % master_name,
126       }
127     AssertIn(master_entry, data)
128
129   def _VerifyNodesBulk(data):
130     for node in data:
131       for entry in NODE_FIELDS:
132         AssertIn(entry, node)
133
134   _DoTests([
135     ("/", None),
136     ("/info", _VerifyInfo),
137     ("/tags", None),
138     ("/nodes", _VerifyNodes),
139     ("/nodes?bulk=1", _VerifyNodesBulk),
140     ("/instances", []),
141     ("/instances?bulk=1", []),
142     ("/os", None),
143     ])
144
145
146 @qa_utils.DefineHook('rapi-instance')
147 def TestInstance(instance):
148   """Testing getting instance(s) info via remote API.
149
150   """
151   def _VerifyInstance(data):
152     for entry in INSTANCE_FIELDS:
153       AssertIn(entry, data)
154   
155   def _VerifyInstancesList(data):
156     for instance in data:
157       for entry in LIST_FIELDS: 
158         AssertIn(entry, instance)
159       
160   def _VerifyInstancesBulk(data):
161     for instance_data in data:
162       _VerifyInstance(instance_data)
163
164   _DoTests([
165     ("/instances/%s" % instance["name"], _VerifyInstance),
166     ("/instances", _VerifyInstancesList),
167     ("/instances?bulk=1", _VerifyInstancesBulk),
168     ])
169
170
171 @qa_utils.DefineHook('rapi-node')
172 def TestNode(node):
173   """Testing getting node(s) info via remote API.
174
175   """
176   def _VerifyNode(data):
177     for entry in NODE_FIELDS:
178       AssertIn(entry, data)
179   
180   def _VerifyNodesList(data):
181     for node in data:
182       for entry in LIST_FIELDS: 
183         AssertIn(entry, node)
184   
185   def _VerifyNodesBulk(data):
186     for node_data in data:
187       _VerifyNode(node_data)
188
189   _DoTests([
190     ("/nodes/%s" % node["primary"], _VerifyNode),
191     ("/nodes", _VerifyNodesList),
192     ("/nodes?bulk=1", _VerifyNodesBulk),
193     ])
194
195
196 def TestTags(kind, name, tags):
197   """Tests .../tags resources.
198
199   """
200   if kind == constants.TAG_CLUSTER:
201     uri = "/tags"
202   elif kind == constants.TAG_NODE:
203     uri = "/nodes/%s/tags" % name
204   elif kind == constants.TAG_INSTANCE:
205     uri = "/instances/%s/tags" % name
206   else:
207     raise errors.ProgrammerError("Unknown tag kind")
208
209   def _VerifyTags(data):
210     # Create copies to modify
211     should = tags[:]
212     should.sort()
213
214     returned = data[:]
215     returned.sort()
216     AssertEqual(should, returned)
217
218   _DoTests([
219     (uri, _VerifyTags),
220     ])