Black lint all the things

This commit is contained in:
Curtis Castrapel
2019-05-16 07:57:02 -07:00
parent 3680d523d4
commit 68fd1556b2
226 changed files with 9340 additions and 5940 deletions

View File

@ -14,7 +14,14 @@ from lemur.notifications.messaging import send_expiration_notifications
manager = Manager(usage="Handles notification related tasks.")
@manager.option('-e', '--exclude', dest='exclude', action='append', default=[], help='Common name matching of certificates that should be excluded from notification')
@manager.option(
"-e",
"--exclude",
dest="exclude",
action="append",
default=[],
help="Common name matching of certificates that should be excluded from notification",
)
def expirations(exclude):
"""
Runs Lemur's notification engine, that looks for expired certificates and sends
@ -33,12 +40,13 @@ def expirations(exclude):
success, failed = send_expiration_notifications(exclude)
print(
"Finished notifying subscribers about expiring certificates! Sent: {success} Failed: {failed}".format(
success=success,
failed=failed
success=success, failed=failed
)
)
status = SUCCESS_METRIC_STATUS
except Exception as e:
sentry.captureException()
metrics.send('expiration_notification_job', 'counter', 1, metric_tags={'status': status})
metrics.send(
"expiration_notification_job", "counter", 1, metric_tags={"status": status}
)

View File

@ -36,15 +36,17 @@ def get_certificates(exclude=None):
now = arrow.utcnow()
max = now + timedelta(days=90)
q = database.db.session.query(Certificate) \
.filter(Certificate.not_after <= max) \
.filter(Certificate.notify == True) \
.filter(Certificate.expired == False) # noqa
q = (
database.db.session.query(Certificate)
.filter(Certificate.not_after <= max)
.filter(Certificate.notify == True)
.filter(Certificate.expired == False)
) # noqa
exclude_conditions = []
if exclude:
for e in exclude:
exclude_conditions.append(~Certificate.name.ilike('%{}%'.format(e)))
exclude_conditions.append(~Certificate.name.ilike("%{}%".format(e)))
q = q.filter(and_(*exclude_conditions))
@ -101,7 +103,12 @@ def send_notification(event_type, data, targets, notification):
except Exception as e:
sentry.captureException()
metrics.send('notification', 'counter', 1, metric_tags={'status': status, 'event_type': event_type})
metrics.send(
"notification",
"counter",
1,
metric_tags={"status": status, "event_type": event_type},
)
if status == SUCCESS_METRIC_STATUS:
return True
@ -115,7 +122,7 @@ def send_expiration_notifications(exclude):
success = failure = 0
# security team gets all
security_email = current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')
security_email = current_app.config.get("LEMUR_SECURITY_TEAM_EMAIL")
security_data = []
for owner, notification_group in get_eligible_certificates(exclude=exclude).items():
@ -127,26 +134,43 @@ def send_expiration_notifications(exclude):
for data in certificates:
n, certificate = data
cert_data = certificate_notification_output_schema.dump(certificate).data
cert_data = certificate_notification_output_schema.dump(
certificate
).data
notification_data.append(cert_data)
security_data.append(cert_data)
notification_recipient = get_plugin_option('recipients', notification.options)
notification_recipient = get_plugin_option(
"recipients", notification.options
)
if notification_recipient:
notification_recipient = notification_recipient.split(",")
if send_notification('expiration', notification_data, [owner], notification):
if send_notification(
"expiration", notification_data, [owner], notification
):
success += 1
else:
failure += 1
if notification_recipient and owner != notification_recipient and security_email != notification_recipient:
if send_notification('expiration', notification_data, notification_recipient, notification):
if (
notification_recipient
and owner != notification_recipient
and security_email != notification_recipient
):
if send_notification(
"expiration",
notification_data,
notification_recipient,
notification,
):
success += 1
else:
failure += 1
if send_notification('expiration', security_data, security_email, notification):
if send_notification(
"expiration", security_data, security_email, notification
):
success += 1
else:
failure += 1
@ -165,24 +189,35 @@ def send_rotation_notification(certificate, notification_plugin=None):
"""
status = FAILURE_METRIC_STATUS
if not notification_plugin:
notification_plugin = plugins.get(current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN'))
notification_plugin = plugins.get(
current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN")
)
data = certificate_notification_output_schema.dump(certificate).data
try:
notification_plugin.send('rotation', data, [data['owner']])
notification_plugin.send("rotation", data, [data["owner"]])
status = SUCCESS_METRIC_STATUS
except Exception as e:
current_app.logger.error('Unable to send notification to {}.'.format(data['owner']), exc_info=True)
current_app.logger.error(
"Unable to send notification to {}.".format(data["owner"]), exc_info=True
)
sentry.captureException()
metrics.send('notification', 'counter', 1, metric_tags={'status': status, 'event_type': 'rotation'})
metrics.send(
"notification",
"counter",
1,
metric_tags={"status": status, "event_type": "rotation"},
)
if status == SUCCESS_METRIC_STATUS:
return True
def send_pending_failure_notification(pending_cert, notify_owner=True, notify_security=True, notification_plugin=None):
def send_pending_failure_notification(
pending_cert, notify_owner=True, notify_security=True, notification_plugin=None
):
"""
Sends a report to certificate owners when their pending certificate failed to be created.
@ -194,32 +229,47 @@ def send_pending_failure_notification(pending_cert, notify_owner=True, notify_se
if not notification_plugin:
notification_plugin = plugins.get(
current_app.config.get('LEMUR_DEFAULT_NOTIFICATION_PLUGIN', 'email-notification')
current_app.config.get(
"LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification"
)
)
data = pending_certificate_output_schema.dump(pending_cert).data
data["security_email"] = current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')
data["security_email"] = current_app.config.get("LEMUR_SECURITY_TEAM_EMAIL")
if notify_owner:
try:
notification_plugin.send('failed', data, [data['owner']], pending_cert)
notification_plugin.send("failed", data, [data["owner"]], pending_cert)
status = SUCCESS_METRIC_STATUS
except Exception as e:
current_app.logger.error('Unable to send pending failure notification to {}.'.format(data['owner']),
exc_info=True)
current_app.logger.error(
"Unable to send pending failure notification to {}.".format(
data["owner"]
),
exc_info=True,
)
sentry.captureException()
if notify_security:
try:
notification_plugin.send('failed', data, data["security_email"], pending_cert)
notification_plugin.send(
"failed", data, data["security_email"], pending_cert
)
status = SUCCESS_METRIC_STATUS
except Exception as e:
current_app.logger.error('Unable to send pending failure notification to '
'{}.'.format(data['security_email']),
exc_info=True)
current_app.logger.error(
"Unable to send pending failure notification to "
"{}.".format(data["security_email"]),
exc_info=True,
)
sentry.captureException()
metrics.send('notification', 'counter', 1, metric_tags={'status': status, 'event_type': 'rotation'})
metrics.send(
"notification",
"counter",
1,
metric_tags={"status": status, "event_type": "rotation"},
)
if status == SUCCESS_METRIC_STATUS:
return True
@ -242,20 +292,22 @@ def needs_notification(certificate):
if not notification.active or not notification.options:
return
interval = get_plugin_option('interval', notification.options)
unit = get_plugin_option('unit', notification.options)
interval = get_plugin_option("interval", notification.options)
unit = get_plugin_option("unit", notification.options)
if unit == 'weeks':
if unit == "weeks":
interval *= 7
elif unit == 'months':
elif unit == "months":
interval *= 30
elif unit == 'days': # it's nice to be explicit about the base unit
elif unit == "days": # it's nice to be explicit about the base unit
pass
else:
raise Exception("Invalid base unit for expiration interval: {0}".format(unit))
raise Exception(
"Invalid base unit for expiration interval: {0}".format(unit)
)
if days == interval:
notifications.append(notification)

View File

@ -11,12 +11,14 @@ from sqlalchemy_utils import JSONType
from lemur.database import db
from lemur.plugins.base import plugins
from lemur.models import certificate_notification_associations, \
pending_cert_notification_associations
from lemur.models import (
certificate_notification_associations,
pending_cert_notification_associations,
)
class Notification(db.Model):
__tablename__ = 'notifications'
__tablename__ = "notifications"
id = Column(Integer, primary_key=True)
label = Column(String(128), unique=True)
description = Column(Text())
@ -28,14 +30,14 @@ class Notification(db.Model):
secondary=certificate_notification_associations,
passive_deletes=True,
backref="notification",
cascade='all,delete'
cascade="all,delete",
)
pending_certificates = relationship(
"PendingCertificate",
secondary=pending_cert_notification_associations,
passive_deletes=True,
backref="notification",
cascade='all,delete'
cascade="all,delete",
)
@property

View File

@ -7,7 +7,11 @@
"""
from marshmallow import fields, post_dump
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.schemas import PluginInputSchema, PluginOutputSchema, AssociatedCertificateSchema
from lemur.schemas import (
PluginInputSchema,
PluginOutputSchema,
AssociatedCertificateSchema,
)
class NotificationInputSchema(LemurInputSchema):
@ -30,7 +34,7 @@ class NotificationOutputSchema(LemurOutputSchema):
@post_dump
def fill_object(self, data):
if data:
data['plugin']['pluginOptions'] = data['options']
data["plugin"]["pluginOptions"] = data["options"]
return data

View File

@ -31,26 +31,28 @@ def create_default_expiration_notifications(name, recipients, intervals=None):
options = [
{
'name': 'unit',
'type': 'select',
'required': True,
'validation': '',
'available': ['days', 'weeks', 'months'],
'helpMessage': 'Interval unit',
'value': 'days',
"name": "unit",
"type": "select",
"required": True,
"validation": "",
"available": ["days", "weeks", "months"],
"helpMessage": "Interval unit",
"value": "days",
},
{
'name': 'recipients',
'type': 'str',
'required': True,
'validation': '^([\w+-.%]+@[\w-.]+\.[A-Za-z]{2,4},?)+$',
'helpMessage': 'Comma delimited list of email addresses',
'value': ','.join(recipients)
"name": "recipients",
"type": "str",
"required": True,
"validation": "^([\w+-.%]+@[\w-.]+\.[A-Za-z]{2,4},?)+$",
"helpMessage": "Comma delimited list of email addresses",
"value": ",".join(recipients),
},
]
if intervals is None:
intervals = current_app.config.get("LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS", [30, 15, 2])
intervals = current_app.config.get(
"LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS", [30, 15, 2]
)
notifications = []
for i in intervals:
@ -58,21 +60,25 @@ def create_default_expiration_notifications(name, recipients, intervals=None):
if not n:
inter = [
{
'name': 'interval',
'type': 'int',
'required': True,
'validation': '^\d+$',
'helpMessage': 'Number of days to be alert before expiration.',
'value': i,
"name": "interval",
"type": "int",
"required": True,
"validation": "^\d+$",
"helpMessage": "Number of days to be alert before expiration.",
"value": i,
}
]
inter.extend(options)
n = create(
label="{name}_{interval}_DAY".format(name=name, interval=i),
plugin_name=current_app.config.get("LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification"),
plugin_name=current_app.config.get(
"LEMUR_DEFAULT_NOTIFICATION_PLUGIN", "email-notification"
),
options=list(inter),
description="Default {interval} day expiration notification".format(interval=i),
certificates=[]
description="Default {interval} day expiration notification".format(
interval=i
),
certificates=[],
)
notifications.append(n)
@ -91,7 +97,9 @@ def create(label, plugin_name, options, description, certificates):
:rtype : Notification
:return:
"""
notification = Notification(label=label, options=options, plugin_name=plugin_name, description=description)
notification = Notification(
label=label, options=options, plugin_name=plugin_name, description=description
)
notification.certificates = certificates
return database.create(notification)
@ -147,7 +155,7 @@ def get_by_label(label):
:param label:
:return:
"""
return database.get(Notification, label, field='label')
return database.get(Notification, label, field="label")
def get_all():
@ -161,18 +169,20 @@ def get_all():
def render(args):
filt = args.pop('filter')
certificate_id = args.pop('certificate_id', None)
filt = args.pop("filter")
certificate_id = args.pop("certificate_id", None)
if certificate_id:
query = database.session_query(Notification).join(Certificate, Notification.certificate)
query = database.session_query(Notification).join(
Certificate, Notification.certificate
)
query = query.filter(Certificate.id == certificate_id)
else:
query = database.session_query(Notification)
if filt:
terms = filt.split(';')
if terms[0] == 'active':
terms = filt.split(";")
if terms[0] == "active":
query = query.filter(Notification.active == truthiness(terms[1]))
else:
query = database.filter(query, Notification, terms)

View File

@ -9,7 +9,11 @@
from flask import Blueprint
from flask_restful import Api, reqparse, inputs
from lemur.notifications import service
from lemur.notifications.schemas import notification_input_schema, notification_output_schema, notifications_output_schema
from lemur.notifications.schemas import (
notification_input_schema,
notification_output_schema,
notifications_output_schema,
)
from lemur.auth.service import AuthenticatedResource
from lemur.common.utils import paginated_parser
@ -17,12 +21,13 @@ from lemur.common.utils import paginated_parser
from lemur.common.schema import validate_schema
mod = Blueprint('notifications', __name__)
mod = Blueprint("notifications", __name__)
api = Api(mod)
class NotificationsList(AuthenticatedResource):
""" Defines the 'notifications' endpoint """
def __init__(self):
self.reqparse = reqparse.RequestParser()
super(NotificationsList, self).__init__()
@ -103,7 +108,7 @@ class NotificationsList(AuthenticatedResource):
:statuscode 200: no error
"""
parser = paginated_parser.copy()
parser.add_argument('active', type=inputs.boolean, location='args')
parser.add_argument("active", type=inputs.boolean, location="args")
args = parser.parse_args()
return service.render(args)
@ -215,11 +220,11 @@ class NotificationsList(AuthenticatedResource):
:statuscode 200: no error
"""
return service.create(
data['label'],
data['plugin']['slug'],
data['plugin']['plugin_options'],
data['description'],
data['certificates']
data["label"],
data["plugin"]["slug"],
data["plugin"]["plugin_options"],
data["description"],
data["certificates"],
)
@ -334,20 +339,21 @@ class Notifications(AuthenticatedResource):
"""
return service.update(
notification_id,
data['label'],
data['plugin']['plugin_options'],
data['description'],
data['active'],
data['certificates']
data["label"],
data["plugin"]["plugin_options"],
data["description"],
data["active"],
data["certificates"],
)
def delete(self, notification_id):
service.delete(notification_id)
return {'result': True}
return {"result": True}
class CertificateNotifications(AuthenticatedResource):
""" Defines the 'certificate/<int:certificate_id/notifications'' endpoint """
def __init__(self):
super(CertificateNotifications, self).__init__()
@ -426,10 +432,15 @@ class CertificateNotifications(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error
"""
return service.render({'certificate_id': certificate_id})
return service.render({"certificate_id": certificate_id})
api.add_resource(NotificationsList, '/notifications', endpoint='notifications')
api.add_resource(Notifications, '/notifications/<int:notification_id>', endpoint='notification')
api.add_resource(CertificateNotifications, '/certificates/<int:certificate_id>/notifications',
endpoint='certificateNotifications')
api.add_resource(NotificationsList, "/notifications", endpoint="notifications")
api.add_resource(
Notifications, "/notifications/<int:notification_id>", endpoint="notification"
)
api.add_resource(
CertificateNotifications,
"/certificates/<int:certificate_id>/notifications",
endpoint="certificateNotifications",
)