mirror of https://github.com/jumpserver/jumpserver
[Update] 统一可连接性,添加sql debug
commit
0f8d4f5b32
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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:
|
||||
|
|
|
@ -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 = ''
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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')}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -15,3 +15,6 @@ def on_db_connection_ready(sender, **kwargs):
|
|||
|
||||
class CommonConfig(AppConfig):
|
||||
name = 'common'
|
||||
|
||||
def ready(self):
|
||||
from . import signals_handlers
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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):
|
||||
|
|
|
@ -111,6 +111,7 @@ MIDDLEWARE = [
|
|||
'orgs.middleware.OrgMiddleware',
|
||||
]
|
||||
|
||||
|
||||
ROOT_URLCONF = 'jumpserver.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
|
|
|
@ -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'),
|
||||
]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()]
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue