mirror of https://github.com/jumpserver/jumpserver
Merge branch 'master' of code.jumpserver.org:Jumpserver/jumpserver
# Conflicts: # apps/assets/templates/assets/asset_list.htmlpull/417/head
commit
b34c5dde40
|
@ -21,3 +21,4 @@ migrations/
|
|||
host_rsa_key
|
||||
*.bat
|
||||
tags
|
||||
tmp/*
|
||||
|
|
|
@ -95,9 +95,6 @@ class TerminateConnectionView(APIView):
|
|||
proxy_log_id = d.get('proxy_log_id')
|
||||
proxy_log = get_object_or_404(ProxyLog, id=proxy_log_id)
|
||||
terminal_id = proxy_log.terminal
|
||||
proxy_log.is_finished = True
|
||||
proxy_log.date_finished = timezone.now()
|
||||
proxy_log.save()
|
||||
if terminal_id in tasks:
|
||||
tasks[terminal_id].append({'name': 'kill_proxy',
|
||||
'proxy_log_id': proxy_log_id})
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'Type' %}</th>
|
||||
<th class="text-center">{% trans 'proxy online' %}</th>
|
||||
<th class="text-center">{% trans 'Session online' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center">{% trans 'Alive' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
|
|
|
@ -12,7 +12,7 @@ from django.shortcuts import get_object_or_404
|
|||
from common.mixins import IDInFilterMixin
|
||||
from common.utils import get_object_or_none, signer
|
||||
from .hands import IsSuperUser, IsAppUser
|
||||
from .models import AssetGroup, Asset, IDC, SystemUser, AdminUser, Tag
|
||||
from .models import AssetGroup, Asset, IDC, SystemUser, AdminUser
|
||||
from . import serializers
|
||||
|
||||
|
||||
|
@ -25,14 +25,11 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
|
|||
def get_queryset(self):
|
||||
queryset = super(AssetViewSet, self).get_queryset()
|
||||
idc_id = self.request.query_params.get('idc_id', '')
|
||||
tags_id = self.request.query_params.get('tag_id', '')
|
||||
system_users_id = self.request.query_params.get('system_user_id', '')
|
||||
asset_group_id = self.request.query_params.get('asset_group_id', '')
|
||||
admin_user_id = self.request.query_params.get('admin_user_id', '')
|
||||
if idc_id:
|
||||
queryset = queryset.filter(idc__id=idc_id)
|
||||
if tags_id:
|
||||
queryset = queryset.filter(tags__id=tags_id)
|
||||
if system_users_id:
|
||||
queryset = queryset.filter(system_users__id=system_users_id)
|
||||
if admin_user_id:
|
||||
|
@ -147,16 +144,3 @@ class SystemUserAuthInfoApi(generics.RetrieveAPIView):
|
|||
}
|
||||
return Response(data)
|
||||
|
||||
|
||||
class TagViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
queryset = Tag.objects.all()
|
||||
serializer_class = serializers.TagSerializer
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
||||
|
||||
## update the IDC, and add or delete the assets to the IDC
|
||||
class TagUpdateAssetsApi(generics.RetrieveUpdateAPIView):
|
||||
queryset = Tag.objects.all()
|
||||
serializer_class = serializers.TagUpdateAssetsSerializer
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag
|
||||
from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser
|
||||
from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen, get_logger
|
||||
|
||||
|
||||
|
@ -10,20 +10,6 @@ logger = get_logger(__file__)
|
|||
|
||||
|
||||
class AssetCreateForm(forms.ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get('instance', None)
|
||||
if instance:
|
||||
initial = kwargs.get('initial', {})
|
||||
initial['tags'] = [t.pk for t in kwargs['instance'].tags.all()]
|
||||
super(AssetCreateForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def _save_m2m(self):
|
||||
super(AssetCreateForm, self)._save_m2m()
|
||||
tags = self.cleaned_data['tags']
|
||||
self.instance.tags.clear()
|
||||
self.instance.tags.add(*tuple(tags))
|
||||
|
||||
def clean_admin_user(self):
|
||||
if not self.cleaned_data['admin_user']:
|
||||
raise forms.ValidationError(_('Select admin user'))
|
||||
|
@ -31,16 +17,13 @@ class AssetCreateForm(forms.ModelForm):
|
|||
|
||||
class Meta:
|
||||
model = Asset
|
||||
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
|
||||
fields = [
|
||||
'hostname', 'ip', 'public_ip', 'port', 'type', 'comment', 'admin_user',
|
||||
'idc', 'groups', 'status', 'env', 'tags', 'is_active'
|
||||
'idc', 'groups', 'status', 'env', 'is_active'
|
||||
]
|
||||
widgets = {
|
||||
'groups': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'tags': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset tags')}),
|
||||
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
|
||||
}
|
||||
help_texts = {
|
||||
|
@ -48,24 +31,20 @@ class AssetCreateForm(forms.ModelForm):
|
|||
'ip': '* required',
|
||||
'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'),
|
||||
'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'),
|
||||
'tags': '最多5个标签,单个标签最长8个汉字,按回车确认'
|
||||
}
|
||||
|
||||
|
||||
class AssetUpdateForm(AssetCreateForm):
|
||||
class Meta:
|
||||
model = Asset
|
||||
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
|
||||
fields = [
|
||||
'hostname', 'ip', 'port', 'groups', 'admin_user', 'idc', 'is_active',
|
||||
'type', 'env', 'status', 'public_ip', 'remote_card_ip', 'cabinet_no',
|
||||
'cabinet_pos', 'number', 'comment', 'tags'
|
||||
'cabinet_pos', 'number', 'comment'
|
||||
]
|
||||
widgets = {
|
||||
'groups': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'tags': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset tags')}),
|
||||
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
|
||||
}
|
||||
help_texts = {
|
||||
|
@ -73,18 +52,18 @@ class AssetUpdateForm(AssetCreateForm):
|
|||
'ip': '* required',
|
||||
'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'),
|
||||
'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'),
|
||||
'tags': '最多5个标签,单个标签最长8个汉字,按回车确认'
|
||||
}
|
||||
|
||||
|
||||
class AssetGroupForm(forms.ModelForm):
|
||||
# See AdminUserForm comment same it
|
||||
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
|
||||
label=_('Asset'),
|
||||
required=False,
|
||||
widget=forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
||||
)
|
||||
assets = forms.ModelMultipleChoiceField(
|
||||
queryset=Asset.objects.all(),
|
||||
label=_('Asset'),
|
||||
required=False,
|
||||
widget=forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.get('instance', None):
|
||||
|
@ -297,39 +276,5 @@ class SystemUserForm(forms.ModelForm):
|
|||
}
|
||||
|
||||
|
||||
class AssetTagForm(forms.ModelForm):
|
||||
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
|
||||
label=_('Asset'),
|
||||
required=False,
|
||||
widget=forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.get('instance', None):
|
||||
initial = kwargs.get('initial', {})
|
||||
initial['assets'] = kwargs['instance'].asset_set.all()
|
||||
super(AssetTagForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def _save_m2m(self):
|
||||
assets = self.cleaned_data['assets']
|
||||
self.instance.assets.clear()
|
||||
self.instance.assets.add(*tuple(assets))
|
||||
super(AssetTagForm, self)._save_m2m()
|
||||
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = [
|
||||
"name",
|
||||
]
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={}),
|
||||
|
||||
}
|
||||
help_texts = {
|
||||
'name': '* required',
|
||||
}
|
||||
|
||||
|
||||
class FileForm(forms.Form):
|
||||
file = forms.FileField()
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from . import IDC, AssetGroup, AdminUser, SystemUser
|
||||
|
||||
__all__ = ['Asset', 'Tag']
|
||||
__all__ = ['Asset']
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -83,7 +83,6 @@ class Asset(models.Model):
|
|||
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date added'))
|
||||
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||
tags = models.ManyToManyField('Tag', related_name='assets', blank=True, verbose_name=_('Tags'))
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s <%s: %s>' % (self.hostname, self.ip, self.port)
|
||||
|
@ -112,7 +111,12 @@ class Asset(models.Model):
|
|||
'groups': [group.name for group in self.groups.all()],
|
||||
'username': self.admin_user.username if self.admin_user else '',
|
||||
'password': self.admin_user.password if self.admin_user else '',
|
||||
'private_key': self.admin_user.private_key if self.admin_user else None,
|
||||
'private_key': self.admin_user.private_key_file if self.admin_user else None,
|
||||
'become': {
|
||||
'method': self.admin_user.become_method,
|
||||
'user': self.admin_user.become_user,
|
||||
'pass': self.admin_user.become_pass,
|
||||
} if self.admin_user.become else {},
|
||||
}
|
||||
|
||||
class Meta:
|
||||
|
@ -141,16 +145,3 @@ class Asset(models.Model):
|
|||
print('Error continue')
|
||||
continue
|
||||
|
||||
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
|
||||
created_time = models.DateTimeField(auto_now_add=True, verbose_name=_('Create time'))
|
||||
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
__str__ = __unicode__
|
||||
|
||||
class Meta:
|
||||
db_table = 'tag'
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import logging
|
||||
from hashlib import md5
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import signer, validate_ssh_private_key, ssh_key_string_to_obj
|
||||
|
||||
|
@ -38,7 +40,7 @@ class AdminUser(models.Model):
|
|||
become = models.BooleanField(default=True)
|
||||
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
|
||||
become_user = models.CharField(default='root', max_length=64)
|
||||
become_password = models.CharField(default='', max_length=128)
|
||||
become_pass = models.CharField(default='', max_length=128)
|
||||
_public_key = models.CharField(
|
||||
max_length=4096, blank=True, verbose_name=_('SSH public key'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
|
@ -74,6 +76,18 @@ class AdminUser(models.Model):
|
|||
def private_key(self, private_key_raw):
|
||||
self._private_key = signer.sign(private_key_raw)
|
||||
|
||||
@property
|
||||
def private_key_file(self):
|
||||
if not self.private_key:
|
||||
return None
|
||||
project_dir = settings.PROJECT_DIR
|
||||
tmp_dir = os.path.join(project_dir, 'tmp')
|
||||
key_name = md5(self._private_key).hexdigest()
|
||||
key_path = os.path.join(tmp_dir, key_name)
|
||||
if not os.path.exists(key_path):
|
||||
self.private_key.write_private_key_file(key_path)
|
||||
return key_path
|
||||
|
||||
@property
|
||||
def public_key(self):
|
||||
return signer.unsign(self._public_key)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import viewsets, serializers, generics
|
||||
from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser, Tag
|
||||
from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser
|
||||
from common.mixins import IDInFilterMixin
|
||||
from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin
|
||||
|
||||
|
@ -61,20 +61,6 @@ class IDCUpdateAssetsSerializer(serializers.ModelSerializer):
|
|||
fields = ['id', 'assets']
|
||||
|
||||
|
||||
class TagSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||
assets_amount = serializers.SerializerMethodField()
|
||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = Tag
|
||||
list_serializer_class = BulkListSerializer
|
||||
fields = '__all__'
|
||||
|
||||
@staticmethod
|
||||
def get_assets_amount(obj):
|
||||
return obj.assets.count()
|
||||
|
||||
|
||||
class AdminUserSerializer(serializers.ModelSerializer):
|
||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
||||
|
||||
|
@ -189,10 +175,3 @@ class IDCSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
|||
fields.append('assets_amount')
|
||||
return fields
|
||||
|
||||
|
||||
class TagUpdateAssetsSerializer(serializers.ModelSerializer):
|
||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = ['id', 'assets']
|
|
@ -12,8 +12,7 @@ def update_assets_hardware_info(assets):
|
|||
task_tuple = (
|
||||
('setup', ''),
|
||||
)
|
||||
task_name = ','.join([asset.hostname for asset in assets])
|
||||
summary, result = run_AdHoc(task_tuple, assets, record=True, task_name=task_name)
|
||||
summary, result = run_AdHoc(task_tuple, assets, record=False)
|
||||
for hostname, info in result['contacted'].items():
|
||||
if info:
|
||||
info = info[0]['ansible_facts']
|
||||
|
|
|
@ -61,22 +61,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2 col-lg-2 " for="id_tags">标签集合</label>
|
||||
<div class=" col-sm-9 col-lg-9 ">
|
||||
<select multiple="multiple" class="select2 form-control" data-placeholder="Select asset tags" id="tags" name="tags">
|
||||
{% for tag in tags %}
|
||||
<option value="{{ tag.id }}">{{ tag.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p class="help-block">
|
||||
最多5个标签,单个标签最长8个汉字,按回车确认
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block modal_confirm_id %}btn_asset_bulk_update{% endblock %}
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
{{ form.tags|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
{{ form.is_active|bootstrap_horizontal }}
|
||||
|
||||
|
|
|
@ -104,37 +104,6 @@ function tagShow() {
|
|||
}
|
||||
} //onload;
|
||||
|
||||
function objDelete(obj, name, url) {
|
||||
function doDelete() {
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
$(obj).parent().parent().remove();
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
|
|
|
@ -13,7 +13,6 @@ router.register(r'v1/assets', api.AssetViewSet, 'asset')
|
|||
router.register(r'v1/idc', api.IDCViewSet, 'idc')
|
||||
router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user')
|
||||
router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user')
|
||||
router.register(r'v1/tags', api.TagViewSet, 'asset-tag')
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^v1/assets_bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
|
||||
|
@ -45,8 +44,6 @@ urlpatterns = [
|
|||
url(r'^v1/idc/(?P<pk>\d+)/assets/$',
|
||||
api.IDCupdateAssetsApi.as_view(), name='idc-update-assets'),
|
||||
|
||||
url(r'v1/tag/(?P<pk>\d+)/assets/$',
|
||||
api.TagUpdateAssetsApi.as_view(), name='tag-update-assets'),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
|
|
@ -24,13 +24,6 @@ urlpatterns = [
|
|||
url(r'^asset-group/(?P<pk>[0-9]+)/update/$', views.AssetGroupUpdateView.as_view(), name='asset-group-update'),
|
||||
url(r'^asset-group/(?P<pk>[0-9]+)/delete/$', views.AssetGroupDeleteView.as_view(), name='asset-group-delete'),
|
||||
|
||||
url(r'^tags/$', views.TagsListView.as_view(), name='asset-tag-list'),
|
||||
url(r'^asset-by-tag/(?P<tag_id>[0-9]+)/$', views.TagView.as_view(), name='asset-tags'),
|
||||
url(r'^tags/create/$', views.AssetTagCreateView.as_view(), name='asset-tag-create'),
|
||||
url(r'^asset-tag/(?P<pk>[0-9]+)/$', views.AssetTagDetailView.as_view(), name='asset-tag-detail'),
|
||||
url(r'^asset-tag/(?P<pk>[0-9]+)/update/$', views.AssetTagUpdateView.as_view(), name='asset-tag-update'),
|
||||
url(r'^asset-tag/(?P<pk>[0-9]+)/delete/$', views.AssetTagDeleteView.as_view(), name='asset-tag-delete'),
|
||||
|
||||
# Resource idc url
|
||||
url(r'^idc/$', views.IDCListView.as_view(), name='idc-list'),
|
||||
url(r'^idc/create/$', views.IDCCreateView.as_view(), name='idc-create'),
|
||||
|
|
|
@ -1,40 +1,3 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
from rest_framework import serializers
|
||||
from models import Tag
|
||||
from django.views.generic.edit import CreateView
|
||||
|
||||
|
||||
class CreateAssetTagsMiXin(CreateView):
|
||||
def get_form_kwargs(self):
|
||||
tags_list = self.request.POST.getlist('tags')
|
||||
kwargs = {
|
||||
'initial': self.get_initial(),
|
||||
'prefix': self.get_prefix(),
|
||||
}
|
||||
if self.request.method in ('POST', 'PUT'):
|
||||
post_data = self.request.POST.copy()
|
||||
if post_data.has_key('tags'):
|
||||
post_data.pop('tags')
|
||||
for t in tags_list:
|
||||
try:
|
||||
oTag = Tag.objects.get(pk=int(t))
|
||||
except (Tag.DoesNotExist, UnicodeEncodeError):
|
||||
oTag = Tag(name=t, created_by=self.request.user.username or 'Admin')
|
||||
oTag.save()
|
||||
post_data.update({'tags':oTag.pk})
|
||||
else:
|
||||
post_data.update({'tags':int(t)})
|
||||
kwargs.update({
|
||||
'data': post_data,
|
||||
'files': self.request.FILES,
|
||||
})
|
||||
return kwargs
|
||||
|
||||
|
||||
class UpdateAssetTagsMiXin(CreateAssetTagsMiXin):
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UpdateAssetTagsMiXin, self).get_form_kwargs()
|
||||
if hasattr(self, 'object'):
|
||||
kwargs.update({'instance': self.object})
|
||||
return kwargs
|
|
@ -25,9 +25,8 @@ from django.utils import timezone
|
|||
|
||||
from common.mixins import JSONResponseMixin
|
||||
from common.utils import get_object_or_none
|
||||
from .utils import CreateAssetTagsMiXin, UpdateAssetTagsMiXin
|
||||
from . import forms
|
||||
from .models import Asset, AssetGroup, AdminUser, IDC, SystemUser, Tag
|
||||
from .models import Asset, AssetGroup, AdminUser, IDC, SystemUser
|
||||
from .hands import AdminUserRequiredMixin
|
||||
|
||||
|
||||
|
@ -40,16 +39,13 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
|
|||
'action': 'asset list',
|
||||
'groups': AssetGroup.objects.all(),
|
||||
'system_users': SystemUser.objects.all(),
|
||||
'tag_list': [(i.id, i.name, i.assets.all().count())for i in Tag.objects.all().order_by('name')],
|
||||
'tags': Tag.objects.all().order_by('name')
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView):
|
||||
class AssetCreateView(AdminUserRequiredMixin, CreateView):
|
||||
model = Asset
|
||||
tag_type = 'asset'
|
||||
form_class = forms.AssetCreateForm
|
||||
template_name = 'assets/asset_create.html'
|
||||
success_url = reverse_lazy('assets:asset-list')
|
||||
|
@ -69,7 +65,7 @@ class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView):
|
|||
return super(AssetCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetModalCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, ListView):
|
||||
class AssetModalCreateView(AdminUserRequiredMixin, ListView):
|
||||
model = Asset
|
||||
form_class = forms.AssetCreateForm
|
||||
template_name = 'assets/asset_modal_update.html'
|
||||
|
@ -97,31 +93,11 @@ class AssetModalCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, ListVie
|
|||
return super(AssetModalCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
|
||||
class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = Asset
|
||||
form_class = forms.AssetUpdateForm
|
||||
template_name = 'assets/asset_update.html'
|
||||
success_url = reverse_lazy('assets:asset-list')
|
||||
# new_form = ''
|
||||
# assets_ids = ''
|
||||
|
||||
# def post(self, request, *args, **kwargs):
|
||||
# default_keys = [
|
||||
# 'csrfmiddlewaretoken',
|
||||
# 'assets_ids',
|
||||
# 'ip',
|
||||
# 'number',
|
||||
# 'hostname',
|
||||
# 'system_users',
|
||||
# 'admin_user',
|
||||
# ]
|
||||
# self.assets_ids = self.request.POST.getlist('assets_ids')
|
||||
# self.new_form = self.request.POST.copy()
|
||||
# for i in default_keys:
|
||||
# if self.new_form.has_key(i):
|
||||
# self.new_form.pop(i)
|
||||
|
||||
# return super(AssetUpdateView, self).post(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
|
@ -135,26 +111,6 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
|
|||
print(form.errors)
|
||||
return super(AssetUpdateView, self).form_invalid(form)
|
||||
|
||||
# def form_valid(self, form):
|
||||
# asset = form.save(commit=False)
|
||||
#
|
||||
# def prn_obj_key(obj_form):
|
||||
# return obj_form.clean().keys()
|
||||
#
|
||||
# for i in prn_obj_key(form):
|
||||
# if i not in self.new_form.keys():
|
||||
# print i
|
||||
|
||||
#delattr(asset, '"%s" % i')
|
||||
#del asset.i
|
||||
# asset.save()
|
||||
# asset.id = 27
|
||||
# # asset.created_by = self.request.user.username or 'Admin'
|
||||
# asset.save()
|
||||
# asset.id = 28
|
||||
# asset.save()
|
||||
# return super(AssetUpdateView, self).form_valid(form)
|
||||
|
||||
|
||||
class AssetDeleteView(DeleteView):
|
||||
model = Asset
|
||||
|
@ -192,7 +148,6 @@ class AssetModalListView(AdminUserRequiredMixin, ListView):
|
|||
|
||||
def get_context_data(self, **kwargs):
|
||||
group_id = self.request.GET.get('group_id')
|
||||
tag_id = self.request.GET.get('tag_id')
|
||||
plain_id_lists = self.request.GET.get('plain_id_lists')
|
||||
self.s = self.request.GET.get('plain_id_lists')
|
||||
assets = Asset.objects.all()
|
||||
|
@ -208,24 +163,15 @@ class AssetModalListView(AdminUserRequiredMixin, ListView):
|
|||
plain_id_lists = [int(self.s)]
|
||||
context = {
|
||||
'all_assets': plain_id_lists,
|
||||
'assets': assets
|
||||
}
|
||||
kwargs.update(context)
|
||||
if group_id:
|
||||
group = AssetGroup.objects.get(id=group_id)
|
||||
print group
|
||||
context = {
|
||||
'all_assets': [x.id for x in group.assets.all()],
|
||||
'assets': assets
|
||||
}
|
||||
kwargs.update(context)
|
||||
if tag_id:
|
||||
tag = Tag.objects.get(id=tag_id)
|
||||
context = {
|
||||
'all_assets': [x.id for x in tag.asset_set.all()],
|
||||
'assets': assets
|
||||
}
|
||||
kwargs.update(context)
|
||||
else:
|
||||
context = {
|
||||
'assets': assets
|
||||
|
@ -315,7 +261,6 @@ class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView):
|
|||
'assets_on_list': assets_all,
|
||||
'assets_count': len(assets_all),
|
||||
'group_id': self.object.id,
|
||||
'tags': Tag.objects.all()
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetGroupUpdateView, self).get_context_data(**kwargs)
|
||||
|
@ -401,7 +346,6 @@ class IDCAssetsView(AdminUserRequiredMixin, DetailView):
|
|||
'action': _('Asset detail'),
|
||||
'groups': AssetGroup.objects.all(),
|
||||
'system_users': SystemUser.objects.all(),
|
||||
'tags': Tag.objects.all(),
|
||||
'assets_remain': assets_remain,
|
||||
'assets': [asset for asset in Asset.objects.all() if asset not in assets_remain],
|
||||
}
|
||||
|
@ -626,123 +570,8 @@ class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
|||
return super(SystemUserAssetView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class TagView(ListView):
|
||||
context_object_name = 'asset_list'
|
||||
template_name = 'assets/asset_list.html'
|
||||
|
||||
def get_queryset(self):
|
||||
asset_list = Asset.objects.filter(tags=self.kwargs['tag_id'])
|
||||
return asset_list
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['app'] = 'Assets'
|
||||
kwargs['action']='asset list'
|
||||
kwargs['tag_list'] = [(i.id,i.name,i.asset_set.all().count() )for i in Tag.objects.all().order_by('name')]
|
||||
kwargs['tag_id'] = self.kwargs['tag_id']
|
||||
return super(TagView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class TagsListView(AdminUserRequiredMixin, ListView):
|
||||
model = Tag
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
context_object_name = 'asset_tags_list'
|
||||
template_name = 'assets/asset_tags_list.html'
|
||||
ordering = '-id'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': _('Tag'),
|
||||
'action': _('Asset Tags list'),
|
||||
'keyword': self.request.GET.get('keyword', '')
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(TagsListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetTagCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView):
|
||||
model = Tag
|
||||
form_class = forms.AssetTagForm
|
||||
template_name = 'assets/asset_tag_create.html'
|
||||
success_url = reverse_lazy('assets:asset-tag-list')
|
||||
#ordering = '-id'
|
||||
|
||||
# Todo: Asset group create template select assets so hard, need be resolve next
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': _('Tag'),
|
||||
'action': _('Asset Tags list'),
|
||||
'assets_count': 0,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetTagCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
asset_tag = form.save()
|
||||
assets_id_list = self.request.POST.getlist('assets', [])
|
||||
assets = [get_object_or_404(Asset, id=int(asset_id)) for asset_id in assets_id_list]
|
||||
asset_tag.created_by = self.request.user.username or 'Admin'
|
||||
asset_tag.assets.add(*tuple(assets))
|
||||
asset_tag.save()
|
||||
return super(AssetTagCreateView, self).form_valid(form)
|
||||
|
||||
|
||||
class AssetTagDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView):
|
||||
template_name = 'assets/asset_tag_detail.html'
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=Tag.objects.all())
|
||||
return super(AssetTagDetailView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return self.object.assets.all()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
assets_remain = Asset.objects.exclude(id__in=self.object.assets.all())
|
||||
context = {
|
||||
'app': _('Tag'),
|
||||
'action': _('Asset Tags detail'),
|
||||
'asset_tag': self.object,
|
||||
'assets_remain': assets_remain,
|
||||
'assets': [asset for asset in Asset.objects.all() if asset not in assets_remain]
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetTagDetailView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetTagUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = Tag
|
||||
form_class = forms.AssetTagForm
|
||||
template_name = 'assets/asset_tag_create.html'
|
||||
success_url = reverse_lazy('assets:asset-tag-list')
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=Tag.objects.all())
|
||||
return super(AssetTagUpdateView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
assets_all = self.object.assets.all()
|
||||
context = {
|
||||
'app': _('Tag'),
|
||||
'action': _('Asset Tags detail'),
|
||||
'assets_count': len(assets_all),
|
||||
'assets_on_list': assets_all,
|
||||
'tag_id':self.object.id,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetTagUpdateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetTagDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||
template_name = 'assets/delete_confirm.html'
|
||||
model = Tag
|
||||
success_url = reverse_lazy('assets:asset-tag-list')
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class AssetExportView(View):
|
||||
|
||||
@staticmethod
|
||||
def get_asset_attr(asset, attr):
|
||||
if attr in ['admin_user', 'idc']:
|
||||
|
|
|
@ -90,8 +90,3 @@ class RecordLogViewSet(BulkModelViewSet):
|
|||
else:
|
||||
return record_store.all()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -23,18 +23,18 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="user">
|
||||
<select class="select2 form-control" name="username">
|
||||
<option value="">{% trans 'User' %}</option>
|
||||
{% for u in user_list %}
|
||||
<option value="{{ u.username }}" {% if user == u.username %} selected {% endif %}>{{ u.username }}</option>
|
||||
<option value="{{ u.username }}" {% if username == u.username %} selected {% endif %}>{{ u.username }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="asset">
|
||||
<select class="select2 form-control" name="ip">
|
||||
<option value="">{% trans 'Asset' %}</option>
|
||||
{% for a in asset_list %}
|
||||
<option value="{{ a.ip }}" {% if asset == a.ip %} selected {% endif %}>{{ a.ip }}</option>
|
||||
<option value="{{ a.ip }}" {% if ip == a.ip %} selected {% endif %}>{{ a.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block content_left_head %}
|
||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
||||
<style>
|
||||
#search_btn {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block table_search %}
|
||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
||||
<div class="form-group" id="date">
|
||||
<div class="input-daterange input-group" id="datepicker">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
|
||||
<span class="input-group-addon">to</span>
|
||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="username">
|
||||
<option value="">{% trans 'User' %}</option>
|
||||
{% for u in user_list %}
|
||||
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="ip">
|
||||
<option value="">{% trans 'Asset' %}</option>
|
||||
{% for a in asset_list %}
|
||||
<option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="system_user">
|
||||
<option value="">{% trans 'System user' %}</option>
|
||||
{% for su in system_user_list %}
|
||||
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||
搜索
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block table_head %}
|
||||
<th class="text-center"></th>
|
||||
<th class="text-center">{% trans 'ID' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Terminal' %}</th>
|
||||
<th class="text-center">{% trans 'Command' %}</th>
|
||||
<th class="text-center">{% trans 'Success' %}</th>
|
||||
<th class="text-center">{% trans 'Finished' %}</th>
|
||||
<th class="text-center">{% trans 'Play' %}</th>
|
||||
<th class="text-center">{% trans 'Date start' %}</th>
|
||||
<th class="text-center">{% trans 'Time' %}</th>
|
||||
{% endblock %}
|
||||
|
||||
{% block table_body %}
|
||||
{% for proxy_log in proxy_log_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"><input type="checkbox" class="cbx-term" value="{{ proxy_log.id }}"></td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
|
||||
</td>
|
||||
<td class="text-center">{{ proxy_log.user }}</td>
|
||||
<td class="text-center">{{ proxy_log.asset }}</td>
|
||||
<td class="text-center">{{ proxy_log.system_user }}</td>
|
||||
<td class="text-center">{{ proxy_log.terminal }}</td>
|
||||
<td class="text-center">{{ proxy_log.commands.all|length}}</td>
|
||||
<td class="text-center">
|
||||
{% if proxy_log.is_failed %}
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if proxy_log.is_finished %}
|
||||
<td class="text-center">
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td class="text-center">
|
||||
<a class="btn-term" value="{{ proxy_log.id }}"><i class="fa fa-times text-danger"></i></a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="text-center">{{ proxy_log.date_start }}</td>
|
||||
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
function terminateConnection(data) {
|
||||
function success() {
|
||||
window.setTimeout(function () {
|
||||
window.location.reload()
|
||||
}, 300)
|
||||
}
|
||||
var the_url = "{% url 'api-applications:terminate-connection' %}";
|
||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
||||
}
|
||||
$(document).ready(function() {
|
||||
$('table').DataTable({
|
||||
"searching": false,
|
||||
"paging": false,
|
||||
"bInfo" : false,
|
||||
"order": []
|
||||
});
|
||||
$('.select2').select2();
|
||||
$('#date .input-daterange').datepicker({
|
||||
dateFormat: 'mm/dd/yy',
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
autoclose: true
|
||||
});
|
||||
}).on('click', '.btn-term', function () {
|
||||
var $this = $(this);
|
||||
var proxy_log_id = $this.attr('value');
|
||||
var data = {
|
||||
proxy_log_id: proxy_log_id
|
||||
};
|
||||
terminateConnection(data)
|
||||
}).on('click', '#btn_bulk_update', function () {
|
||||
var data = [];
|
||||
$('.cbx-term:checked').each(function () {
|
||||
data.push({proxy_log_id: $(this).attr('value')})
|
||||
});
|
||||
terminateConnection(data)
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -24,16 +24,16 @@
|
|||
<div class="input-group">
|
||||
<select class="select2 form-control" name="username">
|
||||
<option value="">{% trans 'User' %}</option>
|
||||
{% for user in user_list %}
|
||||
<option value="{{ user }}" {% if user == username %} selected {% endif %}>{{ user }}</option>
|
||||
{% for u in user_list %}
|
||||
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="ip">
|
||||
<option value="">{% trans 'Asset' %}</option>
|
||||
{% for asset in asset_list %}
|
||||
<option value="{{ asset }}" {% if asset == ip %} selected {% endif %}>{{ asset }}</option>
|
||||
{% for a in asset_list %}
|
||||
<option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -68,7 +68,7 @@
|
|||
<th class="text-center">{% trans 'Command' %}</th>
|
||||
<th class="text-center">{% trans 'Success' %}</th>
|
||||
<th class="text-center">{% trans 'Finished' %}</th>
|
||||
<th class="text-center">{% trans 'R/M' %}</th>
|
||||
<th class="text-center">{% trans 'Monitor' %}</th>
|
||||
<th class="text-center">{% trans 'Date start' %}</th>
|
||||
<th class="text-center">{% trans 'Time' %}</th>
|
||||
{% endblock %}
|
|
@ -4,14 +4,16 @@ from .. import views
|
|||
app_name = 'audits'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^proxy-log$', views.ProxyLogListView.as_view(),
|
||||
name='proxy-log-list'),
|
||||
url(r'^proxy-log/(?P<pk>\d+)$', views.ProxyLogDetailView.as_view(),
|
||||
url(r'^proxy-log-offline/$', views.ProxyLogOfflineListView.as_view(),
|
||||
name='proxy-log-offline-list'),
|
||||
url(r'^proxy-log-online/$', views.ProxyLogOnlineListView.as_view(),
|
||||
name='proxy-log-online-list'),
|
||||
url(r'^proxy-log/(?P<pk>\d+)/$', views.ProxyLogDetailView.as_view(),
|
||||
name='proxy-log-detail'),
|
||||
# url(r'^proxy-log/(?P<pk>\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'),
|
||||
url(r'^command-log$', views.CommandLogListView.as_view(),
|
||||
url(r'^command-log/$', views.CommandLogListView.as_view(),
|
||||
name='command-log-list'),
|
||||
url(r'^login-log$', views.LoginLogListView.as_view(),
|
||||
url(r'^login-log/$', views.LoginLogListView.as_view(),
|
||||
name='login-log-list'),
|
||||
]
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import pytz
|
||||
from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView
|
||||
from django.views.generic.edit import SingleObjectMixin
|
||||
from django.utils.translation import ugettext as _
|
||||
|
@ -22,10 +21,10 @@ from audits.backends import CommandLogSerializer
|
|||
|
||||
class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
||||
model = ProxyLog
|
||||
template_name = 'audits/proxy_log_list.html'
|
||||
template_name = 'audits/proxy_log_online_list.html'
|
||||
context_object_name = 'proxy_log_list'
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
keyword = user = asset = system_user = date_from_s = date_to_s = ''
|
||||
keyword = username = hostname = system_user = date_from_s = date_to_s = ''
|
||||
ordering = ['is_finished', '-id']
|
||||
date_format = '%m/%d/%Y'
|
||||
|
||||
|
@ -37,8 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
|||
|
||||
self.queryset = super(ProxyLogListView, self).get_queryset()
|
||||
self.keyword = self.request.GET.get('keyword', '')
|
||||
self.user = self.request.GET.get('user')
|
||||
self.asset = self.request.GET.get('asset')
|
||||
self.username = self.request.GET.get('username')
|
||||
self.ip = self.request.GET.get('ip')
|
||||
self.system_user = self.request.GET.get('system_user')
|
||||
self.date_from_s = self.request.GET.get('date_from', date_from_default)
|
||||
self.date_to_s = self.request.GET.get('date_to', date_to_default)
|
||||
|
@ -53,10 +52,10 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
|||
self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
||||
date_to = date_to.replace(tzinfo=timezone.get_current_timezone())
|
||||
filter_kwargs['date_start__lt'] = date_to
|
||||
if self.user:
|
||||
filter_kwargs['user'] = self.user
|
||||
if self.asset:
|
||||
filter_kwargs['asset'] = self.asset
|
||||
if self.username:
|
||||
filter_kwargs['user'] = self.username
|
||||
if self.ip:
|
||||
filter_kwargs['ip'] = self.ip
|
||||
if self.system_user:
|
||||
filter_kwargs['system_user'] = self.system_user
|
||||
if self.keyword:
|
||||
|
@ -81,14 +80,46 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
|||
'keyword': self.keyword,
|
||||
'date_from': self.date_from_s,
|
||||
'date_to': self.date_to_s,
|
||||
'user': self.user,
|
||||
'asset': self.asset,
|
||||
'username': self.username,
|
||||
'ip': self.ip,
|
||||
'system_user': self.system_user,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(ProxyLogListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class ProxyLogOfflineListView(ProxyLogListView):
|
||||
template_name = 'audits/proxy_log_offline_list.html'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(ProxyLogOfflineListView, self).get_queryset()
|
||||
queryset = queryset.filter(is_finished=True)
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'action': _('Proxy log offline list'),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(ProxyLogOfflineListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class ProxyLogOnlineListView(ProxyLogListView):
|
||||
template_name = 'audits/proxy_log_online_list.html'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(ProxyLogOnlineListView, self).get_queryset()
|
||||
queryset = queryset.filter(is_finished=False)
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'action': _('Proxy log online list'),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(ProxyLogOnlineListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class ProxyLogDetailView(AdminUserRequiredMixin,
|
||||
SingleObjectMixin,
|
||||
ListView):
|
||||
|
@ -131,7 +162,7 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
|||
template_name = 'audits/command_log_list.html'
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
context_object_name = 'command_list'
|
||||
user = asset = system_user = command = date_from_s = date_to_s = ''
|
||||
username = ip = system_user = command = date_from_s = date_to_s = ''
|
||||
date_format = '%m/%d/%Y'
|
||||
ordering = ['-id']
|
||||
|
||||
|
@ -141,8 +172,8 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
|||
date_from_default = (date_now - timezone.timedelta(7)) \
|
||||
.strftime(self.date_format)
|
||||
self.command = self.request.GET.get('command', '')
|
||||
self.user = self.request.GET.get('user')
|
||||
self.asset = self.request.GET.get('asset')
|
||||
self.username = self.request.GET.get('username')
|
||||
self.ip = self.request.GET.get('ip')
|
||||
self.system_user = self.request.GET.get('system_user')
|
||||
self.date_from_s = \
|
||||
self.request.GET.get('date_from', date_from_default)
|
||||
|
@ -162,10 +193,10 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
|||
.replace(tzinfo=timezone.get_current_timezone())
|
||||
date_to_ts = time.mktime(date_to.timetuple())
|
||||
filter_kwargs['date_to_ts'] = date_to_ts
|
||||
if self.user:
|
||||
filter_kwargs['user'] = self.user
|
||||
if self.asset:
|
||||
filter_kwargs['asset'] = self.asset
|
||||
if self.username:
|
||||
filter_kwargs['user'] = self.username
|
||||
if self.ip:
|
||||
filter_kwargs['asset'] = self.ip
|
||||
if self.system_user:
|
||||
filter_kwargs['system_user'] = self.system_user
|
||||
if self.command:
|
||||
|
@ -183,8 +214,8 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
|||
'command': self.command,
|
||||
'date_from': self.date_from_s,
|
||||
'date_to': self.date_to_s,
|
||||
'user': self.user,
|
||||
'asset': self.asset,
|
||||
'username': self.username,
|
||||
'ip': self.ip,
|
||||
'system_user': self.system_user,
|
||||
}
|
||||
kwargs.update(context)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from collections import OrderedDict
|
||||
from six import string_types
|
||||
import base64
|
||||
import os
|
||||
|
@ -53,6 +54,7 @@ def get_object_or_none(model, **kwargs):
|
|||
|
||||
|
||||
class Signer(object):
|
||||
"""用来加密,解密,和基于时间戳的方式验证token"""
|
||||
def __init__(self, secret_key=SECRET_KEY):
|
||||
self.secret_key = secret_key
|
||||
|
||||
|
@ -330,13 +332,13 @@ def encrypt_password(password):
|
|||
return None
|
||||
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
def capacity_convert(size, expect='auto', rate=1000):
|
||||
"""
|
||||
:param cap: '100MB', '1G'
|
||||
:param size: '100MB', '1G'
|
||||
:param expect: 'K, M, G, T
|
||||
:param rate: Default 1000, may be 1024
|
||||
:return:
|
||||
"""
|
||||
rate_mapping = (
|
||||
|
|
|
@ -320,8 +320,9 @@ CACHES = {
|
|||
}
|
||||
|
||||
# Captcha settings, more see https://django-simple-captcha.readthedocs.io/en/latest/advanced.html
|
||||
CAPTCHA_IMAGE_SIZE = (75, 33)
|
||||
CAPTCHA_IMAGE_SIZE = (80, 33)
|
||||
CAPTCHA_FOREGROUND_COLOR = '#001100'
|
||||
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
|
||||
|
||||
COMMAND_STORE_BACKEND = 'audits.backends.command.db'
|
||||
RECORD_STORE_BACKEND = 'audits.backends.record.db'
|
||||
|
|
|
@ -21,16 +21,16 @@ class JMSHost(Host):
|
|||
# 添加密码和秘钥
|
||||
if asset.get('password'):
|
||||
self.set_variable('ansible_ssh_pass', asset['password'])
|
||||
if asset.get('key'):
|
||||
if asset.get('private_key'):
|
||||
self.set_variable('ansible_ssh_private_key_file', asset['private_key'])
|
||||
|
||||
# 添加become支持
|
||||
become = asset.get("become", None)
|
||||
if become is not None:
|
||||
become = asset.get("become", False)
|
||||
if become:
|
||||
self.set_variable("ansible_become", True)
|
||||
self.set_variable("ansible_become_method", become.get('method'))
|
||||
self.set_variable("ansible_become_user", become.get('user'))
|
||||
self.set_variable("ansible_become_pass", become.get('pass'))
|
||||
self.set_variable("ansible_become_method", become.get('method', 'sudo'))
|
||||
self.set_variable("ansible_become_user", become.get('user', 'root'))
|
||||
self.set_variable("ansible_become_pass", become.get('pass', ''))
|
||||
else:
|
||||
self.set_variable("ansible_become", False)
|
||||
|
||||
|
|
|
@ -265,8 +265,10 @@ class AdHocRunner(object):
|
|||
result['success'].append(host)
|
||||
|
||||
for host, msgs in self.results_callback.result_q['dark'].items():
|
||||
msg = '\n'.join(['{}: {}'.format(msg.get('invocation', {}).get('module_name'),
|
||||
msg.get('msg', '')) for msg in msgs])
|
||||
msg = '\n'.join(['{} {}: {}'.format(
|
||||
msg.get('module_stdout', ''),
|
||||
msg.get('invocation', {}).get('module_name'),
|
||||
msg.get('msg', '')) for msg in msgs])
|
||||
result['failed'].append((host, msg))
|
||||
return result
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
|
||||
from rest_framework import viewsets
|
||||
|
||||
from .hands import IsSuperUser
|
||||
from .models import Task
|
||||
from .serializers import TaskSerializer
|
||||
|
||||
|
||||
class TaskViewSet(viewsets.ModelViewSet):
|
||||
queryset = Task.objects.all()
|
||||
serializer_class = TaskSerializer
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
|
@ -1 +0,0 @@
|
|||
from views import *
|
|
@ -1,16 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
from rest_framework.exceptions import APIException
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
||||
class ServiceUnavailable(APIException):
|
||||
status_code = default_code = 503
|
||||
default_detail = _('Service temporarily unavailable, try again later.')
|
||||
|
||||
|
||||
class ServiceNotImplemented(APIException):
|
||||
status_code = default_code = 501
|
||||
default_detail = _('This service maybe implemented in the future, but now not implemented!')
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
class AdminUserRequired(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to only allow admin user to access the resource.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Write permissions are only allowed to the admin role.
|
||||
return request.user.is_staff
|
|
@ -1,4 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
from rest_framework import viewsets
|
||||
|
||||
from serializers import *
|
||||
from permissions import *
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from users.permissions import IsSuperUser
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import Task
|
||||
|
||||
|
||||
class TaskSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Task
|
||||
fields = '__all__'
|
||||
|
||||
|
|
@ -68,7 +68,17 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is success ' %}:</td>
|
||||
{% if object.is_finished %}
|
||||
<td><b>{{ object.is_success|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
{% else %}
|
||||
<td>
|
||||
<div class="progress progress-striped active">
|
||||
<div style="width: 50%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="75" role="progressbar" class="progress-bar progress-bar-danger">
|
||||
<span class="sr-only">40% Complete (success)</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Assets ' %}:</td>
|
||||
|
@ -84,6 +94,31 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span><b>Result</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<pre>
|
||||
{{ object.result }}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-danger">
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block table_head %}
|
||||
<th></th>
|
||||
<th class="text-center"></th>
|
||||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'Success' %}</th>
|
||||
|
@ -69,6 +69,7 @@
|
|||
<td class="text-center">{{ object.timedelta }} s</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'ops:task-run' pk=object.uuid %}" class="btn btn-xs btn-info">{% trans "Run again" %}</a>
|
||||
<a data-uid="{{ object.uuid }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -92,45 +93,14 @@
|
|||
forceParse: false,
|
||||
autoclose: true
|
||||
});
|
||||
|
||||
}).on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-ops:task-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
})
|
||||
</script>
|
||||
{# function terminateConnection(data) {#}
|
||||
{# function success() {#}
|
||||
{# window.setTimeout(function () {#}
|
||||
{# window.location.reload()#}
|
||||
{# }, 300)#}
|
||||
{# }#}
|
||||
{# var the_url = "{% url 'api-applications:terminate-connection' %}";#}
|
||||
{# APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});#}
|
||||
{# }#}
|
||||
{# $(document).ready(function() {#}
|
||||
{# $('table').DataTable({#}
|
||||
{# "searching": false,#}
|
||||
{# "paging": false,#}
|
||||
{# "bInfo" : false,#}
|
||||
{# "order": []#}
|
||||
{# });#}
|
||||
{# $('.select2').select2();#}
|
||||
{# $('#date .input-daterange').datepicker({#}
|
||||
{# dateFormat: 'mm/dd/yy',#}
|
||||
{# keyboardNavigation: false,#}
|
||||
{# forceParse: false,#}
|
||||
{# autoclose: true#}
|
||||
{# });#}
|
||||
{# }).on('click', '.btn-term', function () {#}
|
||||
{# var $this = $(this);#}
|
||||
{# var proxy_log_id = $this.attr('value');#}
|
||||
{# var data = {#}
|
||||
{# proxy_log_id: proxy_log_id#}
|
||||
{# };#}
|
||||
{# terminateConnection(data)#}
|
||||
{# }).on('click', '#btn_bulk_update', function () {#}
|
||||
{# var data = [];#}
|
||||
{# $('.cbx-term:checked').each(function () {#}
|
||||
{# data.push({proxy_log_id: $(this).attr('value')})#}
|
||||
{# });#}
|
||||
{# terminateConnection(data)#}
|
||||
{# })#}
|
||||
{# </script>#}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from .. import api
|
||||
|
||||
|
||||
urlpatterns = []
|
||||
router = DefaultRouter()
|
||||
router.register(r'v1/tasks', api.TaskViewSet, 'task')
|
||||
|
||||
urlpatterns = []
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
|
|
@ -18,7 +18,7 @@ logger = get_logger(__file__)
|
|||
def run_AdHoc(task_tuple, assets,
|
||||
task_name='Ansible AdHoc runner',
|
||||
task_id=None, pattern='all',
|
||||
record=True, verbose=False):
|
||||
record=True, verbose=True):
|
||||
"""
|
||||
:param task_tuple: (('module_name', 'module_args'), ('module_name', 'module_args'))
|
||||
:param assets: [asset1, asset2]
|
||||
|
@ -51,6 +51,11 @@ def run_AdHoc(task_tuple, assets,
|
|||
else:
|
||||
record = Task.objects.get(uuid=task_id)
|
||||
record.date_start = timezone.now()
|
||||
record.date_finished = None
|
||||
record.timedelta = None
|
||||
record.is_finished = False
|
||||
record.is_success = False
|
||||
record.save()
|
||||
ts_start = time.time()
|
||||
if verbose:
|
||||
logger.debug('Start runner {}'.format(task_name))
|
||||
|
@ -61,7 +66,7 @@ def run_AdHoc(task_tuple, assets,
|
|||
record.date_finished = timezone.now()
|
||||
record.is_finished = True
|
||||
if verbose:
|
||||
record.result = json.dumps(result)
|
||||
record.result = json.dumps(result, indent=4, sort_keys=True)
|
||||
record.summary = json.dumps(summary)
|
||||
record.timedelta = timedelta
|
||||
if len(summary['failed']) == 0:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
|
@ -81,4 +82,5 @@ class TaskRunView(View):
|
|||
def get(self, request, *args, **kwargs):
|
||||
pk = kwargs.get(self.pk_url_kwarg)
|
||||
rerun_task.delay(pk)
|
||||
time.sleep(0.5)
|
||||
return redirect(reverse('ops:task-detail', kwargs={'pk': pk}))
|
||||
|
|
|
@ -35,10 +35,10 @@ def push_users(self, assets, users):
|
|||
('authorized_key', "user={} state=present key='{}'".format(
|
||||
user['username'], user['public_key'])),
|
||||
('lineinfile',
|
||||
"name=/etc/sudoers state=present regexp='^{0} ALL=(ALL)' "
|
||||
"dest=/etc/sudoers state=present regexp='^{0} ALL=' "
|
||||
"line='{0} ALL=(ALL) NOPASSWD: {1}' "
|
||||
"validate='visudo -cf %s'".format(
|
||||
user['username'], user.get('sudo', '/bin/whoami')
|
||||
user['username'], user.get('sudo', '/sbin/ifconfig')
|
||||
))
|
||||
])
|
||||
task_name = 'Push user {}'.format(','.join([user['name'] for user in users]))
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<div class="footer fixed">
|
||||
<div class="pull-right">
|
||||
Version <strong>0.4.0</strong> GPL.
|
||||
<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">
|
||||
</div>
|
||||
<div>
|
||||
<strong>Copyright</strong> Jumpserver.org Team © 2014-2016
|
||||
<strong>Copyright</strong> Jumpserver.org Team © 2014-2017
|
||||
</div>
|
||||
</div>
|
|
@ -23,7 +23,6 @@
|
|||
<li id="idc"><a href="{% url 'assets:idc-list' %}">{% trans 'IDC' %}</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="asset-tag"><a href="{% url 'assets:asset-tag-list' %}">{% trans 'Label' %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="perms">
|
||||
|
@ -56,8 +55,11 @@
|
|||
<li id="audits">
|
||||
<a href="#"><i class="fa fa-files-o"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="proxy-log">
|
||||
<a href="{% url 'audits:proxy-log-list' %}">{% trans 'Proxy log' %}</a>
|
||||
<li id="proxy-log-online">
|
||||
<a href="{% url 'audits:proxy-log-online-list' %}">{% trans 'Session online' %}</a>
|
||||
</li>
|
||||
<li id="proxy-log-offline">
|
||||
<a href="{% url 'audits:proxy-log-offline-list' %}">{% trans 'Session history' %}</a>
|
||||
</li>
|
||||
<li id="command-log">
|
||||
<a href="{% url 'audits:command-log-list' %}">{% trans 'Command log' %}</a>
|
||||
|
@ -65,26 +67,26 @@
|
|||
<li id="login-log">
|
||||
<a href="{% url 'audits:login-log-list' %}">{% trans 'Login log' %}</a>
|
||||
</li>
|
||||
<li id="admin-log">
|
||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Admin log' %}</a>
|
||||
</li>
|
||||
{# <li id="admin-log">#}
|
||||
{# <a href="{% url 'perms:asset-permission-list' %}">{% trans 'Admin log' %}</a>#}
|
||||
{# </li>#}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li id="">
|
||||
<a href="#">
|
||||
<i class="fa fa-download"></i> <span class="nav-label">{% trans 'File' %}</span><span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="upload"><a href="">{% trans 'File upload' %}</a></li>
|
||||
<li id="download"><a href="">{% trans 'File download' %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="">
|
||||
<a href="">
|
||||
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>
|
||||
</a>
|
||||
</li>
|
||||
{#<li id="">#}
|
||||
{# <a href="#">#}
|
||||
{# <i class="fa fa-download"></i> <span class="nav-label">{% trans 'File' %}</span><span class="fa arrow"></span>#}
|
||||
{# </a>#}
|
||||
{# <ul class="nav nav-second-level">#}
|
||||
{# <li id="upload"><a href="">{% trans 'File upload' %}</a></li>#}
|
||||
{# <li id="download"><a href="">{% trans 'File download' %}</a></li>#}
|
||||
{# </ul>#}
|
||||
{#</li>#}
|
||||
{#<li id="">#}
|
||||
{# <a href="">#}
|
||||
{# <i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>#}
|
||||
{# </a>#}
|
||||
{#</li>#}
|
||||
<li class="special_link">
|
||||
<a href="http://www.jumpserver.org" target="_blank"><i class="fa fa-database"></i>
|
||||
<span class="nav-label">{% trans 'Visit us' %}</span>
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
## Jumpserver v0.4.0 版本安装详细过程
|
||||
### 环境
|
||||
- 系统: CentOS 6.5 x86\_64 mini_ - Python: 版本 2.7.13 (未来支持 3.5)
|
||||
- 安装目录
|
||||
- /opt/jumpserver
|
||||
- /opt/coco
|
||||
|
||||
#### 一. 环境准备
|
||||
**1.1 安装基本工具和库**
|
||||
```
|
||||
`$ yum -y install sqlite-devel git epel-release
|
||||
```
|
||||
`
|
||||
**1.2 安装Python**
|
||||
这里可以参考 [https://segmentfault.com/a/1190000000654227][1]
|
||||
也可以下载我编译的rpm版本:
|
||||
```
|
||||
`$ wget http://repo.jumpserver.org/python27-2.7.13-1.el6.x86_64.rpm_
|
||||
$ yum localinstall -y python27-2.7.13-1.el6.x86_64.rpm
|
||||
$ bash
|
||||
$ python2.7 -V
|
||||
Python 2.7.13
|
||||
```
|
||||
`
|
||||
#### 二. Jumpserver安装
|
||||
**2.1 下载仓库代码 **
|
||||
|
||||
```
|
||||
`$ cd /opt
|
||||
$ git clone [https://github.com/jumpserver/jumpserver.git][2]
|
||||
$ cd jumpserver
|
||||
$ git checkout dev
|
||||
```
|
||||
`**2.1 安装依赖**
|
||||
|
||||
```
|
||||
`$ cd requirements
|
||||
$ sudo yum -y install `cat rpm_requirements.txt`
|
||||
$ pip2.7 install -r requirements.txt -i https://pypi.doubanio.com/simple
|
||||
```
|
||||
`**2.3 准备配置文件 **
|
||||
|
||||
```
|
||||
`$ cd ..
|
||||
$ cp config_example.py config.py
|
||||
$ vim config.py
|
||||
|
||||
// 默认使用的是 DevelpmentConfig 所以应该去修改这部分
|
||||
class DevelopmentConfig(Config):
|
||||
EMAIL_HOST = 'smtp.exmail.qq.com'
|
||||
EMAIL_PORT = 465
|
||||
EMAIL_HOST_USER = 'ask@jumpserver.org'
|
||||
EMAIL_HOST_PASSWORD = 'xxx'
|
||||
EMAIL_USE_SSL = True // 端口是 465 设置 True 否则 False
|
||||
EMAIL_USE_TLS = False // 端口是 587 设置为 True 否则 False
|
||||
SITE_URL = 'http://localhost:8080' // 发送邮件会使用这个地址
|
||||
```
|
||||
`
|
||||
**2.4 初始化数据库**
|
||||
```
|
||||
`$ cd utils
|
||||
$ sh make_migrations.sh
|
||||
$ sh init_db.sh
|
||||
```
|
||||
`
|
||||
**2.5 安装redis server**
|
||||
```
|
||||
`$ yum -y install redis
|
||||
$ service redis start
|
||||
```
|
||||
`
|
||||
**2.6 启动**
|
||||
```
|
||||
`$ cd ..
|
||||
$ python2.7 run_server.py
|
||||
```
|
||||
`访问 http://ip:8080
|
||||
账号密码: admin admin
|
||||
|
||||
**2.7 测试使用**
|
||||
- 创建用户
|
||||
会发送邮件,测试是否正常修改密码,登录
|
||||
|
||||
- 创建管理用户
|
||||
创建一个管理用户, 创建资产时需要关联
|
||||
|
||||
- 创建资产
|
||||
创建一个 资产,关联刚创建的管理用户
|
||||
|
||||
- 创建系统用户
|
||||
系统用户是用来登录资产的,授权时需要
|
||||
|
||||
- 创建授权规则
|
||||
关联用户,资产,系统用户 形成授权规则,授权的系统用户会自动推送到资产上
|
||||
|
||||
|
||||
#### 三. 安装 SSH SERVER - COCO
|
||||
**3.1 下载代码库**
|
||||
```
|
||||
`$ cd /opt
|
||||
$[git clone https://github.com/jumpserver/coco.git][3]
|
||||
```
|
||||
`
|
||||
**3.2 安装依赖**
|
||||
```
|
||||
`$ pip2.7 install -r requirements.txt -i https://pypi.doubanio.com/simple
|
||||
```
|
||||
`
|
||||
**3.3 启动**
|
||||
|
||||
```
|
||||
`$ python2.7 run_server.py
|
||||
```
|
||||
`
|
||||
说明: Coco启动后会向jumpserver注册,请去 jumpserver页面 - 应用程序 - terminal - coco - Accept 允许, 这时 coco就 运行在 2222端口,可以ssh来连接
|
||||
|
||||
命令行:
|
||||
```
|
||||
`ssh admin@192.168.244.128 -p2222
|
||||
```
|
||||
`
|
||||
**3.5 测试**
|
||||
- 测试登录 ssh server
|
||||
- 测试跳转
|
||||
- 测试命令记录回
|
||||
|
||||
[1]: https://segmentfault.com/a/1190000000654227
|
||||
[2]: https://github.com/jumpserver/jumpserver.git
|
||||
[3]: https://github.com/jumpserver/coco.git
|
|
@ -20,3 +20,4 @@ tornado==4.4.2
|
|||
eventlet==0.20.1
|
||||
django-filter==1.0.0
|
||||
passlib==1.7.1
|
||||
sshpass
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
python ../apps/manage.py shell << EOF
|
||||
python2.7 ../apps/manage.py shell << EOF
|
||||
from users.models.utils import *
|
||||
generate_fake()
|
||||
from assets.models.utils import *
|
||||
generate_fake()
|
||||
EOF
|
||||
|
||||
python ../apps/manage.py dbshell << EOF
|
||||
python2.7 ../apps/manage.py dbshell << EOF
|
||||
delete from django_content_type;
|
||||
delete from auth_permission;
|
||||
EOF
|
||||
|
||||
|
||||
python ../apps/manage.py dumpdata > ../apps/fixtures/fake.json
|
||||
python2.7 ../apps/manage.py dumpdata > ../apps/fixtures/fake.json
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
python ../apps/manage.py shell << EOF
|
||||
python2.7 ../apps/manage.py shell << EOF
|
||||
from users.models import *
|
||||
init_all_models()
|
||||
|
||||
|
@ -10,9 +10,9 @@ init_all_models()
|
|||
EOF
|
||||
|
||||
|
||||
python ../apps/manage.py dbshell << EOF
|
||||
python2.7 ../apps/manage.py dbshell << EOF
|
||||
delete from django_content_type;
|
||||
delete from auth_permission;
|
||||
EOF
|
||||
|
||||
python ../apps/manage.py dumpdata > ../apps/fixtures/init.json
|
||||
python2.7 ../apps/manage.py dumpdata > ../apps/fixtures/init.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
python ../apps/manage.py loaddata init
|
||||
python2.7 ../apps/manage.py loaddata init
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
python ../apps/manage.py loaddata fake
|
||||
python2.7 ../apps/manage.py loaddata fake
|
||||
|
|
Loading…
Reference in New Issue