Revision 2771835c qa/qa_rapi.py
b/qa/qa_rapi.py | ||
---|---|---|
22 | 22 |
|
23 | 23 |
""" |
24 | 24 |
|
25 |
import urllib2
|
|
25 |
import tempfile
|
|
26 | 26 |
|
27 | 27 |
from ganeti import utils |
28 | 28 |
from ganeti import constants |
29 | 29 |
from ganeti import errors |
30 | 30 |
from ganeti import serializer |
31 |
from ganeti import cli |
|
32 |
from ganeti import rapi |
|
33 |
|
|
34 |
import ganeti.rapi.client |
|
35 |
import ganeti.rapi.client_utils |
|
31 | 36 |
|
32 | 37 |
import qa_config |
33 | 38 |
import qa_utils |
... | ... | |
37 | 42 |
StartSSH) |
38 | 43 |
|
39 | 44 |
|
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 |
_rapi_user = None |
|
48 |
_rapi_secret = None |
|
49 |
|
|
50 |
@classmethod |
|
51 |
def SetCredentials(cls, rapi_user, rapi_secret): |
|
52 |
"""Set the credentials for authorized access. |
|
53 |
|
|
54 |
""" |
|
55 |
cls._rapi_user = rapi_user |
|
56 |
cls._rapi_secret = rapi_secret |
|
45 |
_rapi_ca = None |
|
46 |
_rapi_client = None |
|
57 | 47 |
|
58 |
@classmethod |
|
59 |
def Opener(cls): |
|
60 |
"""Construct the opener if not yet done. |
|
61 | 48 |
|
62 |
""" |
|
63 |
if not cls._opener: |
|
64 |
if not cls._rapi_user or not cls._rapi_secret: |
|
65 |
raise errors.ProgrammerError("SetCredentials was never called.") |
|
49 |
def Setup(username, password): |
|
50 |
"""Configures the RAPI client. |
|
66 | 51 |
|
67 |
# Create opener which doesn't try to look for proxies and does auth |
|
68 |
master = qa_config.GetMasterNode() |
|
69 |
host = master["primary"] |
|
70 |
port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT) |
|
71 |
passman = urllib2.HTTPPasswordMgrWithDefaultRealm() |
|
72 |
passman.add_password(None, 'https://%s:%s' % (host, port), |
|
73 |
cls._rapi_user, |
|
74 |
cls._rapi_secret) |
|
75 |
authhandler = urllib2.HTTPBasicAuthHandler(passman) |
|
76 |
cls._opener = urllib2.build_opener(urllib2.ProxyHandler({}), authhandler) |
|
52 |
""" |
|
53 |
global _rapi_ca |
|
54 |
global _rapi_client |
|
77 | 55 |
|
78 |
return cls._opener
|
|
56 |
master = qa_config.GetMasterNode()
|
|
79 | 57 |
|
58 |
# Load RAPI certificate from master node |
|
59 |
cmd = ["cat", constants.RAPI_CERT_FILE] |
|
80 | 60 |
|
81 |
class RapiRequest(urllib2.Request): |
|
82 |
"""This class supports other methods beside GET/POST. |
|
61 |
# Write to temporary file |
|
62 |
_rapi_ca = tempfile.NamedTemporaryFile() |
|
63 |
_rapi_ca.write(qa_utils.GetCommandOutput(master["primary"], |
|
64 |
utils.ShellQuoteArgs(cmd))) |
|
65 |
_rapi_ca.flush() |
|
83 | 66 |
|
84 |
""" |
|
67 |
port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT) |
|
68 |
cfg_ssl = rapi.client.CertAuthorityVerify(cafile=_rapi_ca.name) |
|
85 | 69 |
|
86 |
def __init__(self, method, url, headers, data): |
|
87 |
urllib2.Request.__init__(self, url, data=data, headers=headers) |
|
88 |
self._method = method |
|
70 |
_rapi_client = rapi.client.GanetiRapiClient(master["primary"], port=port, |
|
71 |
username=username, |
|
72 |
password=password, |
|
73 |
config_ssl_verification=cfg_ssl, |
|
74 |
ignore_proxy=True) |
|
89 | 75 |
|
90 |
def get_method(self): |
|
91 |
return self._method |
|
76 |
print "RAPI protocol version: %s" % _rapi_client.GetVersion() |
|
92 | 77 |
|
93 | 78 |
|
94 | 79 |
INSTANCE_FIELDS = ("name", "os", "pnode", "snodes", |
... | ... | |
119 | 104 |
|
120 | 105 |
|
121 | 106 |
def _DoTests(uris): |
122 |
master = qa_config.GetMasterNode() |
|
123 |
host = master["primary"] |
|
124 |
port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT) |
|
125 | 107 |
results = [] |
126 | 108 |
|
127 | 109 |
for uri, verify, method, body in uris: |
128 | 110 |
assert uri.startswith("/") |
129 | 111 |
|
130 |
url = "https://%s:%s%s" % (host, port, uri) |
|
131 |
|
|
132 |
headers = {} |
|
133 |
|
|
134 |
if body: |
|
135 |
data = serializer.DumpJson(body, indent=False) |
|
136 |
headers["Content-Type"] = "application/json" |
|
137 |
else: |
|
138 |
data = None |
|
139 |
|
|
140 |
if headers or data: |
|
141 |
details = [] |
|
142 |
if headers: |
|
143 |
details.append("headers=%s" % |
|
144 |
serializer.DumpJson(headers, indent=False).rstrip()) |
|
145 |
if data: |
|
146 |
details.append("data=%s" % data.rstrip()) |
|
147 |
info = "(%s)" % (", ".join(details), ) |
|
148 |
else: |
|
149 |
info = "" |
|
150 |
|
|
151 |
print "Testing %s %s %s..." % (method, url, info) |
|
152 |
|
|
153 |
req = RapiRequest(method, url, headers, data) |
|
154 |
response = OpenerFactory.Opener().open(req) |
|
155 |
|
|
156 |
AssertEqual(response.info()["Content-type"], "application/json") |
|
157 |
|
|
158 |
data = serializer.LoadJson(response.read()) |
|
112 |
data = _rapi_client._SendRequest(method, uri, None, body) |
|
159 | 113 |
|
160 | 114 |
if verify is not None: |
161 | 115 |
if callable(verify): |
... | ... | |
305 | 259 |
("/2/jobs/%s" % job_id, _VerifyJob, "GET", None), |
306 | 260 |
]) |
307 | 261 |
|
308 |
# FIXME: Use "gnt-job watch" until RAPI supports waiting for job |
|
309 |
cmd = ["gnt-job", "watch", str(job_id)] |
|
310 |
AssertEqual(StartSSH(master["primary"], |
|
311 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
|
262 |
rapi.client_utils.PollJob(_rapi_client, job_id, cli.StdioJobPollReportCb()) |
|
312 | 263 |
|
313 | 264 |
|
314 | 265 |
def TestRapiInstanceAdd(node): |
Also available in: Unified diff