Statistics
| Branch: | Tag: | Revision:

root / qa / qa_rapi.py @ e6ce18ac

History | View | Annotate | Download (6.4 kB)

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, AssertMatch,
37
                      StartSSH)
38

    
39

    
40
class OpenerFactory:
41
  """A factory singleton to construct urllib opener chain.
42

43
  This is needed because qa_config is not initialized yet at module load time
44

45
  """
46
  _opener = None
47

    
48
  @classmethod
49
  def Opener(cls):
50
    """Construct the opener if not yet done.
51

52
    """
53
    if not cls._opener:
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)
64

    
65
    return cls._opener
66

    
67

    
68
class RapiRequest(urllib2.Request):
69
  """This class supports other methods beside GET/POST.
70

71
  """
72

    
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,
76
                             unverifiable)
77
    self._method = method
78

    
79
  def get_method(self):
80
    return self._method
81

    
82

    
83
INSTANCE_FIELDS = ("name", "os", "pnode", "snodes",
84
                   "admin_state",
85
                   "disk_template", "disk.sizes",
86
                   "nic.ips", "nic.macs", "nic.modes", "nic.links",
87
                   "beparams", "hvparams",
88
                   "oper_state", "oper_ram", "status", "tags")
89

    
90
NODE_FIELDS = ("name", "dtotal", "dfree",
91
               "mtotal", "mnode", "mfree",
92
               "pinst_cnt", "sinst_cnt", "tags")
93

    
94
LIST_FIELDS = ("id", "uri")
95

    
96

    
97
def Enabled():
98
  """Return whether remote API tests should be run.
99

100
  """
101
  return qa_config.TestEnabled('rapi')
102

    
103

    
104
def _DoTests(uris):
105
  master = qa_config.GetMasterNode()
106
  host = master["primary"]
107
  port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT)
108

    
109
  for uri, verify, method in uris:
110
    assert uri.startswith("/")
111

    
112
    url = "https://%s:%s%s" % (host, port, uri)
113

    
114
    print "Testing %s ..." % url
115

    
116
    req = RapiRequest(url, method=method)
117
    response = OpenerFactory.Opener().open(req)
118

    
119
    AssertEqual(response.info()["Content-type"], "application/json")
120

    
121
    data = serializer.LoadJson(response.read())
122

    
123
    if verify is not None:
124
      if callable(verify):
125
        verify(data)
126
      else:
127
        AssertEqual(data, verify)
128

    
129

    
130
def TestVersion():
131
  """Testing remote API version.
132

133
  """
134
  _DoTests([
135
    ("/version", constants.RAPI_VERSION, 'GET'),
136
    ])
137

    
138

    
139
def TestEmptyCluster():
140
  """Testing remote API on an empty cluster.
141

142
  """
143
  master_name = qa_config.GetMasterNode()["primary"]
144

    
145
  def _VerifyInfo(data):
146
    AssertIn("name", data)
147
    AssertIn("master", data)
148
    AssertEqual(data["master"], master_name)
149

    
150
  def _VerifyNodes(data):
151
    master_entry = {
152
      "id": master_name,
153
      "uri": "/2/nodes/%s" % master_name,
154
      }
155
    AssertIn(master_entry, data)
156

    
157
  def _VerifyNodesBulk(data):
158
    for node in data:
159
      for entry in NODE_FIELDS:
160
        AssertIn(entry, node)
161

    
162
  _DoTests([
163
    ("/", None, 'GET'),
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'),
171
    ])
172

    
173

    
174
def TestInstance(instance):
175
  """Testing getting instance(s) info via remote API.
176

177
  """
178
  def _VerifyInstance(data):
179
    for entry in INSTANCE_FIELDS:
180
      AssertIn(entry, data)
181

    
182
  def _VerifyInstancesList(data):
183
    for instance in data:
184
      for entry in LIST_FIELDS:
185
        AssertIn(entry, instance)
186

    
187
  def _VerifyInstancesBulk(data):
188
    for instance_data in data:
189
      _VerifyInstance(instance_data)
190

    
191
  def _VerifyReturnsJob(data):
192
    AssertMatch(data, r'^\d+$')
193

    
194
  _DoTests([
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'),
200
    ])
201

    
202

    
203
def TestNode(node):
204
  """Testing getting node(s) info via remote API.
205

206
  """
207
  def _VerifyNode(data):
208
    for entry in NODE_FIELDS:
209
      AssertIn(entry, data)
210

    
211
  def _VerifyNodesList(data):
212
    for node in data:
213
      for entry in LIST_FIELDS:
214
        AssertIn(entry, node)
215

    
216
  def _VerifyNodesBulk(data):
217
    for node_data in data:
218
      _VerifyNode(node_data)
219

    
220
  _DoTests([
221
    ("/2/nodes/%s" % node["primary"], _VerifyNode, 'GET'),
222
    ("/2/nodes", _VerifyNodesList, 'GET'),
223
    ("/2/nodes?bulk=1", _VerifyNodesBulk, 'GET'),
224
    ])
225

    
226

    
227
def TestTags(kind, name, tags):
228
  """Tests .../tags resources.
229

230
  """
231
  if kind == constants.TAG_CLUSTER:
232
    uri = "/2/tags"
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
237
  else:
238
    raise errors.ProgrammerError("Unknown tag kind")
239

    
240
  def _VerifyTags(data):
241
    # Create copies to modify
242
    should = tags[:]
243
    should.sort()
244

    
245
    returned = data[:]
246
    returned.sort()
247
    AssertEqual(should, returned)
248

    
249
  _DoTests([
250
    (uri, _VerifyTags, 'GET'),
251
    ])