3 # Copyright (C) 2007, 2008 Google Inc.
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.
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.
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
21 """Remote API QA tests.
27 from ganeti import utils
28 from ganeti import constants
29 from ganeti import errors
30 from ganeti import serializer
36 from qa_utils import (AssertEqual, AssertNotEqual, AssertIn, AssertMatch,
41 """A factory singleton to construct urllib opener chain.
43 This is needed because qa_config is not initialized yet at module load time
50 """Construct the opener if not yet done.
54 # Create opener which doesn't try to look for proxies and does auth
55 master = qa_config.GetMasterNode()
56 host = master["primary"]
57 port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT)
58 passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
59 passman.add_password(None, 'https://%s:%s' % (host, port),
60 qa_config.get("rapi-user", default=""),
61 qa_config.get("rapi-pass", default=""))
62 authhandler = urllib2.HTTPBasicAuthHandler(passman)
63 cls._opener = urllib2.build_opener(urllib2.ProxyHandler({}), authhandler)
68 class RapiRequest(urllib2.Request):
69 """This class supports other methods beside GET/POST.
73 def __init__(self, url, data=None, headers={}, origin_req_host=None,
74 unverifiable=False, method="GET"):
75 urllib2.Request.__init__(self, url, data, headers, origin_req_host,
83 INSTANCE_FIELDS = ("name", "os", "pnode", "snodes",
85 "disk_template", "disk.sizes",
86 "nic.ips", "nic.macs", "nic.modes", "nic.links",
87 "beparams", "hvparams",
88 "oper_state", "oper_ram", "status", "tags")
90 NODE_FIELDS = ("name", "dtotal", "dfree",
91 "mtotal", "mnode", "mfree",
92 "pinst_cnt", "sinst_cnt", "tags")
94 LIST_FIELDS = ("id", "uri")
98 """Return whether remote API tests should be run.
101 return qa_config.TestEnabled('rapi')
105 master = qa_config.GetMasterNode()
106 host = master["primary"]
107 port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT)
109 for uri, verify, method in uris:
110 assert uri.startswith("/")
112 url = "https://%s:%s%s" % (host, port, uri)
114 print "Testing %s ..." % url
116 req = RapiRequest(url, method=method)
117 response = OpenerFactory.Opener().open(req)
119 AssertEqual(response.info()["Content-type"], "application/json")
121 data = serializer.LoadJson(response.read())
123 if verify is not None:
127 AssertEqual(data, verify)
131 """Testing remote API version.
135 ("/version", constants.RAPI_VERSION, 'GET'),
139 def TestEmptyCluster():
140 """Testing remote API on an empty cluster.
143 master_name = qa_config.GetMasterNode()["primary"]
145 def _VerifyInfo(data):
146 AssertIn("name", data)
147 AssertIn("master", data)
148 AssertEqual(data["master"], master_name)
150 def _VerifyNodes(data):
153 "uri": "/2/nodes/%s" % master_name,
155 AssertIn(master_entry, data)
157 def _VerifyNodesBulk(data):
159 for entry in NODE_FIELDS:
160 AssertIn(entry, node)
164 ("/2/info", _VerifyInfo, 'GET'),
165 ("/2/tags", None, 'GET'),
166 ("/2/nodes", _VerifyNodes, 'GET'),
167 ("/2/nodes?bulk=1", _VerifyNodesBulk, 'GET'),
168 ("/2/instances", [], 'GET'),
169 ("/2/instances?bulk=1", [], 'GET'),
170 ("/2/os", None, 'GET'),
174 def TestInstance(instance):
175 """Testing getting instance(s) info via remote API.
178 def _VerifyInstance(data):
179 for entry in INSTANCE_FIELDS:
180 AssertIn(entry, data)
182 def _VerifyInstancesList(data):
183 for instance in data:
184 for entry in LIST_FIELDS:
185 AssertIn(entry, instance)
187 def _VerifyInstancesBulk(data):
188 for instance_data in data:
189 _VerifyInstance(instance_data)
191 def _VerifyReturnsJob(data):
192 AssertMatch(data, r'^\d+$')
195 ("/2/instances/%s" % instance["name"], _VerifyInstance, 'GET'),
196 ("/2/instances", _VerifyInstancesList, 'GET'),
197 ("/2/instances?bulk=1", _VerifyInstancesBulk, 'GET'),
198 ("/2/instances/%s/activate-disks" % instance["name"], _VerifyReturnsJob, 'PUT'),
199 ("/2/instances/%s/deactivate-disks" % instance["name"], _VerifyReturnsJob, 'PUT'),
204 """Testing getting node(s) info via remote API.
207 def _VerifyNode(data):
208 for entry in NODE_FIELDS:
209 AssertIn(entry, data)
211 def _VerifyNodesList(data):
213 for entry in LIST_FIELDS:
214 AssertIn(entry, node)
216 def _VerifyNodesBulk(data):
217 for node_data in data:
218 _VerifyNode(node_data)
221 ("/2/nodes/%s" % node["primary"], _VerifyNode, 'GET'),
222 ("/2/nodes", _VerifyNodesList, 'GET'),
223 ("/2/nodes?bulk=1", _VerifyNodesBulk, 'GET'),
227 def TestTags(kind, name, tags):
228 """Tests .../tags resources.
231 if kind == constants.TAG_CLUSTER:
233 elif kind == constants.TAG_NODE:
234 uri = "/2/nodes/%s/tags" % name
235 elif kind == constants.TAG_INSTANCE:
236 uri = "/2/instances/%s/tags" % name
238 raise errors.ProgrammerError("Unknown tag kind")
240 def _VerifyTags(data):
241 # Create copies to modify
247 AssertEqual(should, returned)
250 (uri, _VerifyTags, 'GET'),