Saltnado test fixes

This commit is contained in:
Daniel A. Wozniak 2023-05-15 18:50:04 -07:00 committed by Gareth J. Greenaway
parent 574e6cd2c2
commit 38d1df3b46
6 changed files with 46 additions and 18 deletions

View file

@ -39,6 +39,8 @@ def get_application(opts):
except ImportError as err:
log.error("ImportError! %s", err)
return None
log = logging.getLogger()
log.setLevel(logging.DEBUG)
mod_opts = opts.get(__virtualname__, {})
@ -56,6 +58,7 @@ def get_application(opts):
# if you have enabled websockets, add them!
if mod_opts.get("websockets", False):
log.error("ENABEL WEBSOC")
from . import saltnado_websockets
token_pattern = r"([0-9A-Fa-f]{{{0}}})".format(
@ -73,9 +76,10 @@ def get_application(opts):
(all_events_pattern, saltnado_websockets.AllEventsHandler),
(formatted_events_pattern, saltnado_websockets.FormattedEventsHandler),
]
log.error("ENABEL WEBSOC - DONE")
application = salt.ext.tornado.web.Application(
paths, debug=mod_opts.get("debug", False)
paths, debug=True
)
application.opts = opts

View file

@ -403,6 +403,10 @@ class BaseSaltAPIHandler(salt.ext.tornado.web.RequestHandler): # pylint: disabl
("application/x-yaml", salt.utils.yaml.safe_dump),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._auto_finish = False
def _verify_client(self, low):
"""
Verify that the client is in fact one we have
@ -502,6 +506,11 @@ class BaseSaltAPIHandler(salt.ext.tornado.web.RequestHandler): # pylint: disabl
# TODO: set a header or something??? so we know it was a timeout
self.application.event_listener.clean_by_request(self)
def finish(self):
import traceback
log.error("FINISH CALLED: %s", "\n".join(traceback.format_stack()))
super().finish()
def on_finish(self):
"""
When the job has been done, lets cleanup
@ -659,6 +668,7 @@ class SaltAuthHandler(BaseSaltAPIHandler): # pylint: disable=W0223
ret = {"status": "401 Unauthorized", "return": "Please log in"}
self.write(self.serialize(ret))
self.finish()
# TODO: make asynchronous? Underlying library isn't... and we ARE making disk calls :(
def post(self): # pylint: disable=arguments-differ
@ -785,6 +795,7 @@ class SaltAuthHandler(BaseSaltAPIHandler): # pylint: disable=W0223
}
self.write(self.serialize(ret))
self.finish()
class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
@ -828,6 +839,7 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
"""
ret = {"clients": list(self.saltclients.keys()), "return": "Welcome"}
self.write(self.serialize(ret))
self.finish()
@salt.ext.tornado.gen.coroutine
def post(self): # pylint: disable=arguments-differ
@ -912,6 +924,7 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
"""
Disbatch all lowstates to the appropriate clients
"""
log.error("BEGIN DISBATCH")
ret = []
# check clients before going, we want to throw 400 if one is bad
@ -947,8 +960,10 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
try:
self.write(self.serialize({"return": ret}))
self.finish()
except RuntimeError:
except RuntimeError as exc:
log.exception("DISBATCH RUNTIME ERROR")
pass # Do we need any logging here?
log.error("END DISBATCH")
@salt.ext.tornado.gen.coroutine
def get_minion_returns(
@ -1416,14 +1431,17 @@ class JobsSaltAPIHandler(SaltAPIHandler): # pylint: disable=W0223
"""
# if you aren't authenticated, redirect to login
if not self._verify_auth():
log.error("AUTH ERROR")
self.redirect("/login")
return
log.error("LOWSTATE")
if jid:
self.lowstate = [{"fun": "jobs.list_job", "jid": jid, "client": "runner"}]
else:
self.lowstate = [{"fun": "jobs.list_jobs", "client": "runner"}]
log.error("DISBATCH")
self.disbatch()
@ -1790,6 +1808,7 @@ class WebhookSaltAPIHandler(SaltAPIHandler): # pylint: disable=W0223
)
self.write(self.serialize({"success": ret}))
self.finish()
def _check_cors_origin(origin, allowed_origins):

View file

@ -313,26 +313,28 @@ class AllEventsHandler(
"""
# pylint: disable=W0221
#@salt.ext.tornado.gen.coroutine
def get(self, token):
"""
Check the token, returns a 401 if the token is invalid.
Else open the websocket connection
"""
log.debug("In the websocket get method")
log.error("In the websocket get method")
self.token = token
# close the connection, if not authenticated
if not self.application.auth.get_tok(token):
log.debug("Refusing websocket connection, bad token!")
self.send_error(401)
return
super().get(token)
log.error("In the websocket get method - get")
return super().get(token)
def open(self, token): # pylint: disable=W0221
"""
Return a websocket connection to Salt
representing Salt's "real time" event stream.
"""
log.error("Open websocket")
self.connected = False
@salt.ext.tornado.gen.coroutine
@ -343,7 +345,7 @@ class AllEventsHandler(
These messages make up salt's
"real time" event stream.
"""
log.debug("Got websocket message %s", message)
log.error("Got websocket message %s", message)
if message == "websocket client ready":
if self.connected:
# TBD: Add ability to run commands in this branch
@ -370,7 +372,7 @@ class AllEventsHandler(
def on_close(self, *args, **kwargs):
"""Cleanup."""
log.debug("In the websocket close method")
log.error("In the websocket close method")
self.close()
def check_origin(self, origin):
@ -395,7 +397,7 @@ class FormattedEventsHandler(AllEventsHandler): # pylint: disable=W0223,W0232
These messages make up salt's
"real time" event stream.
"""
log.debug("Got websocket message %s", message)
log.error("Got websocket message %s", message)
if message == "websocket client ready":
if self.connected:
# TBD: Add ability to run commands in this branch

View file

@ -27,6 +27,7 @@ class StubHandler(saltnado.BaseSaltAPIHandler): # pylint: disable=abstract-meth
ret_dict[attr] = getattr(self, attr)
self.write(self.serialize(ret_dict))
self.finish()
@pytest.fixture
@ -37,7 +38,7 @@ def app_urls():
]
async def test_accept_content_type(http_client, content_type_map, subtests):
async def test_accept_content_type(http_client, content_type_map, subtests, io_loop):
"""
Test the base handler's accept picking
"""

View file

@ -1,4 +1,5 @@
import urllib.parse
import salt.ext.tornado
import pytest
@ -28,6 +29,7 @@ async def test_hook_can_handle_get_parameters(http_client, app, content_type_map
)
assert response.code == 200
host = urllib.parse.urlparse(response.effective_url).netloc
print(event.fire_event.calls)
event.fire_event.assert_called_once_with(
{
"headers": {
@ -36,7 +38,7 @@ async def test_hook_can_handle_get_parameters(http_client, app, content_type_map
"Content-Type": "application/json",
"Host": host,
"Accept-Encoding": "gzip",
"User-Agent": "Tornado/6.1",
"User-Agent": f"Tornado/{salt.ext.tornado.version}",
},
"post": {},
"get": {"param": ["1", "2"]},

View file

@ -16,7 +16,7 @@ pytestmark = [
@pytest.fixture
def app(client_config):
def app(client_config, io_loop):
client_config.setdefault("rest_tornado", {})["websockets"] = True
return rest_tornado.get_application(client_config)
@ -27,7 +27,7 @@ def http_server_port(http_server):
async def test_websocket_handler_upgrade_to_websocket(
http_client, auth_creds, content_type_map, http_server_port
http_client, auth_creds, content_type_map, http_server_port, io_loop,
):
response = await http_client.fetch(
"/login",
@ -41,12 +41,12 @@ async def test_websocket_handler_upgrade_to_websocket(
request = HTTPRequest(
url, headers={"Origin": "http://example.com", "Host": "example.com"}
)
ws = await websocket_connect(request)
ws.write_message("websocket client ready")
ws = await websocket_connect(request, connect_timeout=None)
await ws.write_message("websocket client ready")
ws.close()
async def test_websocket_handler_bad_token(client_config, http_server):
async def test_websocket_handler_bad_token(client_config, http_server, io_loop):
"""
A bad token should returns a 401 during a websocket connect
"""
@ -64,7 +64,7 @@ async def test_websocket_handler_bad_token(client_config, http_server):
async def test_websocket_handler_cors_origin_wildcard(
app, http_client, auth_creds, content_type_map, http_server_port
app, http_client, auth_creds, content_type_map, http_server_port, io_loop
):
app.mod_opts["cors_origin"] = "*"
response = await http_client.fetch(
@ -85,7 +85,7 @@ async def test_websocket_handler_cors_origin_wildcard(
async def test_cors_origin_single(
app, http_client, auth_creds, content_type_map, http_server_port
app, http_client, auth_creds, content_type_map, http_server_port, io_loop
):
app.mod_opts["cors_origin"] = "http://example.com"
response = await http_client.fetch(
@ -116,7 +116,7 @@ async def test_cors_origin_single(
async def test_cors_origin_multiple(
app, http_client, auth_creds, content_type_map, http_server_port
app, http_client, auth_creds, content_type_map, http_server_port, io_loop
):
app.mod_opts["cors_origin"] = ["http://example.com", "http://foo.bar"]