Skip to content

Commit

Permalink
email notification + run one copy functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
gotlium committed Jun 12, 2014
1 parent 038478c commit e10a95f
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 7 deletions.
11 changes: 11 additions & 0 deletions demo/apps/test/management/commands/test_command_one.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__author__ = 'gotlium'

from time import sleep

from django.core.management.base import BaseCommand


class Command(BaseCommand):
def handle(self, *args, **options):
sleep(300)
print "OK"
2 changes: 2 additions & 0 deletions demo/demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
)

MANAGERS = ADMINS
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

DATABASES = {
'default': {
Expand Down Expand Up @@ -120,6 +121,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
# 'south',
'mmc',
'apps.test',
)
13 changes: 12 additions & 1 deletion mmc/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__author__ = 'gotlium'

from django.contrib import admin
from models import MMCLog, MMCScript, MMCHost
from models import MMCLog, MMCScript, MMCHost, MMCEmail


class MMCLogAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -54,6 +54,17 @@ def has_delete_permission(self, request, obj=None):
return False


class MMCEmailAdmin(admin.ModelAdmin):
list_display = ('email', 'is_active', 'created', 'id',)
list_filter = ('created', 'is_active',)
list_display_links = ('email',)

date_hierarchy = 'created'
ordering = ('-id',)
search_fields = ('email',)


admin.site.register(MMCLog, MMCLogAdmin)
admin.site.register(MMCHost, MMCBaseAdmin)
admin.site.register(MMCScript, MMCBaseAdmin)
admin.site.register(MMCEmail, MMCEmailAdmin)
12 changes: 12 additions & 0 deletions mmc/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# -*- encoding: utf-8 -*-

__author__ = 'gotlium'

from django.conf import settings


def get_settings(key, default):
return getattr(settings, key, default)


SUBJECT = get_settings('MMC_SUBJECT', '[MMC] Errors')
64 changes: 64 additions & 0 deletions mmc/migrations/0003_auto__add_mmcemail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models


class Migration(SchemaMigration):

def forwards(self, orm):
# Adding model 'MMCEmail'
db.create_table('mmc_mmcemail', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('created', self.gf('django.db.models.fields.DateField')(auto_now=True, blank=True)),
('email', self.gf('django.db.models.fields.EmailField')(max_length=75)),
('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)),
))
db.send_create_signal('mmc', ['MMCEmail'])


def backwards(self, orm):
# Deleting model 'MMCEmail'
db.delete_table('mmc_mmcemail')


models = {
'mmc.mmcemail': {
'Meta': {'object_name': 'MMCEmail'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'mmc.mmchost': {
'Meta': {'object_name': 'MMCHost'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ignore': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
},
'mmc.mmclog': {
'Meta': {'object_name': 'MMCLog'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'elapsed': ('django.db.models.fields.FloatField', [], {}),
'end': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'error_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'hostname': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mmc.MMCHost']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'script': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mmc.MMCScript']"}),
'start': ('django.db.models.fields.DateTimeField', [], {}),
'success': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'sys_argv': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'traceback': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'mmc.mmcscript': {
'Meta': {'object_name': 'MMCScript'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ignore': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
}
}

complete_apps = ['mmc']
61 changes: 61 additions & 0 deletions mmc/migrations/0004_auto__add_field_mmcscript_one_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models


class Migration(SchemaMigration):

def forwards(self, orm):
# Adding field 'MMCScript.one_copy'
db.add_column('mmc_mmcscript', 'one_copy',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)


def backwards(self, orm):
# Deleting field 'MMCScript.one_copy'
db.delete_column('mmc_mmcscript', 'one_copy')


models = {
'mmc.mmcemail': {
'Meta': {'object_name': 'MMCEmail'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'mmc.mmchost': {
'Meta': {'object_name': 'MMCHost'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ignore': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
},
'mmc.mmclog': {
'Meta': {'object_name': 'MMCLog'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'elapsed': ('django.db.models.fields.FloatField', [], {}),
'end': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'error_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'hostname': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mmc.MMCHost']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'script': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mmc.MMCScript']"}),
'start': ('django.db.models.fields.DateTimeField', [], {}),
'success': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'sys_argv': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'traceback': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'mmc.mmcscript': {
'Meta': {'object_name': 'MMCScript'},
'created': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ignore': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'one_copy': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
}
}

complete_apps = ['mmc']
58 changes: 53 additions & 5 deletions mmc/mixins.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
__author__ = 'gotlium'

import traceback
import tempfile
import socket
import atexit
import time
import sys
import os

from django.core.management.base import BaseCommand
from django.utils.encoding import smart_str

try:
from django.utils.timezone import now
except:
except ImportError:
from datetime import datetime

now = datetime.now

from utils import monkey_mix
Expand All @@ -28,9 +32,40 @@ def __init__(self):
self._error_message = None
self._traceback = None
self._show_traceback = False
self._tempdir = tempfile.gettempdir()
self._script = sys.argv[1]

def __mmc_get_lock_file(self):
return os.path.join(self._tempdir, self._script + '.lock')

def __mmc_unlock(self):
if self.__mmc_is_run():
os.unlink(self.__mmc_get_lock_file())

def __mmc_lock(self):
open(self.__mmc_get_lock_file(), 'w').close()

def __mmc_is_run(self):
return os.path.exists(self.__mmc_get_lock_file())

def __mmc_check_is_running(self):
if self.__mmc_is_run():
sys.stdout.write('Already running\n')
sys.exit(-1)

def __mmc_one_copy(self):
try:
from models import MMCScript

if MMCScript.get_one_copy(self._script):
self.__mmc_check_is_running()
self.__mmc_lock()
except Exception, msg:
print '[MMC]', msg.__str__()

def execute(self, *args, **options):
atexit.register(self._save_results)
self.__mmc_one_copy()
atexit.register(self._mmc_atexit_callback)
self._show_traceback = options.get('traceback', False)

try:
Expand All @@ -40,23 +75,30 @@ def execute(self, *args, **options):
self._error_message = ex.__str__()
self._traceback = traceback.format_exc()

def _save_results(self, *args, **kwargs):
def __mmc_store_log(self):
try:
from mmc.models import MMCLog

MMCLog.logging(
start=self._start_date,
hostname=socket.gethostname(),
script=sys.argv[1],
script=self._script,
elapsed="%0.2f" % (time.time() - self._start_time),
success=self._success,
error_message=self._error_message,
traceback=self._traceback,
sys_argv=' '.join(map(unicode, sys.argv))
)
except Exception, msg:
print 'Logging broken with message:', msg
print '[MMC] Logging broken with message:', msg.__str__()

def __mmc_send_mail(self):
if not self._success:
from mmc.models import MMCEmail

MMCEmail.send(self._traceback)

def __mmc_print_log(self):
if not self._success:
if self._show_traceback:
print self._traceback
Expand All @@ -66,6 +108,12 @@ def _save_results(self, *args, **kwargs):
))
sys.exit(1)

def _mmc_atexit_callback(self, *args, **kwargs):
self.__mmc_store_log()
self.__mmc_send_mail()
self.__mmc_print_log()
self.__mmc_unlock()


def inject_management():
monkey_mix(BaseCommand, BaseCommandMixin)
30 changes: 30 additions & 0 deletions mmc/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
__author__ = 'gotlium'

from django.core.mail import send_mail
from django.db import models
from django.conf import settings

from mmc.defaults import SUBJECT


class MMCHost(models.Model):
Expand All @@ -20,6 +24,11 @@ class MMCScript(models.Model):
created = models.DateField(auto_now=True)
name = models.CharField(max_length=255, unique=True)
ignore = models.BooleanField(default=False)
one_copy = models.BooleanField(default=False)

@classmethod
def get_one_copy(cls, name):
return cls.objects.get(name=name).one_copy

class Meta:
verbose_name = 'Script'
Expand Down Expand Up @@ -53,3 +62,24 @@ def logging(cls, **kwargs):
name=kwargs['hostname'])[0]
if not kwargs['script'].ignore and not kwargs['hostname'].ignore:
cls.objects.create(**kwargs)


class MMCEmail(models.Model):
created = models.DateField(auto_now=True, editable=False)
email = models.EmailField()
is_active = models.BooleanField(default=True)

class Meta:
verbose_name = 'Email'
verbose_name_plural = 'Emails'

@classmethod
def send(cls, message):
try:
emails = list(cls.objects.values_list(
'email', flat=True).filter(is_active=True))
if emails:
send_mail(
SUBJECT, message, settings.DEFAULT_FROM_EMAIL, emails)
except Exception, msg:
print '[MMC]', msg.__str__()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

setup(
name='django-mmc',
version="1.0",
version="1.1",
description='Monitor management commands on Django',
keywords="django management",
long_description=open('README.rst').read(),
Expand Down

0 comments on commit e10a95f

Please sign in to comment.