Skip to content

Commit

Permalink
int: error mgmt (#105)
Browse files Browse the repository at this point in the history
intercept requests before token expire
  • Loading branch information
mattLLVW committed Dec 10, 2019
1 parent f2cd0bc commit 93e821b
Show file tree
Hide file tree
Showing 26 changed files with 181 additions and 99 deletions.
11 changes: 8 additions & 3 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
[run]
omit =
config/ldap_config.py
config/settings.py
config/wsgi.py
api/apps.py
api/permissions.py
api/migrations/*
tests/*
api/pyapi.py
config/wsgi.py
manage.py
api/utils/output/*
tests/*
manage.py
setup.py
bin/__init__.py
[report]
exclude_lines =
pragma: no cover
except PepperException as e:
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# These are supported funding model platforms

github: mattLLVW
130 changes: 79 additions & 51 deletions api/backend/netapi.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import os
import json
from urllib.error import URLError

import urllib3

from django.contrib.auth.models import User
from pepper import Pepper
from pepper import Pepper, PepperException
from django_currentuser.middleware import get_current_user

from ..utils.input import RawCommand
Expand All @@ -15,21 +17,20 @@


def api_connect():
# TODO fix this!
user = get_current_user()
api = Pepper(url, ignore_ssl_errors=True)
login_ret = api.login(
str(user.username),
user.user_settings.token,
os.environ.get("SALT_AUTH", "alcali"),
)
try:
login_ret = api.login(
str(user.username),
user.user_settings.token,
os.environ.get("SALT_AUTH", "alcali"),
)
except URLError:
raise PepperException("URL Error")
user.user_settings.salt_permissions = json.dumps(login_ret["perms"])
user.save()
return api

# except (PepperException, ConnectionRefusedError, URLError) as e:
# print("Can't connect to {url}: {e}".format(url=url, e=e))


def get_keys(refresh=False):
if refresh:
Expand All @@ -41,8 +42,11 @@ def get_keys(refresh=False):
"minions": "accepted",
}

api = api_connect()
api_ret = api.wheel("key.list_all")["return"][0]["data"]["return"]
try:
api = api_connect()
api_ret = api.wheel("key.list_all")["return"][0]["data"]["return"]
except PepperException as e:
return {"error": str(e)}

Keys.objects.all().delete()
for key, value in minion_status.items():
Expand All @@ -58,12 +62,15 @@ def get_keys(refresh=False):
pass
# LOG CREATED

return Keys.objects.all()
return {"result": "refreshed"}


def refresh_minion(minion_id):
api = api_connect()
grain = api.local(minion_id, "grains.items")
try:
api = api_connect()
grain = api.local(minion_id, "grains.items")
except PepperException as e:
return {"error": str(e)}
grain = grain["return"][0]
# TODO: return smt useful, better error mgmt.
if grain.get(minion_id):
Expand All @@ -82,17 +89,23 @@ def refresh_minion(minion_id):
for field in minion_fields:
command = RawCommand("salt {} {}".format(minion_id, field["function"]))
custom_field_return = run_raw(command.parse())
if "error" in custom_field_return:
return custom_field_return
MinionsCustomFields.objects.update_or_create(
name=field["name"],
function=field["function"],
minion=Minions.objects.get(minion_id=minion_id),
defaults={"value": json.dumps(custom_field_return[minion_id])},
)
return {"result": "{} refreshed".format(minion_id)}


def run_raw(load):
api = api_connect()
api_ret = api.low(load)
try:
api = api_connect()
api_ret = api.low(load)
except PepperException as e:
return {"error": str(e)}
api_ret = api_ret["return"][0]
return api_ret

Expand All @@ -111,51 +124,60 @@ def get_events():


def init_db(target):
api = api_connect()
# Modules.
modules_func = api.local(target, "sys.list_functions")
modules_func = modules_func["return"][0][target]
try:
api = api_connect()
# Modules.
modules_func = api.local(target, "sys.list_functions")
modules_func = modules_func["return"][0][target]

modules_doc = api.local(target, "sys.doc")
modules_doc = api.local(target, "sys.doc")

for func in modules_func:
desc = modules_doc["return"][0][target][func]
for func in modules_func:
desc = modules_doc["return"][0][target][func]

Functions.objects.update_or_create(
name=func, type="local", description=desc or ""
)
# Runner.
# TODO: Factorize.
runner_func = api.local(target, "sys.list_runner_functions")
runner_func = runner_func["return"][0][target]
Functions.objects.update_or_create(
name=func, type="local", description=desc or ""
)
# Runner.
# TODO: Factorize.
runner_func = api.local(target, "sys.list_runner_functions")
runner_func = runner_func["return"][0][target]

runner_doc = api.local(target, "sys.runner_doc")
runner_doc = api.local(target, "sys.runner_doc")

for func in runner_func:
desc = runner_doc["return"][0][target][func]
for func in runner_func:
desc = runner_doc["return"][0][target][func]

Functions.objects.update_or_create(
name=func, type="runner", description=desc or ""
)
wheel_docs = api.runner("doc.wheel")
wheel_docs = wheel_docs["return"][0]
for fun, doc in wheel_docs.items():
Functions.objects.update_or_create(
name=fun, type="wheel", description=doc or ""
)
return {"something": "useful"}
Functions.objects.update_or_create(
name=func, type="runner", description=desc or ""
)
wheel_docs = api.runner("doc.wheel")
wheel_docs = wheel_docs["return"][0]
for fun, doc in wheel_docs.items():
Functions.objects.update_or_create(
name=fun, type="wheel", description=doc or ""
)
except PepperException as e:
return {"error": str(e)}
return {"result": "refreshed modules using {}".format(target)}


def manage_key(action, target, kwargs):
api = api_connect()
response = api.wheel("key.{}".format(action), match=target, **kwargs)
try:
api = api_connect()
response = api.wheel("key.{}".format(action), match=target, **kwargs)
except PepperException as e:
return {"error": str(e)}
return response


def refresh_schedules(minion=None):
minion = minion or "*"
api = api_connect()
api_ret = api.local(minion, "schedule.list", kwarg={"return_yaml": False})
try:
api = api_connect()
api_ret = api.local(minion, "schedule.list", kwarg={"return_yaml": False})
except PepperException as e:
return {"error": str(e)}
for minion_id in api_ret["return"][0]:
# TODO: error mgmt
minion_jobs = api_ret["return"][0][minion_id]
Expand All @@ -171,8 +193,11 @@ def refresh_schedules(minion=None):


def manage_schedules(action, name, minion):
api = api_connect()
api_ret = api.local(minion, "schedule.{}".format(action), arg=name)
try:
api = api_connect()
api_ret = api.local(minion, "schedule.{}".format(action), arg=name)
except PepperException as e:
return {"error": str(e)}
for target in api_ret["return"][0]:
# If action was successful.
if api_ret["return"][0][target]["result"]:
Expand All @@ -183,7 +208,9 @@ def manage_schedules(action, name, minion):
schedule = Schedule.objects.filter(minion=minion, name=name).get()
except Schedule.DoesNotExist:
# Retry after refreshing schedules for this minion.
refresh_schedules(minion)
ret = refresh_schedules(minion)
if "error" in ret:
return ret
try:
schedule = Schedule.objects.filter(
minion=minion, name=name
Expand All @@ -197,3 +224,4 @@ def manage_schedules(action, name, minion):
loaded_job["enabled"] = False
schedule.job = json.dumps(loaded_job)
schedule.save()
return {"result": "ok"}
1 change: 1 addition & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,5 @@ def validate(self, attrs):
data["username"] = self.user.username
data["id"] = self.user.id
data["email"] = self.user.email
data["is_staff"] = self.user.is_staff
return data
39 changes: 30 additions & 9 deletions api/views/alcali.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ class KeysViewSet(viewsets.ReadOnlyModelViewSet):

@action(methods=["POST"], detail=False)
def refresh(self, request):
get_keys(refresh=True)
return Response({"result": "refreshed"})
ret = get_keys(refresh=True)
if "error" in ret:
return Response(ret["error"], status=401)
return Response(ret)

@action(detail=False)
def keys_status(self, request):
Expand All @@ -88,7 +90,9 @@ def manage_keys(self, request):
kwargs = {"include_rejected": True, "include_denied": True}
elif key_action == "reject":
kwargs = {"include_accepted": True, "include_denied": True}
manage_key(key_action, key, kwargs)
ret = manage_key(key_action, key, kwargs)
if "error" in ret:
return Response(ret["error"], status=401)
return Response({"result": "{} on {}: done".format(key_action, key)})


Expand All @@ -102,14 +106,19 @@ class MinionsViewSet(viewsets.ModelViewSet):
def refresh_minions(self, request):
if request.POST.get("minion_id"):
minion_id = request.POST.get("minion_id")
refresh_minion(minion_id)
ret = refresh_minion(minion_id)
if "error" in ret:
return Response(ret["error"], status=401)

return Response({"result": "refreshed {}".format(minion_id)})

accepted_minions = Keys.objects.filter(status="accepted").values_list(
"minion_id", flat=True
)
for minion in accepted_minions:
refresh_minion(minion)
ret = refresh_minion(minion)
if "error" in ret:
return Response(ret["error"], status=401)
return Response({"refreshed": [i for i in accepted_minions]})

@action(detail=False)
Expand Down Expand Up @@ -282,15 +291,21 @@ def list(self, request, *args, **kwargs):

@action(methods=["POST"], detail=False)
def refresh(self, request):
refresh_schedules()
ret = refresh_schedules()
if "error" in ret:
return Response(ret["error"], status=401)
return Response({"result": "refreshed"})

@action(methods=["POST"], detail=False)
def manage(self, request):
action = request.data.get("action")
minion = request.data.get("minion")
name = request.data.get("name")
manage_schedules(action, name, minion)
ret = manage_schedules(action, name, minion)
if not ret:
return Response({"result": "not good"})
if "error" in ret:
return Response(ret["error"], status=401)
return Response(
{"result": "schedule " + name + " on " + minion + " " + action + "d"}
)
Expand Down Expand Up @@ -353,8 +368,10 @@ def jobs_graph(request):
@api_view(["POST"])
def parse_modules(request):
if request.data.get("target"):
init_db(request.data.get("target"))
return Response({"result": "modules updated"})
ret = init_db(request.data.get("target"))
if "error" in ret:
return Response(ret["error"], status=401)
return Response(ret)


@api_view(["GET"])
Expand Down Expand Up @@ -443,6 +460,8 @@ def run(request):
cron = request.POST.get("cron")
schedule_parsed[0]["arg"].append("cron={}".format(cron))
ret = run_raw(schedule_parsed)
if "error" in ret:
return Response(ret["error"], status=401)
formatted = nested_output.output(ret)
conv = Ansi2HTMLConverter(inline=False, scheme="xterm")
html = conv.convert(formatted, ensure_trailing_newline=True)
Expand All @@ -451,6 +470,8 @@ def run(request):
cli_ret = request.POST.get("cli")
conv = Ansi2HTMLConverter(inline=False, scheme="xterm")
ret = run_raw(parsed_command)
if "error" in ret:
return Response(ret["error"], status=401)
formatted = "\n"

# Error.
Expand Down
2 changes: 1 addition & 1 deletion dist/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/static/favicon.ico><title>ALCALI</title><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"><link href="https://fonts.googleapis.com/css?family=Material+Icons" rel=stylesheet><link href=/static/css/app.7dd676e0.css rel=preload as=style><link href=/static/css/chunk-vendors.a6f43c83.css rel=preload as=style><link href=/static/js/app.6dcc5189.js rel=preload as=script><link href=/static/js/chunk-vendors.90ddc1f0.js rel=preload as=script><link href=/static/css/chunk-vendors.a6f43c83.css rel=stylesheet><link href=/static/css/app.7dd676e0.css rel=stylesheet></head><body><noscript><strong>We're sorry but my-app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-vendors.90ddc1f0.js></script><script src=/static/js/app.6dcc5189.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/static/favicon.ico><title>ALCALI</title><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"><link href="https://fonts.googleapis.com/css?family=Material+Icons" rel=stylesheet><link href=/static/css/app.b908910f.css rel=preload as=style><link href=/static/css/chunk-vendors.0c7ea4d3.css rel=preload as=style><link href=/static/js/app.d95ed552.js rel=preload as=script><link href=/static/js/chunk-vendors.90ddc1f0.js rel=preload as=script><link href=/static/css/chunk-vendors.0c7ea4d3.css rel=stylesheet><link href=/static/css/app.b908910f.css rel=stylesheet></head><body><noscript><strong>We're sorry but my-app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-vendors.90ddc1f0.js></script><script src=/static/js/app.d95ed552.js></script></body></html>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
2 changes: 0 additions & 2 deletions dist/static/js/app.6dcc5189.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/static/js/app.6dcc5189.js.map

This file was deleted.

2 changes: 2 additions & 0 deletions dist/static/js/app.d95ed552.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/static/js/app.d95ed552.js.map

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/components/CommonSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@
this.$toast(response.data.result)
}).then(() => {
this.loadData()
}).catch((error) => {
this.$toast.error(error.response.data)
})
},
deleteConformity(id) {
Expand Down
2 changes: 2 additions & 0 deletions src/components/KeysTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@
formData.set("target", key)
this.$http.post("api/keys/manage_keys/", formData).then(response => {
this.$toast(response.data.result)
}).catch((error) => {
this.$toast.error(error.response.data)
})
this.sleep(2000).then(() => {
this.loadData()
Expand Down
Loading

0 comments on commit 93e821b

Please sign in to comment.