master daemon: allow skipping the voting process
[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",
45                    "disk_template", "disk.sizes",
46                    "nic.ips", "nic.macs", "nic.bridges",
47                    "beparams", "hvparams",
48                    "oper_state", "oper_ram", "status", "tags")
49
50 NODE_FIELDS = ("name", "dtotal", "dfree",
51                "mtotal", "mnode", "mfree",
52                "pinst_cnt", "sinst_cnt", "tags")
53
54 LIST_FIELDS = ("id", "uri")
55
56
57 def Enabled():
58   """Return whether remote API tests should be run.
59
60   """
61   return constants.RAPI_ENABLE and qa_config.TestEnabled('rapi')
62
63
64 def PrintRemoteAPIWarning():
65   """Print warning if remote API is not enabled.
66
67   """
68   if constants.RAPI_ENABLE or not qa_config.TestEnabled('rapi'):
69     return
70   msg = ("Remote API is not enabled in this Ganeti build. Please run"
71          " `configure [...] --enable-rapi'.")
72   print
73   print qa_utils.FormatWarning(msg)
74
75
76 def _DoTests(uris):
77   master = qa_config.GetMasterNode()
78   host = master["primary"]
79   port = qa_config.get("rapi-port", default=constants.RAPI_PORT)
80
81   for uri, verify in uris:
82     assert uri.startswith("/")
83
84     url = "https://%s:%s%s" % (host, port, uri)
85
86     print "Testing %s ..." % url
87
88     response = NoProxyOpener.open(url)
89
90     AssertEqual(response.info()["Content-type"], "application/json")
91
92     data = serializer.LoadJson(response.read())
93
94     if verify is not None:
95       if callable(verify):
96         verify(data)
97       else:
98         AssertEqual(data, verify)
99
100
101 def TestVersion():
102   """Testing remote API version.
103
104   """
105   _DoTests([
106     ("/version", constants.RAPI_VERSION),
107     ])
108
109
110 def TestEmptyCluster():
111   """Testing remote API on an empty cluster.
112
113   """
114   master_name = qa_config.GetMasterNode()["primary"]
115
116   def _VerifyInfo(data):
117     AssertIn("name", data)
118     AssertIn("master", data)
119     AssertEqual(data["master"], master_name)
120
121   def _VerifyNodes(data):
122     master_entry = {
123       "id": master_name,
124       "uri": "/2/nodes/%s" % master_name,
125       }
126     AssertIn(master_entry, data)
127
128   def _VerifyNodesBulk(data):
129     for node in data:
130       for entry in NODE_FIELDS:
131         AssertIn(entry, node)
132
133   _DoTests([
134     ("/", None),
135     ("/2/info", _VerifyInfo),
136     ("/2/tags", None),
137     ("/2/nodes", _VerifyNodes),
138     ("/2/nodes?bulk=1", _VerifyNodesBulk),
139     ("/2/instances", []),
140     ("/2/instances?bulk=1", []),
141     ("/2/os", None),
142     ])
143
144
145 def TestInstance(instance):
146   """Testing getting instance(s) info via remote API.
147
148   """
149   def _VerifyInstance(data):
150     for entry in INSTANCE_FIELDS:
151       AssertIn(entry, data)
152
153   def _VerifyInstancesList(data):
154     for instance in data:
155       for entry in LIST_FIELDS:
156         AssertIn(entry, instance)
157
158   def _VerifyInstancesBulk(data):
159     for instance_data in data:
160       _VerifyInstance(instance_data)
161
162   _DoTests([
163     ("/2/instances/%s" % instance["name"], _VerifyInstance),
164     ("/2/instances", _VerifyInstancesList),
165     ("/2/instances?bulk=1", _VerifyInstancesBulk),
166     ])
167
168
169 def TestNode(node):
170   """Testing getting node(s) info via remote API.
171
172   """
173   def _VerifyNode(data):
174     for entry in NODE_FIELDS:
175       AssertIn(entry, data)
176
177   def _VerifyNodesList(data):
178     for node in data:
179       for entry in LIST_FIELDS:
180         AssertIn(entry, node)
181
182   def _VerifyNodesBulk(data):
183     for node_data in data:
184       _VerifyNode(node_data)
185
186   _DoTests([
187     ("/2/nodes/%s" % node["primary"], _VerifyNode),
188     ("/2/nodes", _VerifyNodesList),
189     ("/2/nodes?bulk=1", _VerifyNodesBulk),
190     ])
191
192
193 def TestTags(kind, name, tags):
194   """Tests .../tags resources.
195
196   """
197   if kind == constants.TAG_CLUSTER:
198     uri = "/2/tags"
199   elif kind == constants.TAG_NODE:
200     uri = "/2/nodes/%s/tags" % name
201   elif kind == constants.TAG_INSTANCE:
202     uri = "/2/instances/%s/tags" % name
203   else:
204     raise errors.ProgrammerError("Unknown tag kind")
205
206   def _VerifyTags(data):
207     # Create copies to modify
208     should = tags[:]
209     should.sort()
210
211     returned = data[:]
212     returned.sort()
213     AssertEqual(should, returned)
214
215   _DoTests([
216     (uri, _VerifyTags),
217     ])