Commit b34c5dde authored by 右书僮's avatar 右书僮

Merge branch 'master' of code.jumpserver.org:Jumpserver/jumpserver

# Conflicts:
#	apps/assets/templates/assets/asset_list.html
parents 9de2ff20 49f6ed52
...@@ -21,3 +21,4 @@ migrations/ ...@@ -21,3 +21,4 @@ migrations/
host_rsa_key host_rsa_key
*.bat *.bat
tags tags
tmp/*
...@@ -95,9 +95,6 @@ class TerminateConnectionView(APIView): ...@@ -95,9 +95,6 @@ class TerminateConnectionView(APIView):
proxy_log_id = d.get('proxy_log_id') proxy_log_id = d.get('proxy_log_id')
proxy_log = get_object_or_404(ProxyLog, id=proxy_log_id) proxy_log = get_object_or_404(ProxyLog, id=proxy_log_id)
terminal_id = proxy_log.terminal terminal_id = proxy_log.terminal
proxy_log.is_finished = True
proxy_log.date_finished = timezone.now()
proxy_log.save()
if terminal_id in tasks: if terminal_id in tasks:
tasks[terminal_id].append({'name': 'kill_proxy', tasks[terminal_id].append({'name': 'kill_proxy',
'proxy_log_id': proxy_log_id}) 'proxy_log_id': proxy_log_id})
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<th class="text-center">{% trans 'Name' %}</th> <th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'IP' %}</th> <th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'Type' %}</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 'Active' %}</th>
<th class="text-center">{% trans 'Alive' %}</th> <th class="text-center">{% trans 'Alive' %}</th>
<th class="text-center">{% trans 'Action' %}</th> <th class="text-center">{% trans 'Action' %}</th>
......
...@@ -12,7 +12,7 @@ from django.shortcuts import get_object_or_404 ...@@ -12,7 +12,7 @@ from django.shortcuts import get_object_or_404
from common.mixins import IDInFilterMixin from common.mixins import IDInFilterMixin
from common.utils import get_object_or_none, signer from common.utils import get_object_or_none, signer
from .hands import IsSuperUser, IsAppUser 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 from . import serializers
...@@ -25,14 +25,11 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet): ...@@ -25,14 +25,11 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = super(AssetViewSet, self).get_queryset() queryset = super(AssetViewSet, self).get_queryset()
idc_id = self.request.query_params.get('idc_id', '') 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', '') system_users_id = self.request.query_params.get('system_user_id', '')
asset_group_id = self.request.query_params.get('asset_group_id', '') asset_group_id = self.request.query_params.get('asset_group_id', '')
admin_user_id = self.request.query_params.get('admin_user_id', '') admin_user_id = self.request.query_params.get('admin_user_id', '')
if idc_id: if idc_id:
queryset = queryset.filter(idc__id=idc_id) queryset = queryset.filter(idc__id=idc_id)
if tags_id:
queryset = queryset.filter(tags__id=tags_id)
if system_users_id: if system_users_id:
queryset = queryset.filter(system_users__id=system_users_id) queryset = queryset.filter(system_users__id=system_users_id)
if admin_user_id: if admin_user_id:
...@@ -147,16 +144,3 @@ class SystemUserAuthInfoApi(generics.RetrieveAPIView): ...@@ -147,16 +144,3 @@ class SystemUserAuthInfoApi(generics.RetrieveAPIView):
} }
return Response(data) 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 @@ ...@@ -2,7 +2,7 @@
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _ 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 from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen, get_logger
...@@ -10,20 +10,6 @@ logger = get_logger(__file__) ...@@ -10,20 +10,6 @@ logger = get_logger(__file__)
class AssetCreateForm(forms.ModelForm): 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): def clean_admin_user(self):
if not self.cleaned_data['admin_user']: if not self.cleaned_data['admin_user']:
raise forms.ValidationError(_('Select admin user')) raise forms.ValidationError(_('Select admin user'))
...@@ -31,16 +17,13 @@ class AssetCreateForm(forms.ModelForm): ...@@ -31,16 +17,13 @@ class AssetCreateForm(forms.ModelForm):
class Meta: class Meta:
model = Asset model = Asset
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
fields = [ fields = [
'hostname', 'ip', 'public_ip', 'port', 'type', 'comment', 'admin_user', 'hostname', 'ip', 'public_ip', 'port', 'type', 'comment', 'admin_user',
'idc', 'groups', 'status', 'env', 'tags', 'is_active' 'idc', 'groups', 'status', 'env', 'is_active'
] ]
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'groups': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select asset groups')}), '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')}), 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
} }
help_texts = { help_texts = {
...@@ -48,24 +31,20 @@ class AssetCreateForm(forms.ModelForm): ...@@ -48,24 +31,20 @@ class AssetCreateForm(forms.ModelForm):
'ip': '* required', 'ip': '* required',
'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'), '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'), 'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'),
'tags': '最多5个标签,单个标签最长8个汉字,按回车确认'
} }
class AssetUpdateForm(AssetCreateForm): class AssetUpdateForm(AssetCreateForm):
class Meta: class Meta:
model = Asset model = Asset
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
fields = [ fields = [
'hostname', 'ip', 'port', 'groups', 'admin_user', 'idc', 'is_active', 'hostname', 'ip', 'port', 'groups', 'admin_user', 'idc', 'is_active',
'type', 'env', 'status', 'public_ip', 'remote_card_ip', 'cabinet_no', 'type', 'env', 'status', 'public_ip', 'remote_card_ip', 'cabinet_no',
'cabinet_pos', 'number', 'comment', 'tags' 'cabinet_pos', 'number', 'comment'
] ]
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'groups': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select asset groups')}), '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')}), 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
} }
help_texts = { help_texts = {
...@@ -73,18 +52,18 @@ class AssetUpdateForm(AssetCreateForm): ...@@ -73,18 +52,18 @@ class AssetUpdateForm(AssetCreateForm):
'ip': '* required', 'ip': '* required',
'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'), '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'), 'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'),
'tags': '最多5个标签,单个标签最长8个汉字,按回车确认'
} }
class AssetGroupForm(forms.ModelForm): class AssetGroupForm(forms.ModelForm):
# See AdminUserForm comment same it # See AdminUserForm comment same it
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), assets = forms.ModelMultipleChoiceField(
label=_('Asset'), queryset=Asset.objects.all(),
required=False, label=_('Asset'),
widget=forms.SelectMultiple( required=False,
attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) widget=forms.SelectMultiple(
) attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if kwargs.get('instance', None): if kwargs.get('instance', None):
...@@ -297,39 +276,5 @@ class SystemUserForm(forms.ModelForm): ...@@ -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): class FileForm(forms.Form):
file = forms.FileField() file = forms.FileField()
...@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
from . import IDC, AssetGroup, AdminUser, SystemUser from . import IDC, AssetGroup, AdminUser, SystemUser
__all__ = ['Asset', 'Tag'] __all__ = ['Asset']
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -83,7 +83,6 @@ class Asset(models.Model): ...@@ -83,7 +83,6 @@ class Asset(models.Model):
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) 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')) 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')) 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): def __unicode__(self):
return '%s <%s: %s>' % (self.hostname, self.ip, self.port) return '%s <%s: %s>' % (self.hostname, self.ip, self.port)
...@@ -112,7 +111,12 @@ class Asset(models.Model): ...@@ -112,7 +111,12 @@ class Asset(models.Model):
'groups': [group.name for group in self.groups.all()], 'groups': [group.name for group in self.groups.all()],
'username': self.admin_user.username if self.admin_user else '', 'username': self.admin_user.username if self.admin_user else '',
'password': self.admin_user.password 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: class Meta:
...@@ -141,16 +145,3 @@ class Asset(models.Model): ...@@ -141,16 +145,3 @@ class Asset(models.Model):
print('Error continue') print('Error continue')
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 @@ ...@@ -3,12 +3,14 @@
# #
from __future__ import unicode_literals from __future__ import unicode_literals
import os
import logging import logging
from hashlib import md5
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ 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 from common.utils import signer, validate_ssh_private_key, ssh_key_string_to_obj
...@@ -38,7 +40,7 @@ class AdminUser(models.Model): ...@@ -38,7 +40,7 @@ class AdminUser(models.Model):
become = models.BooleanField(default=True) become = models.BooleanField(default=True)
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4) become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
become_user = models.CharField(default='root', max_length=64) 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( _public_key = models.CharField(
max_length=4096, blank=True, verbose_name=_('SSH public key')) max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
...@@ -74,6 +76,18 @@ class AdminUser(models.Model): ...@@ -74,6 +76,18 @@ class AdminUser(models.Model):
def private_key(self, private_key_raw): def private_key(self, private_key_raw):
self._private_key = signer.sign(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 @property
def public_key(self): def public_key(self):
return signer.unsign(self._public_key) return signer.unsign(self._public_key)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import viewsets, serializers, generics 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 common.mixins import IDInFilterMixin
from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin
...@@ -61,20 +61,6 @@ class IDCUpdateAssetsSerializer(serializers.ModelSerializer): ...@@ -61,20 +61,6 @@ class IDCUpdateAssetsSerializer(serializers.ModelSerializer):
fields = ['id', 'assets'] 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): class AdminUserSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
...@@ -189,10 +175,3 @@ class IDCSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -189,10 +175,3 @@ class IDCSerializer(BulkSerializerMixin, serializers.ModelSerializer):
fields.append('assets_amount') fields.append('assets_amount')
return fields return fields
class TagUpdateAssetsSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
class Meta:
model = Tag
fields = ['id', 'assets']
\ No newline at end of file
...@@ -12,8 +12,7 @@ def update_assets_hardware_info(assets): ...@@ -12,8 +12,7 @@ def update_assets_hardware_info(assets):
task_tuple = ( task_tuple = (
('setup', ''), ('setup', ''),
) )
task_name = ','.join([asset.hostname for asset in assets]) summary, result = run_AdHoc(task_tuple, assets, record=False)
summary, result = run_AdHoc(task_tuple, assets, record=True, task_name=task_name)
for hostname, info in result['contacted'].items(): for hostname, info in result['contacted'].items():
if info: if info:
info = info[0]['ansible_facts'] info = info[0]['ansible_facts']
......
...@@ -61,22 +61,6 @@ ...@@ -61,22 +61,6 @@
</div> </div>
</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> </form>
{% endblock %} {% endblock %}
{% block modal_confirm_id %}btn_asset_bulk_update{% endblock %} {% block modal_confirm_id %}btn_asset_bulk_update{% endblock %}
\ No newline at end of file
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3> <h3>{% trans 'Other' %}</h3>
{{ form.tags|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }} {{ form.comment|bootstrap_horizontal }}
{{ form.is_active|bootstrap_horizontal }} {{ form.is_active|bootstrap_horizontal }}
......
...@@ -104,37 +104,6 @@ function tagShow() { ...@@ -104,37 +104,6 @@ function tagShow() {
} }
} //onload; } //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(){ $(document).ready(function(){
var options = { var options = {
......
...@@ -13,7 +13,6 @@ router.register(r'v1/assets', api.AssetViewSet, 'asset') ...@@ -13,7 +13,6 @@ router.register(r'v1/assets', api.AssetViewSet, 'asset')
router.register(r'v1/idc', api.IDCViewSet, 'idc') router.register(r'v1/idc', api.IDCViewSet, 'idc')
router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user') router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user')
router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user') router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user')
router.register(r'v1/tags', api.TagViewSet, 'asset-tag')
urlpatterns = [ urlpatterns = [
url(r'^v1/assets_bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), url(r'^v1/assets_bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
...@@ -45,8 +44,6 @@ urlpatterns = [ ...@@ -45,8 +44,6 @@ urlpatterns = [
url(r'^v1/idc/(?P<pk>\d+)/assets/$', url(r'^v1/idc/(?P<pk>\d+)/assets/$',
api.IDCupdateAssetsApi.as_view(), name='idc-update-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 urlpatterns += router.urls
......
...@@ -24,13 +24,6 @@ urlpatterns = [ ...@@ -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]+)/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'^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 # Resource idc url
url(r'^idc/$', views.IDCListView.as_view(), name='idc-list'), url(r'^idc/$', views.IDCListView.as_view(), name='idc-list'),
url(r'^idc/create/$', views.IDCCreateView.as_view(), name='idc-create'), url(r'^idc/create/$', views.IDCCreateView.as_view(), name='idc-create'),
......
# ~*~ coding: utf-8 ~*~ # ~*~ 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
\ No newline at end of file
This diff is collapsed.
...@@ -90,8 +90,3 @@ class RecordLogViewSet(BulkModelViewSet): ...@@ -90,8 +90,3 @@ class RecordLogViewSet(BulkModelViewSet):
else: else:
return record_store.all() return record_store.all()
...@@ -23,18 +23,18 @@ ...@@ -23,18 +23,18 @@
</div> </div>
</div> </div>
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="user"> <select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option> <option value="">{% trans 'User' %}</option>
{% for u in user_list %} {% 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 %} {% endfor %}
</select> </select>
</div> </div>
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="asset"> <select class="select2 form-control" name="ip">
<option value="">{% trans 'Asset' %}</option> <option value="">{% trans 'Asset' %}</option>
{% for a in asset_list %} {% 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 %} {% endfor %}
</select> </select>
</div> </div>
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load common_tags %}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet"> <link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
......
{% 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 @@ ...@@ -24,16 +24,16 @@
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="username"> <select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option> <option value="">{% trans 'User' %}</option>
{% for user in user_list %} {% for u in user_list %}
<option value="{{ user }}" {% if user == username %} selected {% endif %}>{{ user }}</option> <option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="ip"> <select class="select2 form-control" name="ip">
<option value="">{% trans 'Asset' %}</option> <option value="">{% trans 'Asset' %}</option>
{% for asset in asset_list %} {% for a in asset_list %}
<option value="{{ asset }}" {% if asset == ip %} selected {% endif %}>{{ asset }}</option> <option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
<th class="text-center">{% trans 'Command' %}</th> <th class="text-center">{% trans 'Command' %}</th>
<th class="text-center">{% trans 'Success' %}</th> <th class="text-center">{% trans 'Success' %}</th>
<th class="text-center">{% trans 'Finished' %}</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 'Date start' %}</th>
<th class="text-center">{% trans 'Time' %}</th> <th class="text-center">{% trans 'Time' %}</th>
{% endblock %} {% endblock %}
......
...@@ -4,14 +4,16 @@ from .. import views ...@@ -4,14 +4,16 @@ from .. import views
app_name = 'audits' app_name = 'audits'
urlpatterns = [ urlpatterns = [
url(r'^proxy-log$', views.ProxyLogListView.as_view(), url(r'^proxy-log-offline/$', views.ProxyLogOfflineListView.as_view(),
name='proxy-log-list'), name='proxy-log-offline-list'),
url(r'^proxy-log/(?P<pk>\d+)$', views.ProxyLogDetailView.as_view(), 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'), name='proxy-log-detail'),
# url(r'^proxy-log/(?P<pk>\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'), # 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'), name='command-log-list'),
url(r'^login-log$', views.LoginLogListView.as_view(), url(r'^login-log/$', views.LoginLogListView.as_view(),
name='login-log-list'), name='login-log-list'),
] ]
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
import time import time
from datetime import datetime from datetime import datetime
import pytz
from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView
from django.views.generic.edit import SingleObjectMixin from django.views.generic.edit import SingleObjectMixin
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
...@@ -22,10 +21,10 @@ from audits.backends import CommandLogSerializer ...@@ -22,10 +21,10 @@ from audits.backends import CommandLogSerializer
class ProxyLogListView(AdminUserRequiredMixin, ListView): class ProxyLogListView(AdminUserRequiredMixin, ListView):
model = ProxyLog model = ProxyLog
template_name = 'audits/proxy_log_list.html' template_name = 'audits/proxy_log_online_list.html'
context_object_name = 'proxy_log_list' context_object_name = 'proxy_log_list'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE 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'] ordering = ['is_finished', '-id']
date_format = '%m/%d/%Y' date_format = '%m/%d/%Y'
...@@ -37,8 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView): ...@@ -37,8 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
self.queryset = super(ProxyLogListView, self).get_queryset() self.queryset = super(ProxyLogListView, self).get_queryset()
self.keyword = self.request.GET.get('keyword', '') self.keyword = self.request.GET.get('keyword', '')
self.user = self.request.GET.get('user') self.username = self.request.GET.get('username')
self.asset = self.request.GET.get('asset') self.ip = self.request.GET.get('ip')
self.system_user = self.request.GET.get('system_user') self.system_user = self.request.GET.get('system_user')
self.date_from_s = self.request.GET.get('date_from', date_from_default) 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) self.date_to_s = self.request.GET.get('date_to', date_to_default)
...@@ -53,10 +52,10 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView): ...@@ -53,10 +52,10 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S') self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
date_to = date_to.replace(tzinfo=timezone.get_current_timezone()) date_to = date_to.replace(tzinfo=timezone.get_current_timezone())
filter_kwargs['date_start__lt'] = date_to filter_kwargs['date_start__lt'] = date_to
if self.user: if self.username:
filter_kwargs['user'] = self.user filter_kwargs['user'] = self.username
if self.asset: if self.ip:
filter_kwargs['asset'] = self.asset filter_kwargs['ip'] = self.ip
if self.system_user: if self.system_user:
filter_kwargs['system_user'] = self.system_user filter_kwargs['system_user'] = self.system_user
if self.keyword: if self.keyword:
...@@ -81,14 +80,46 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView): ...@@ -81,14 +80,46 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
'keyword': self.keyword, 'keyword': self.keyword,
'date_from': self.date_from_s, 'date_from': self.date_from_s,
'date_to': self.date_to_s, 'date_to': self.date_to_s,
'user': self.user, 'username': self.username,
'asset': self.asset, 'ip': self.ip,
'system_user': self.system_user, 'system_user': self.system_user,
} }
kwargs.update(context) kwargs.update(context)
return super(ProxyLogListView, self).get_context_data(**kwargs) 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, class ProxyLogDetailView(AdminUserRequiredMixin,
SingleObjectMixin, SingleObjectMixin,
ListView): ListView):
...@@ -131,7 +162,7 @@ class CommandLogListView(AdminUserRequiredMixin, ListView): ...@@ -131,7 +162,7 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
template_name = 'audits/command_log_list.html' template_name = 'audits/command_log_list.html'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'command_list' 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' date_format = '%m/%d/%Y'
ordering = ['-id'] ordering = ['-id']
...@@ -141,8 +172,8 @@ class CommandLogListView(AdminUserRequiredMixin, ListView): ...@@ -141,8 +172,8 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
date_from_default = (date_now - timezone.timedelta(7)) \ date_from_default = (date_now - timezone.timedelta(7)) \
.strftime(self.date_format) .strftime(self.date_format)
self.command = self.request.GET.get('command', '') self.command = self.request.GET.get('command', '')
self.user = self.request.GET.get('user') self.username = self.request.GET.get('username')
self.asset = self.request.GET.get('asset') self.ip = self.request.GET.get('ip')
self.system_user = self.request.GET.get('system_user') self.system_user = self.request.GET.get('system_user')
self.date_from_s = \ self.date_from_s = \
self.request.GET.get('date_from', date_from_default) self.request.GET.get('date_from', date_from_default)
...@@ -162,10 +193,10 @@ class CommandLogListView(AdminUserRequiredMixin, ListView): ...@@ -162,10 +193,10 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
.replace(tzinfo=timezone.get_current_timezone()) .replace(tzinfo=timezone.get_current_timezone())
date_to_ts = time.mktime(date_to.timetuple()) date_to_ts = time.mktime(date_to.timetuple())
filter_kwargs['date_to_ts'] = date_to_ts filter_kwargs['date_to_ts'] = date_to_ts
if self.user: if self.username:
filter_kwargs['user'] = self.user filter_kwargs['user'] = self.username
if self.asset: if self.ip:
filter_kwargs['asset'] = self.asset filter_kwargs['asset'] = self.ip
if self.system_user: if self.system_user:
filter_kwargs['system_user'] = self.system_user filter_kwargs['system_user'] = self.system_user
if self.command: if self.command:
...@@ -183,8 +214,8 @@ class CommandLogListView(AdminUserRequiredMixin, ListView): ...@@ -183,8 +214,8 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
'command': self.command, 'command': self.command,
'date_from': self.date_from_s, 'date_from': self.date_from_s,
'date_to': self.date_to_s, 'date_to': self.date_to_s,
'user': self.user, 'username': self.username,
'asset': self.asset, 'ip': self.ip,
'system_user': self.system_user, 'system_user': self.system_user,
} }
kwargs.update(context) kwargs.update(context)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# #
from __future__ import unicode_literals from __future__ import unicode_literals
from collections import OrderedDict
from six import string_types from six import string_types
import base64 import base64
import os import os
...@@ -53,6 +54,7 @@ def get_object_or_none(model, **kwargs): ...@@ -53,6 +54,7 @@ def get_object_or_none(model, **kwargs):
class Signer(object): class Signer(object):
"""用来加密,解密,和基于时间戳的方式验证token"""
def __init__(self, secret_key=SECRET_KEY): def __init__(self, secret_key=SECRET_KEY):
self.secret_key = secret_key self.secret_key = secret_key
...@@ -330,13 +332,13 @@ def encrypt_password(password): ...@@ -330,13 +332,13 @@ def encrypt_password(password):
return None return None
from collections import OrderedDict
def capacity_convert(size, expect='auto', rate=1000): def capacity_convert(size, expect='auto', rate=1000):
""" """
:param cap: '100MB', '1G' :param size: '100MB', '1G'
:param expect: 'K, M, G, T :param expect: 'K, M, G, T
:param rate: Default 1000, may be 1024
:return: :return:
""" """
rate_mapping = ( rate_mapping = (
......
...@@ -320,8 +320,9 @@ CACHES = { ...@@ -320,8 +320,9 @@ CACHES = {
} }
# Captcha settings, more see https://django-simple-captcha.readthedocs.io/en/latest/advanced.html # 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_FOREGROUND_COLOR = '#001100'
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
COMMAND_STORE_BACKEND = 'audits.backends.command.db' COMMAND_STORE_BACKEND = 'audits.backends.command.db'
RECORD_STORE_BACKEND = 'audits.backends.record.db' RECORD_STORE_BACKEND = 'audits.backends.record.db'
......
...@@ -21,16 +21,16 @@ class JMSHost(Host): ...@@ -21,16 +21,16 @@ class JMSHost(Host):
# 添加密码和秘钥 # 添加密码和秘钥
if asset.get('password'): if asset.get('password'):
self.set_variable('ansible_ssh_pass', asset['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']) self.set_variable('ansible_ssh_private_key_file', asset['private_key'])
# 添加become支持 # 添加become支持
become = asset.get("become", None) become = asset.get("become", False)
if become is not None: if become:
self.set_variable("ansible_become", True) self.set_variable("ansible_become", True)
self.set_variable("ansible_become_method", become.get('method')) self.set_variable("ansible_become_method", become.get('method', 'sudo'))
self.set_variable("ansible_become_user", become.get('user')) self.set_variable("ansible_become_user", become.get('user', 'root'))
self.set_variable("ansible_become_pass", become.get('pass')) self.set_variable("ansible_become_pass", become.get('pass', ''))
else: else:
self.set_variable("ansible_become", False) self.set_variable("ansible_become", False)
......
...@@ -265,8 +265,10 @@ class AdHocRunner(object): ...@@ -265,8 +265,10 @@ class AdHocRunner(object):
result['success'].append(host) result['success'].append(host)
for host, msgs in self.results_callback.result_q['dark'].items(): for host, msgs in self.results_callback.result_q['dark'].items():
msg = '\n'.join(['{}: {}'.format(msg.get('invocation', {}).get('module_name'), msg = '\n'.join(['{} {}: {}'.format(
msg.get('msg', '')) for msg in msgs]) msg.get('module_stdout', ''),
msg.get('invocation', {}).get('module_name'),
msg.get('msg', '')) for msg in msgs])
result['failed'].append((host, msg)) result['failed'].append((host, msg))
return result return result
......
# ~*~ 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,)
from views import *
\ No newline at end of file
# ~*~ 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!')
# ~*~ 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
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from rest_framework import viewsets
from serializers import *
from permissions import *
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from users.permissions import IsSuperUser
# ~*~ 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 @@ ...@@ -68,7 +68,17 @@
</tr> </tr>
<tr> <tr>
<td>{% trans 'Is success ' %}:</td> <td>{% trans 'Is success ' %}:</td>
{% if object.is_finished %}
<td><b>{{ object.is_success|yesno:"Yes,No,Unkown" }}</b></td> <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>
<tr> <tr>
<td>{% trans 'Assets ' %}:</td> <td>{% trans 'Assets ' %}:</td>
...@@ -84,6 +94,31 @@ ...@@ -84,6 +94,31 @@
</table> </table>
</div> </div>
</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>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0"> <div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-danger"> <div class="panel panel-danger">
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
{% endblock %} {% endblock %}
{% block table_head %} {% block table_head %}
<th></th> <th class="text-center"></th>
<th class="text-center">{% trans 'Name' %}</th> <th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Asset' %}</th> <th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Success' %}</th> <th class="text-center">{% trans 'Success' %}</th>
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
<td class="text-center">{{ object.timedelta }} s</td> <td class="text-center">{{ object.timedelta }} s</td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'ops:task-run' pk=object.uuid %}" class="btn btn-xs btn-info">{% trans "Run again" %}</a> <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> </td>
</tr> </tr>
{% endfor %} {% endfor %}
...@@ -92,45 +93,14 @@ ...@@ -92,45 +93,14 @@
forceParse: false, forceParse: false,
autoclose: true 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> </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 %} {% endblock %}
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from .. import api
urlpatterns = [] router = DefaultRouter()
\ No newline at end of file router.register(r'v1/tasks', api.TaskViewSet, 'task')
urlpatterns = []
urlpatterns += router.urls
...@@ -18,7 +18,7 @@ logger = get_logger(__file__) ...@@ -18,7 +18,7 @@ logger = get_logger(__file__)
def run_AdHoc(task_tuple, assets, def run_AdHoc(task_tuple, assets,
task_name='Ansible AdHoc runner', task_name='Ansible AdHoc runner',
task_id=None, pattern='all', 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 task_tuple: (('module_name', 'module_args'), ('module_name', 'module_args'))
:param assets: [asset1, asset2] :param assets: [asset1, asset2]
...@@ -51,6 +51,11 @@ def run_AdHoc(task_tuple, assets, ...@@ -51,6 +51,11 @@ def run_AdHoc(task_tuple, assets,
else: else:
record = Task.objects.get(uuid=task_id) record = Task.objects.get(uuid=task_id)
record.date_start = timezone.now() 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() ts_start = time.time()
if verbose: if verbose:
logger.debug('Start runner {}'.format(task_name)) logger.debug('Start runner {}'.format(task_name))
...@@ -61,7 +66,7 @@ def run_AdHoc(task_tuple, assets, ...@@ -61,7 +66,7 @@ def run_AdHoc(task_tuple, assets,
record.date_finished = timezone.now() record.date_finished = timezone.now()
record.is_finished = True record.is_finished = True
if verbose: if verbose:
record.result = json.dumps(result) record.result = json.dumps(result, indent=4, sort_keys=True)
record.summary = json.dumps(summary) record.summary = json.dumps(summary)
record.timedelta = timedelta record.timedelta = timedelta
if len(summary['failed']) == 0: if len(summary['failed']) == 0:
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
import time
import json import json
from datetime import datetime from datetime import datetime
...@@ -81,4 +82,5 @@ class TaskRunView(View): ...@@ -81,4 +82,5 @@ class TaskRunView(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
pk = kwargs.get(self.pk_url_kwarg) pk = kwargs.get(self.pk_url_kwarg)
rerun_task.delay(pk) rerun_task.delay(pk)
time.sleep(0.5)
return redirect(reverse('ops:task-detail', kwargs={'pk': pk})) return redirect(reverse('ops:task-detail', kwargs={'pk': pk}))
...@@ -35,10 +35,10 @@ def push_users(self, assets, users): ...@@ -35,10 +35,10 @@ def push_users(self, assets, users):
('authorized_key', "user={} state=present key='{}'".format( ('authorized_key', "user={} state=present key='{}'".format(
user['username'], user['public_key'])), user['username'], user['public_key'])),
('lineinfile', ('lineinfile',
"name=/etc/sudoers state=present regexp='^{0} ALL=(ALL)' " "dest=/etc/sudoers state=present regexp='^{0} ALL=' "
"line='{0} ALL=(ALL) NOPASSWD: {1}' " "line='{0} ALL=(ALL) NOPASSWD: {1}' "
"validate='visudo -cf %s'".format( "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])) task_name = 'Push user {}'.format(','.join([user['name'] for user in users]))
......
<div class="footer fixed"> <div class="footer fixed">
<div class="pull-right"> <div class="pull-right">
Version <strong>0.4.0</strong> GPL. Version <strong>0.4.0</strong> GPL.
<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">
</div> </div>
<div> <div>
<strong>Copyright</strong> Jumpserver.org Team &copy; 2014-2016 <strong>Copyright</strong> Jumpserver.org Team &copy; 2014-2017
</div> </div>
</div> </div>
\ No newline at end of file
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
<li id="idc"><a href="{% url 'assets:idc-list' %}">{% trans 'IDC' %}</a></li> <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="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="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> </ul>
</li> </li>
<li id="perms"> <li id="perms">
...@@ -56,8 +55,11 @@ ...@@ -56,8 +55,11 @@
<li id="audits"> <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> <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"> <ul class="nav nav-second-level">
<li id="proxy-log"> <li id="proxy-log-online">
<a href="{% url 'audits:proxy-log-list' %}">{% trans 'Proxy log' %}</a> <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>
<li id="command-log"> <li id="command-log">
<a href="{% url 'audits:command-log-list' %}">{% trans 'Command log' %}</a> <a href="{% url 'audits:command-log-list' %}">{% trans 'Command log' %}</a>
...@@ -65,26 +67,26 @@ ...@@ -65,26 +67,26 @@
<li id="login-log"> <li id="login-log">
<a href="{% url 'audits:login-log-list' %}">{% trans 'Login log' %}</a> <a href="{% url 'audits:login-log-list' %}">{% trans 'Login log' %}</a>
</li> </li>
<li id="admin-log"> {# <li id="admin-log">#}
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Admin log' %}</a> {# <a href="{% url 'perms:asset-permission-list' %}">{% trans 'Admin log' %}</a>#}
</li> {# </li>#}
</ul> </ul>
</li> </li>
<li id=""> {#<li id="">#}
<a href="#"> {# <a href="#">#}
<i class="fa fa-download"></i> <span class="nav-label">{% trans 'File' %}</span><span class="fa arrow"></span> {# <i class="fa fa-download"></i> <span class="nav-label">{% trans 'File' %}</span><span class="fa arrow"></span>#}
</a> {# </a>#}
<ul class="nav nav-second-level"> {# <ul class="nav nav-second-level">#}
<li id="upload"><a href="">{% trans 'File upload' %}</a></li> {# <li id="upload"><a href="">{% trans 'File upload' %}</a></li>#}
<li id="download"><a href="">{% trans 'File download' %}</a></li> {# <li id="download"><a href="">{% trans 'File download' %}</a></li>#}
</ul> {# </ul>#}
</li> {#</li>#}
<li id=""> {#<li id="">#}
<a href=""> {# <a href="">#}
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span> {# <i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>#}
</a> {# </a>#}
</li> {#</li>#}
<li class="special_link"> <li class="special_link">
<a href="http://www.jumpserver.org" target="_blank"><i class="fa fa-database"></i> <a href="http://www.jumpserver.org" target="_blank"><i class="fa fa-database"></i>
<span class="nav-label">{% trans 'Visit us' %}</span> <span class="nav-label">{% trans 'Visit us' %}</span>
......
## 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
\ No newline at end of file
...@@ -20,3 +20,4 @@ tornado==4.4.2 ...@@ -20,3 +20,4 @@ tornado==4.4.2
eventlet==0.20.1 eventlet==0.20.1
django-filter==1.0.0 django-filter==1.0.0
passlib==1.7.1 passlib==1.7.1
sshpass
#!/bin/bash #!/bin/bash
# #
python ../apps/manage.py shell << EOF python2.7 ../apps/manage.py shell << EOF
from users.models.utils import * from users.models.utils import *
generate_fake() generate_fake()
from assets.models.utils import * from assets.models.utils import *
generate_fake() generate_fake()
EOF EOF
python ../apps/manage.py dbshell << EOF python2.7 ../apps/manage.py dbshell << EOF
delete from django_content_type; delete from django_content_type;
delete from auth_permission; delete from auth_permission;
EOF EOF
python ../apps/manage.py dumpdata > ../apps/fixtures/fake.json python2.7 ../apps/manage.py dumpdata > ../apps/fixtures/fake.json
#!/bin/bash #!/bin/bash
# #
python ../apps/manage.py shell << EOF python2.7 ../apps/manage.py shell << EOF
from users.models import * from users.models import *
init_all_models() init_all_models()
...@@ -10,9 +10,9 @@ init_all_models() ...@@ -10,9 +10,9 @@ init_all_models()
EOF EOF
python ../apps/manage.py dbshell << EOF python2.7 ../apps/manage.py dbshell << EOF
delete from django_content_type; delete from django_content_type;
delete from auth_permission; delete from auth_permission;
EOF EOF
python ../apps/manage.py dumpdata > ../apps/fixtures/init.json python2.7 ../apps/manage.py dumpdata > ../apps/fixtures/init.json
#!/bin/bash #!/bin/bash
# #
python ../apps/manage.py loaddata init python2.7 ../apps/manage.py loaddata init
#!/bin/bash #!/bin/bash
# #
python ../apps/manage.py loaddata fake python2.7 ../apps/manage.py loaddata fake
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment