Commit bf9bb1b9 authored by ibuler's avatar ibuler

[Update] 修改ops task运行

parent 30efec1b
...@@ -25,9 +25,9 @@ from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \ ...@@ -25,9 +25,9 @@ from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
get_user_granted_assets get_user_granted_assets
from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser
from . import serializers from . import serializers
from .tasks import update_assets_hardware_info, test_admin_user_connectability, \ from .tasks import update_assets_hardware_info_manual, test_admin_user_connectability_util, \
test_admin_user_connectability_manual, push_system_user_to_cluster_assets, \ test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \
test_system_user_connectability test_system_user_connectability_manual
class AssetViewSet(IDInFilterMixin, BulkModelViewSet): class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
...@@ -222,7 +222,7 @@ class AssetRefreshHardwareApi(generics.RetrieveAPIView): ...@@ -222,7 +222,7 @@ class AssetRefreshHardwareApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
asset_id = kwargs.get('pk') asset_id = kwargs.get('pk')
asset = get_object_or_404(Asset, pk=asset_id) asset = get_object_or_404(Asset, pk=asset_id)
summary = update_assets_hardware_info([asset]) summary = update_assets_hardware_info_manual([asset])
if summary.get('dark'): if summary.get('dark'):
return Response(summary['dark'].values(), status=501) return Response(summary['dark'].values(), status=501)
else: else:
...@@ -239,7 +239,7 @@ class AssetAdminUserTestApi(generics.RetrieveAPIView): ...@@ -239,7 +239,7 @@ class AssetAdminUserTestApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
asset_id = kwargs.get('pk') asset_id = kwargs.get('pk')
asset = get_object_or_404(Asset, pk=asset_id) asset = get_object_or_404(Asset, pk=asset_id)
ok, msg = test_admin_user_connectability_manual(asset) ok, msg = test_asset_connectability_manual(asset)
if ok: if ok:
return Response({"msg": "pong"}) return Response({"msg": "pong"})
else: else:
...@@ -255,7 +255,7 @@ class AdminUserTestConnectiveApi(generics.RetrieveAPIView): ...@@ -255,7 +255,7 @@ class AdminUserTestConnectiveApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
admin_user = self.get_object() admin_user = self.get_object()
test_admin_user_connectability.delay(admin_user, force=True) test_admin_user_connectability_util.delay(admin_user, force=True)
return Response({"msg": "Task created"}) return Response({"msg": "Task created"})
...@@ -268,7 +268,7 @@ class SystemUserPushApi(generics.RetrieveAPIView): ...@@ -268,7 +268,7 @@ class SystemUserPushApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
system_user = self.get_object() system_user = self.get_object()
push_system_user_to_cluster_assets.delay(system_user, force=True) push_system_user_to_cluster_assets_manual.delay(system_user, force=True)
return Response({"msg": "Task created"}) return Response({"msg": "Task created"})
...@@ -281,5 +281,5 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView): ...@@ -281,5 +281,5 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
system_user = self.get_object() system_user = self.get_object()
test_system_user_connectability.delay(system_user, force=True) test_system_user_connectability_manual.delay(system_user, force=True)
return Response({"msg": "Task created"}) return Response({"msg": "Task created"})
...@@ -2,14 +2,20 @@ ...@@ -2,14 +2,20 @@
# #
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
PUSH_SYSTEM_USER_PERIOD_LOCK_KEY = "PUSH_SYSTEM_USER_PERIOD_KEY" # PUSH_SYSTEM_USER_PERIOD_LOCK_KEY = "PUSH_SYSTEM_USER_PERIOD_KEY"
PUSH_SYSTEM_USER_PERIOD_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER PERIOD TASK") PUSH_SYSTEM_USER_PERIOD_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER PERIOD: {}")
PUSH_SYSTEM_USER_MANUAL_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER MANUALLY: {}")
PUSH_SYSTEM_USER_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER: {}") PUSH_SYSTEM_USER_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER: {}")
PUSH_SYSTEM_USER_LOCK_KEY = "PUSH_SYSTEM_USER_TO_CLUSTER_LOCK_{}" # PUSH_SYSTEM_USER_LOCK_KEY = "PUSH_SYSTEM_USER_TO_CLUSTER_LOCK_{}"
PUSH_SYSTEM_USER_ON_CHANGE_TASK_NAME = _("PUSH SYSTEM USER ON CHANGE: {}")
PUSH_SYSTEM_USER_ON_CREATE_TASK_NAME = _("PUSH SYSTEM USER ON CREATE: {}")
PUSH_SYSTEM_USERS_ON_ASSET_CREATE_TASK_NAME = _("PUSH SYSTEM USERS ON ASSET CREAT: {}")
UPDATE_ASSETS_HARDWARE_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO') UPDATE_ASSETS_HARDWARE_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO')
UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY = "UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY" UPDATE_ASSETS_HARDWARE_MANUAL_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO MANUALLY')
UPDATE_ASSETS_HARDWARE_ON_CREATE_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO ON CREATE')
# UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY = "UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY"
UPDATE_ASSETS_HARDWARE_PERIOD_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO PERIOD') UPDATE_ASSETS_HARDWARE_PERIOD_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO PERIOD')
UPDATE_ASSETS_HARDWARE_TASKS = [ UPDATE_ASSETS_HARDWARE_TASKS = [
{ {
...@@ -20,10 +26,10 @@ UPDATE_ASSETS_HARDWARE_TASKS = [ ...@@ -20,10 +26,10 @@ UPDATE_ASSETS_HARDWARE_TASKS = [
} }
] ]
TEST_ADMIN_USER_CONN_PERIOD_LOCK_KEY = "TEST_ADMIN_USER_CONN_PERIOD_KEY" # TEST_ADMIN_USER_CONN_PERIOD_LOCK_KEY = "TEST_ADMIN_USER_CONN_PERIOD_KEY"
TEST_ADMIN_USER_CONN_PERIOD_TASK_NAME = _("TEST ADMIN USER CONN PERIOD TASK") TEST_ADMIN_USER_CONN_PERIOD_TASK_NAME = _("TEST ADMIN USER CONN PERIOD: {}")
TEST_ADMIN_USER_CONN_MANUAL_TASK_NAME = _("TEST ADMIN USER CONN MANUALLY: {}")
TEST_ADMIN_USER_CONN_TASK_NAME = _("TEST ADMIN USER CONN: {}") TEST_ADMIN_USER_CONN_TASK_NAME = _("TEST ADMIN USER CONN: {}")
TEST_ADMIN_USER_CONN_LOCK_KEY = TEST_ADMIN_USER_CONN_TASK_NAME
ADMIN_USER_CONN_CACHE_KEY = "ADMIN_USER_CONN_{}" ADMIN_USER_CONN_CACHE_KEY = "ADMIN_USER_CONN_{}"
TEST_ADMIN_USER_CONN_TASKS = [ TEST_ADMIN_USER_CONN_TASKS = [
{ {
...@@ -38,10 +44,8 @@ ASSET_ADMIN_CONN_CACHE_KEY = "ASSET_ADMIN_USER_CONN_{}" ...@@ -38,10 +44,8 @@ ASSET_ADMIN_CONN_CACHE_KEY = "ASSET_ADMIN_USER_CONN_{}"
TEST_ASSET_CONN_TASK_NAME = _("ASSET CONN TEST MANUAL") TEST_ASSET_CONN_TASK_NAME = _("ASSET CONN TEST MANUAL")
TEST_SYSTEM_USER_CONN_PERIOD_LOCK_KEY = "TEST_SYSTEM_USER_CONN_PERIOD_KEY" TEST_SYSTEM_USER_CONN_PERIOD_LOCK_KEY = "TEST_SYSTEM_USER_CONN_PERIOD_KEY"
TEST_SYSTEM_USER_CONN_PERIOD_TASK_NAME = _("TEST SYSTEM USER CONN PERIOD TASK") TEST_SYSTEM_USER_CONN_PERIOD_TASK_NAME = _("TEST SYSTEM USER CONN PERIOD: {}")
TEST_SYSTEM_USER_CONN_CACHE_KEY_PREFIX = "SYSTEM_USER_CONN_" TEST_SYSTEM_USER_CONN_MANUAL_TASK_NAME = _("TEST SYSTEM USER CONN MANUALLY: {}")
TEST_SYSTEM_USER_CONN_TASK_NAME = _("TEST SYSTEM USER CONN: {}")
TEST_SYSTEM_USER_CONN_LOCK_KEY = "TEST_SYSTEM_USER_CONN_{}"
SYSTEM_USER_CONN_CACHE_KEY = "SYSTEM_USER_CONN_{}" SYSTEM_USER_CONN_CACHE_KEY = "SYSTEM_USER_CONN_{}"
TEST_SYSTEM_USER_CONN_TASKS = [ TEST_SYSTEM_USER_CONN_TASKS = [
{ {
......
...@@ -13,13 +13,14 @@ from django.db import models ...@@ -13,13 +13,14 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
from common.utils import signer, ssh_key_string_to_obj, ssh_key_gen from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen
from .utils import private_key_validator from .utils import private_key_validator
from ..const import SYSTEM_USER_CONN_CACHE_KEY from ..const import SYSTEM_USER_CONN_CACHE_KEY
__all__ = ['AdminUser', 'SystemUser',] __all__ = ['AdminUser', 'SystemUser',]
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
signer = get_signer()
class AssetUser(models.Model): class AssetUser(models.Model):
......
This diff is collapsed.
...@@ -49,9 +49,6 @@ $(document).ready(function(){ ...@@ -49,9 +49,6 @@ $(document).ready(function(){
"aaSorting": [[2, "asc"]], "aaSorting": [[2, "asc"]],
"aoColumnDefs": [ { "bSortable": false, "aTargets": [ 0 ] }], "aoColumnDefs": [ { "bSortable": false, "aTargets": [ 0 ] }],
"bAutoWidth": false, "bAutoWidth": false,
"language": {
"url": "/static/js/plugins/dataTables/i18n/zh-hans.json"
},
columns: [ columns: [
{data: "checkbox"}, {data: "checkbox"},
{data: "id"}, {data: "id"},
......
...@@ -28,7 +28,7 @@ from common.utils import get_object_or_none, get_logger, is_uuid ...@@ -28,7 +28,7 @@ from common.utils import get_object_or_none, get_logger, is_uuid
from .. import forms from .. import forms
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
from ..hands import AdminUserRequiredMixin from ..hands import AdminUserRequiredMixin
from ..tasks import update_assets_hardware_info from ..tasks import update_assets_hardware_info_util
__all__ = [ __all__ = [
...@@ -314,10 +314,6 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): ...@@ -314,10 +314,6 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
except Exception as e: except Exception as e:
failed.append('%s: %s' % (asset_dict['hostname'], str(e))) failed.append('%s: %s' % (asset_dict['hostname'], str(e)))
if assets:
update_assets_hardware_info.delay([asset._to_secret_json() for asset in assets])
data = { data = {
'created': created, 'created': created,
'created_info': 'Created {}'.format(len(created)), 'created_info': 'Created {}'.format(len(created)),
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
import os import os
import json
from functools import wraps
from celery import Celery from celery import Celery, subtask
from celery.signals import worker_ready, worker_shutdown
from .utils import get_logger
logger = get_logger(__file__)
# set the default Django settings module for the 'celery' program. # set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings')
...@@ -15,3 +22,167 @@ app = Celery('jumpserver') ...@@ -15,3 +22,167 @@ app = Celery('jumpserver')
# pickle the object when using Windows. # pickle the object when using Windows.
app.config_from_object('django.conf:settings', namespace='CELERY') app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in settings.INSTALLED_APPS]) app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in settings.INSTALLED_APPS])
def create_or_update_celery_periodic_tasks(tasks):
from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule
"""
:param tasks: {
'add-every-monday-morning': {
'task': 'tasks.add' # A registered celery task,
'interval': 30,
'crontab': "30 7 * * *",
'args': (16, 16),
'kwargs': {},
'enabled': False,
},
}
:return:
"""
# Todo: check task valid, task and callback must be a celery task
for name, detail in tasks.items():
interval = None
crontab = None
if isinstance(detail.get("interval"), int):
intervals = IntervalSchedule.objects.filter(
every=detail["interval"], period=IntervalSchedule.SECONDS
)
if intervals:
interval = intervals[0]
else:
interval = IntervalSchedule.objects.create(
every=detail['interval'],
period=IntervalSchedule.SECONDS,
)
elif isinstance(detail.get("crontab"), str):
try:
minute, hour, day, month, week = detail["crontab"].split()
except ValueError:
raise SyntaxError("crontab is not valid")
kwargs = dict(
minute=minute, hour=hour, day_of_week=week,
day_of_month=day, month_of_year=month,
)
contabs = CrontabSchedule.objects.filter(
**kwargs
)
if contabs:
crontab = contabs[0]
else:
crontab = CrontabSchedule.objects.create(**kwargs)
else:
raise SyntaxError("Schedule is not valid")
defaults = dict(
interval=interval,
crontab=crontab,
name=name,
task=detail['task'],
args=json.dumps(detail.get('args', [])),
kwargs=json.dumps(detail.get('kwargs', {})),
enabled=detail.get('enabled', True),
)
task = PeriodicTask.objects.update_or_create(
defaults=defaults, name=name,
)
return task
def disable_celery_periodic_task(task_name):
from django_celery_beat.models import PeriodicTask
PeriodicTask.objects.filter(name=task_name).update(enabled=False)
def delete_celery_periodic_task(task_name):
from django_celery_beat.models import PeriodicTask
PeriodicTask.objects.filter(name=task_name).delete()
__REGISTER_PERIODIC_TASKS = []
__AFTER_APP_SHUTDOWN_CLEAN_TASKS = []
__AFTER_APP_READY_RUN_TASKS = []
def register_as_period_task(crontab=None, interval=None):
"""
Warning: Task must be have not any args and kwargs
:param crontab: "* * * * *"
:param interval: 60*60*60
:return:
"""
if crontab is None and interval is None:
raise SyntaxError("Must set crontab or interval one")
def decorate(func):
if crontab is None and interval is None:
raise SyntaxError("Interval and crontab must set one")
# Because when this decorator run, the task was not created,
# So we can't use func.name
name = '{func.__module__}.{func.__name__}'.format(func=func)
if name not in __REGISTER_PERIODIC_TASKS:
create_or_update_celery_periodic_tasks({
name: {
'task': name,
'interval': interval,
'crontab': crontab,
'args': (),
'enabled': True,
}
})
__REGISTER_PERIODIC_TASKS.append(name)
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorate
def after_app_ready_start(func):
# Because when this decorator run, the task was not created,
# So we can't use func.name
name = '{func.__module__}.{func.__name__}'.format(func=func)
if name not in __AFTER_APP_READY_RUN_TASKS:
__AFTER_APP_READY_RUN_TASKS.append(name)
@wraps(func)
def decorate(*args, **kwargs):
return func(*args, **kwargs)
return decorate
def after_app_shutdown_clean(func):
# Because when this decorator run, the task was not created,
# So we can't use func.name
name = '{func.__module__}.{func.__name__}'.format(func=func)
if name not in __AFTER_APP_READY_RUN_TASKS:
__AFTER_APP_SHUTDOWN_CLEAN_TASKS.append(name)
@wraps(func)
def decorate(*args, **kwargs):
return func(*args, **kwargs)
return decorate
@worker_ready.connect
def on_app_ready(sender=None, headers=None, body=None, **kwargs):
logger.debug("App ready signal recv")
logger.debug("Start need start task: [{}]".format(
", ".join(__AFTER_APP_READY_RUN_TASKS))
)
for task in __AFTER_APP_READY_RUN_TASKS:
subtask(task).delay()
@worker_shutdown.connect
def after_app_shutdown(sender=None, headers=None, body=None, **kwargs):
from django_celery_beat.models import PeriodicTask
logger.debug("App shutdown signal recv")
logger.debug("Clean need cleaned period tasks: [{}]".format(
', '.join(__AFTER_APP_SHUTDOWN_CLEAN_TASKS))
)
PeriodicTask.objects.filter(name__in=__AFTER_APP_SHUTDOWN_CLEAN_TASKS).delete()
from django.core.mail import send_mail from django.core.mail import send_mail
from django.conf import settings from django.conf import settings
from common import celery_app as app from .celery import app
from .utils import get_logger from .utils import get_logger
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import json
import re import re
from collections import OrderedDict from collections import OrderedDict
from six import string_types from six import string_types
import base64 import base64
import os import os
from itertools import chain from itertools import chain
import string
import logging import logging
import datetime import datetime
import time import time
...@@ -27,9 +25,6 @@ from django.conf import settings ...@@ -27,9 +25,6 @@ from django.conf import settings
from django.utils import timezone from django.utils import timezone
from .compat import to_bytes, to_string
SECRET_KEY = settings.SECRET_KEY
UUID_PATTERN = re.compile(r'[0-9a-zA-Z\-]{36}') UUID_PATTERN = re.compile(r'[0-9a-zA-Z\-]{36}')
...@@ -51,9 +46,22 @@ def get_object_or_none(model, **kwargs): ...@@ -51,9 +46,22 @@ def get_object_or_none(model, **kwargs):
return obj return obj
class Signer(object): class Singleton(type):
def __init__(cls, *args, **kwargs):
cls.__instance = None
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
else:
return cls.__instance
class Signer(metaclass=Singleton):
"""用来加密,解密,和基于时间戳的方式验证token""" """用来加密,解密,和基于时间戳的方式验证token"""
def __init__(self, secret_key=SECRET_KEY): def __init__(self, secret_key=None):
self.secret_key = secret_key self.secret_key = secret_key
def sign(self, value): def sign(self, value):
...@@ -100,58 +108,10 @@ def combine_seq(s1, s2, callback=None): ...@@ -100,58 +108,10 @@ def combine_seq(s1, s2, callback=None):
return seq return seq
def search_object_attr(obj, value='', attr_list=None, ignore_case=False):
"""It's provide a method to search a object attribute equal some value
If object some attribute equal :param: value, return True else return False
class A():
name = 'admin'
age = 7
:param obj: A object
:param value: A string match object attribute
:param attr_list: Only match attribute in attr_list
:param ignore_case: Ignore case
:return: Boolean
"""
if value == '':
return True
try:
object_attr = obj.__dict__
except AttributeError:
return False
if attr_list is not None:
new_object_attr = {}
for attr in attr_list:
new_object_attr[attr] = object_attr.pop(attr)
object_attr = new_object_attr
if ignore_case:
if not isinstance(value, string_types):
return False
if value.lower() in map(string.lower, map(str, object_attr.values())):
return True
else:
if value in object_attr.values():
return True
return False
def get_logger(name=None): def get_logger(name=None):
return logging.getLogger('jumpserver.%s' % name) return logging.getLogger('jumpserver.%s' % name)
def int_seq(seq):
try:
return map(int, seq)
except ValueError:
return seq
def timesince(dt, since='', default="just now"): def timesince(dt, since='', default="just now"):
""" """
Returns string representing "time since" e.g. Returns string representing "time since" e.g.
...@@ -391,4 +351,6 @@ def is_uuid(s): ...@@ -391,4 +351,6 @@ def is_uuid(s):
return False return False
signer = Signer() def get_signer():
signer = Signer(settings.SECRET_KEY)
return signer
...@@ -337,8 +337,9 @@ CELERY_ACCEPT_CONTENT = ['json', 'pickle'] ...@@ -337,8 +337,9 @@ CELERY_ACCEPT_CONTENT = ['json', 'pickle']
CELERY_RESULT_EXPIRES = 3600 CELERY_RESULT_EXPIRES = 3600
CELERY_WORKER_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s' CELERY_WORKER_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s'
CELERY_WORKER_TASK_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s' CELERY_WORKER_TASK_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s'
CELERY_TASK_EAGER_PROPAGATES = True
CELERY_TIMEZONE = TIME_ZONE CELERY_TIMEZONE = TIME_ZONE
# TERMINAL_HEATBEAT_INTERVAL = CONFIG.TERMINAL_HEATBEAT_INTERVAL or 30 # CELERY_ENABLE_UTC = True
# Cache use redis # Cache use redis
......
# -*- coding: utf-8 -*-
#
from functools import wraps
TASK_PREFIX = "TOOT"
CALLBACK_PREFIX = "COC"
def register_as_period_task(crontab=None, interval=None):
"""
:param crontab: "* * * * *"
:param interval: 60*60*60
:return:
"""
from .utils import create_or_update_celery_periodic_tasks
if crontab is None and interval is None:
raise SyntaxError("Must set crontab or interval one")
def decorate(func):
@wraps(func)
def wrapper(*args, **kwargs):
tasks = {
func.__name__: {
'task': func.__name__,
'args': args,
'kwargs': kwargs,
'interval': interval,
'crontab': crontab,
'enabled': True,
}
}
create_or_update_celery_periodic_tasks(tasks)
return func(*args, **kwargs)
return wrapper
return decorate
...@@ -9,7 +9,9 @@ from django.utils import timezone ...@@ -9,7 +9,9 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_celery_beat.models import CrontabSchedule, IntervalSchedule, PeriodicTask from django_celery_beat.models import CrontabSchedule, IntervalSchedule, PeriodicTask
from common.utils import signer, get_logger from common.utils import get_signer, get_logger
from common.celery import delete_celery_periodic_task, create_or_update_celery_periodic_tasks, \
disable_celery_periodic_task
from .ansible import AdHocRunner, AnsibleError from .ansible import AdHocRunner, AnsibleError
from .inventory import JMSInventory from .inventory import JMSInventory
...@@ -17,6 +19,7 @@ __all__ = ["Task", "AdHoc", "AdHocRunHistory"] ...@@ -17,6 +19,7 @@ __all__ = ["Task", "AdHoc", "AdHocRunHistory"]
logger = get_logger(__file__) logger = get_logger(__file__)
signer = get_signer()
class Task(models.Model): class Task(models.Model):
...@@ -82,8 +85,6 @@ class Task(models.Model): ...@@ -82,8 +85,6 @@ class Task(models.Model):
def save(self, force_insert=False, force_update=False, using=None, def save(self, force_insert=False, force_update=False, using=None,
update_fields=None): update_fields=None):
from .utils import create_or_update_celery_periodic_tasks, \
disable_celery_periodic_task
from .tasks import run_ansible_task from .tasks import run_ansible_task
super().save( super().save(
force_insert=force_insert, force_update=force_update, force_insert=force_insert, force_update=force_update,
...@@ -114,7 +115,6 @@ class Task(models.Model): ...@@ -114,7 +115,6 @@ class Task(models.Model):
disable_celery_periodic_task(self.name) disable_celery_periodic_task(self.name)
def delete(self, using=None, keep_parents=False): def delete(self, using=None, keep_parents=False):
from .utils import delete_celery_periodic_task
super().delete(using=using, keep_parents=keep_parents) super().delete(using=using, keep_parents=keep_parents)
delete_celery_periodic_task(self.name) delete_celery_periodic_task(self.name)
...@@ -246,7 +246,7 @@ class AdHoc(models.Model): ...@@ -246,7 +246,7 @@ class AdHoc(models.Model):
} }
:return: :return:
""" """
self._become = signer.sign(json.dumps(item)) self._become = signer.sign(json.dumps(item)).decode('utf-8')
@property @property
def options(self): def options(self):
...@@ -271,6 +271,11 @@ class AdHoc(models.Model): ...@@ -271,6 +271,11 @@ class AdHoc(models.Model):
except AdHocRunHistory.DoesNotExist: except AdHocRunHistory.DoesNotExist:
return None return None
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
super().save(force_insert=force_insert, force_update=force_update,
using=using, update_fields=update_fields)
def __str__(self): def __str__(self):
return "{} of {}".format(self.task.name, self.short_id) return "{} of {}".format(self.task.name, self.short_id)
......
...@@ -21,9 +21,9 @@ def run_ansible_task(task_id, callback=None, **kwargs): ...@@ -21,9 +21,9 @@ def run_ansible_task(task_id, callback=None, **kwargs):
task = get_object_or_none(Task, id=task_id) task = get_object_or_none(Task, id=task_id)
if task: if task:
result = task.object.run() result = task.run()
if callback is not None: if callback is not None:
subtask(callback).delay(result) subtask(callback).delay(result, task_name=task.name)
return result return result
else: else:
logger.error("No task found") logger.error("No task found")
......
...@@ -57,14 +57,20 @@ ...@@ -57,14 +57,20 @@
<td class="text-center">{{ object.adhoc.all | length}}</td> <td class="text-center">{{ object.adhoc.all | length}}</td>
<td class="text-center">{{ object.latest_adhoc.hosts | length}}</td> <td class="text-center">{{ object.latest_adhoc.hosts | length}}</td>
<td class="text-center"> <td class="text-center">
{% if object.latest_history.is_success %} {% if object.latest_history %}
<i class="fa fa-check text-navy"></i> {% if object.latest_history.is_success %}
{% else %} <i class="fa fa-check text-navy"></i>
<i class="fa fa-times text-danger"></i> {% else %}
<i class="fa fa-times text-danger"></i>
{% endif %}
{% endif %} {% endif %}
</td> </td>
<td class="text-center">{{ object.latest_history.date_start }}</td> <td class="text-center">{{ object.latest_history.date_start }}</td>
<td class="text-center">{{ object.latest_history.timedelta|floatformat }} s</td> <td class="text-center">
{% if object.latest_history %}
{{ object.latest_history.timedelta|floatformat }} s
{% endif %}
</td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'ops:task-run' pk=object.id %}" class="btn btn-xs btn-info">{% trans "Run" %}</a> <a href="{% url 'ops:task-run' pk=object.id %}" class="btn btn-xs btn-info">{% trans "Run" %}</a>
<a data-uid="{{ object.id }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a> <a data-uid="{{ object.id }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
import json
from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule
from common.utils import get_logger, get_object_or_none from common.utils import get_logger, get_object_or_none
from .models import Task, AdHoc from .models import Task, AdHoc
...@@ -13,22 +9,27 @@ def get_task_by_id(task_id): ...@@ -13,22 +9,27 @@ def get_task_by_id(task_id):
return get_object_or_none(Task, id=task_id) return get_object_or_none(Task, id=task_id)
def create_or_update_ansible_task( def update_or_create_ansible_task(
task_name, hosts, tasks, pattern='all', options=None, task_name, hosts, tasks,
interval=None, crontab=None, is_periodic=False,
callback=None, pattern='all', options=None,
run_as_admin=False, run_as="", become_info=None, run_as_admin=False, run_as="", become_info=None,
created_by=None, interval=None, crontab=None, created_by=None,
is_periodic=False, callback=None,
): ):
task = get_object_or_none(Task, name=task_name) defaults = {
'name': task_name,
'interval': interval,
'crontab': crontab,
'is_periodic': is_periodic,
'callback': callback,
'created_by': created_by,
}
if task is None: created = False
task = Task( task, _ = Task.objects.update_or_create(
name=task_name, interval=interval, defaults=defaults, name=task_name,
crontab=crontab, is_periodic=is_periodic, )
callback=callback, created_by=created_by
)
task.save()
adhoc = task.latest_adhoc adhoc = task.latest_adhoc
new_adhoc = AdHoc(task=task, pattern=pattern, new_adhoc = AdHoc(task=task, pattern=pattern,
...@@ -38,70 +39,13 @@ def create_or_update_ansible_task( ...@@ -38,70 +39,13 @@ def create_or_update_ansible_task(
new_adhoc.tasks = tasks new_adhoc.tasks = tasks
new_adhoc.options = options new_adhoc.options = options
new_adhoc.become = become_info new_adhoc.become = become_info
if not adhoc or adhoc != new_adhoc: if not adhoc or adhoc != new_adhoc:
logger.debug("Task create new adhoc: {}".format(task_name))
new_adhoc.save() new_adhoc.save()
task.latest_adhoc = new_adhoc task.latest_adhoc = new_adhoc
return task created = True
return task, created
def create_or_update_celery_periodic_tasks(tasks):
"""
:param tasks: {
'add-every-monday-morning': {
'task': 'tasks.add' # A registered celery task,
'interval': 30,
'crontab': "30 7 * * *",
'args': (16, 16),
'kwargs': {},
'enabled': False,
},
}
:return:
"""
# Todo: check task valid, task and callback must be a celery task
for name, detail in tasks.items():
interval = None
crontab = None
if isinstance(detail.get("interval"), int):
interval, _ = IntervalSchedule.objects.get_or_create(
every=detail['interval'],
period=IntervalSchedule.SECONDS,
)
elif isinstance(detail.get("crontab"), str):
try:
minute, hour, day, month, week = detail["crontab"].split()
except ValueError:
raise SyntaxError("crontab is not valid")
crontab, _ = CrontabSchedule.objects.get_or_create(
minute=minute, hour=hour, day_of_week=week,
day_of_month=day, month_of_year=month,
)
else:
raise SyntaxError("Schedule is not valid")
defaults = dict(
interval=interval,
crontab=crontab,
name=name,
task=detail['task'],
args=json.dumps(detail.get('args', [])),
kwargs=json.dumps(detail.get('kwargs', {})),
enabled=detail['enabled']
)
task = PeriodicTask.objects.update_or_create(
defaults=defaults, name=name,
)
logger.info("Create periodic task: {}".format(task))
return task
def disable_celery_periodic_task(task_name):
PeriodicTask.objects.filter(name=task_name).update(enabled=False)
def delete_celery_periodic_task(task_name):
PeriodicTask.objects.filter(name=task_name).delete()
...@@ -262,9 +262,6 @@ jumpserver.initDataTable = function (options) { ...@@ -262,9 +262,6 @@ jumpserver.initDataTable = function (options) {
var table = ele.DataTable({ var table = ele.DataTable({
pageLength: options.pageLength || 15, pageLength: options.pageLength || 15,
dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>', dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>',
language: {
url: options.i18n_url || "/static/js/plugins/dataTables/i18n/zh-hans.json"
},
order: options.order || [], order: options.order || [],
select: options.select || 'multi', select: options.select || 'multi',
buttons: [], buttons: [],
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="sidebar-collapse"> <div class="sidebar-collapse">
<ul class="nav" id="side-menu"> <ul class="nav" id="side-menu">
{% include '_user_profile.html' %} {% include '_user_profile.html' %}
{% if request.user.is_superuser and request.COOKIES.admin == "Yes" %} {% if request.user.is_superuser and request.COOKIES.IN_ADMIN_PAGE != "No" %}
{% include '_nav.html' %} {% include '_nav.html' %}
{% else %} {% else %}
{% include '_nav_user.html' %} {% include '_nav_user.html' %}
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<li><a href="{% url 'users:user-profile-update' %}">{% trans 'Profile settings' %}</a></li> <li><a href="{% url 'users:user-profile-update' %}">{% trans 'Profile settings' %}</a></li>
<li class="divider"></li> <li class="divider"></li>
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
{% if request.COOKIES.admin == 'No' %} {% if request.COOKIES.IN_ADMIN_PAGE == 'No' %}
<li><a id="switch_admin">{% trans 'Admin page' %}</a></li> <li><a id="switch_admin">{% trans 'Admin page' %}</a></li>
{% else %} {% else %}
<li><a id="switch_user">{% trans 'User page' %}</a></li> <li><a id="switch_user">{% trans 'User page' %}</a></li>
...@@ -37,11 +37,11 @@ ...@@ -37,11 +37,11 @@
$(document).ready(function () { $(document).ready(function () {
}) })
.on('click', '#switch_admin', function () { .on('click', '#switch_admin', function () {
setCookie("admin", "Yes"); setCookie("IN_ADMIN_PAGE", "Yes");
window.location = "/" window.location = "/"
}) })
.on('click', '#switch_user', function () { .on('click', '#switch_user', function () {
setCookie("admin", "No"); setCookie("IN_ADMIN_PAGE", "No");
window.location = "/" window.location = "/"
}) })
</script> </script>
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
import uuid import uuid
from django.db import models, IntegrityError from django.db import models, IntegrityError
from django.contrib.auth.models import Group
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import signer, date_expired_default
from common.mixins import NoDeleteModelMixin from common.mixins import NoDeleteModelMixin
__all__ = ['UserGroup'] __all__ = ['UserGroup']
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import os
import uuid import uuid
from collections import OrderedDict from collections import OrderedDict
...@@ -15,10 +14,11 @@ from django.utils import timezone ...@@ -15,10 +14,11 @@ from django.utils import timezone
from django.shortcuts import reverse from django.shortcuts import reverse
from .group import UserGroup from .group import UserGroup
from common.utils import signer, date_expired_default from common.utils import get_signer, date_expired_default
__all__ = ['User'] __all__ = ['User']
signer = get_signer()
class User(AbstractUser): class User(AbstractUser):
......
...@@ -5,10 +5,12 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -5,10 +5,12 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk import BulkListSerializer from rest_framework_bulk import BulkListSerializer
from common.utils import signer, validate_ssh_public_key from common.utils import get_signer, validate_ssh_public_key
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from .models import User, UserGroup from .models import User, UserGroup
signer = get_signer()
class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer): class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
groups_display = serializers.SerializerMethodField() groups_display = serializers.SerializerMethodField()
......
...@@ -45,7 +45,7 @@ def start_beat(): ...@@ -45,7 +45,7 @@ def start_beat():
os.chdir(APPS_DIR) os.chdir(APPS_DIR)
os.environ.setdefault('PYTHONOPTIMIZE', '1') os.environ.setdefault('PYTHONOPTIMIZE', '1')
scheduler = "django_celery_beat.schedulers:DatabaseScheduler" scheduler = "django_celery_beat.schedulers:DatabaseScheduler"
cmd = 'celery -A common beat -l {} --scheduler {} --max-interval 30 '.format(LOG_LEVEL, scheduler) cmd = 'celery -A common beat -l {} --scheduler {} --max-interval 5 '.format(LOG_LEVEL, scheduler)
subprocess.call(cmd, shell=True) subprocess.call(cmd, shell=True)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment