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):
|