mirror of https://github.com/jumpserver/jumpserver
[Update] 完成资产书
parent
c8728cace4
commit
08edda35e1
|
@ -96,4 +96,5 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
|
|||
def perform_update(self, serializer):
|
||||
assets = serializer.validated_data.get('assets')
|
||||
instance = self.get_object()
|
||||
instance.assets.remove(*tuple(assets))
|
||||
if instance != Node.root():
|
||||
instance.assets.remove(*tuple(assets))
|
||||
|
|
|
@ -64,7 +64,10 @@ class AssetUpdateForm(forms.ModelForm):
|
|||
'ip': '* required',
|
||||
'port': '* required',
|
||||
'cluster': '* required',
|
||||
'admin_user': _('')
|
||||
'admin_user': _(
|
||||
'Admin user is a privilege user exist on this asset,'
|
||||
'Example: root or other NOPASSWD sudo privilege user'
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -238,6 +238,13 @@ class SystemUser(AssetUser):
|
|||
'auto_push': self.auto_push,
|
||||
}
|
||||
|
||||
@property
|
||||
def assets(self):
|
||||
assets = set()
|
||||
for node in self.nodes.all():
|
||||
assets.update(set(node.get_all_assets()))
|
||||
return assets
|
||||
|
||||
@property
|
||||
def assets_connective(self):
|
||||
_result = cache.get(SYSTEM_USER_CONN_CACHE_KEY.format(self.name), {})
|
||||
|
|
|
@ -14,11 +14,12 @@ class NodeGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
|||
assets_granted = AssetGrantedSerializer(many=True, read_only=True)
|
||||
assets_amount = serializers.SerializerMethodField()
|
||||
parent = serializers.SerializerMethodField()
|
||||
name = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Node
|
||||
fields = [
|
||||
'id', 'key', 'value', 'parent',
|
||||
'id', 'key', 'name', 'value', 'parent',
|
||||
'assets_granted', 'assets_amount',
|
||||
]
|
||||
|
||||
|
@ -26,6 +27,10 @@ class NodeGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
|||
def get_assets_amount(obj):
|
||||
return len(obj.assets_granted)
|
||||
|
||||
@staticmethod
|
||||
def get_name(obj):
|
||||
return obj.name
|
||||
|
||||
@staticmethod
|
||||
def get_parent(obj):
|
||||
return obj.parent.id
|
||||
|
|
|
@ -33,8 +33,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
|
|||
|
||||
@staticmethod
|
||||
def get_assets_amount(obj):
|
||||
amount = 0
|
||||
return amount
|
||||
return len(obj.assets)
|
||||
|
||||
|
||||
class AssetSystemUserSerializer(serializers.ModelSerializer):
|
||||
|
|
|
@ -24,9 +24,15 @@ def test_asset_conn_on_created(asset):
|
|||
test_asset_connectability_util.delay(asset)
|
||||
|
||||
|
||||
def set_asset_root_node(asset):
|
||||
logger.debug("Set asset default node: {}".format(Node.root()))
|
||||
asset.nodes.add(Node.root())
|
||||
|
||||
|
||||
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
|
||||
def on_asset_created(sender, instance=None, created=False, **kwargs):
|
||||
if instance and created:
|
||||
def on_asset_created_or_update(sender, instance=None, created=False, **kwargs):
|
||||
set_asset_root_node(instance)
|
||||
if created:
|
||||
logger.info("Asset `{}` create signal received".format(instance))
|
||||
update_asset_hardware_info_on_created(instance)
|
||||
test_asset_conn_on_created(instance)
|
||||
|
|
|
@ -166,6 +166,8 @@ def test_admin_user_connectability_util(admin_user, task_name):
|
|||
|
||||
assets = admin_user.get_related_assets()
|
||||
hosts = [asset.hostname for asset in assets]
|
||||
if not hosts:
|
||||
return
|
||||
tasks = const.TEST_ADMIN_USER_CONN_TASKS
|
||||
task, created = update_or_create_ansible_task(
|
||||
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||
|
@ -184,19 +186,10 @@ def test_admin_user_connectability_period():
|
|||
"""
|
||||
A period task that update the ansible task period
|
||||
"""
|
||||
from ops.utils import update_or_create_ansible_task
|
||||
admin_users = AdminUser.objects.all()
|
||||
for admin_user in admin_users:
|
||||
task_name = _("Test admin user connectability period: {}").format(admin_user)
|
||||
assets = admin_user.get_related_assets()
|
||||
hosts = [asset.hostname for asset in assets]
|
||||
tasks = const.TEST_ADMIN_USER_CONN_TASKS
|
||||
update_or_create_ansible_task(
|
||||
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||
options=const.TASK_OPTIONS, run_as_admin=True, created_by='System',
|
||||
interval=3600, is_periodic=True,
|
||||
callback=set_admin_user_connectability_info.name,
|
||||
)
|
||||
task_name = _("Test admin user connectability period: {}".format(admin_user.name))
|
||||
test_admin_user_connectability_util(admin_user, task_name)
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -262,23 +255,21 @@ def test_system_user_connectability_util(system_user, task_name):
|
|||
:param task_name:
|
||||
:return:
|
||||
"""
|
||||
# todo
|
||||
# from ops.utils import update_or_create_ansible_task
|
||||
# assets = system_user.get_clusters_assets()
|
||||
# hosts = [asset.hostname for asset in assets]
|
||||
# tasks = const.TEST_SYSTEM_USER_CONN_TASKS
|
||||
# if not hosts:
|
||||
# logger.info("No hosts, passed")
|
||||
# return {}
|
||||
# task, created = update_or_create_ansible_task(
|
||||
# task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||
# options=const.TASK_OPTIONS,
|
||||
# run_as=system_user.name, created_by="System",
|
||||
# )
|
||||
# result = task.run()
|
||||
# set_system_user_connectablity_info(result, system_user=system_user.name)
|
||||
# return result
|
||||
return {}
|
||||
from ops.utils import update_or_create_ansible_task
|
||||
assets = system_user.assets
|
||||
hosts = [asset.hostname for asset in assets]
|
||||
tasks = const.TEST_SYSTEM_USER_CONN_TASKS
|
||||
if not hosts:
|
||||
logger.info("No hosts, passed")
|
||||
return {}
|
||||
task, created = update_or_create_ansible_task(
|
||||
task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||
options=const.TASK_OPTIONS,
|
||||
run_as=system_user.name, created_by="System",
|
||||
)
|
||||
result = task.run()
|
||||
set_system_user_connectablity_info(result, system_user=system_user.name)
|
||||
return result
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -292,23 +283,10 @@ def test_system_user_connectability_manual(system_user):
|
|||
@after_app_ready_start
|
||||
@after_app_shutdown_clean
|
||||
def test_system_user_connectability_period():
|
||||
# Todo
|
||||
pass
|
||||
# from ops.utils import update_or_create_ansible_task
|
||||
# system_users = SystemUser.objects.all()
|
||||
# for system_user in system_users:
|
||||
# task_name = _("Test system user connectability period: {}").format(
|
||||
# system_user.name
|
||||
# )
|
||||
# assets = system_user.get_clusters_assets()
|
||||
# hosts = [asset.hostname for asset in assets]
|
||||
# tasks = const.TEST_SYSTEM_USER_CONN_TASKS
|
||||
# update_or_create_ansible_task(
|
||||
# task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||
# options=const.TASK_OPTIONS, run_as_admin=False, run_as=system_user.name,
|
||||
# created_by='System', interval=3600, is_periodic=True,
|
||||
# callback=set_admin_user_connectability_info.name,
|
||||
# )
|
||||
system_users = SystemUser.objects.all()
|
||||
for system_user in system_users:
|
||||
task_name = _("test system user connectability period: {}".format(system_user))
|
||||
test_system_user_connectability_util(system_user, task_name)
|
||||
|
||||
|
||||
#### Push system user tasks ####
|
||||
|
@ -416,10 +394,10 @@ def push_node_system_users_to_asset(node, assets):
|
|||
push_system_user_util.delay(system_users, assets, task_name)
|
||||
|
||||
|
||||
@shared_task
|
||||
@register_as_period_task(interval=3600)
|
||||
@after_app_ready_start
|
||||
@after_app_shutdown_clean
|
||||
def push_system_user_period():
|
||||
for system_user in SystemUser.objects.all():
|
||||
push_system_user_related_nodes(system_user)
|
||||
# @shared_task
|
||||
# @register_as_period_task(interval=3600)
|
||||
# @after_app_ready_start
|
||||
# # @after_app_shutdown_clean
|
||||
# def push_system_user_period():
|
||||
# for system_user in SystemUser.objects.all():
|
||||
# push_system_user_related_nodes(system_user)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
{% block help_message %}
|
||||
<div class="alert alert-info help-message">
|
||||
管理用户是 服务器上已存在的特权用户,Jumpserver使用该用户来 `推送系统用户`、`获取资产硬件信息`等。可以设置主机级别管理用户,也设置集群级别管理用户,这样资产可以不用再单独设置
|
||||
管理用户是 服务器上已存在的特权用户,Jumpserver使用该用户来 `推送系统用户`、`获取资产硬件信息`等。
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
{% block custom_head_css_js %}
|
||||
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
|
||||
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
<style type="text/css">
|
||||
div#rMenu {
|
||||
position:absolute;
|
||||
|
|
|
@ -289,5 +289,29 @@ $(document).ready(function () {
|
|||
var redirect_url = "{% url 'assets:system-user-list' %}";
|
||||
objectDelete($this, name, the_url, redirect_url);
|
||||
})
|
||||
.on('click', '.btn-push', function () {
|
||||
var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}";
|
||||
var error = function (data) {
|
||||
alert(data)
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
error: error,
|
||||
method: 'GET',
|
||||
success_message: "{% trans "Task has been send, Go to ops task list seen result" %}"
|
||||
});
|
||||
})
|
||||
.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)
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
error: error,
|
||||
method: 'GET',
|
||||
success_message: "{% trans "Task has been send, seen left assets status" %}"
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% block help_message %}
|
||||
<div class="alert alert-info help-message">
|
||||
系统用户是 用户登录资产(服务器)时使用的用户,如 web, sa, dba等具有特殊功能的用户。系统用户创建时,如果选择了自动推送
|
||||
Jumpserver会使用ansible自动推送到系统用户所在集群的资产中,如果资产(交换机)不支持ansible, 请手动填写账号密码。
|
||||
Jumpserver会使用ansible自动推送系统用户到资产中,如果资产(交换机、windows)不支持ansible, 请手动填写账号密码。
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -213,22 +213,19 @@ class AssetExportView(View):
|
|||
]
|
||||
]
|
||||
filename = 'assets-{}.csv'.format(
|
||||
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
|
||||
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S')
|
||||
)
|
||||
response = HttpResponse(content_type='text/csv')
|
||||
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
||||
response.write(codecs.BOM_UTF8)
|
||||
assets = Asset.objects.filter(id__in=assets_id)
|
||||
writer = csv.writer(response, dialect='excel',
|
||||
quoting=csv.QUOTE_MINIMAL)
|
||||
writer = csv.writer(response, dialect='excel', quoting=csv.QUOTE_MINIMAL)
|
||||
|
||||
header = [field.verbose_name for field in fields]
|
||||
header.append(_('Asset groups'))
|
||||
writer.writerow(header)
|
||||
|
||||
for asset in assets:
|
||||
groups = ','.join([group.name for group in asset.groups.all()])
|
||||
data = [getattr(asset, field.name) for field in fields]
|
||||
data.append(groups)
|
||||
writer.writerow(data)
|
||||
return response
|
||||
|
||||
|
@ -262,7 +259,6 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
|
|||
]
|
||||
header_ = csv_data[0]
|
||||
mapping_reverse = {field.verbose_name: field.name for field in fields}
|
||||
mapping_reverse[_('Asset groups')] = 'groups'
|
||||
attr = [mapping_reverse.get(n, None) for n in header_]
|
||||
if None in attr:
|
||||
data = {'valid': False,
|
||||
|
@ -279,20 +275,15 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
|
|||
asset_dict = dict(zip(attr, row))
|
||||
id_ = asset_dict.pop('id', 0)
|
||||
for k, v in asset_dict.items():
|
||||
if k == 'cluster':
|
||||
v = get_object_or_none(Cluster, name=v)
|
||||
elif k == 'is_active':
|
||||
v = bool(v)
|
||||
if k == 'is_active':
|
||||
v = True if v in ['TRUE', 1, 'true'] else False
|
||||
elif k == 'admin_user':
|
||||
v = get_object_or_none(AdminUser, name=v)
|
||||
elif k in ['port', 'cabinet_pos', 'cpu_count', 'cpu_cores']:
|
||||
elif k in ['port', 'cpu_count', 'cpu_cores']:
|
||||
try:
|
||||
v = int(v)
|
||||
except ValueError:
|
||||
v = 0
|
||||
elif k == 'groups':
|
||||
groups_name = v.split(',')
|
||||
v = AssetGroup.objects.filter(name__in=groups_name)
|
||||
else:
|
||||
continue
|
||||
asset_dict[k] = v
|
||||
|
@ -300,20 +291,15 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
|
|||
asset = get_object_or_none(Asset, id=id_) if is_uuid(id_) else None
|
||||
if not asset:
|
||||
try:
|
||||
groups = asset_dict.pop('groups')
|
||||
if len(Asset.objects.filter(hostname=asset_dict.get('hostname'))):
|
||||
raise Exception(_('already exists'))
|
||||
asset = Asset.objects.create(**asset_dict)
|
||||
asset.groups.set(groups)
|
||||
created.append(asset_dict['hostname'])
|
||||
assets.append(asset)
|
||||
except Exception as e:
|
||||
failed.append('%s: %s' % (asset_dict['hostname'], str(e)))
|
||||
else:
|
||||
for k, v in asset_dict.items():
|
||||
if k == 'groups':
|
||||
asset.groups.set(v)
|
||||
continue
|
||||
if v:
|
||||
setattr(asset, k, v)
|
||||
try:
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -112,13 +112,13 @@ function initTable() {
|
|||
}
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||
var name = rowData.user_group.name + "=>" + rowData.system_user.name + "=>" + rowData.node.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 del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('{{ DEFAULT_PK }}', cellData)
|
||||
.replace('99991938', rowData.name);
|
||||
.replace('99991938', name);
|
||||
$(td).html(update_btn + del_btn);
|
||||
}}
|
||||
|
||||
],
|
||||
ajax_url: '{% url "api-perms:asset-permission-list" %}',
|
||||
columns: [
|
||||
|
@ -207,8 +207,8 @@ $(document).ready(function(){
|
|||
})
|
||||
.on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var name = $this.data('name');
|
||||
var uid = $this.data('uid');
|
||||
var name = $this.data('name');
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'
|
||||
.replace('{{ DEFAULT_PK }}', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<i class="fa fa-group" style="font-size: 13px"></i> <span class="nav-label">{% trans 'Users' %}</span><span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level active">
|
||||
<li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User' %}</a></li>
|
||||
<li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User list' %}</a></li>
|
||||
<li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li>
|
||||
<li id="login-log"><a href="{% url 'users:login-log-list' %}">{% trans 'Login logs' %}</a></li>
|
||||
</ul>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<i class="fa fa-inbox"></i> <span class="nav-label">{% trans 'Assets' %}</span><span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset' %}</a></li>
|
||||
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset list' %}</a></li>
|
||||
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li>
|
||||
<li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li>
|
||||
<li id="label"><a href="{% url 'assets:label-list' %}">{% trans 'Labels' %}</a></li>
|
||||
|
@ -49,7 +49,7 @@
|
|||
<i class="fa fa-coffee"></i> <span class="nav-label">{% trans 'Job Center' %}</span><span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="task"><a href="{% url 'ops:task-list' %}">{% trans 'Task' %}</a></li>
|
||||
<li id="task"><a href="{% url 'ops:task-list' %}">{% trans 'Task list' %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{#<li id="">#}
|
||||
|
|
|
@ -110,10 +110,6 @@
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">{% trans 'Perm assets' %}</td>
|
||||
<td>{{ assets | length }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">{% trans 'Comment' %}:</td>
|
||||
<td><b>{{ user.comment }}</b></td>
|
||||
|
|
|
@ -308,12 +308,9 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
|
|||
template_name = 'users/user_profile.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from perms.utils import get_user_granted_assets
|
||||
assets = get_user_granted_assets(self.request.user)
|
||||
context = {
|
||||
'app': _('Users'),
|
||||
'action': _('Profile'),
|
||||
'assets': assets,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
|
Loading…
Reference in New Issue