[Update] 统一可连接性,添加sql debug

pull/2874/head
ibuler 2019-06-24 20:16:18 +08:00
commit 0f8d4f5b32
31 changed files with 313 additions and 224 deletions

View File

@ -78,7 +78,7 @@ class AssetUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
system_user_id = self.request.GET.get("system_user_id")
kwargs = {}
assets = []
assets = None
manager = AssetUserManager()
if system_user_id:
@ -92,7 +92,7 @@ class AssetUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
manager.prefer('admin_user')
if asset_id:
asset = get_object_or_none(Asset, pk=asset_id)
asset = get_object_or_404(Asset, id=asset_id)
assets = [asset]
elif node_id:
node = get_object_or_404(Node, id=node_id)
@ -100,7 +100,7 @@ class AssetUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
if username:
kwargs['username'] = username
if assets:
if assets is not None:
kwargs['assets'] = assets
queryset = manager.filter(**kwargs)

View File

@ -33,6 +33,9 @@ class AssetUserManager:
_using = None
def filter(self, username=None, assets=None, latest=True):
if assets is not None and not assets:
return AssetUserQuerySet([])
if self._using:
backend = dict(self.backends).get(self._using)
if not backend:

View File

@ -0,0 +1,53 @@
# Generated by Django 2.1.7 on 2019-06-21 05:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0030_auto_20190619_1135'),
]
operations = [
migrations.AlterField(
model_name='adminuser',
name='date_created',
field=models.DateTimeField(auto_now_add=True, verbose_name='Date created'),
),
migrations.AlterField(
model_name='adminuser',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
migrations.AlterField(
model_name='authbook',
name='date_created',
field=models.DateTimeField(auto_now_add=True, verbose_name='Date created'),
),
migrations.AlterField(
model_name='authbook',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
migrations.AlterField(
model_name='gateway',
name='date_created',
field=models.DateTimeField(auto_now_add=True, verbose_name='Date created'),
),
migrations.AlterField(
model_name='gateway',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
migrations.AlterField(
model_name='systemuser',
name='date_created',
field=models.DateTimeField(auto_now_add=True, verbose_name='Date created'),
),
migrations.AlterField(
model_name='systemuser',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
]

View File

@ -229,11 +229,15 @@ class Asset(OrgModelMixin):
def connectivity(self):
if not self.admin_user:
return Connectivity.unknown()
return self.admin_user.get_asset_connectivity(self)
instance = self.admin_user.get_asset_user(self)
return instance.connectivity
@connectivity.setter
def connectivity(self, value):
self.admin_user.set_asset_connectivity(self, value)
if not self.admin_user:
return
instance = self.admin_user.get_asset_user(self)
instance.set_asset_connectivity(self, value)
def get_auth_info(self):
if not self.admin_user:

View File

@ -169,27 +169,27 @@ class AssetUser(OrgModelMixin):
def set_asset_connectivity(self, asset, c):
i = self.generate_id_with_asset(asset)
key = self.CONNECTIVITY_ASSET_CACHE_KEY.format(i)
Connectivity.set(key, c, 3600)
Connectivity.set(key, c)
def load_specific_asset_auth(self, asset):
def get_asset_user(self, asset):
from ..backends import AssetUserManager
try:
manager = AssetUserManager().prefer(self._prefer)
other = manager.get(username=self.username, asset=asset)
return other
except Exception as e:
logger.error(e, exc_info=True)
else:
self._merge_auth(other)
return None
def load_specific_asset_auth(self, asset):
instance = self.get_asset_user(asset)
if instance:
self._merge_auth(instance)
def _merge_auth(self, other):
if not other:
return
if other.password:
self.password = other.password
if other.public_key:
self.public_key = other.public_key
if other.private_key:
self.private_key = other.private_key
self.password = other.password
self.public_key = other.public_key
self.private_key = other.private_key
def clear_auth(self):
self._password = ''

View File

@ -45,24 +45,24 @@ class Connectivity:
(UNKNOWN, _("Unknown")),
)
value = UNKNOWN
status = UNKNOWN
datetime = timezone.now()
def __init__(self, value, datetime):
self.value = value
def __init__(self, status, datetime):
self.status = status
self.datetime = datetime
def display(self):
return dict(self.__class__.CONNECTIVITY_CHOICES).get(self.value)
return dict(self.__class__.CONNECTIVITY_CHOICES).get(self.status)
def is_reachable(self):
return self.value == self.REACHABLE
return self.status == self.REACHABLE
def is_unreachable(self):
return self.value == self.UNREACHABLE
return self.status == self.UNREACHABLE
def is_unknown(self):
return self.value == self.UNKNOWN
return self.status == self.UNKNOWN
@classmethod
def unreachable(cls):
@ -96,4 +96,7 @@ class Connectivity:
cls.set(key, cls.reachable(), ttl)
def __eq__(self, other):
return self.value == other.value
return self.status == other.status
def __str__(self):
return self.display()

View File

@ -9,6 +9,7 @@ from orgs.mixins import BulkOrgResourceModelSerializer
from common.serializers import AdaptedBulkListSerializer
from ..models import Asset, Protocol
from .system_user import AssetSystemUserSerializer
from .base import ConnectivitySerializer
__all__ = [
'AssetSerializer', 'AssetGrantedSerializer', 'AssetSimpleSerializer',
@ -43,6 +44,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
protocols = ProtocolsRelatedField(
many=True, queryset=Protocol.objects.all(), label=_("Protocols")
)
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
"""
资产的数据结构
@ -69,7 +71,6 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
'protocol': {'write_only': True},
'port': {'write_only': True},
'hardware_info': {'label': _('Hardware info')},
'connectivity': {'label': _('Connectivity')},
'org_name': {'label': _('Org name')}
}

View File

@ -4,11 +4,12 @@
from django.utils.translation import ugettext as _
from rest_framework import serializers
from ..models import AuthBook, Asset
from ..backends import AssetUserManager
from common.utils import validate_ssh_private_key
from common.serializers import AdaptedBulkListSerializer
from orgs.mixins import BulkOrgResourceModelSerializer
from ..models import AuthBook, Asset
from ..backends import AssetUserManager
from .base import ConnectivitySerializer
__all__ = [
@ -26,7 +27,7 @@ class BasicAssetSerializer(serializers.ModelSerializer):
class AssetUserSerializer(BulkOrgResourceModelSerializer):
hostname = serializers.CharField(read_only=True, label=_("Hostname"))
ip = serializers.CharField(read_only=True, label=_("IP"))
connectivity = serializers.CharField(read_only=True, label=_("Connectivity"))
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
password = serializers.CharField(
max_length=256, allow_blank=True, allow_null=True, write_only=True,

View File

@ -24,3 +24,8 @@ class AuthSerializer(serializers.ModelSerializer):
self.instance.set_auth(password=password, private_key=private_key,
public_key=public_key)
return self.instance
class ConnectivitySerializer(serializers.Serializer):
status = serializers.IntegerField()
datetime = serializers.DateTimeField()

View File

@ -15,51 +15,23 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer):
password = serializers.CharField(
required=False, write_only=True, label=_('Password')
)
unreachable_amount = serializers.SerializerMethodField(
label=_('Unreachable')
)
unreachable_assets = serializers.SerializerMethodField(
label=_('Unreachable assets')
)
reachable_assets = serializers.SerializerMethodField(
label=_('Reachable assets')
)
reachable_amount = serializers.SerializerMethodField(label=_('Reachable'))
assets_amount = serializers.SerializerMethodField(label=_('Asset'))
class Meta:
model = SystemUser
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'name', 'username', 'login_mode', 'login_mode_display',
'login_mode_display', 'priority', 'protocol', 'auto_push',
'password', 'assets_amount', 'reachable_amount', 'reachable_assets',
'unreachable_amount', 'unreachable_assets', 'cmd_filters', 'sudo',
'shell', 'comment', 'nodes', 'assets'
'priority', 'protocol', 'auto_push', 'password',
'cmd_filters', 'sudo', 'shell', 'comment', 'nodes', 'assets',
'assets_amount', 'connectivity_amount'
]
extra_kwargs = {
'assets_amount': {'label': _('Asset')},
'connectivity_amount': {'label': _('Connectivity')},
'login_mode_display': {'label': _('Login mode display')},
'created_by': {'read_only': True},
}
@staticmethod
def get_unreachable_assets(obj):
return obj.assets_unreachable
@staticmethod
def get_reachable_assets(obj):
return obj.assets_reachable
def get_unreachable_amount(self, obj):
return len(self.get_unreachable_assets(obj))
def get_reachable_amount(self, obj):
return len(self.get_reachable_assets(obj))
@staticmethod
def get_assets_amount(obj):
return len(obj.get_related_assets())
class SystemUserAuthSerializer(AuthSerializer):
"""

View File

@ -208,8 +208,7 @@ def test_asset_connectivity_util(assets, task_name=None):
pattern='all', options=const.TASK_OPTIONS, run_as_admin=True,
created_by=created_by,
)
result = task.run()
summary = result.get("summary", {})
raw, summary = task.run()
success = summary.get('success', False)
contacted = summary.get('contacted', {})
dark = summary.get('dark', {})
@ -332,8 +331,7 @@ def test_system_user_connectivity_util(system_user, assets, task_name):
pattern='all', options=const.TASK_OPTIONS,
run_as=system_user.username, created_by=system_user.org_id,
)
result = task.run()
summary = result[1]
raw, summary = task.run()
success = summary.get('success', False)
contacted = summary.get('contacted', {})
dark = summary.get('dark', {})
@ -563,18 +561,6 @@ def get_test_asset_user_connectivity_tasks(asset):
return tasks
@shared_task
def set_asset_user_connectivity_info(asset_user, result):
summary = result[1]
if summary.get('contacted'):
connectivity = 1
elif summary.get("dark"):
connectivity = 0
else:
connectivity = 3
asset_user.connectivity = connectivity
@shared_task
def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False):
"""
@ -603,8 +589,8 @@ def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False)
else:
kwargs["run_as"] = asset_user.username
task, created = update_or_create_ansible_task(*args, **kwargs)
result = task.run()
asset_user.set_connectivity(result.get("summary", {}))
raw, summary = task.run()
asset_user.set_connectivity(summary)
@shared_task

View File

@ -33,6 +33,7 @@ var assetUserTable;
var needPush = false;
var prefer = null;
var lastMFATime = "{{ request.session.OTP_LAST_VERIFY_TIME }}";
var testDatetime = "{% trans 'Test datetime: ' %}";
function initAssetUserTable() {
var options = {
@ -41,13 +42,19 @@ function initAssetUserTable() {
columnDefs: [
{
targets: 5, createdCell: function (td, cellData) {
if (cellData == 1) {
$(td).html('<i class="fa fa-circle text-navy"></i>')
} else if (cellData == 0) {
$(td).html('<i class="fa fa-circle text-danger"></i>')
var innerHtml = "";
if (cellData.status == 1) {
innerHtml = '<i class="fa fa-circle text-navy"></i>'
} else if (cellData.status == 0) {
innerHtml = '<i class="fa fa-circle text-danger"></i>'
} else {
$(td).html('<i class="fa fa-circle text-warning"></i>')
innerHtml = '<i class="fa fa-circle text-warning"></i>'
}
var date = new Date(cellData.datetime);
var dateManual = date.toLocaleString();
var dataContent = testDatetime + dateManual;
innerHtml = "<a data-toggle='popover' data-content='" + dataContent + "'" + 'data-placement="auto bottom"' + ">" + innerHtml + "</a>";
$(td).html(innerHtml);
}
},
{
@ -102,7 +109,7 @@ $(document).ready(function(){
authUsername = $(this).data('user');
var now = new Date();
var nowTime = now.getTime() / 1000;
if (nowTime - lastMFATime > 60*10 ) {
if ( !lastMFATime || nowTime - lastMFATime > 60*10 ) {
mfaFor = "viewAuth";
$("#mfa_auth_confirm").modal("show");
} else {

View File

@ -23,7 +23,7 @@
</ul>
</div>
<div class="tab-content">
<div class="col-sm-9" style="padding-left: 0;">
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span>
@ -46,7 +46,7 @@
</div>
</div>
</div>
<div class="col-sm-3" style="padding-left: 0;padding-right: 0">
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
@ -81,21 +81,6 @@ $(document).ready(function () {
prefer = "admin_user";
initAssetUserTable();
})
.on('click', '.btn-test-asset', function () {
var asset_id = $(this).data('uid');
var the_url = "{% url 'api-assets:asset-alive-test' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', asset_id);
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
flash_message: false
});
})
.on('click', '.btn-test-connective', function () {
var the_url = "{% url 'api-assets:admin-user-connective' pk=admin_user.id %}";
var success = function (data) {
@ -110,17 +95,5 @@ $(document).ready(function () {
flash_message: false
});
})
.on('click', '.btn-update-asset-user-auth', function() {
asset_id = $(this).data('aid');
hostname = $(this).data('hostname');
username = '{{ admin_user.username }}';
$("#asset_user_auth_update_modal").modal();
})
.on("click", ".btn-view-auth", function (evt) {
asset_id = $(this).data("aid") ;
host = $(this).data("hostname");
username = "{{ admin_user.username }}";
$("#asset_user_auth_view").modal();
})
</script>
{% endblock %}

View File

@ -11,27 +11,27 @@
{% endblock %}
{% block table_search %}
<div class="" style="float: right">
<div class=" btn-group">
<button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">CSV <span class="caret"></span></button>
<ul class="dropdown-menu">
<li>
<a class=" btn_export" tabindex="0">
<span>{% trans "Export" %}</span>
</a>
</li>
<li>
<a class=" btn_import" data-toggle="modal" data-target="#import_modal" tabindex="0">
<span>{% trans "Import" %}</span>
</a>
</li>
<li>
<a class=" btn_update" data-toggle="modal" data-target="#update_modal" tabindex="0">
<span>{% trans "Update" %}</span>
</a>
</li>
</ul>
</div>
</div>
<div class=" btn-group">
<button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">CSV <span class="caret"></span></button>
<ul class="dropdown-menu">
<li>
<a class=" btn_export" tabindex="0">
<span>{% trans "Export" %}</span>
</a>
</li>
<li>
<a class=" btn_import" data-toggle="modal" data-target="#import_modal" tabindex="0">
<span>{% trans "Import" %}</span>
</a>
</li>
<li>
<a class=" btn_update" data-toggle="modal" data-target="#update_modal" tabindex="0">
<span>{% trans "Update" %}</span>
</a>
</li>
</ul>
</div>
</div>
{% endblock %}
{% block table_container %}
@ -81,7 +81,7 @@ function initTable() {
} else {
innerHtml = "<span>" + data + "</span>";
}
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + data +'">' + innerHtml + '</span>');
$(td).html(innerHtml)
}},
{targets: 5, createdCell: function (td, cellData) {
var data = cellData['unreachable'];
@ -127,7 +127,7 @@ function initTable() {
}
$(document).ready(function(){
initTable()
initTable();
})
.on('click', '.btn_admin_user_delete', function () {

View File

@ -163,6 +163,7 @@ var zTree, rMenu, asset_table, show = 0;
var update_node_action = "";
var current_node_id = null;
var current_node = null;
var testDatetime = "{% trans 'Test datetime: ' %}";
function initTable() {
var options = {
ele: $('#asset_list_table'),
@ -176,16 +177,21 @@ function initTable() {
{targets: 3, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.hardware_info)
}},
{targets: 4, createdCell: function (td, cellData) {
if (cellData === 1){
$(td).html('<i class="fa fa-circle text-navy"></i>')
} else if (cellData === 0) {
$(td).html('<i class="fa fa-circle text-danger"></i>')
} else {
$(td).html('<i class="fa fa-circle text-warning"></i>')
}
{targets: 4, createdCell: function (td, cellData, rowData) {
var innerHtml = "";
if (cellData.status == 1) {
innerHtml = '<i class="fa fa-circle text-navy"></i>'
} else if (cellData.status == 0) {
innerHtml = '<i class="fa fa-circle text-danger"></i>'
} else {
innerHtml = '<i class="fa fa-circle text-warning"></i>'
}
var date = new Date(cellData.datetime);
var dateManual = date.toLocaleString();
var dataContent = testDatetime + dateManual;
innerHtml = "<a data-toggle='popover' data-content='" + dataContent + "'" + 'data-placement="auto bottom"' + ">" + innerHtml + "</a>";
$(td).html(innerHtml);
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:asset-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);

View File

@ -25,7 +25,7 @@
</ul>
</div>
<div class="tab-content">
<div class="col-sm-9" style="padding-left: 0;">
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Assets of ' %} <b>{{ system_user.name }} </b><span class="badge">{{ paginator.count }}</span></span>
@ -48,7 +48,7 @@
</div>
</div>
</div>
<div class="col-sm-3" style="padding-left: 0;padding-right: 0">
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
@ -169,40 +169,6 @@ $(document).ready(function () {
initAssetUserTable();
})
.on('click', '.btn-push', function () {
var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}";
var error = function (data) {
alert(data)
};
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
error: error,
method: 'GET',
success: success
});
})
.on('click', '.btn-test-connective', function () {
var the_url = "{% url 'api-assets:system-user-connective' pk=system_user.id %}";
var error = function (data) {
alert(data)
};
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
error: error,
method: 'GET',
success: success
});
})
.on('click', '.btn-remove-from-node', function() {
var $this = $(this);
var $tr = $this.closest('tr');
@ -230,6 +196,23 @@ $(document).ready(function () {
});
updateSystemUserNode(nodes);
})
.on('click', '.btn-push', function () {
var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}";
var error = function (data) {
alert(data)
};
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
error: error,
method: 'GET',
success: success
});
})
.on('click', '.btn-push-auth', function () {
var $this = $(this);
var asset_id = $this.data('asset');
@ -250,6 +233,23 @@ $(document).ready(function () {
error: error
})
})
.on('click', '.btn-test-connective', function () {
var the_url = "{% url 'api-assets:system-user-connective' pk=system_user.id %}";
var error = function (data) {
alert(data)
};
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
error: error,
method: 'GET',
success: success
});
})
</script>

View File

@ -80,27 +80,29 @@ function initTable() {
}},
{targets: 6, createdCell: function (td, cellData) {
var innerHtml = "";
if (cellData !== 0) {
innerHtml = "<span class='text-navy'>" + cellData + "</span>";
var data = cellData['reachable'];
if (data !== 0) {
innerHtml = "<span class='text-navy'>" + data + "</span>";
} else {
innerHtml = "<span>" + cellData + "</span>";
innerHtml = "<span>" + data + "</span>";
}
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData +'">' + innerHtml + '</span>');
$(td).html(innerHtml)
}},
{targets: 7, createdCell: function (td, cellData) {
var data = cellData['unreachable'];
var innerHtml = "";
if (cellData !== 0) {
innerHtml = "<span class='text-danger'>" + cellData + "</span>";
if (data !== 0) {
innerHtml = "<span class='text-danger'>" + data + "</span>";
} else {
innerHtml = "<span>" + cellData + "</span>";
innerHtml = "<span>" + data + "</span>";
}
$(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="' + data + '">' + innerHtml + '</span>');
}},
{targets: 8, createdCell: function (td, cellData, rowData) {
var val = 0;
var innerHtml = "";
var total = rowData.assets_amount;
var reachable = rowData.reachable_amount;
var reachable = cellData.reachable;
if (total !== 0) {
val = reachable/total * 100;
}
@ -112,7 +114,6 @@ function initTable() {
innerHtml = "<span class='text-danger'>" + num.toFixed(1) + "% </span>";
}
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}},
{targets: 10, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:system-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
@ -122,10 +123,10 @@ function initTable() {
ajax_url: '{% url "api-assets:system-user-list" %}',
columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "login_mode_display"}, {data: "assets_amount" },
{data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }
{data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "comment" }, {data: "id" }
],
op_html: $('#actions').html()
};
};
system_user_table = jumpserver.initServerSideDataTable(options);
return system_user_table
}

View File

@ -92,7 +92,7 @@ class SystemUserDeleteView(PermissionsMixin, DeleteView):
class SystemUserAssetView(PermissionsMixin, DetailView):
model = SystemUser
template_name = 'assets/system_user_asset.html'
template_name = 'assets/system_user_assets.html'
context_object_name = 'system_user'
permission_classes = [IsOrgAdmin]

View File

@ -15,3 +15,6 @@ def on_db_connection_ready(sender, **kwargs):
class CommonConfig(AppConfig):
name = 'common'
def ready(self):
from . import signals_handlers

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
#
import re
from collections import defaultdict
from django.conf import settings
from django.core.signals import request_finished
from django.db import connection
from .utils import get_logger
logger = get_logger(__file__)
pattern = re.compile(r'FROM `(\w+)`')
class Counter:
def __init__(self):
self.counter = 0
self.time = 0
def __gt__(self, other):
return self.counter > other.counter
def __lt__(self, other):
return self.counter < other.counter
def __eq__(self, other):
return self.counter == other.counter
def on_request_finished_logging_db_query(sender, **kwargs):
queries = connection.queries
counters = defaultdict(Counter)
for query in queries:
if not query['sql'].startswith('SELECT'):
continue
tables = pattern.findall(query['sql'])
table_name = ''.join(tables)
time = query['time']
counters[table_name].counter += 1
counters[table_name].time += float(time)
counters['total'].counter += 1
counters['total'].time += float(time)
counters = sorted(counters.items(), key=lambda x: x[1])
for name, counter in counters:
logger.debug("Query {:3} times using {:.2f}s {}".format(
counter.counter, counter.time, name)
)
if settings.DEBUG:
request_finished.connect(on_request_finished_logging_db_query)

View File

@ -51,7 +51,7 @@ class Signer(metaclass=Singleton):
try:
return s.loads(value)
except BadSignature:
return {}
return None
def sign_t(self, value, expires_in=3600):
s = TimedJSONWebSignatureSerializer(self.secret_key, expires_in=expires_in)
@ -62,7 +62,7 @@ class Signer(metaclass=Singleton):
try:
return s.loads(value)
except (BadSignature, SignatureExpired):
return {}
return None
def ssh_key_string_to_obj(text, password=None):

View File

@ -111,6 +111,7 @@ MIDDLEWARE = [
'orgs.middleware.OrgMiddleware',
]
ROOT_URLCONF = 'jumpserver.urls'
TEMPLATES = [

View File

@ -92,3 +92,4 @@ if settings.DEBUG:
path('docs/v2/', get_swagger_view("v2").with_ui('swagger', cache_timeout=1), name="docs"),
path('redoc/v2/', get_swagger_view("v2").with_ui('redoc', cache_timeout=1), name='redoc'),
]

View File

@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
#
from .utils import current_org, get_current_org
from .utils import current_org, get_org_from_request
from .models import Organization
def org_processor(request):
context = {
'ADMIN_ORGS': Organization.get_user_admin_orgs(request.user),
'CURRENT_ORG': get_current_org(),
'CURRENT_ORG': get_org_from_request(request),
'HAS_ORG_PERM': current_org.can_admin_by(request.user),
}
return context

View File

@ -11,7 +11,7 @@ class OrgMiddleware:
@staticmethod
def set_permed_org_if_need(request):
if request.content_type != "text/plain":
if request.path.startswith('/api'):
return
if not (request.user.is_authenticated and request.user.is_org_admin):
return

View File

@ -3,6 +3,7 @@
from werkzeug.local import Local
from django.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import redirect, get_object_or_404
from django.forms import ModelForm
@ -20,7 +21,7 @@ from .utils import (
from .models import Organization
logger = get_logger(__file__)
tl = Local()
local = Local()
__all__ = [
'OrgManager', 'OrgViewGenericMixin', 'OrgModelMixin', 'OrgModelForm',
@ -28,16 +29,13 @@ __all__ = [
'OrgMembershipModelViewSetMixin', 'OrgResourceSerializerMixin',
'BulkOrgResourceSerializerMixin', 'BulkOrgResourceModelSerializer',
]
debug = settings.DEBUG
class OrgManager(models.Manager):
def get_queryset(self):
queryset = super(OrgManager, self).get_queryset()
kwargs = {}
# if not hasattr(tl, 'times'):
# tl.times = 0
# logger.debug("[{}]>>>>>>>>>> Get query set".format(tl.times))
if not current_org:
kwargs['id'] = None
elif current_org.is_real():
@ -45,7 +43,6 @@ class OrgManager(models.Manager):
elif current_org.is_default():
queryset = queryset.filter(org_id="")
queryset = queryset.filter(**kwargs)
# tl.times += 1
return queryset
def filter_by_fullname(self, fullname, field=None):

View File

@ -26,7 +26,7 @@ from ..hands import (
)
from .. import serializers, const
from ..mixins import (
AssetsFilterMixin, RemoteAppFilterMixin, ChangeOrgIfNeedMixin
AssetsFilterMixin, RemoteAppFilterMixin
)
from ..models import Action
@ -48,14 +48,6 @@ class UserPermissionCacheMixin:
CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME
_object = None
@staticmethod
def change_org_if_need(request, kwargs):
if request.user.is_authenticated and \
request.user.is_superuser or \
request.user.is_app or \
kwargs.get('pk') is None:
set_to_root_org()
def get_object(self):
return None
@ -115,7 +107,6 @@ class UserPermissionCacheMixin:
cache.set(key, response.data, self.CACHE_TIME)
def get(self, request, *args, **kwargs):
self.change_org_if_need(request, kwargs)
self.cache_policy = request.GET.get('cache_policy', '0')
obj = self._get_object()
@ -461,7 +452,7 @@ class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, APIView):
# RemoteApp permission
class UserGrantedRemoteAppsApi(ChangeOrgIfNeedMixin, RemoteAppFilterMixin, ListAPIView):
class UserGrantedRemoteAppsApi(RemoteAppFilterMixin, ListAPIView):
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = RemoteAppSerializer
pagination_class = LimitOffsetPagination
@ -486,7 +477,7 @@ class UserGrantedRemoteAppsApi(ChangeOrgIfNeedMixin, RemoteAppFilterMixin, ListA
return super().get_permissions()
class UserGrantedRemoteAppsAsTreeApi(ChangeOrgIfNeedMixin, ListAPIView):
class UserGrantedRemoteAppsAsTreeApi(ListAPIView):
serializer_class = TreeNodeSerializer
permission_classes = (IsOrgAdminOrAppUser,)
@ -518,11 +509,10 @@ class UserGrantedRemoteAppsAsTreeApi(ChangeOrgIfNeedMixin, ListAPIView):
return super().get_permissions()
class ValidateUserRemoteAppPermissionApi(ChangeOrgIfNeedMixin, APIView):
class ValidateUserRemoteAppPermissionApi(APIView):
permission_classes = (IsOrgAdminOrAppUser,)
def get(self, request, *args, **kwargs):
self.change_org_if_need(request, kwargs)
user_id = request.query_params.get('user_id', '')
remote_app_id = request.query_params.get('remote_app_id', '')
user = get_object_or_404(User, id=user_id)

View File

@ -11,6 +11,7 @@ from django.core.cache import cache
from django.conf import settings
from django.utils.translation import ugettext as _
from orgs.utils import set_to_root_org
from common.utils import get_logger
from common.tree import TreeNode
from .. import const
@ -162,6 +163,11 @@ class AssetPermissionUtil:
self._filter_id = 'None' # 当通过filter更改 permission是标记
self.cache_policy = cache_policy
self.tree = GenerateTree()
self.change_org_if_need()
@staticmethod
def change_org_if_need():
set_to_root_org()
@classmethod
def is_not_using_cache(cls, cache_policy):

View File

@ -4,6 +4,7 @@
from django.db.models import Q
from common.tree import TreeNode
from orgs.utils import set_to_root_org
from ..models import RemoteAppPermission
@ -38,6 +39,11 @@ class RemoteAppPermissionUtil:
def __init__(self, obj):
self.object = obj
self.change_org_if_need()
@staticmethod
def change_org_if_need():
set_to_root_org()
@property
def permissions(self):

View File

@ -26,10 +26,10 @@ def refresh_settings_on_changed(sender, instance=None, **kwargs):
def monkey_patch_settings(sender, **kwargs):
cache_key_prefix = '_SETTING_'
custom_need_cache_settings = [
'AUTHENTICATION_BACKENDS'
'AUTHENTICATION_BACKENDS', 'TERMINAL_HOST_KEY',
]
custom_no_cache_settings = [
'BASE_DIR', 'VERSION', 'AUTH_OPENID'
'BASE_DIR', 'VERSION', 'AUTH_OPENID',
]
django_settings = dir(global_settings)
uncached_settings = [i for i in django_settings if i.isupper()]

View File

@ -500,8 +500,10 @@ jumpserver.initDataTable = function (options) {
$('[data-toggle="popover"]').popover({
html: true,
placement: 'bottom',
// trigger: 'hover',
trigger: 'click',
container: 'body'
}).on('click', function (e) {
$('[data-toggle="popover"]').not(this).popover('hide');
});
});
$('.ipt_check_all').on('click', function() {
@ -670,6 +672,14 @@ jumpserver.initServerSideDataTable = function (options) {
}).on('draw', function(){
$('#op').html(options.op_html || '');
$('#uc').html(options.uc_html || '');
$('[data-toggle="popover"]').popover({
html: true,
placement: 'bottom',
trigger: 'click',
container: 'body'
}).on('click', function (e) {
$('[data-toggle="popover"]').not(this).popover('hide');
});
var table_data = [];
$.each(table.rows().data(), function (id, row) {
if (row.id) {