...
 
Commits (2)
config.py
.pytest_cache/
.mypy_cache/
.python-version
# IDE Files #
#############
......
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
yapf = "*"
flake8 = "*"
bandit = "*"
black = "*"
pycodestyle = "*"
pydocstyle = "*"
pylint = "*"
mypy = "*"
pytest = "*"
[packages]
pandas = ">=0.19.2"
requests = "*"
redis = "*"
pytest = "*"
coverage = "*"
Flask = "*"
XlsxWriter = "*"
[requires]
python_version = "3.7"
......@@ -16,6 +16,9 @@ Use of a password manager with a CLI tool (1Password) is recommended for develop
`REDIS_HOST`: The URL of your Redis host. Redis is used to cache organization names and speed up certain reports. If you are using the Docker image provided, a local Redis server is available. Otherwise you must run redis-server locally or connect to an external instance.
## Optional Variables:
`INSECURE_SSL`: Defaults to False. Set value to `True` if you want to make GET and POST requests without verifying SSL certificates. Certain SL1 development environments will require this to function. DO NOT SET THIS IN PRODUCTION!
# How to run
Linux:
```shell
......@@ -60,4 +63,7 @@ docker container run \
--env PASS=$(op get item em7admin_password | jq '.details.fields[] | select(.designation=="password").value') \
--env REDIS_HOST="localhost" \
sl1ther:latest
```
\ No newline at end of file
```
# Security
Please note that the app is currently written to run without a WSGI server. This is not intended for production environments and a server such as [Green Unicorn](https://gunicorn.org/) is recommended for a secure, production-ready deployment. SL1ther should only be used in its current form a secure development environment.
\ No newline at end of file
......@@ -9,6 +9,9 @@ exclude =
__pycache__
max-line-length = 119
[pycodestyle]
max-line-length = 119
[metadata]
description-file = README.md
from setuptools import setup, find_packages
setup(name='sl1ther',
version='0.8.0',
version='0.8.1',
description='ScienceLogic Python wrapper, extending the EM7/SL1 API.',
url='https://gitlab.com/saxmanmike/slither',
author='Michael Gray',
......
This diff is collapsed.
"""SL1ther, for ScienceLogic SL1 stacks."""
import json
import os
from sys import stderr
......@@ -9,12 +11,19 @@ import redis
import requests
app = Flask(__name__)
__version__ = "0.8.0"
app.config["BASE"] = os.getenv("BASE") + "/api"
app.config["USER"] = os.getenv("USER")
app.config["PASS"] = os.getenv("PASS")
app.config["REDIS_HOST"] = os.getenv("REDIS_HOST")
__version__ = "0.8.1"
if os.getenv("BASE"):
app.config["BASE"] = str(os.getenv("BASE")) + "/api"
if os.getenv("USER"):
app.config["USER"] = os.getenv("USER")
if os.getenv("PASS"):
app.config["PASS"] = os.getenv("PASS")
if os.getenv("REDIS_HOST"):
app.config["REDIS_HOST"] = os.getenv("REDIS_HOST")
app.config["INSECURE_SSL"] = False
if os.getenv("INSECURE_SSL") == "True":
app.config["INSECURE_SSL"] = True
if app.config["BASE"] is None:
print(
......@@ -44,11 +53,13 @@ except Exception as e: # TODO: Specific exception
@app.route("/")
def index():
"""View the home page."""
return render_template("index.html", version=__version__)
@app.route("/sku", methods=["GET", "POST"])
def assign_sku():
"""Assign a SKU to one or more devices."""
if request.method == "POST":
sku = request.form.get("sku")
dids = request.form["dids"].split(",")
......@@ -68,6 +79,7 @@ def assign_sku():
def devgroup_report(USER=app.config["USER"],
PASS=app.config["PASS"],
base=app.config["BASE"]):
"""Generate a device group report."""
if request.method == "POST":
try:
username = request.form.get("username")
......@@ -86,7 +98,7 @@ def devgroup_report(USER=app.config["USER"],
except requests.exceptions.RequestException as e:
return e
r = requests.get(base + "/device_group?limit=1000", auth=(USER, PASS), verify=False)
r = requests.get(base + "/device_group?limit=1000", auth=(USER, PASS), verify=app.config["INSECURE_SSL"])
data = []
for dev in r.json()["result_set"]:
data.append({dev["URI"].strip("/api/device_group/"): dev["description"]})
......@@ -96,6 +108,7 @@ def devgroup_report(USER=app.config["USER"],
@app.route("/empty_skus", methods=["GET", "POST"])
def empty_sku_page():
"""Get a list of devices that don't have a custom attribute called SKU."""
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
......@@ -111,6 +124,7 @@ def empty_sku_page():
@app.route("/event_id", methods=["GET", "POST"])
def event_page():
"""Get information on an event based on its event ID."""
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
......@@ -129,6 +143,7 @@ def event_page():
@app.route("/add_notes", methods=["GET", "POST"])
def add_notes_page():
"""Add a note to one or more devices by DID."""
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
......@@ -146,6 +161,7 @@ def add_notes_page():
@app.route("/see_notes", methods=["GET", "POST"])
def see_notes_page():
"""See all notes on one or more devices."""
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
......@@ -162,6 +178,7 @@ def see_notes_page():
@app.route("/cidr", methods=["GET", "POST"])
def view_cidr():
"""Rapidly strip 1-3 octets and add a subnet mask, returning CIDR notation."""
if request.method == "POST":
ips = request.form.get("ips").split("\r\n")
subnet = request.form.get("subnet")
......@@ -178,6 +195,7 @@ def view_cidr():
@app.route("/extractor", methods=["GET", "POST"])
def view_ip():
"""Pull IP addresses out of a large block of text."""
if request.method == "POST":
raw_text = request.form.get("raw_text")
results = functions.ip_extractor(raw_text)
......@@ -187,6 +205,7 @@ def view_ip():
@app.route("/serial", methods=["POST", "GET"])
def serial_report():
"""Generate a list of devices and their serial numbers, if they have them."""
if request.method == "POST":
company = request.form.get("company")
username = request.form.get("username")
......@@ -205,6 +224,7 @@ def serial_report():
@app.errorhandler(500)
def server_error(e):
"""Handle HTTP 500 errors."""
print("An error occurred during a request.", file=stderr)
return (
"""
......@@ -215,10 +235,11 @@ def server_error(e):
@app.errorhandler(404)
def not_found(e):
"""It's me, 404."""
print("Page not found.", file=stderr)
return render_template("404.html"), 404
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=False, threaded=True)
app.run(port=5000, debug=False, threaded=True)
# [END app]