Commit ebd92547 authored by ibuler's avatar ibuler

[Update] merged

parents f6f8d13b ba288396
...@@ -62,7 +62,7 @@ def clean_hosts_by_protocol(system_user, assets): ...@@ -62,7 +62,7 @@ def clean_hosts_by_protocol(system_user, assets):
return hosts return hosts
@shared_task @shared_task(queue="ansible")
def set_assets_hardware_info(assets, result, **kwargs): def set_assets_hardware_info(assets, result, **kwargs):
""" """
Using ops task run result, to update asset info Using ops task run result, to update asset info
...@@ -148,7 +148,7 @@ def update_assets_hardware_info_util(assets, task_name=None): ...@@ -148,7 +148,7 @@ def update_assets_hardware_info_util(assets, task_name=None):
return result return result
@shared_task @shared_task(queue="ansible")
def update_asset_hardware_info_manual(asset): def update_asset_hardware_info_manual(asset):
task_name = _("Update asset hardware info: {}").format(asset.hostname) task_name = _("Update asset hardware info: {}").format(asset.hostname)
update_assets_hardware_info_util( update_assets_hardware_info_util(
...@@ -156,7 +156,7 @@ def update_asset_hardware_info_manual(asset): ...@@ -156,7 +156,7 @@ def update_asset_hardware_info_manual(asset):
) )
@shared_task @shared_task(queue="ansible")
def update_assets_hardware_info_period(): def update_assets_hardware_info_period():
""" """
Update asset hardware period task Update asset hardware period task
...@@ -170,7 +170,7 @@ def update_assets_hardware_info_period(): ...@@ -170,7 +170,7 @@ def update_assets_hardware_info_period():
## ADMIN USER CONNECTIVE ## ## ADMIN USER CONNECTIVE ##
@shared_task @shared_task(queue="ansible")
def test_asset_connectivity_util(assets, task_name=None): def test_asset_connectivity_util(assets, task_name=None):
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
...@@ -227,7 +227,7 @@ def test_asset_connectivity_util(assets, task_name=None): ...@@ -227,7 +227,7 @@ def test_asset_connectivity_util(assets, task_name=None):
return results_summary return results_summary
@shared_task @shared_task(queue="ansible")
def test_asset_connectivity_manual(asset): def test_asset_connectivity_manual(asset):
task_name = _("Test assets connectivity: {}").format(asset) task_name = _("Test assets connectivity: {}").format(asset)
summary = test_asset_connectivity_util([asset], task_name=task_name) summary = test_asset_connectivity_util([asset], task_name=task_name)
...@@ -238,7 +238,7 @@ def test_asset_connectivity_manual(asset): ...@@ -238,7 +238,7 @@ def test_asset_connectivity_manual(asset):
return True, "" return True, ""
@shared_task @shared_task(queue="ansible")
def test_admin_user_connectivity_util(admin_user, task_name): def test_admin_user_connectivity_util(admin_user, task_name):
""" """
Test asset admin user can connect or not. Using ansible api do that Test asset admin user can connect or not. Using ansible api do that
...@@ -254,7 +254,7 @@ def test_admin_user_connectivity_util(admin_user, task_name): ...@@ -254,7 +254,7 @@ def test_admin_user_connectivity_util(admin_user, task_name):
return summary return summary
@shared_task @shared_task(queue="ansible")
@register_as_period_task(interval=3600) @register_as_period_task(interval=3600)
def test_admin_user_connectivity_period(): def test_admin_user_connectivity_period():
""" """
...@@ -276,7 +276,7 @@ def test_admin_user_connectivity_period(): ...@@ -276,7 +276,7 @@ def test_admin_user_connectivity_period():
cache.set(key, 1, 60*40) cache.set(key, 1, 60*40)
@shared_task @shared_task(queue="ansible")
def test_admin_user_connectivity_manual(admin_user): def test_admin_user_connectivity_manual(admin_user):
task_name = _("Test admin user connectivity: {}").format(admin_user.name) task_name = _("Test admin user connectivity: {}").format(admin_user.name)
test_admin_user_connectivity_util(admin_user, task_name) test_admin_user_connectivity_util(admin_user, task_name)
...@@ -286,7 +286,7 @@ def test_admin_user_connectivity_manual(admin_user): ...@@ -286,7 +286,7 @@ def test_admin_user_connectivity_manual(admin_user):
## System user connective ## ## System user connective ##
@shared_task @shared_task(queue="ansible")
def test_system_user_connectivity_util(system_user, assets, task_name): def test_system_user_connectivity_util(system_user, assets, task_name):
""" """
Test system cant connect his assets or not. Test system cant connect his assets or not.
...@@ -344,14 +344,14 @@ def test_system_user_connectivity_util(system_user, assets, task_name): ...@@ -344,14 +344,14 @@ def test_system_user_connectivity_util(system_user, assets, task_name):
return results_summary return results_summary
@shared_task @shared_task(queue="ansible")
def test_system_user_connectivity_manual(system_user): def test_system_user_connectivity_manual(system_user):
task_name = _("Test system user connectivity: {}").format(system_user) task_name = _("Test system user connectivity: {}").format(system_user)
assets = system_user.get_all_assets() assets = system_user.get_all_assets()
return test_system_user_connectivity_util(system_user, assets, task_name) return test_system_user_connectivity_util(system_user, assets, task_name)
@shared_task @shared_task(queue="ansible")
def test_system_user_connectivity_a_asset(system_user, asset): def test_system_user_connectivity_a_asset(system_user, asset):
task_name = _("Test system user connectivity: {} => {}").format( task_name = _("Test system user connectivity: {} => {}").format(
system_user, asset system_user, asset
...@@ -359,7 +359,7 @@ def test_system_user_connectivity_a_asset(system_user, asset): ...@@ -359,7 +359,7 @@ def test_system_user_connectivity_a_asset(system_user, asset):
return test_system_user_connectivity_util(system_user, [asset], task_name) return test_system_user_connectivity_util(system_user, [asset], task_name)
@shared_task @shared_task(queue="ansible")
def test_system_user_connectivity_period(): def test_system_user_connectivity_period():
if PERIOD_TASK != "on": if PERIOD_TASK != "on":
logger.debug("Period task disabled, test system user connectivity pass") logger.debug("Period task disabled, test system user connectivity pass")
...@@ -374,19 +374,16 @@ def test_system_user_connectivity_period(): ...@@ -374,19 +374,16 @@ def test_system_user_connectivity_period():
#### Push system user tasks #### #### Push system user tasks ####
def get_push_linux_system_user_tasks(system_user): def get_push_linux_system_user_tasks(system_user):
tasks = [] tasks = [
if system_user.password: {
tasks.append({
'name': 'Add user {}'.format(system_user.username), 'name': 'Add user {}'.format(system_user.username),
'action': { 'action': {
'module': 'user', 'module': 'user',
'args': 'name={} shell={} state=present password={}'.format( 'args': 'name={} shell={} state=present'.format(
system_user.username, system_user.shell, system_user.username, system_user.shell,
encrypt_password(system_user.password, salt="K3mIlKK"),
), ),
} }
}) },
tasks.extend([
{ {
'name': 'Check home dir exists', 'name': 'Check home dir exists',
'action': { 'action': {
...@@ -403,7 +400,18 @@ def get_push_linux_system_user_tasks(system_user): ...@@ -403,7 +400,18 @@ def get_push_linux_system_user_tasks(system_user):
}, },
'when': 'home_existed.stat.exists == true' 'when': 'home_existed.stat.exists == true'
} }
]) ]
if system_user.password:
tasks.append({
'name': 'Set {} password'.format(system_user.username),
'action': {
'module': 'user',
'args': 'name={} shell={} state=present password={}'.format(
system_user.username, system_user.shell,
encrypt_password(system_user.password, salt="K3mIlKK"),
),
}
})
if system_user.public_key: if system_user.public_key:
tasks.append({ tasks.append({
'name': 'Set {} authorized key'.format(system_user.username), 'name': 'Set {} authorized key'.format(system_user.username),
...@@ -475,7 +483,7 @@ def get_push_system_user_tasks(host, system_user): ...@@ -475,7 +483,7 @@ def get_push_system_user_tasks(host, system_user):
return tasks return tasks
@shared_task @shared_task(queue="ansible")
def push_system_user_util(system_user, assets, task_name): def push_system_user_util(system_user, assets, task_name):
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
if not system_user.is_need_push(): if not system_user.is_need_push():
...@@ -511,14 +519,14 @@ def push_system_user_util(system_user, assets, task_name): ...@@ -511,14 +519,14 @@ def push_system_user_util(system_user, assets, task_name):
task.run() task.run()
@shared_task @shared_task(queue="ansible")
def push_system_user_to_assets_manual(system_user): def push_system_user_to_assets_manual(system_user):
assets = system_user.get_all_assets() assets = system_user.get_all_assets()
task_name = _("Push system users to assets: {}").format(system_user.name) task_name = _("Push system users to assets: {}").format(system_user.name)
return push_system_user_util(system_user, assets, task_name=task_name) return push_system_user_util(system_user, assets, task_name=task_name)
@shared_task @shared_task(queue="ansible")
def push_system_user_a_asset_manual(system_user, asset): def push_system_user_a_asset_manual(system_user, asset):
task_name = _("Push system users to asset: {} => {}").format( task_name = _("Push system users to asset: {} => {}").format(
system_user.name, asset system_user.name, asset
...@@ -526,7 +534,7 @@ def push_system_user_a_asset_manual(system_user, asset): ...@@ -526,7 +534,7 @@ def push_system_user_a_asset_manual(system_user, asset):
return push_system_user_util(system_user, [asset], task_name=task_name) return push_system_user_util(system_user, [asset], task_name=task_name)
@shared_task @shared_task(queue="ansible")
def push_system_user_to_assets(system_user, assets): def push_system_user_to_assets(system_user, assets):
task_name = _("Push system users to assets: {}").format(system_user.name) task_name = _("Push system users to assets: {}").format(system_user.name)
return push_system_user_util(system_user, assets, task_name) return push_system_user_util(system_user, assets, task_name)
...@@ -561,7 +569,7 @@ def get_test_asset_user_connectivity_tasks(asset): ...@@ -561,7 +569,7 @@ def get_test_asset_user_connectivity_tasks(asset):
return tasks return tasks
@shared_task @shared_task(queue="ansible")
def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False): def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False):
""" """
:param asset_user: <AuthBook>对象 :param asset_user: <AuthBook>对象
...@@ -594,7 +602,7 @@ def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False) ...@@ -594,7 +602,7 @@ def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False)
asset_user.set_connectivity(summary) asset_user.set_connectivity(summary)
@shared_task @shared_task(queue="ansible")
def test_asset_users_connectivity_manual(asset_users, run_as_admin=False): def test_asset_users_connectivity_manual(asset_users, run_as_admin=False):
""" """
:param asset_users: <AuthBook>对象 :param asset_users: <AuthBook>对象
......
...@@ -213,10 +213,10 @@ class NodeUtil: ...@@ -213,10 +213,10 @@ class NodeUtil:
children.add(node) children.add(node)
return list(children) return list(children)
def get_children(self, node, with_self=True): def get_all_children(self, node, with_self=True):
return self.get_all_children_by_key(node.key, with_self=with_self) return self.get_all_children_by_key(node.key, with_self=with_self)
def get_children_keys_by_key(self, key, with_self=True): def get_all_children_keys_by_key(self, key, with_self=True):
nodes = self.get_all_children_by_key(key, with_self=with_self) nodes = self.get_all_children_by_key(key, with_self=with_self)
return [n.key for n in nodes] return [n.key for n in nodes]
......
...@@ -5,6 +5,7 @@ import re ...@@ -5,6 +5,7 @@ import re
import pytz import pytz
from django.utils import timezone from django.utils import timezone
from django.shortcuts import HttpResponse from django.shortcuts import HttpResponse
from django.conf import settings
from .utils import set_current_request from .utils import set_current_request
...@@ -56,6 +57,7 @@ class RequestMiddleware: ...@@ -56,6 +57,7 @@ class RequestMiddleware:
def __call__(self, request): def __call__(self, request):
set_current_request(request) set_current_request(request)
response = self.get_response(request) response = self.get_response(request)
if not settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
age = request.session.get_expiry_age() age = request.session.get_expiry_age()
request.session.set_expiry(age) request.session.set_expiry(age)
return response return response
...@@ -297,10 +297,10 @@ LOGGING = { ...@@ -297,10 +297,10 @@ LOGGING = {
'handlers': ['console', 'file'], 'handlers': ['console', 'file'],
'level': "INFO", 'level': "INFO",
}, },
'gunicorn': { # 'gunicorn': {
'handlers': ['gunicorn_console', 'gunicorn_file'], # 'handlers': ['gunicorn_console', 'gunicorn_file'],
'level': 'INFO', # 'level': 'INFO',
}, # },
# 'django.db': { # 'django.db': {
# 'handlers': ['console', 'file'], # 'handlers': ['console', 'file'],
# 'level': 'DEBUG' # 'level': 'DEBUG'
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import os import os
from kombu import Exchange,Queue
from celery import Celery from celery import Celery
# set the default Django settings module for the 'celery' program. # set the default Django settings module for the 'celery' program.
...@@ -15,6 +16,14 @@ configs = {k: v for k, v in settings.__dict__.items() if k.startswith('CELERY')} ...@@ -15,6 +16,14 @@ configs = {k: v for k, v in settings.__dict__.items() if k.startswith('CELERY')}
# Using a string here means the worker will not have to # Using a string here means the worker will not have to
# 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')
configs["CELERY_QUEUES"] = [
Queue("celery", Exchange("celery"), routing_key="celery"),
Queue("ansible", Exchange("ansible"), routing_key="ansible"),
]
configs["CELERY_ROUTES"] = {
"ops.tasks.run_ansible_task": {'exchange': 'ansible', 'routing_key': 'ansible'},
}
app.namespace = 'CELERY' app.namespace = 'CELERY'
app.conf.update(configs) app.conf.update(configs)
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])
...@@ -23,7 +23,7 @@ def rerun_task(): ...@@ -23,7 +23,7 @@ def rerun_task():
pass pass
@shared_task @shared_task(queue="ansible")
def run_ansible_task(tid, callback=None, **kwargs): def run_ansible_task(tid, callback=None, **kwargs):
""" """
:param tid: is the tasks serialized data :param tid: is the tasks serialized data
...@@ -98,7 +98,7 @@ def create_or_update_registered_periodic_tasks(): ...@@ -98,7 +98,7 @@ def create_or_update_registered_periodic_tasks():
create_or_update_celery_periodic_tasks(task) create_or_update_celery_periodic_tasks(task)
@shared_task @shared_task(queue="ansible")
def hello(name, callback=None): def hello(name, callback=None):
import time import time
time.sleep(10) time.sleep(10)
......
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings
from django.apps import AppConfig from django.apps import AppConfig
...@@ -8,4 +9,6 @@ class PermsConfig(AppConfig): ...@@ -8,4 +9,6 @@ class PermsConfig(AppConfig):
def ready(self): def ready(self):
from . import signals_handler from . import signals_handler
if not settings.XPACK_ENABLED:
settings.ASSETS_PERM_CACHE_ENABLE = False
return super().ready() return super().ready()
...@@ -174,10 +174,11 @@ function initTable() { ...@@ -174,10 +174,11 @@ function initTable() {
} }
}}, }},
{targets: 8, createdCell: function (td, cellData, rowData) { {targets: 8, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = '<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>' var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', name);
if (rowData.inherit) { if (rowData.inherit) {
del_btn = del_btn.replace("mark", "disabled") del_btn = del_btn.replace("mark", "disabled")
} }
......
...@@ -449,6 +449,8 @@ class AssetPermissionUtil(AssetPermissionCacheMixin): ...@@ -449,6 +449,8 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
self._nodes = None self._nodes = None
self._assets_direct = None self._assets_direct = None
self._nodes_direct = None self._nodes_direct = None
self.node_util = NodeUtil()
self.tree._node_util = self.node_util
@staticmethod @staticmethod
def change_org_if_need(): def change_org_if_need():
...@@ -491,13 +493,14 @@ class AssetPermissionUtil(AssetPermissionCacheMixin): ...@@ -491,13 +493,14 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
self.tree.add_nodes(nodes_keys) self.tree.add_nodes(nodes_keys)
pattern = set() all_nodes_keys = set()
for key in nodes_keys: for key in nodes_keys:
pattern.add(r'^{0}$|^{0}:'.format(key)) children_keys = self.node_util.get_all_children_keys_by_key(key)
pattern = '|'.join(list(pattern)) all_nodes_keys.update(set(children_keys))
if pattern:
if all_nodes_keys:
assets_ids = Asset.objects.filter( assets_ids = Asset.objects.filter(
nodes__key__regex=pattern nodes__key__in=all_nodes_keys
).valid().values_list("id", flat=True).distinct() ).valid().values_list("id", flat=True).distinct()
else: else:
assets_ids = [] assets_ids = []
......
...@@ -69,16 +69,17 @@ function initTable() { ...@@ -69,16 +69,17 @@ function initTable() {
} }
}}, }},
{targets: 6, createdCell: function (td, cellData, rowData) { {targets: 6, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = '<a href="{% url "terminal:terminal-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>' var update_btn = '<a href="{% url "terminal:terminal-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData); .replace('{{ DEFAULT_PK }}', cellData);
var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>' var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', name);
var accept_btn = '<a class="btn btn-xs btn-primary btn-accept" data-id="{{ DEFAULT_PK }}">{% trans "Accept" %}</a> ' var accept_btn = '<a class="btn btn-xs btn-primary btn-accept" data-id="{{ DEFAULT_PK }}">{% trans "Accept" %}</a> '
.replace('{{ DEFAULT_PK }}', cellData); .replace('{{ DEFAULT_PK }}', cellData);
var reject_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Reject" %}</a>' var reject_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Reject" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', name);
if (rowData.is_accepted) { if (rowData.is_accepted) {
$(td).html(update_btn + delete_btn); $(td).html(update_btn + delete_btn);
} else { } else {
......
...@@ -111,7 +111,7 @@ class AuthMixin: ...@@ -111,7 +111,7 @@ class AuthMixin:
@property @property
def password_will_expired(self): def password_will_expired(self):
if self.is_local and self.password_expired_remain_days < 5: if self.is_local and 0 <= self.password_expired_remain_days < 5:
return True return True
return False return False
......
...@@ -20,13 +20,13 @@ logger = get_logger(__file__) ...@@ -20,13 +20,13 @@ logger = get_logger(__file__)
def check_password_expired(): def check_password_expired():
users = User.objects.exclude(role=User.ROLE_APP) users = User.objects.exclude(role=User.ROLE_APP)
for user in users: for user in users:
if not user.is_valid:
continue
if not user.password_will_expired: if not user.password_will_expired:
continue continue
send_password_expiration_reminder_mail(user) send_password_expiration_reminder_mail(user)
logger.info("The user {} password expires in {} days".format( msg = "The user {} password expires in {} days"
user, user.password_expired_remain_days) logger.info(msg.format(user, user.password_expired_remain_days))
)
@shared_task @shared_task
......
...@@ -67,11 +67,12 @@ function initTable() { ...@@ -67,11 +67,12 @@ function initTable() {
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
{targets: 4, createdCell: function (td, cellData, rowData) { {targets: 4, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = '<a href="{% url "users:user-group-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>' var update_btn = '<a href="{% url "users:user-group-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData); .replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete_user_group" data-gid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>' var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete_user_group" data-gid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', name);
if (rowData.id === 1) { if (rowData.id === 1) {
$(td).html(update_btn) $(td).html(update_btn)
} else { } else {
......
...@@ -97,6 +97,7 @@ function initTable() { ...@@ -97,6 +97,7 @@ function initTable() {
} }
}}, }},
{targets: 7, createdCell: function (td, cellData, rowData) { {targets: 7, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = ""; var update_btn = "";
if (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin')) { if (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin')) {
update_btn = '<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>'; update_btn = '<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>';
...@@ -109,11 +110,11 @@ function initTable() { ...@@ -109,11 +110,11 @@ function initTable() {
if (rowData.id === 1 || rowData.username === "admin" || rowData.username === "{{ request.user.username }}" || (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin'))) { if (rowData.id === 1 || rowData.username === "admin" || rowData.username === "{{ request.user.username }}" || (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin'))) {
del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>' del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', name);
} else { } else {
del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>' del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', name);
} }
$(td).html(update_btn + del_btn) $(td).html(update_btn + del_btn)
}}], }}],
......
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
import os import os
import subprocess import subprocess
import threading import threading
import logging
import logging.handlers
import time import time
import argparse import argparse
import sys import sys
import signal import signal
from collections import defaultdict
import daemon
from daemon import pidfile
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, BASE_DIR) sys.path.insert(0, BASE_DIR)
...@@ -50,7 +55,9 @@ WORKERS = 4 ...@@ -50,7 +55,9 @@ WORKERS = 4
DAEMON = False DAEMON = False
EXIT_EVENT = threading.Event() EXIT_EVENT = threading.Event()
all_services = ['gunicorn', 'celery', 'beat'] LOCK = threading.Lock()
daemon_pid_file = ''
try: try:
os.makedirs(os.path.join(BASE_DIR, "data", "static")) os.makedirs(os.path.join(BASE_DIR, "data", "static"))
...@@ -58,6 +65,58 @@ try: ...@@ -58,6 +65,58 @@ try:
except: except:
pass pass
class LogPipe(threading.Thread):
def __init__(self, name, file_path, to_stdout=False):
"""Setup the object with a logger and a loglevel
and start the thread
"""
threading.Thread.__init__(self)
self.daemon = False
self.name = name
self.file_path = file_path
self.to_stdout = to_stdout
self.fdRead, self.fdWrite = os.pipe()
self.pipeReader = os.fdopen(self.fdRead)
self.logger = self.init_logger()
self.start()
def init_logger(self):
_logger = logging.getLogger(self.name)
_logger.setLevel(logging.INFO)
_formatter = logging.Formatter('%(message)s')
_handler = logging.handlers.RotatingFileHandler(
self.file_path, mode='a', maxBytes=5*1024*1024, backupCount=5
)
_handler.setFormatter(_formatter)
_handler.setLevel(logging.INFO)
_logger.addHandler(_handler)
if self.to_stdout:
_console = logging.StreamHandler()
_console.setLevel(logging.INFO)
_console.setFormatter(_formatter)
_logger.addHandler(_console)
return _logger
def fileno(self):
"""Return the write file descriptor of the pipe
"""
return self.fdWrite
def run(self):
"""Run the thread, logging everything.
"""
for line in iter(self.pipeReader.readline, ''):
self.logger.info(line.strip('\n'))
self.pipeReader.close()
def close(self):
"""Close the write end of the pipe.
"""
os.close(self.fdWrite)
def check_database_connection(): def check_database_connection():
os.chdir(os.path.join(BASE_DIR, 'apps')) os.chdir(os.path.join(BASE_DIR, 'apps'))
for i in range(60): for i in range(60):
...@@ -81,7 +140,9 @@ def make_migrations(): ...@@ -81,7 +140,9 @@ def make_migrations():
def collect_static(): def collect_static():
print("Collect static files") print("Collect static files")
os.chdir(os.path.join(BASE_DIR, 'apps')) os.chdir(os.path.join(BASE_DIR, 'apps'))
subprocess.call('python3 manage.py collectstatic --no-input -c &> /dev/null && echo "Collect static file done"', shell=True) command = 'python3 manage.py collectstatic --no-input -c &> /dev/null ' \
'&& echo "Collect static file done"'
subprocess.call(command, shell=True)
def prepare(): def prepare():
...@@ -100,18 +161,17 @@ def check_pid(pid): ...@@ -100,18 +161,17 @@ def check_pid(pid):
return True return True
def get_pid_file_path(service): def get_pid_file_path(s):
return os.path.join(TMP_DIR, '{}.pid'.format(service)) return os.path.join('/tmp', '{}.pid'.format(s))
def get_log_file_path(service): def get_log_file_path(s):
return os.path.join(LOG_DIR, '{}.log'.format(service)) return os.path.join(LOG_DIR, '{}.log'.format(s))
def get_pid(service): def get_pid_from_file(path):
pid_file = get_pid_file_path(service) if os.path.isfile(path):
if os.path.isfile(pid_file): with open(path) as f:
with open(pid_file) as f:
try: try:
return int(f.read().strip()) return int(f.read().strip())
except ValueError: except ValueError:
...@@ -119,12 +179,19 @@ def get_pid(service): ...@@ -119,12 +179,19 @@ def get_pid(service):
return 0 return 0
def get_pid(s):
pid_file = get_pid_file_path(s)
return get_pid_from_file(pid_file)
def is_running(s, unlink=True): def is_running(s, unlink=True):
pid_file = get_pid_file_path(s) pid_file = get_pid_file_path(s)
if os.path.isfile(pid_file): if os.path.isfile(pid_file):
pid = get_pid(s) pid = get_pid(s)
if check_pid(pid): if pid == 0:
return False
elif check_pid(pid):
return True return True
if unlink: if unlink:
...@@ -133,82 +200,73 @@ def is_running(s, unlink=True): ...@@ -133,82 +200,73 @@ def is_running(s, unlink=True):
def parse_service(s): def parse_service(s):
all_services = ['gunicorn', 'celery_ansible', 'celery_default', 'beat']
if s == 'all': if s == 'all':
return all_services return all_services
elif s == "celery":
return ["celery_ansible", "celery_default"]
elif "," in s: elif "," in s:
return [i.strip() for i in s.split(',')] services = set()
for i in s.split(','):
services.update(parse_service(i))
return services
else: else:
return [s] return [s]
def start_gunicorn(): def get_start_gunicorn_kwargs():
print("\n- Start Gunicorn WSGI HTTP Server") print("\n- Start Gunicorn WSGI HTTP Server")
prepare() prepare()
service = 'gunicorn' service = 'gunicorn'
bind = '{}:{}'.format(HTTP_HOST, HTTP_PORT) bind = '{}:{}'.format(HTTP_HOST, HTTP_PORT)
log_format = '%(h)s %(t)s "%(r)s" %(s)s %(b)s ' log_format = '%(h)s %(t)s "%(r)s" %(s)s %(b)s '
pid_file = get_pid_file_path(service) pid_file = get_pid_file_path(service)
log_file = get_log_file_path(service)
cmd = [ cmd = [
'gunicorn', 'jumpserver.wsgi', 'gunicorn', 'jumpserver.wsgi',
'-b', bind, '-b', bind,
#'-k', 'eventlet',
'-k', 'gthread', '-k', 'gthread',
'--threads', '10', '--threads', '10',
'-w', str(WORKERS), '-w', str(WORKERS),
'--max-requests', '4096', '--max-requests', '4096',
'--access-logformat', log_format, '--access-logformat', log_format,
'-p', pid_file, '-p', pid_file,
'--access-logfile', '-'
] ]
if DAEMON:
cmd.extend([
'--daemon',
])
else:
cmd.extend([
'--access-logfile', '-'
])
if DEBUG: if DEBUG:
cmd.append('--reload') cmd.append('--reload')
p = subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=APPS_DIR) return {'cmd': cmd, 'cwd': APPS_DIR}
return p
def start_celery(): def get_start_celery_ansible_kwargs():
print("\n- Start Celery as Distributed Task Queue") print("\n- Start Celery as Distributed Task Queue")
return get_start_worker_kwargs('ansible', 4)
def get_start_celery_default_kwargs():
return get_start_worker_kwargs('celery', 2)
def get_start_worker_kwargs(queue, num):
# Todo: Must set this environment, otherwise not no ansible result return # Todo: Must set this environment, otherwise not no ansible result return
os.environ.setdefault('PYTHONOPTIMIZE', '1') os.environ.setdefault('PYTHONOPTIMIZE', '1')
if os.getuid() == 0: if os.getuid() == 0:
os.environ.setdefault('C_FORCE_ROOT', '1') os.environ.setdefault('C_FORCE_ROOT', '1')
service = 'celery'
pid_file = get_pid_file_path(service)
cmd = [ cmd = [
'celery', 'worker', 'celery', 'worker',
'-A', 'ops', '-A', 'ops',
'-l', 'INFO', '-l', 'INFO',
'--pidfile', pid_file, '-c', str(num),
'--autoscale', '20,4', '-Q', queue,
] ]
if DAEMON: return {"cmd": cmd, "cwd": APPS_DIR}
cmd.extend([
'--logfile', os.path.join(LOG_DIR, 'celery.log'),
'--detach',
])
p = subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=APPS_DIR)
return p
def start_beat(): def get_start_beat_kwargs():
print("\n- Start Beat as Periodic Task Scheduler") print("\n- Start Beat as Periodic Task Scheduler")
pid_file = get_pid_file_path('beat')
log_file = get_log_file_path('beat')
os.environ.setdefault('PYTHONOPTIMIZE', '1') os.environ.setdefault('PYTHONOPTIMIZE', '1')
if os.getuid() == 0: if os.getuid() == 0:
os.environ.setdefault('C_FORCE_ROOT', '1') os.environ.setdefault('C_FORCE_ROOT', '1')
...@@ -217,72 +275,116 @@ def start_beat(): ...@@ -217,72 +275,116 @@ def start_beat():
cmd = [ cmd = [
'celery', 'beat', 'celery', 'beat',
'-A', 'ops', '-A', 'ops',
'--pidfile', pid_file, '-l', 'INFO',
'-l', LOG_LEVEL,
'--scheduler', scheduler, '--scheduler', scheduler,
'--max-interval', '60' '--max-interval', '60'
] ]
if DAEMON: return {"cmd": cmd, 'cwd': APPS_DIR}
cmd.extend([
'--logfile', log_file,
'--detach',
])
p = subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=APPS_DIR)
return p
def start_service(s): processes = {}
print(time.ctime())
print('Jumpserver version {}, more see https://www.jumpserver.org'.format(
__version__))
services_handler = {
"gunicorn": start_gunicorn,
"celery": start_celery,
"beat": start_beat
}
services_set = parse_service(s) def watch_services():
processes = [] max_retry = 3
for i in services_set: signal.signal(signal.SIGTERM, lambda x, y: clean_up())
if is_running(i): services_retry = defaultdict(int)
show_service_status(i) stopped_services = {}
continue
func = services_handler.get(i)
p = func()
processes.append(p)
now = int(time.time()) def check_services():
for i in services_set: for s, p in processes.items():
while not is_running(i): try:
if int(time.time()) - now < START_TIMEOUT: p.wait(timeout=1)
time.sleep(1) stopped_services[s] = ''
except subprocess.TimeoutExpired:
stopped_services.pop(s, None)
services_retry.pop(s, None)
continue continue
else:
print("Error: {} start error".format(i))
stop_multi_services(services_set)
return
stop_event = threading.Event() def retry_start_stopped_services():
for s in stopped_services:
if services_retry[s] > max_retry:
print("\nService start failed, exit: ", s)
EXIT_EVENT.set()
break
if not DAEMON: print("\n> Find {} stopped, retry {}".format(
signal.signal(signal.SIGTERM, lambda x, y: stop_event.set()) s, services_retry[s] + 1)
while not stop_event.is_set(): )
p = start_service(s)
processes[s] = p
services_retry[s] += 1
while not EXIT_EVENT.is_set():
try: try:
with LOCK:
check_services()
retry_start_stopped_services()
time.sleep(10) time.sleep(10)
except KeyboardInterrupt: except KeyboardInterrupt:
stop_event.set() time.sleep(1)
break break
clean_up()
def start_service(s):
services_kwargs = {
"gunicorn": get_start_gunicorn_kwargs,
"celery_ansible": get_start_celery_ansible_kwargs,
"celery_default": get_start_celery_default_kwargs,
"beat": get_start_beat_kwargs,
}
kwargs = services_kwargs.get(s)()
pid_file = get_pid_file_path(s)
print("Stop services") if os.path.isfile(pid_file):
for p in processes: os.unlink(pid_file)
p.terminate() cmd = kwargs.pop('cmd')
to_stdout = False
if not DAEMON:
to_stdout = True
log_file = get_log_file_path(s)
_logger = LogPipe(s, log_file, to_stdout=to_stdout)
stderr = stdout = _logger
kwargs.update({"stderr": stderr, "stdout": stdout})
p = subprocess.Popen(cmd, **kwargs)
with open(pid_file, 'w') as f:
f.write(str(p.pid))
return p
def start_services_and_watch(s):
print(time.ctime())
print('Jumpserver version {}, more see https://www.jumpserver.org'.format(
__version__)
)
services_set = parse_service(s)
for i in services_set: for i in services_set:
stop_service(i) if is_running(i):
show_service_status(i)
continue
p = start_service(i)
time.sleep(2)
processes[i] = p
if not DAEMON:
watch_services()
else: else:
print()
show_service_status(s) show_service_status(s)
global daemon_pid_file
daemon_pid_file = get_pid_file_path('jms')
context = daemon.DaemonContext(
pidfile=pidfile.TimeoutPIDLockFile(daemon_pid_file),
signal_map={
signal.SIGTERM: clean_up,
signal.SIGHUP: 'terminate',
},
)
with context:
watch_services()
def stop_service(s, sig=15): def stop_service(s, sig=15):
...@@ -294,6 +396,12 @@ def stop_service(s, sig=15): ...@@ -294,6 +396,12 @@ def stop_service(s, sig=15):
print("Stop service: {}".format(s)) print("Stop service: {}".format(s))
pid = get_pid(s) pid = get_pid(s)
os.kill(pid, sig) os.kill(pid, sig)
with LOCK:
processes.pop(s, None)
if s == "all":
pid = get_pid('jms')
os.kill(pid, sig)
def stop_multi_services(services): def stop_multi_services(services):
...@@ -305,6 +413,15 @@ def stop_service_force(s): ...@@ -305,6 +413,15 @@ def stop_service_force(s):
stop_service(s, sig=9) stop_service(s, sig=9)
def clean_up():
if not EXIT_EVENT.is_set():
EXIT_EVENT.set()
processes_dump = {k: v for k, v in processes.items()}
for s1, p1 in processes_dump.items():
stop_service(s1)
p1.wait()
def show_service_status(s): def show_service_status(s):
services_set = parse_service(s) services_set = parse_service(s)
for ns in services_set: for ns in services_set:
...@@ -348,13 +465,14 @@ if __name__ == '__main__': ...@@ -348,13 +465,14 @@ if __name__ == '__main__':
srv = args.service srv = args.service
if action == "start": if action == "start":
start_service(srv) start_services_and_watch(srv)
os._exit(0)
elif action == "stop": elif action == "stop":
stop_service(srv) stop_service(srv)
elif action == "restart": elif action == "restart":
DAEMON = True DAEMON = True
stop_service(srv) stop_service(srv)
time.sleep(5) time.sleep(5)
start_service(srv) start_services_and_watch(srv)
else: else:
show_service_status(srv) show_service_status(srv)
...@@ -81,4 +81,5 @@ django-radius==1.3.3 ...@@ -81,4 +81,5 @@ django-radius==1.3.3
ipip-ipdb==1.2.1 ipip-ipdb==1.2.1
django-redis-sessions==0.6.1 django-redis-sessions==0.6.1
unicodecsv==0.14.1 unicodecsv==0.14.1
python-daemon==2.2.3
httpsig==1.3.0 httpsig==1.3.0
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