【二次开发jumpserver】——整合jumpserver与zabbix推送主机功能
jasset/forms.py
"ip", "other_ip", "hostname", "port", "group", "username", "password", "use_default_auth",
"idc", "mac", "remote_ip", "brand", "cpu", "memory", "disk", "system_type", "system_version",
"cabinet", "position", "number", "status", "asset_type", "env", "sn", "is_active", "comment",
- "system_arch"
+ "system_arch", "zbx_hostid"
]
# coding:utf-8
from django import forms from jasset.models import IDC, Asset, AssetGroup class AssetForm(forms.ModelForm): class Meta:
model = Asset fields = [
"ip", "other_ip", "hostname", "port", "group", "username", "password", "use_default_auth",
"idc", "mac", "remote_ip", "brand", "cpu", "memory", "disk", "system_type", "system_version",
"cabinet", "position", "number", "status", "asset_type", "env", "sn", "is_active", "comment",
"system_arch", "zbx_hostid"
] class AssetGroupForm(forms.ModelForm):
class Meta:
model = AssetGroup
fields = [
"name", "comment"
] class IdcForm(forms.ModelForm):
class Meta:
model = IDC
fields = ['name', "bandwidth", "operator", 'linkman', 'phone', 'address', 'network', 'comment']
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'Name'}),
'network': forms.Textarea(
attrs={'placeholder': '192.168.1.0/24\n192.168.2.0/24'})
}
jasset/models.py
date_added = models.DateTimeField(auto_now=True, null=True)
is_active = models.BooleanField(default=True, verbose_name=u"是否激活")
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
+ zbx_hostid = models.CharField(max_length=32, blank=True, verbose_name=u"zabbix主机ID") def __unicode__(self):
return self.ip
# coding: utf-8 import datetime
from django.db import models
from juser.models import User, UserGroup ASSET_ENV = (
(1, U'生产环境'),
(2, U'测试环境')
) ASSET_STATUS = (
(1, u"已使用"),
(2, u"未使用"),
(3, u"报废")
) ASSET_TYPE = (
(1, u"物理机"),
(2, u"虚拟机"),
(3, u"交换机"),
(4, u"路由器"),
(5, u"防火墙"),
(6, u"Docker"),
(7, u"其他")
) class AssetGroup(models.Model):
GROUP_TYPE = (
('P', 'PRIVATE'),
('A', 'ASSET'),
)
name = models.CharField(max_length=80, unique=True)
comment = models.CharField(max_length=160, blank=True, null=True) def __unicode__(self):
return self.name class IDC(models.Model):
name = models.CharField(max_length=32, verbose_name=u'机房名称')
bandwidth = models.CharField(max_length=32, blank=True, null=True, default='', verbose_name=u'机房带宽')
linkman = models.CharField(max_length=16, blank=True, null=True, default='', verbose_name=u'联系人')
phone = models.CharField(max_length=32, blank=True, null=True, default='', verbose_name=u'联系电话')
address = models.CharField(max_length=128, blank=True, null=True, default='', verbose_name=u"机房地址")
network = models.TextField(blank=True, null=True, default='', verbose_name=u"IP地址段")
date_added = models.DateField(auto_now=True, null=True)
operator = models.CharField(max_length=32, blank=True, default='', null=True, verbose_name=u"运营商")
comment = models.CharField(max_length=128, blank=True, default='', null=True, verbose_name=u"备注") def __unicode__(self):
return self.name class Meta:
verbose_name = u"IDC机房"
verbose_name_plural = verbose_name class Asset(models.Model):
"""
asset modle
"""
ip = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"主机IP")
other_ip = models.CharField(max_length=255, blank=True, null=True, verbose_name=u"其他IP")
hostname = models.CharField(unique=True, max_length=128, verbose_name=u"主机名")
port = models.IntegerField(blank=True, null=True, verbose_name=u"端口号")
group = models.ManyToManyField(AssetGroup, blank=True, verbose_name=u"所属主机组")
username = models.CharField(max_length=16, blank=True, null=True, verbose_name=u"管理用户名")
password = models.CharField(max_length=256, blank=True, null=True, verbose_name=u"密码")
use_default_auth = models.BooleanField(default=True, verbose_name=u"使用默认管理账号")
idc = models.ForeignKey(IDC, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=u'机房')
mac = models.CharField(max_length=20, blank=True, null=True, verbose_name=u"MAC地址")
remote_ip = models.CharField(max_length=16, blank=True, null=True, verbose_name=u'远控卡IP')
brand = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'硬件厂商型号')
cpu = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'CPU')
memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存')
disk = models.CharField(max_length=1024, blank=True, null=True, verbose_name=u'硬盘')
system_type = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"系统类型")
system_version = models.CharField(max_length=8, blank=True, null=True, verbose_name=u"系统版本号")
system_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=u"系统平台")
cabinet = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'机柜号')
position = models.IntegerField(blank=True, null=True, verbose_name=u'机器位置')
number = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'资产编号')
status = models.IntegerField(choices=ASSET_STATUS, blank=True, null=True, default=1, verbose_name=u"机器状态")
asset_type = models.IntegerField(choices=ASSET_TYPE, blank=True, null=True, verbose_name=u"主机类型")
env = models.IntegerField(choices=ASSET_ENV, blank=True, null=True, verbose_name=u"运行环境")
sn = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"SN编号")
date_added = models.DateTimeField(auto_now=True, null=True)
is_active = models.BooleanField(default=True, verbose_name=u"是否激活")
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
zbx_hostid = models.CharField(max_length=32, blank=True, verbose_name=u"zabbix主机ID") def __unicode__(self):
return self.ip class AssetRecord(models.Model):
asset = models.ForeignKey(Asset)
username = models.CharField(max_length=30, null=True)
alert_time = models.DateTimeField(auto_now_add=True)
content = models.TextField(null=True, blank=True)
comment = models.TextField(null=True, blank=True) class AssetAlias(models.Model):
user = models.ForeignKey(User)
asset = models.ForeignKey(Asset)
alias = models.CharField(max_length=100, blank=True, null=True) def __unicode__(self):
return self.alias
jasset/urls.py
url(r'^asset/edit_batch/$', asset_edit_batch, name='asset_edit_batch'),
url(r'^asset/update/$', asset_update, name='asset_update'),
url(r'^asset/update_batch/$', asset_update_batch, name='asset_update_batch'),
+ url(r'^asset/zabbix_update_batch/$', zabbix_update_batch, name='zabbix_update_batch'),
url(r'^asset/upload/$', asset_upload, name='asset_upload'),
url(r'^group/del/$', group_del, name='asset_group_del'),
url(r'^group/add/$', group_add, name='asset_group_add'),
# coding:utf-8
from django.conf.urls import patterns, include, url
from jasset.views import * urlpatterns = patterns('',
url(r'^asset/add/$', asset_add, name='asset_add'),
url(r"^asset/add_batch/$", asset_add_batch, name='asset_add_batch'),
url(r'^asset/list/$', asset_list, name='asset_list'),
url(r'^asset/del/$', asset_del, name='asset_del'),
url(r"^asset/detail/$", asset_detail, name='asset_detail'),
url(r'^asset/edit/$', asset_edit, name='asset_edit'),
url(r'^asset/edit_batch/$', asset_edit_batch, name='asset_edit_batch'),
url(r'^asset/update/$', asset_update, name='asset_update'),
url(r'^asset/update_batch/$', asset_update_batch, name='asset_update_batch'),
url(r'^asset/zabbix_update_batch/$', zabbix_update_batch, name='zabbix_update_batch'),
url(r'^asset/upload/$', asset_upload, name='asset_upload'),
url(r'^group/del/$', group_del, name='asset_group_del'),
url(r'^group/add/$', group_add, name='asset_group_add'),
url(r'^group/list/$', group_list, name='asset_group_list'),
url(r'^group/edit/$', group_edit, name='asset_group_edit'),
url(r'^idc/add/$', idc_add, name='idc_add'),
url(r'^idc/list/$', idc_list, name='idc_list'),
url(r'^idc/edit/$', idc_edit, name='idc_edit'),
url(r'^idc/del/$', idc_del, name='idc_del'),
)
jasset/views.py
asset_save.save()
af_post.save_m2m() - msg = u'主机 %s 添加成功' % hostname
+ #add host to zabbix
+ if IS_ZABBIX:
+ #全局开启
+ zbx_result = ZABBIX_API.create_host(hostname, ip, 5)
+ if zbx_result.get('result'):
+ #同步zabbix成功
+ zbx_hostid = zbx_result['result']['hostids'][0]
+ #更新asset数据库
+ Asset.objects.filter(hostname=hostname).update(zbx_hostid=zbx_hostid)
+ msg = u'主机 %s 添加成功,同步至zabbix成功,hostid: %s' %(hostname,zbx_hostid)
+ else:
+ #同步zabbix失败
+ zbx_error = zbx_result.get('error')['data']
+ msg = u'主机 %s 添加成功,同步至zabbix失败,失败原因:%s' %(hostname,zbx_error)
+ else:
+ msg = u'主机 %s 添加成功' % hostname
else:
esg = u'主机 %s 添加失败' % hostname @@ -180,16 +195,28 @@ def asset_del(request):
删除主机
"""
asset_id = request.GET.get('id', '')
+ zbx_hostid = request.GET.get('zbx_hostid', '') if asset_id:
Asset.objects.filter(id=asset_id).delete() + if zbx_hostid:
+ #同步删除zabbix
+ ZABBIX_API.delete_host(zbx_hostid) if request.method == 'POST':
asset_batch = request.GET.get('arg', '')
asset_id_all = str(request.POST.get('asset_id_all', '')) if asset_batch:
for asset_id in asset_id_all.split(','):
asset = get_object(Asset, id=asset_id)
+ #同步删除zabbix
+ batch_zbx_hostid = asset.zbx_hostid
+ ZABBIX_API.delete_host(batch_zbx_hostid)
asset.delete() return HttpResponse(u'删除成功')
@@ -204,6 +231,7 @@ def asset_edit(request):
header_title, path1, path2 = u'修改资产', u'资产管理', u'修改资产' asset_id = request.GET.get('id', '')
+ zbx_hostid = request.GET.get('zbx_hostid', '')
username = request.user.username
asset = get_object(Asset, id=asset_id)
if asset:
@@ -246,6 +274,11 @@ def asset_edit(request):
info = asset_diff(af_post.__dict__.get('initial'), request.POST)
db_asset_alert(asset, username, info) + if zbx_hostid:
+ #同步修改zabbix
+ zbx_result = ZABBIX_API.update_host(zbx_hostid, hostname)
+ #print zbx_result smg = u'主机 %s 修改成功' % ip
else:
emg = u'主机 %s 修改失败' % ip
@@ -491,6 +524,32 @@ def asset_update_batch(request):
return HttpResponse(u'批量更新成功!') +@require_role('admin')
+def zabbix_update_batch(request):
+ if request.method == 'POST':
+ arg = request.GET.get('arg', '')
+ name = unicode(request.user.username) + ' - ' + u'自动更新'
+ if arg == 'all':
+ asset_list = Asset.objects.all()
+ else:
+ asset_id_all = unicode(request.POST.get('asset_id_all', ''))
+ asset_id_all = asset_id_all.split(',')
+ for asset_id in asset_id_all:
+ asset = get_object(Asset, id=asset_id)
+ if not asset.zbx_hostid:
+ #同步zabbix
+ hostname = asset.hostname
+ ip = asset.ip
+ zbx_result = ZABBIX_API.create_host(hostname,ip,5)
+ if zbx_result.get('result'):
+ add_zbx_hostid = zbx_result['result']['hostids'][0]
+ asset.zbx_hostid = add_zbx_hostid
+ asset.save()
+ return HttpResponse(u'批量更新成功!')
+ return HttpResponse(u'批量更新成功!') @require_role('admin')
def idc_add(request):
"""
# coding:utf-8 from django.db.models import Q
from jasset.asset_api import *
from jumpserver.api import *
from jumpserver.models import Setting
from jasset.forms import AssetForm, IdcForm
from jasset.models import Asset, IDC, AssetGroup, ASSET_TYPE, ASSET_STATUS
from jperm.perm_api import get_group_asset_perm, get_group_user_perm @require_role('admin')
def group_add(request):
"""
Group add view
添加资产组
"""
header_title, path1, path2 = u'添加资产组', u'资产管理', u'添加资产组'
asset_all = Asset.objects.all() if request.method == 'POST':
name = request.POST.get('name', '')
asset_select = request.POST.getlist('asset_select', [])
comment = request.POST.get('comment', '') try:
if not name:
emg = u'组名不能为空'
raise ServerError(emg) asset_group_test = get_object(AssetGroup, name=name)
if asset_group_test:
emg = u"该组名 %s 已存在" % name
raise ServerError(emg) except ServerError:
pass else:
db_add_group(name=name, comment=comment, asset_select=asset_select)
smg = u"主机组 %s 添加成功" % name return my_render('jasset/group_add.html', locals(), request) @require_role('admin')
def group_edit(request):
"""
Group edit view
编辑资产组
"""
header_title, path1, path2 = u'编辑主机组', u'资产管理', u'编辑主机组'
group_id = request.GET.get('id', '')
group = get_object(AssetGroup, id=group_id) asset_all = Asset.objects.all()
asset_select = Asset.objects.filter(group=group)
asset_no_select = [a for a in asset_all if a not in asset_select] if request.method == 'POST':
name = request.POST.get('name', '')
asset_select = request.POST.getlist('asset_select', [])
comment = request.POST.get('comment', '') try:
if not name:
emg = u'组名不能为空'
raise ServerError(emg) if group.name != name:
asset_group_test = get_object(AssetGroup, name=name)
if asset_group_test:
emg = u"该组名 %s 已存在" % name
raise ServerError(emg) except ServerError:
pass else:
group.asset_set.clear()
db_update_group(id=group_id, name=name, comment=comment, asset_select=asset_select)
smg = u"主机组 %s 添加成功" % name return HttpResponseRedirect(reverse('asset_group_list')) return my_render('jasset/group_edit.html', locals(), request) @require_role('admin')
def group_list(request):
"""
list asset group
列出资产组
"""
header_title, path1, path2 = u'查看资产组', u'资产管理', u'查看资产组'
keyword = request.GET.get('keyword', '')
asset_group_list = AssetGroup.objects.all()
group_id = request.GET.get('id')
if group_id:
asset_group_list = asset_group_list.filter(id=group_id)
if keyword:
asset_group_list = asset_group_list.filter(Q(name__contains=keyword) | Q(comment__contains=keyword)) asset_group_list, p, asset_groups, page_range, current_page, show_first, show_end = pages(asset_group_list, request)
return my_render('jasset/group_list.html', locals(), request) @require_role('admin')
def group_del(request):
"""
Group delete view
删除主机组
"""
group_ids = request.GET.get('id', '')
group_id_list = group_ids.split(',') for group_id in group_id_list:
AssetGroup.objects.filter(id=group_id).delete() return HttpResponse(u'删除成功') @require_role('admin')
def asset_add(request):
"""
Asset add view
添加资产
"""
header_title, path1, path2 = u'添加资产', u'资产管理', u'添加资产'
asset_group_all = AssetGroup.objects.all()
af = AssetForm()
default_setting = get_object(Setting, name='default')
default_port = default_setting.field2 if default_setting else ''
if request.method == 'POST':
af_post = AssetForm(request.POST)
ip = request.POST.get('ip', '')
hostname = request.POST.get('hostname', '') is_active = True if request.POST.get('is_active') == '1' else False
use_default_auth = request.POST.get('use_default_auth', '')
try:
if Asset.objects.filter(hostname=unicode(hostname)):
error = u'该主机名 %s 已存在!' % hostname
raise ServerError(error)
if len(hostname) > 54:
error = u"主机名长度不能超过53位!"
raise ServerError(error)
except ServerError:
pass
else:
if af_post.is_valid():
asset_save = af_post.save(commit=False)
if not use_default_auth:
password = request.POST.get('password', '')
password_encode = CRYPTOR.encrypt(password)
asset_save.password = password_encode
if not ip:
asset_save.ip = hostname
asset_save.is_active = True if is_active else False
asset_save.save()
af_post.save_m2m() #add host to zabbix
if IS_ZABBIX:
#全局开启
zbx_result = ZABBIX_API.create_host(hostname, ip, 5)
if zbx_result.get('result'):
#同步zabbix成功
zbx_hostid = zbx_result['result']['hostids'][0]
#更新asset数据库
Asset.objects.filter(hostname=hostname).update(zbx_hostid=zbx_hostid)
msg = u'主机 %s 添加成功,同步至zabbix成功,hostid: %s' %(hostname,zbx_hostid)
else:
#同步zabbix失败
zbx_error = zbx_result.get('error')['data']
msg = u'主机 %s 添加成功,同步至zabbix失败,失败原因:%s' %(hostname,zbx_error)
else:
msg = u'主机 %s 添加成功' % hostname
else:
esg = u'主机 %s 添加失败' % hostname return my_render('jasset/asset_add.html', locals(), request) @require_role('admin')
def asset_add_batch(request):
header_title, path1, path2 = u'添加资产', u'资产管理', u'批量添加'
return my_render('jasset/asset_add_batch.html', locals(), request) @require_role('admin')
def asset_del(request):
"""
del a asset
删除主机
"""
asset_id = request.GET.get('id', '')
zbx_hostid = request.GET.get('zbx_hostid', '') if asset_id:
Asset.objects.filter(id=asset_id).delete() if zbx_hostid:
#同步删除zabbix
ZABBIX_API.delete_host(zbx_hostid) if request.method == 'POST':
asset_batch = request.GET.get('arg', '')
asset_id_all = str(request.POST.get('asset_id_all', '')) if asset_batch:
for asset_id in asset_id_all.split(','):
asset = get_object(Asset, id=asset_id)
#同步删除zabbix
batch_zbx_hostid = asset.zbx_hostid
ZABBIX_API.delete_host(batch_zbx_hostid)
asset.delete() return HttpResponse(u'删除成功') @require_role(role='super')
def asset_edit(request):
"""
edit a asset
修改主机
"""
header_title, path1, path2 = u'修改资产', u'资产管理', u'修改资产' asset_id = request.GET.get('id', '')
zbx_hostid = request.GET.get('zbx_hostid', '')
username = request.user.username
asset = get_object(Asset, id=asset_id)
if asset:
password_old = asset.password
# asset_old = copy_model_instance(asset)
af = AssetForm(instance=asset)
if request.method == 'POST':
af_post = AssetForm(request.POST, instance=asset)
ip = request.POST.get('ip', '')
hostname = request.POST.get('hostname', '')
password = request.POST.get('password', '')
is_active = True if request.POST.get('is_active') == '1' else False
use_default_auth = request.POST.get('use_default_auth', '')
try:
asset_test = get_object(Asset, hostname=hostname)
if asset_test and asset_id != unicode(asset_test.id):
emg = u'该主机名 %s 已存在!' % hostname
raise ServerError(emg)
if len(hostname) > 54:
emg = u'主机名长度不能超过54位!'
raise ServerError(emg)
else:
if af_post.is_valid():
af_save = af_post.save(commit=False)
if use_default_auth:
af_save.username = ''
af_save.password = ''
# af_save.port = None
else:
if password:
password_encode = CRYPTOR.encrypt(password)
af_save.password = password_encode
else:
af_save.password = password_old
af_save.is_active = True if is_active else False
af_save.save()
af_post.save_m2m()
# asset_new = get_object(Asset, id=asset_id)
# asset_diff_one(asset_old, asset_new)
info = asset_diff(af_post.__dict__.get('initial'), request.POST)
db_asset_alert(asset, username, info) if zbx_hostid:
#同步修改zabbix
zbx_result = ZABBIX_API.update_host(zbx_hostid, hostname)
#print zbx_result smg = u'主机 %s 修改成功' % ip
else:
emg = u'主机 %s 修改失败' % ip
raise ServerError(emg)
except ServerError as e:
error = e.message
return my_render('jasset/asset_edit.html', locals(), request)
return HttpResponseRedirect(reverse('asset_detail')+'?id=%s' % asset_id) return my_render('jasset/asset_edit.html', locals(), request) @require_role('user')
def asset_list(request):
"""
asset list view
"""
header_title, path1, path2 = u'查看资产', u'资产管理', u'查看资产'
username = request.user.username
user_perm = request.session['role_id']
idc_all = IDC.objects.filter()
asset_group_all = AssetGroup.objects.all()
asset_types = ASSET_TYPE
asset_status = ASSET_STATUS
idc_name = request.GET.get('idc', '')
group_name = request.GET.get('group', '')
asset_type = request.GET.get('asset_type', '')
status = request.GET.get('status', '')
keyword = request.GET.get('keyword', '')
export = request.GET.get("export", False)
group_id = request.GET.get("group_id", '')
idc_id = request.GET.get("idc_id", '')
asset_id_all = request.GET.getlist("id", '') if group_id:
group = get_object(AssetGroup, id=group_id)
if group:
asset_find = Asset.objects.filter(group=group)
elif idc_id:
idc = get_object(IDC, id=idc_id)
if idc:
asset_find = Asset.objects.filter(idc=idc)
else:
if user_perm != 0:
asset_find = Asset.objects.all()
else:
asset_id_all = []
user = get_object(User, username=username)
asset_perm = get_group_user_perm(user) if user else {'asset': ''}
user_asset_perm = asset_perm['asset'].keys()
for asset in user_asset_perm:
asset_id_all.append(asset.id)
asset_find = Asset.objects.filter(pk__in=asset_id_all)
asset_group_all = list(asset_perm['asset_group']) if idc_name:
asset_find = asset_find.filter(idc__name__contains=idc_name) if group_name:
asset_find = asset_find.filter(group__name__contains=group_name) if asset_type:
asset_find = asset_find.filter(asset_type__contains=asset_type) if status:
asset_find = asset_find.filter(status__contains=status) if keyword:
asset_find = asset_find.filter(
Q(hostname__contains=keyword) |
Q(other_ip__contains=keyword) |
Q(ip__contains=keyword) |
Q(remote_ip__contains=keyword) |
Q(comment__contains=keyword) |
Q(username__contains=keyword) |
Q(group__name__contains=keyword) |
Q(cpu__contains=keyword) |
Q(memory__contains=keyword) |
Q(disk__contains=keyword) |
Q(brand__contains=keyword) |
Q(cabinet__contains=keyword) |
Q(sn__contains=keyword) |
Q(system_type__contains=keyword) |
Q(system_version__contains=keyword)) if export:
if asset_id_all:
asset_find = []
for asset_id in asset_id_all:
asset = get_object(Asset, id=asset_id)
if asset:
asset_find.append(asset)
s = write_excel(asset_find)
if s[0]:
file_name = s[1]
smg = u'excel文件已生成,请点击下载!'
return my_render('jasset/asset_excel_download.html', locals(), request)
assets_list, p, assets, page_range, current_page, show_first, show_end = pages(asset_find, request)
if user_perm != 0:
return my_render('jasset/asset_list.html', locals(), request)
else:
return my_render('jasset/asset_cu_list.html', locals(), request) @require_role('admin')
def asset_edit_batch(request):
af = AssetForm()
name = request.user.username
asset_group_all = AssetGroup.objects.all() if request.method == 'POST':
env = request.POST.get('env', '')
idc_id = request.POST.get('idc', '')
port = request.POST.get('port', '')
use_default_auth = request.POST.get('use_default_auth', '')
username = request.POST.get('username', '')
password = request.POST.get('password', '')
group = request.POST.getlist('group', [])
cabinet = request.POST.get('cabinet', '')
comment = request.POST.get('comment', '')
asset_id_all = unicode(request.GET.get('asset_id_all', ''))
asset_id_all = asset_id_all.split(',')
for asset_id in asset_id_all:
alert_list = []
asset = get_object(Asset, id=asset_id)
if asset:
if env:
if asset.env != env:
asset.env = env
alert_list.append([u'运行环境', asset.env, env])
if idc_id:
idc = get_object(IDC, id=idc_id)
name_old = asset.idc.name if asset.idc else u''
if idc and idc.name != name_old:
asset.idc = idc
alert_list.append([u'机房', name_old, idc.name])
if port:
if unicode(asset.port) != port:
asset.port = port
alert_list.append([u'端口号', asset.port, port]) if use_default_auth:
if use_default_auth == 'default':
asset.use_default_auth = 1
asset.username = ''
asset.password = ''
alert_list.append([u'使用默认管理账号', asset.use_default_auth, u'默认'])
elif use_default_auth == 'user_passwd':
asset.use_default_auth = 0
asset.username = username
password_encode = CRYPTOR.encrypt(password)
asset.password = password_encode
alert_list.append([u'使用默认管理账号', asset.use_default_auth, username])
if group:
group_new, group_old, group_new_name, group_old_name = [], asset.group.all(), [], []
for group_id in group:
g = get_object(AssetGroup, id=group_id)
if g:
group_new.append(g)
if not set(group_new) < set(group_old):
group_instance = list(set(group_new) | set(group_old))
for g in group_instance:
group_new_name.append(g.name)
for g in group_old:
group_old_name.append(g.name)
asset.group = group_instance
alert_list.append([u'主机组', ','.join(group_old_name), ','.join(group_new_name)])
if cabinet:
if asset.cabinet != cabinet:
asset.cabinet = cabinet
alert_list.append([u'机柜号', asset.cabinet, cabinet])
if comment:
if asset.comment != comment:
asset.comment = comment
alert_list.append([u'备注', asset.comment, comment])
asset.save() if alert_list:
recode_name = unicode(name) + ' - ' + u'批量'
AssetRecord.objects.create(asset=asset, username=recode_name, content=alert_list)
return my_render('jasset/asset_update_status.html', locals(), request) return my_render('jasset/asset_edit_batch.html', locals(), request) @require_role('admin')
def asset_detail(request):
"""
Asset detail view
"""
header_title, path1, path2 = u'主机详细信息', u'资产管理', u'主机详情'
asset_id = request.GET.get('id', '')
asset = get_object(Asset, id=asset_id)
perm_info = get_group_asset_perm(asset)
log = Log.objects.filter(host=asset.hostname)
if perm_info:
user_perm = []
for perm, value in perm_info.items():
if perm == 'user':
for user, role_dic in value.items():
user_perm.append([user, role_dic.get('role', '')])
elif perm == 'user_group' or perm == 'rule':
user_group_perm = value
print perm_info asset_record = AssetRecord.objects.filter(asset=asset).order_by('-alert_time') return my_render('jasset/asset_detail.html', locals(), request) @require_role('admin')
def asset_update(request):
"""
Asset update host info via ansible view
"""
asset_id = request.GET.get('id', '')
asset = get_object(Asset, id=asset_id)
name = request.user.username
if not asset:
return HttpResponseRedirect(reverse('asset_detail')+'?id=%s' % asset_id)
else:
asset_ansible_update([asset], name)
return HttpResponseRedirect(reverse('asset_detail')+'?id=%s' % asset_id) @require_role('admin')
def asset_update_batch(request):
if request.method == 'POST':
arg = request.GET.get('arg', '')
name = unicode(request.user.username) + ' - ' + u'自动更新'
if arg == 'all':
asset_list = Asset.objects.all()
else:
asset_list = []
asset_id_all = unicode(request.POST.get('asset_id_all', ''))
asset_id_all = asset_id_all.split(',')
for asset_id in asset_id_all:
asset = get_object(Asset, id=asset_id)
if asset:
asset_list.append(asset)
asset_ansible_update(asset_list, name)
return HttpResponse(u'批量更新成功!')
return HttpResponse(u'批量更新成功!') @require_role('admin')
def zabbix_update_batch(request):
if request.method == 'POST':
arg = request.GET.get('arg', '')
name = unicode(request.user.username) + ' - ' + u'自动更新'
if arg == 'all':
asset_list = Asset.objects.all()
else:
asset_id_all = unicode(request.POST.get('asset_id_all', ''))
asset_id_all = asset_id_all.split(',')
for asset_id in asset_id_all:
asset = get_object(Asset, id=asset_id)
if not asset.zbx_hostid:
#同步zabbix
hostname = asset.hostname
ip = asset.ip
zbx_result = ZABBIX_API.create_host(hostname,ip,5)
if zbx_result.get('result'):
add_zbx_hostid = zbx_result['result']['hostids'][0]
asset.zbx_hostid = add_zbx_hostid
asset.save()
return HttpResponse(u'批量更新成功!')
return HttpResponse(u'批量更新成功!') @require_role('admin')
def idc_add(request):
"""
IDC add view
"""
header_title, path1, path2 = u'添加IDC', u'资产管理', u'添加IDC'
if request.method == 'POST':
idc_form = IdcForm(request.POST)
if idc_form.is_valid():
idc_name = idc_form.cleaned_data['name'] if IDC.objects.filter(name=idc_name):
emg = u'添加失败, 此IDC %s 已存在!' % idc_name
return my_render('jasset/idc_add.html', locals(), request)
else:
idc_form.save()
smg = u'IDC: %s添加成功' % idc_name
return HttpResponseRedirect(reverse('idc_list'))
else:
idc_form = IdcForm()
return my_render('jasset/idc_add.html', locals(), request) @require_role('admin')
def idc_list(request):
"""
IDC list view
"""
header_title, path1, path2 = u'查看IDC', u'资产管理', u'查看IDC'
posts = IDC.objects.all()
keyword = request.GET.get('keyword', '')
if keyword:
posts = IDC.objects.filter(Q(name__contains=keyword) | Q(comment__contains=keyword))
else:
posts = IDC.objects.exclude(name='ALL').order_by('id')
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
return my_render('jasset/idc_list.html', locals(), request) @require_role('admin')
def idc_edit(request):
"""
IDC edit view
"""
header_title, path1, path2 = u'编辑IDC', u'资产管理', u'编辑IDC'
idc_id = request.GET.get('id', '')
idc = get_object(IDC, id=idc_id)
if request.method == 'POST':
idc_form = IdcForm(request.POST, instance=idc)
if idc_form.is_valid():
idc_form.save()
return HttpResponseRedirect(reverse('idc_list'))
else:
idc_form = IdcForm(instance=idc)
return my_render('jasset/idc_edit.html', locals(), request) @require_role('admin')
def idc_del(request):
"""
IDC delete view
"""
idc_ids = request.GET.get('id', '')
idc_id_list = idc_ids.split(',') for idc_id in idc_id_list:
IDC.objects.filter(id=idc_id).delete() return HttpResponseRedirect(reverse('idc_list')) @require_role('admin')
def asset_upload(request):
"""
Upload asset excel file view
"""
if request.method == 'POST':
excel_file = request.FILES.get('file_name', '')
ret = excel_to_db(excel_file)
if ret:
smg = u'批量添加成功'
else:
emg = u'批量添加失败,请检查格式.'
return my_render('jasset/asset_add_batch.html', locals(), request)
jumpserver.conf
key = 941enj9neshd1wes
ip = 0.0.0.0
port = 8000
-log = debug
+log = DEBUG [db]
engine = mysql
host = 127.0.0.1
port = 3306
-user = jumpserver
-password = mysql234
+user = root
+password = xxx
database = jumpserver [mail]
@@ -24,3 +24,9 @@ email_use_ssl = False [connect]
nav_sort_by = ip +[zbx]
+is_zbx = True
+zbx_url = http://127.0.0.1:8888/zabbix/api_jsonrpc.php
+zbx_user = Admin
+zbx_pwd = zabbix
[base]
url = http://127.0.0.1
key = 941enj9neshd1wes
ip = 0.0.0.0
port = 8000
log = DEBUG [db]
engine = mysql
host = 127.0.0.1
port = 3306
user = root
password = xxx
database = jumpserver [mail]
mail_enable = 1
email_host =
email_port = 587
email_host_user =
email_host_password =
email_use_tls = False
email_use_ssl = False [connect]
nav_sort_by = ip [zbx]
is_zbx = True
zbx_url = http://127.0.0.1:8888/zabbix/api_jsonrpc.php
zbx_user = Admin
zbx_pwd = zabbix
jumpserver/api.py
import uuid
import json
import logging
+import urllib2 from settings import *
from django.core.paginator import Paginator, EmptyPage, InvalidPage
@@ -506,5 +507,333 @@ def get_mac_address():
return mac +class zbx_api(object):
+
+ def __init__(self, url, username, password):
+ self.url = url
+ self.username = username
+ self.password = password
+
+ def requestJson(self, url, values):
+ '''
+ 请求方法,错误返回dict:{"request_error" : "some errors."}
+ '''
+ data = json.dumps(values)
+ try:
+ req = urllib2.Request(url, data, {'Content-Type' : 'application/json-rpc'})
+ response = urllib2.urlopen(req, data=None, timeout=5)
+ data_get = response.read()
+ out_put = json.loads(data_get)
+ return out_put
+ except Exception as e:
+ '''
+ 请求接口出错
+ '''
+ return {"request_error" : "request zabbix api error: %s" %e}
+
+ def __get_token(self):
+ '''
+ 返回结果
+ {
+ "jsonrpc": "2.0",
+ "result": "0424bd59b807674191e7d77572075f33",
+ "id": 1
+ }
+
+ 错误返回
+ {
+ "request_error" : "some errors."
+ }
+ '''
+ values = {
+ "jsonrpc" : "2.0",
+ "method" : "user.login",
+ "params" : {
+ "user" : self.username,
+ "password" : self.password
+ },
+ "id" : 1
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue
+
+
+ def create_host(self, hostname, ip, groupid):
+ '''
+ 创建成功
+ {
+ "jsonrpc": "2.0",
+ "result": {
+ "hostids": [
+ "107819"
+ ]
+ },
+ "id": 1
+ }
+
+ 创建失败
+ {
+ "jsonrpc": "2.0",
+ "error": {
+ "code": -32602,
+ "message": "Invalid params.",
+ "data": "Host with the same name \"test\" already exists."
+ },
+ "id": 1
+ }
+ '''
+ token = self.__get_token()
+ if not token.get("request_error"):
+ values = {
+ "jsonrpc": "2.0",
+ "method": "host.create",
+ "params": {
+ "host": hostname,
+ "interfaces": [
+ {
+ "type": 1,
+ "main": 1,
+ "useip": 1,
+ "ip": ip,
+ "dns": "",
+ "port": "10050"
+ }
+ ],
+ "groups": [
+ {
+ "groupid": groupid
+ }
+ ],
+ },
+ "auth": token["result"],
+ "id": 5
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue
+
+ def delete_host(self, *hostids):
+ '''
+ 成功
+ {
+ "jsonrpc": "2.0",
+ "result": {
+ "hostids": [
+ "13",
+ "32"
+ ]
+ },
+ "id": 1
+ }
+
+ 失败
+ {
+ "jsonrpc": "2.0",
+ "error": {
+ "code": -32500,
+ "message": "Application error.",
+ "data": "No permissions to referred object or it does not exist!"
+ },
+ "id": 1
+ }
+ '''
+ token = self.__get_token()
+ if not token.get("request_error"):
+ '''
+ 获取token成功
+ '''
+ values = {
+ "jsonrpc" : "2.0",
+ "method" : "host.delete",
+ "params" : list(hostids),
+ "auth" : token["result"],
+ "id" : 7
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue
+
+
+ def update_host(self, hostid, hostname):
+ '''
+ 修改zabbix name
+
+ 成功
+ {
+ "jsonrpc": "2.0",
+ "result": {
+ "hostids": [
+ "10151"
+ ]
+ },
+ "id": 1
+ }
+
+ 失败
+ {
+ "jsonrpc": "2.0",
+ "error": {
+ "code": -32602,
+ "message": "Invalid params.",
+ "data": "No permissions to referred object or it does not exist!"
+ },
+ "id": 1
+ }
+ '''
+
+ token = self.__get_token()
+ if not token.get("request_error"):
+ '''
+ 获取token成功
+ '''
+ values = {
+ "jsonrpc" : "2.0",
+ "method" : "host.update",
+ "params" : {
+ "hostid" : hostid,
+ "host" : hostname
+ },
+ "auth" : token["result"],
+ "id" : 8
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue
+
+ def create_hostgroup(self, hostgroup_name):
+ '''
+ 创建成功
+ {
+ "jsonrpc": "2.0",
+ "result": {
+ "groupids": [
+ "107819"
+ ]
+ },
+ "id": 1
+ }
+
+
+ 创建失败
+ {
+ "jsonrpc": "2.0",
+ "error": {
+ "code" : -32602,
+ "message" : "Invalid params.",
+ "data" : "Host group \"Linux servers\" already exists."
+ },
+ "id": 1
+ }
+
+ '''
+ token = self.__get_token()
+ if not token.get("request_error"):
+ '''
+ 获取token成功
+ '''
+ values = {
+ "jsonrpc" : "2.0",
+ "method" : "hostgroup.create",
+ "params" : {
+ "name" : hostgroup_name
+ },
+ "auth" : token["result"],
+ "id" : 2
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue
+ #else:
+ # print "get token error: %s" %token.get("request_error")
+
+
+ def delete_hostgroup(self, *args):
+
+ '''
+ 请求成功
+ {
+ "jsonrpc": "2.0",
+ "result": {
+ "groupids": [
+ "107824",
+ "107825"
+ ]
+ },
+ "id": 1
+ }
+
+ 请求失败
+ {
+ "jsonrpc": "2.0",
+ "error": {
+ "code": -32500,
+ "message": "Application error.",
+ "data": "No permissions to referred object or it does not exist!"
+ },
+ "id": 1
+ }
+ '''
+
+
+ token = self.__get_token()
+ if not token.get("request_error"):
+ values = {
+ "jsonrpc" : "2.0",
+ "method" : "hostgroup.delete",
+ "params" : list(args),
+ "auth" : token["result"],
+ "id" : 3
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue
+
+
+
+
+ def hostgroup_get(self, *args):
+ '''
+ 结果不为空:
+ {
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "groupid": "2",
+ "name": "Linux servers",
+ "internal": "0"
+ },
+ {
+ "groupid": "4",
+ "name": "Zabbix servers",
+ "internal": "0"
+ }
+ ],
+ "id": 1
+ }
+
+ 结果为空:
+ {
+ "jsonrpc": "2.0",
+ "result": [],
+ "id": 1
+ }
+ '''
+
+ token = self.__get_token()
+ if not token.get("request_error"):
+ values = {
+ "jsonrpc" : "2.0",
+ "method" : "hostgroup.get",
+ "params" : {
+ "output" : "extend",
+ "filter" : {
+ "name" : list(*args)
+ }
+ },
+ "auth" : token["result"],
+ "id" : 4
+ }
+ idvalue = self.requestJson(self.url, values)
+ return idvalue CRYPTOR = PyCrypt(KEY)
logger = set_log(LOG_LEVEL) +ZABBIX_API = zbx_api(ZBX_URL, ZBX_USER, ZBX_PWD)
# coding: utf-8 import os, sys, time, re
from Crypto.Cipher import AES
import crypt
import pwd
from binascii import b2a_hex, a2b_hex
import hashlib
import datetime
import random
import subprocess
import uuid
import json
import logging
import urllib2 from settings import *
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.http import HttpResponse, Http404
from django.template import RequestContext
from juser.models import User, UserGroup
from jlog.models import Log, TtyLog
from jasset.models import Asset, AssetGroup
from jperm.models import PermRule, PermRole
from jumpserver.models import Setting
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.core.mail import send_mail
from django.core.urlresolvers import reverse def set_log(level, filename='jumpserver.log'):
"""
return a log file object
根据提示设置log打印
"""
log_file = os.path.join(LOG_DIR, filename)
if not os.path.isfile(log_file):
os.mknod(log_file)
os.chmod(log_file, 0777)
log_level_total = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARN, 'error': logging.ERROR,
'critical': logging.CRITICAL}
logger_f = logging.getLogger('jumpserver')
logger_f.setLevel(logging.DEBUG)
fh = logging.FileHandler(log_file)
fh.setLevel(log_level_total.get(level, logging.DEBUG))
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger_f.addHandler(fh)
return logger_f def list_drop_str(a_list, a_str):
for i in a_list:
if i == a_str:
a_list.remove(a_str)
return a_list def get_asset_info(asset):
"""
获取资产的相关管理账号端口等信息
"""
default = get_object(Setting, name='default')
info = {'hostname': asset.hostname, 'ip': asset.ip}
if asset.use_default_auth:
if default:
info['username'] = default.field1
try:
info['password'] = CRYPTOR.decrypt(default.field3)
except ServerError:
pass
if os.path.isfile(default.field4):
info['ssh_key'] = default.field4
else:
info['username'] = asset.username
info['password'] = CRYPTOR.decrypt(asset.password)
try:
info['port'] = int(asset.port)
except TypeError:
info['port'] = int(default.field2) return info def get_role_key(user, role):
"""
由于role的key的权限是所有人可以读的, ansible执行命令等要求为600,所以拷贝一份到特殊目录
:param user:
:param role:
:return: self key path
"""
user_role_key_dir = os.path.join(KEY_DIR, 'user')
user_role_key_path = os.path.join(user_role_key_dir, '%s_%s.pem' % (user.username, role.name))
mkdir(user_role_key_dir, mode=777)
if not os.path.isfile(user_role_key_path):
with open(os.path.join(role.key_path, 'id_rsa')) as fk:
with open(user_role_key_path, 'w') as fu:
fu.write(fk.read())
logger.debug(u"创建新的系统用户key %s, Owner: %s" % (user_role_key_path, user.username))
chown(user_role_key_path, user.username)
os.chmod(user_role_key_path, 0600)
return user_role_key_path def chown(path, user, group=''):
if not group:
group = user
try:
uid = pwd.getpwnam(user).pw_uid
gid = pwd.getpwnam(group).pw_gid
os.chown(path, uid, gid)
except KeyError:
pass def page_list_return(total, current=1):
"""
page
分页,返回本次分页的最小页数到最大页数列表
"""
min_page = current - 2 if current - 4 > 0 else 1
max_page = min_page + 4 if min_page + 4 < total else total return range(min_page, max_page + 1) def pages(post_objects, request):
"""
page public function , return page's object tuple
分页公用函数,返回分页的对象元组
"""
paginator = Paginator(post_objects, 20)
try:
current_page = int(request.GET.get('page', '1'))
except ValueError:
current_page = 1 page_range = page_list_return(len(paginator.page_range), current_page) try:
page_objects = paginator.page(current_page)
except (EmptyPage, InvalidPage):
page_objects = paginator.page(paginator.num_pages) if current_page >= 5:
show_first = 1
else:
show_first = 0 if current_page <= (len(paginator.page_range) - 3):
show_end = 1
else:
show_end = 0 # 所有对象, 分页器, 本页对象, 所有页码, 本页页码,是否显示第一页,是否显示最后一页
return post_objects, paginator, page_objects, page_range, current_page, show_first, show_end class PyCrypt(object):
"""
This class used to encrypt and decrypt password.
加密类
""" def __init__(self, key):
self.key = key
self.mode = AES.MODE_CBC @staticmethod
def gen_rand_pass(length=16, especial=False):
"""
random password
随机生成密码
"""
salt_key = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
symbol = '!@$%^&*()_'
salt_list = []
if especial:
for i in range(length - 4):
salt_list.append(random.choice(salt_key))
for i in range(4):
salt_list.append(random.choice(symbol))
else:
for i in range(length):
salt_list.append(random.choice(salt_key))
salt = ''.join(salt_list)
return salt @staticmethod
def md5_crypt(string):
"""
md5 encrypt method
md5非对称加密方法
"""
return hashlib.new("md5", string).hexdigest() @staticmethod
def gen_sha512(salt, password):
"""
generate sha512 format password
生成sha512加密密码
"""
return crypt.crypt(password, '$6$%s$' % salt) def encrypt(self, passwd=None, length=32):
"""
encrypt gen password
对称加密之加密生成密码
"""
if not passwd:
passwd = self.gen_rand_pass() cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1')
try:
count = len(passwd)
except TypeError:
raise ServerError('Encrypt password error, TYpe error.') add = (length - (count % length))
passwd += ('\0' * add)
cipher_text = cryptor.encrypt(passwd)
return b2a_hex(cipher_text) def decrypt(self, text):
"""
decrypt pass base the same key
对称加密之解密,同一个加密随机数
"""
cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1')
try:
plain_text = cryptor.decrypt(a2b_hex(text))
except TypeError:
raise ServerError('Decrypt password error, TYpe error.')
return plain_text.rstrip('\0') class ServerError(Exception):
"""
self define exception
自定义异常
"""
pass def get_object(model, **kwargs):
"""
use this function for query
使用改封装函数查询数据库
"""
for value in kwargs.values():
if not value:
return None the_object = model.objects.filter(**kwargs)
if len(the_object) == 1:
the_object = the_object[0]
else:
the_object = None
return the_object def require_role(role='user'):
"""
decorator for require user role in ["super", "admin", "user"]
要求用户是某种角色 ["super", "admin", "user"]的装饰器
""" def _deco(func):
def __deco(request, *args, **kwargs):
request.session['pre_url'] = request.path
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login'))
if role == 'admin':
# if request.session.get('role_id', 0) < 1:
if request.user.role == 'CU':
return HttpResponseRedirect(reverse('index'))
elif role == 'super':
# if request.session.get('role_id', 0) < 2:
if request.user.role in ['CU', 'GA']:
return HttpResponseRedirect(reverse('index'))
return func(request, *args, **kwargs) return __deco return _deco def is_role_request(request, role='user'):
"""
require this request of user is right
要求请求角色正确
"""
role_all = {'user': 'CU', 'admin': 'GA', 'super': 'SU'}
if request.user.role == role_all.get(role, 'CU'):
return True
else:
return False def get_session_user_dept(request):
"""
get department of the user in session
获取session中用户的部门
"""
# user_id = request.session.get('user_id', 0)
# print '#' * 20
# print user_id
# user = User.objects.filter(id=user_id)
# if user:
# user = user[0]
# return user, None
return request.user, None @require_role
def get_session_user_info(request):
"""
get the user info of the user in session, for example id, username etc.
获取用户的信息
"""
# user_id = request.session.get('user_id', 0)
# user = get_object(User, id=user_id)
# if user:
# return [user.id, user.username, user]
return [request.user.id, request.user.username, request.user] def get_user_dept(request):
"""
get the user dept id
获取用户的部门id
"""
user_id = request.user.id
if user_id:
user_dept = User.objects.get(id=user_id).dept
return user_dept.id def api_user(request):
hosts = Log.objects.filter(is_finished=0).count()
users = Log.objects.filter(is_finished=0).values('user').distinct().count()
ret = {'users': users, 'hosts': hosts}
json_data = json.dumps(ret)
return HttpResponse(json_data) def view_splitter(request, su=None, adm=None):
"""
for different user use different view
视图分页器
"""
if is_role_request(request, 'super'):
return su(request)
elif is_role_request(request, 'admin'):
return adm(request)
else:
return HttpResponseRedirect(reverse('login')) def validate(request, user_group=None, user=None, asset_group=None, asset=None, edept=None):
"""
validate the user request
判定用户请求是否合法
"""
dept = get_session_user_dept(request)[1]
if edept:
if dept.id != int(edept[0]):
return False if user_group:
dept_user_groups = dept.usergroup_set.all()
user_group_ids = []
for group in dept_user_groups:
user_group_ids.append(str(group.id)) if not set(user_group).issubset(set(user_group_ids)):
return False if user:
dept_users = dept.user_set.all()
user_ids = []
for dept_user in dept_users:
user_ids.append(str(dept_user.id)) if not set(user).issubset(set(user_ids)):
return False if asset_group:
dept_asset_groups = dept.bisgroup_set.all()
asset_group_ids = []
for group in dept_asset_groups:
asset_group_ids.append(str(group.id)) if not set(asset_group).issubset(set(asset_group_ids)):
return False if asset:
dept_assets = dept.asset_set.all()
asset_ids = []
for dept_asset in dept_assets:
asset_ids.append(str(dept_asset.id)) if not set(asset).issubset(set(asset_ids)):
return False return True def verify(request, user_group=None, user=None, asset_group=None, asset=None, edept=None):
dept = get_session_user_dept(request)[1]
if edept:
if dept.id != int(edept[0]):
return False if user_group:
dept_user_groups = dept.usergroup_set.all()
user_groups = []
for user_group_id in user_group:
user_groups.extend(UserGroup.objects.filter(id=user_group_id))
if not set(user_groups).issubset(set(dept_user_groups)):
return False if user:
dept_users = dept.user_set.all()
users = []
for user_id in user:
users.extend(User.objects.filter(id=user_id)) if not set(users).issubset(set(dept_users)):
return False if asset_group:
dept_asset_groups = dept.bisgroup_set.all()
asset_group_ids = []
for group in dept_asset_groups:
asset_group_ids.append(str(group.id)) if not set(asset_group).issubset(set(asset_group_ids)):
return False if asset:
dept_assets = dept.asset_set.all()
asset_ids = []
for a in dept_assets:
asset_ids.append(str(a.id))
print asset, asset_ids
if not set(asset).issubset(set(asset_ids)):
return False return True def bash(cmd):
"""
run a bash shell command
执行bash命令
"""
return subprocess.call(cmd, shell=True) def mkdir(dir_name, username='', mode=755):
"""
insure the dir exist and mode ok
目录存在,如果不存在就建立,并且权限正确
"""
cmd = '[ ! -d %s ] && mkdir -p %s && chmod %s %s' % (dir_name, dir_name, mode, dir_name)
bash(cmd)
if username:
chown(dir_name, username) def http_success(request, msg):
return render_to_response('success.html', locals()) def http_error(request, emg):
message = emg
return render_to_response('error.html', locals()) def my_render(template, data, request):
return render_to_response(template, data, context_instance=RequestContext(request)) def get_tmp_dir():
seed = uuid.uuid4().hex[:4]
dir_name = os.path.join('/tmp', '%s-%s' % (datetime.datetime.now().strftime('%Y%m%d-%H%M%S'), seed))
mkdir(dir_name, mode=777)
return dir_name def defend_attack(func):
def _deco(request, *args, **kwargs):
if int(request.session.get('visit', 1)) > 10:
logger.debug('请求次数: %s' % request.session.get('visit', 1))
return HttpResponse('Forbidden', status=403)
request.session['visit'] = request.session.get('visit', 1) + 1
request.session.set_expiry(300)
return func(request, *args, **kwargs)
return _deco def get_mac_address():
node = uuid.getnode()
mac = uuid.UUID(int=node).hex[-12:]
return mac class zbx_api(object): def __init__(self, url, username, password):
self.url = url
self.username = username
self.password = password def requestJson(self, url, values):
'''
请求方法,错误返回dict:{"request_error" : "some errors."}
'''
data = json.dumps(values)
try:
req = urllib2.Request(url, data, {'Content-Type' : 'application/json-rpc'})
response = urllib2.urlopen(req, data=None, timeout=5)
data_get = response.read()
out_put = json.loads(data_get)
return out_put
except Exception as e:
'''
请求接口出错
'''
return {"request_error" : "request zabbix api error: %s" %e} def __get_token(self):
'''
返回结果
{
"jsonrpc": "2.0",
"result": "0424bd59b807674191e7d77572075f33",
"id": 1
}
错误返回
{
"request_error" : "some errors."
}
'''
values = {
"jsonrpc" : "2.0",
"method" : "user.login",
"params" : {
"user" : self.username,
"password" : self.password
},
"id" : 1
}
idvalue = self.requestJson(self.url, values)
return idvalue def create_host(self, hostname, ip, groupid):
'''
创建成功
{
"jsonrpc": "2.0",
"result": {
"hostids": [
"107819"
]
},
"id": 1
}
创建失败
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params.",
"data": "Host with the same name \"test\" already exists."
},
"id": 1
}
'''
token = self.__get_token()
if not token.get("request_error"):
values = {
"jsonrpc": "2.0",
"method": "host.create",
"params": {
"host": hostname,
"interfaces": [
{
"type": 1,
"main": 1,
"useip": 1,
"ip": ip,
"dns": "",
"port": "10050"
}
],
"groups": [
{
"groupid": groupid
}
],
},
"auth": token["result"],
"id": 5
}
idvalue = self.requestJson(self.url, values)
return idvalue def delete_host(self, *hostids):
'''
成功
{
"jsonrpc": "2.0",
"result": {
"hostids": [
"13",
"32"
]
},
"id": 1
}
失败
{
"jsonrpc": "2.0",
"error": {
"code": -32500,
"message": "Application error.",
"data": "No permissions to referred object or it does not exist!"
},
"id": 1
}
'''
token = self.__get_token()
if not token.get("request_error"):
'''
获取token成功
'''
values = {
"jsonrpc" : "2.0",
"method" : "host.delete",
"params" : list(hostids),
"auth" : token["result"],
"id" : 7
}
idvalue = self.requestJson(self.url, values)
return idvalue def update_host(self, hostid, hostname):
'''
修改zabbix name
成功
{
"jsonrpc": "2.0",
"result": {
"hostids": [
"10151"
]
},
"id": 1
}
失败
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params.",
"data": "No permissions to referred object or it does not exist!"
},
"id": 1
}
''' token = self.__get_token()
if not token.get("request_error"):
'''
获取token成功
'''
values = {
"jsonrpc" : "2.0",
"method" : "host.update",
"params" : {
"hostid" : hostid,
"host" : hostname
},
"auth" : token["result"],
"id" : 8
}
idvalue = self.requestJson(self.url, values)
return idvalue def create_hostgroup(self, hostgroup_name):
'''
创建成功
{
"jsonrpc": "2.0",
"result": {
"groupids": [
"107819"
]
},
"id": 1
}
创建失败
{
"jsonrpc": "2.0",
"error": {
"code" : -32602,
"message" : "Invalid params.",
"data" : "Host group \"Linux servers\" already exists."
},
"id": 1
}
'''
token = self.__get_token()
if not token.get("request_error"):
'''
获取token成功
'''
values = {
"jsonrpc" : "2.0",
"method" : "hostgroup.create",
"params" : {
"name" : hostgroup_name
},
"auth" : token["result"],
"id" : 2
}
idvalue = self.requestJson(self.url, values)
return idvalue
#else:
# print "get token error: %s" %token.get("request_error") def delete_hostgroup(self, *args): '''
请求成功
{
"jsonrpc": "2.0",
"result": {
"groupids": [
"107824",
"107825"
]
},
"id": 1
}
请求失败
{
"jsonrpc": "2.0",
"error": {
"code": -32500,
"message": "Application error.",
"data": "No permissions to referred object or it does not exist!"
},
"id": 1
}
''' token = self.__get_token()
if not token.get("request_error"):
values = {
"jsonrpc" : "2.0",
"method" : "hostgroup.delete",
"params" : list(args),
"auth" : token["result"],
"id" : 3
}
idvalue = self.requestJson(self.url, values)
return idvalue def hostgroup_get(self, *args):
'''
结果不为空:
{
"jsonrpc": "2.0",
"result": [
{
"groupid": "2",
"name": "Linux servers",
"internal": "0"
},
{
"groupid": "4",
"name": "Zabbix servers",
"internal": "0"
}
],
"id": 1
}
结果为空:
{
"jsonrpc": "2.0",
"result": [],
"id": 1
}
''' token = self.__get_token()
if not token.get("request_error"):
values = {
"jsonrpc" : "2.0",
"method" : "hostgroup.get",
"params" : {
"output" : "extend",
"filter" : {
"name" : list(*args)
}
},
"auth" : token["result"],
"id" : 4
}
idvalue = self.requestJson(self.url, values)
return idvalue CRYPTOR = PyCrypt(KEY)
logger = set_log(LOG_LEVEL) ZABBIX_API = zbx_api(ZBX_URL, ZBX_USER, ZBX_PWD)
jumpserver/settings.py
EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend' if EMAIL_USE_SSL else 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_TIMEOUT = 5 +# ======== zabbix ========
+IS_ZABBIX = config.get("zbx", "is_zbx")
+ZBX_URL = config.get("zbx", "zbx_url")
+ZBX_USER = config.get("zbx", "zbx_user")
+ZBX_PWD = config.get("zbx", "zbx_pwd")
+
# ======== Log ==========
LOG_DIR = os.path.join(BASE_DIR, 'logs')
SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys/role_keys')
"""
Django settings for jumpserver project.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
""" # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import ConfigParser
import getpass config = ConfigParser.ConfigParser() BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
config.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
KEY_DIR = os.path.join(BASE_DIR, 'keys') AUTH_USER_MODEL = 'juser.User'
# mail config
MAIL_ENABLE = config.get('mail', 'mail_enable')
EMAIL_HOST = config.get('mail', 'email_host')
EMAIL_PORT = config.get('mail', 'email_port')
EMAIL_HOST_USER = config.get('mail', 'email_host_user')
EMAIL_HOST_PASSWORD = config.get('mail', 'email_host_password')
EMAIL_USE_TLS = config.getboolean('mail', 'email_use_tls')
try:
EMAIL_USE_SSL = config.getboolean('mail', 'email_use_ssl')
except ConfigParser.NoOptionError:
EMAIL_USE_SSL = False
EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend' if EMAIL_USE_SSL else 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_TIMEOUT = 5 # ======== zabbix ========
IS_ZABBIX = config.get("zbx", "is_zbx")
ZBX_URL = config.get("zbx", "zbx_url")
ZBX_USER = config.get("zbx", "zbx_user")
ZBX_PWD = config.get("zbx", "zbx_pwd") # ======== Log ==========
LOG_DIR = os.path.join(BASE_DIR, 'logs')
SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys/role_keys')
KEY = config.get('base', 'key')
URL = config.get('base', 'url')
LOG_LEVEL = config.get('base', 'log')
IP = config.get('base', 'ip')
PORT = config.get('base', 'port') # ======== Connect ==========
try:
NAV_SORT_BY = config.get('connect', 'nav_sort_by')
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
NAV_SORT_BY = 'ip' # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!%=t81uof5rhmtpi&(zr=q^fah#$enny-c@mswz49l42j0o49-' # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True TEMPLATE_DEBUG = True ALLOWED_HOSTS = ['0.0.0.0/8'] # Application definition INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
'django_crontab',
'bootstrapform',
'jumpserver',
'juser',
'jasset',
'jperm',
'jlog',
) MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
# 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
) ROOT_URLCONF = 'jumpserver.urls' WSGI_APPLICATION = 'jumpserver.wsgi.application' # Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {}
if config.get('db', 'engine') == 'mysql':
DB_HOST = config.get('db', 'host')
DB_PORT = config.getint('db', 'port')
DB_USER = config.get('db', 'user')
DB_PASSWORD = config.get('db', 'password')
DB_DATABASE = config.get('db', 'database')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': DB_DATABASE,
'USER': DB_USER,
'PASSWORD': DB_PASSWORD,
'HOST': DB_HOST,
'PORT': DB_PORT,
}
}
elif config.get('db', 'engine') == 'sqlite':
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': config.get('db', 'database'),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'jumpserver.context_processors.name_proc',
) TEMPLATE_DIRS = (
os.path.join(BASE_DIR, 'templates'),
) # STATIC_ROOT = os.path.join(BASE_DIR, 'static') STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/ STATIC_URL = '/static/' BOOTSTRAP_COLUMN_COUNT = 10 CRONJOBS = [
('0 1 * * *', 'jasset.asset_api.asset_ansible_update_all'),
('*/10 * * * *', 'jlog.log_api.kill_invalid_connection'),
]
templates/jasset/asset_edit.html
</div>
</div> + <input type="text" value="{{ asset.zbx_hostid }}" name="zbx_hostid" style="display:none"> <div class="hr-line-dashed"></div>
{{ af.group|bootstrap_horizontal }} @@ -131,6 +133,7 @@
<div class="hr-line-dashed"></div>
{{ af.status|bootstrap_horizontal }} {# <div class="hr-line-dashed"></div>#}
{# {{ af.is_active|bootstrap_horizontal }}#}
{% extends 'base.html' %}
{% load mytags %}
{% load bootstrap %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 修改资产基本信息 </h5>
<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>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div> <div class="ibox-content">
<div class="panel-body">
<div class="tab-content">
<div id="tab-1" class="ibox float-e-margins tab-pane active">
{% if error %}
<div class="alert alert-warning text-center">{{ error }}</div>
{% endif %}
{% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div>
{% endif %}
<form id="assetForm" method="post" class="form-horizontal"> {{ af.hostname|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.ip|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.other_ip|bootstrap_horizontal }}
<p class="col-sm-offset-2">Tips: 多个IP使用,号隔开</p> <div class="hr-line-dashed"></div>
{{ af.remote_ip|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.mac|bootstrap_horizontal }} {# <div class="hr-line-dashed"></div>#}
{# {{ af.port|bootstrap_horizontal }}#} <div class="hr-line-dashed"></div>
<div class="form-group">
<label for="j_group" class="col-sm-2 control-label">管理账号 <span class="red-fonts">*</span></label>
<div class="col-sm-2">
<div class="radio i-checks">
<label style="padding-left: 0">
<input type="checkbox" {% if asset.use_default_auth %} checked="checked" {% endif %} id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span>
</label>
</div>
</div>
</div>
<div class="form-group" id="admin_account" {% if asset.use_default_auth %} style="display: none" {% endif %}>
<label class="col-sm-2 control-label"> </label>
<div class="col-sm-3">
<input type="text" value="{{ asset.username }}" name="username" class="form-control">
</div> <label class="col-sm-1 control-label"> </label>
<div class="col-sm-4">
<input type="password" value="" name="password" placeholder="不填写即不更改密码." class="form-control">
</div>
</div> <div class="form-group" id="id_port">
<div class="hr-line-dashed"></div>
<label class="col-sm-2 control-label"> 端口<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<input type="text" placeholder="Port" value="{{ asset.port|default_if_none:"" }}" name="port" class="form-control">
</div>
</div> <input type="text" value="{{ asset.zbx_hostid }}" name="zbx_hostid" style="display:none"> <div class="hr-line-dashed"></div>
{{ af.group|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.idc|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.brand|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.cpu|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.memory|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.disk|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.system_type|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.system_version|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.system_arch|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.number|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.sn|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.cabinet|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.position|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.asset_type|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.env|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
{{ af.status|bootstrap_horizontal }} {# <div class="hr-line-dashed"></div>#}
{# {{ af.is_active|bootstrap_horizontal }}#} <div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label"> 是否激活<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<div class="radio i-checks">
{% ifequal asset.is_active 1 %}
<label> <input type="radio" checked="" value="1" name="is_active">激活 </label>
<label> <input type="radio" value="0" name="is_active"> 禁用</label>
{% else %}
<label> <input type="radio" value="1" name="is_active">激活 </label>
<label> <input type="radio" checked="" value="0" name="is_active"> 禁用</label>
{% endifequal %}
</div>
</div>
</div> <div class="hr-line-dashed"></div>
{{ af.comment|bootstrap_horizontal }} <div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset"> 重置 </button>
<button class="btn btn-primary" type="submit"> 提交 </button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %} {% block self_footer_js %}
<script>
$('document').ready(function(){
$('#id_use_default_auth').click(function(){
if ($(this).is(':checked')){
$('#admin_account').css('display', 'none');
}
else {
$('#admin_account').css('display', 'block');
}
})
});
var required_fields = ["id_hostname", "id_port"];
required_fields.forEach(function(field) {
$('label[for="' + field + '"]').parent().addClass("required");
});
$('#assetForm').validator({
timely: 2,
theme: "yellow_right_effect",
rules: {
check_ip: [/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/, 'ip地址不正确'],
check_port: [/^\d{1,5}$/, '端口号不正确'],
use_default_auth: function() {
var str1 = $("#id_use_default_auth").is(":checked");
if (str1 == true){
var decide = false;
} else {
var decide = true;
}
return decide}
},
fields: {
"hostname": {
rule: "required;length[0~53]",
tip: "填写主机名",
ok: "",
msg: {required: "必须填写!"}
},
"port": {
rule: "required(use_default_auth)",
tip: "输入端口号",
ok: "",
msg: {required: "必须填写!"}
},
"username": {
rule: "required(use_default_auth);",
tip: "输入用户名",
ok: "",
msg: {required: "必须填写!"}
},
"password": {
rule: "length[0~64]",
tip: "输入密码",
ok: "",
empty: true
}
},
valid: function(form) {
form.submit();
}
});
</script> {% endblock %}
templates/jasset/asset_list.html
<th class="text-center"> cpu核数 </th>
<th class="text-center"> 内存 </th>
<th class="text-center"> 硬盘 </th>
+ <th class="text-center"> zbx_hostid </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
@@ -130,10 +131,15 @@
<td class="text-center"> {{ asset.cpu|get_cpu_core|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.memory|default_if_none:"" }}{% if asset.memory %}G{% endif %}</td>
<td class="text-center"> {{ asset.disk|get_disk_info }}{% if asset.disk %}G{% endif %}</td>
+ {% if asset.zbx_hostid %}
+ <td class="text-center" bgcolor="#adff2f"> {{ asset.zbx_hostid }}</td>
+ {% else %}
+ <td class="text-center" bgcolor="#cd5c5c"> {{ asset.zbx_hostid }}</td>
+ {% endif %}
<td class="text-center" data-editable='false'>
- <a href="{% url 'asset_edit' %}?id={{ asset.id }}" class="btn btn-xs btn-info">编辑</a>
+ <a href="{% url 'asset_edit' %}?id={{ asset.id }}&zbx_hostid={{ asset.zbx_hostid }}" class="btn btn-xs btn-info">编辑</a>
<a value="{{ asset.id }}" class="conn btn btn-xs btn-warning">连接</a>
- <a value="{% url 'asset_del' %}?id={{ asset.id }}" class="btn btn-xs btn-danger asset_del">删除</a>
+ <a value="{% url 'asset_del' %}?id={{ asset.id }}&zbx_hostid={{ asset.zbx_hostid }}" class="btn btn-xs btn-danger asset_del">删除</a>
</td>
</tr>
{% endfor %}
@@ -144,6 +150,7 @@
<input type="button" id="asset_del" class="btn btn-danger btn-sm" name="del_button" value="删除"/>
<a value="{% url 'asset_edit_batch' %}" type="button" class="btn btn-sm btn-warning iframe">修改</a>
<input type="button" id="asset_update" class="btn btn-info btn-sm" name="update_button" value="更新"/>
+ <input type="button" id="zbx_update" class="btn btn-danger btn-sm" name="update_zbx_button" value="更新zabbix"/>
{# <input type="button" id="asset_update_all" class="btn btn-primary btn-sm" name="update_button" value="更新全部"/>#}
<input type="button" id="exec_cmd" class="btn btn-sm btn-primary" name="exec_cmd" value="执行命令"/>
</div>
@@ -406,6 +413,22 @@
}
}); + $('#zbx_update').click(function () {
+ var asset_id_all = getIDall();
+{# alert(asset_id_all);#}
+ layer.msg('玩命更新中...', {time: 200000});
+ $.ajax({
+ type: "post",
+ data: {asset_id_all: asset_id_all},
+ url: "{% url 'zabbix_update_batch' %}",
+ success: function () {
+ parent.location.reload();
+ }
+ });
+ }); {# $('#asset_update_all').click(function () {#}
{# layer.msg('玩命更新中...', {time: 200000});#}
{# $.ajax({#}
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %} <div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins" id="all">
<div class="ibox-title">
<h5> 主机详细信息列表</h5>
<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>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div> <div class="ibox-content">
<form id="asset_form">
<div class="col-sm-1" style="padding-left: 0">
<a href="{% url 'asset_add' %}" class="btn btn-sm btn-primary "> 添加资产 </a>
</div> <div class="col-sm-7" style="padding-left: 0px">
<label>
<select name="idc" class="form-control m-b input-sm" onchange="change_info()">
<option value="">机房</option>
{% for idc in idc_all %}
{% ifequal idc.name idc_name %}
<option value="{{idc.name}}" selected> {{ idc.name|slice:":20" }}</option>
{% else %}
<option value="{{idc.name}}"> {{ idc.name|slice:":20" }}</option>
{% endifequal %}
{% endfor %}
</select>
</label> <label>
<select name="group" class="form-control m-b input-sm" onchange="change_info()">
<option value="">主机组</option>
{% for asset_group in asset_group_all %}
{% ifequal asset_group.name group_name %}
<option value="{{ asset_group.name }}" selected> {{ asset_group.name|slice:":20" }} </option>
{% else %}
<option value="{{ asset_group.name }}"> {{ asset_group.name|slice:":20" }} </option>
{% endifequal %}
{% endfor %}
</select>
</label> <label>
<select name="asset_type" class="form-control m-b input-sm" onchange="change_info()">
<option value="">资产类型</option>
{% for type in asset_types %}
{% ifequal type.0|int2str asset_type %}
<option value="{{ type.0 }}" selected> {{ type.1 }}</option>
{% else %}
<option value="{{ type.0 }}"> {{ type.1 }}</option>
{% endifequal %}
{% endfor %}
</select>
</label> <label>
<select name="status" class="form-control m-b input-sm" onchange="change_info()">
<option value="">资产状态</option>
{% for s in asset_status %}
{% ifequal s.0|int2str status %}
<option value="{{ s.0 }}" selected> {{ s.1 }}</option>
{% else %}
<option value="{{ s.0 }}"> {{ s.1 }}</option>
{% endifequal %}
{% endfor %}
</select>
</label>
</div> <div class="col-sm-4" style="padding-right: 0">
<div class="input-group inline-group">
<input type="text" class="form-control m-b input-sm" id="search_input" name="keyword" value="{{ keyword }}" placeholder="Search">
<input type="text" style="display: none">
<div class="input-group-btn">
<button id='search_btn' href="{% url 'asset_list' %}?search=true" type="button" class="btn btn-sm btn-primary search-btn" onclick="change_info()">
- 搜索 -
</button>
<button type="button" href="{% url 'asset_list' %}?export=true" name="export" class="btn btn-sm btn-success search-btn-excel" onclick="return false">
- 导出 -
</button>
</div>
</div>
</div>
<div id="export"></div>
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center">
<input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('asset_form')">
</th>
<th class="text-center"> 主机名 </th>
<th class="text-center" name="ip"> IP地址 </th>
<th class="text-center"> IDC </th>
<th class="text-center"> 所属主机组 </th>
{# <th class="text-center"> 配置信息 </th>#}
<th class="text-center"> 操作系统 </th>
<th class="text-center"> cpu核数 </th>
<th class="text-center"> 内存 </th>
<th class="text-center"> 硬盘 </th>
<th class="text-center"> zbx_hostid </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for asset in assets.object_list %}
<tr class="gradeX">
<td class="text-center" name="id" value="{{ asset.id }}" data-editable='false'>
<input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks">
</td>
<td class="text-center hostname"> <a href="{% url 'asset_detail' %}?id={{ asset.id }}">{{ asset.hostname|default_if_none:"" }}</a></td>
<td class="text-center"> {{ asset.ip|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.idc.name|default_if_none:"" }} </td>
<td class="text-center">{{ asset.group.all|group_str2 }}</td>
{# <td class="text-center">{{ asset.cpu }}|{{ asset.memory }}|{{ asset.disk }}</td>#}
<td class="text-center">{{ asset.system_type|default_if_none:"" }}{{ asset.system_version|default_if_none:"" }}</td>
<td class="text-center"> {{ asset.cpu|get_cpu_core|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.memory|default_if_none:"" }}{% if asset.memory %}G{% endif %}</td>
<td class="text-center"> {{ asset.disk|get_disk_info }}{% if asset.disk %}G{% endif %}</td>
{% if asset.zbx_hostid %}
<td class="text-center" bgcolor="#adff2f"> {{ asset.zbx_hostid }}</td>
{% else %}
<td class="text-center" bgcolor="#cd5c5c"> {{ asset.zbx_hostid }}</td>
{% endif %}
<td class="text-center" data-editable='false'>
<a href="{% url 'asset_edit' %}?id={{ asset.id }}&zbx_hostid={{ asset.zbx_hostid }}" class="btn btn-xs btn-info">编辑</a>
<a value="{{ asset.id }}" class="conn btn btn-xs btn-warning">连接</a>
<a value="{% url 'asset_del' %}?id={{ asset.id }}&zbx_hostid={{ asset.zbx_hostid }}" class="btn btn-xs btn-danger asset_del">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="asset_del" class="btn btn-danger btn-sm" name="del_button" value="删除"/>
<a value="{% url 'asset_edit_batch' %}" type="button" class="btn btn-sm btn-warning iframe">修改</a>
<input type="button" id="asset_update" class="btn btn-info btn-sm" name="update_button" value="更新"/>
<input type="button" id="zbx_update" class="btn btn-danger btn-sm" name="update_zbx_button" value="更新zabbix"/>
{# <input type="button" id="asset_update_all" class="btn btn-primary btn-sm" name="update_button" value="更新全部"/>#}
<input type="button" id="exec_cmd" class="btn btn-sm btn-primary" name="exec_cmd" value="执行命令"/>
</div>
{% include 'paginator.html' %}
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %} {% block self_footer_js %}
<script>
$(document).ready(function(){
$('.asset_del').click(function(){
var row = $(this).closest('tr');
if (confirm("确定删除?")) {
$.get(
$(this).attr('value'),
{},
function (data) {
row.remove()
}
)
}
});
$('#exec_cmd').click(function(){
var url = '{% url "role_get" %}';
var new_url = '{% url "exec_cmd" %}?role=';
var check_array = [];
$(".gradeX input:checked").closest('tr').find('.hostname a').each(function() {
check_array.push($(this).text())
});
check_assets = check_array.join(':');
$.ajax({
type: 'GET',
url: url,
data: {},
success: function(data){
var dataArray = data.split(',');
if (dataArray.length == 1 && data != 'error'){
var title = 'Jumpserver Exec Terminal';
layer.open({
type: 2,
title: title,
maxmin: true,
shade: false,
area: ['725px', '600px'],
content: new_url+data+'&check_assets='+check_assets
});
//window.open(new_url + data, '', 'location=no, resizeable=no, height=410, width=625, top=89px, left=99px,toolbar=no,menubar=no,scrollbars=auto,status=no');
} else if (dataArray.length == '1' && data == 'error'){
layer.alert('没有授权系统用户')
} else {
aUrl = '';
$.each(dataArray, function(index, value){
aUrl += '<a onclick="windowOpenExec(this); return false" class="btn btn-xs btn-primary newa" href=' + new_url + value + '&check_assets=' + check_assets + '>' + value + '</a> '
});
layer.alert(aUrl, {
skin: 'layui-layer-molv',
title: '授权多个系统用户,请选择一个连接',
shade: false,
closeBtn: 0
})
}
}
});
return false
});
$('.conn').click(function(){
var url='{% url "role_get" %}?id=' + $(this).attr('value'); // 获取用户有权限的角色
var href = $(this).attr('href');
var new_url = '{% url "terminal" %}?id=' + $(this).attr('value') + '&role='; // webterminal socket url
var hostname = $(this).closest('tr').find('.hostname a')[0].innerHTML;
$.ajax({
type: 'GET',
url: url,
data: {},
success: function(data){
var dataArray = data.split(',');
if (data == 'error' || data == '' || data == null || data == undefined){
layer.alert('没有授权系统用户')
}
else if (dataArray.length == 1 && data != 'error' && navigator.platform == 'Win32'){
/*
var title = 'Jumpserver Web Terminal' + '<span class="text-info"> '+ hostname +'</span>';
layer.open({
type: 2,
title: title,
maxmin: true,
shade: false,
area: ['628px', '420px'],
content: new_url+data
});
window.open(new_url+data, '_blank', 'toolbar=yes, location=yes, scrollbars=yes, resizable=yes, copyhistory=yes, width=628, height=400')
*/
window.open(new_url+data, "_blank");
} else if (dataArray.length == 1 && data != 'error'){
/*layer.open({
type: 2,
title: title,
maxmin: true,
shade: false,
area: ['628px', '452px'],
content: new_url+data
});
*/
window.open(new_url+data, '_blank');
}
else {
aUrl = '';
$.each(dataArray, function(index, value){
aUrl += '<a onclick="windowOpen(this); return false" class="btn btn-xs btn-primary newa" href=' + new_url + value + ' value=' + hostname + '>' + value + '</a> '
});
console.log(aUrl);
layer.alert(aUrl, {
skin: 'layui-layer-molv',
title: '授权多个系统用户,请选择一个连接',
shade: false,
closeBtn: 0
})
}
}
});
return false
});
});
function windowOpen(a){
var new_url = $(a).attr('href');
var hostname = $(a).attr('value');
var title = 'Jumpserver Web Terminal - ' + '<span class="text-info"> '+ hostname +'</span>';
if (navigator.platform == 'Win32'){
/*
layer.open({
type: 2,
title: title,
maxmin: true,
area: ['628px', '420px'],
shade: false,
content: new_url
});
*/
window.open(new_url, '_blank')
} else {
/*
layer.open({
type: 2,
title: title,
maxmin: true,
area: ['628px', '452px'],
shade: false,
content: new_url
});
*/
window.open(new_url, '_blank');
}
return false
}
function windowOpenExec(a){
var new_url = $(a).attr('href');
var title = 'Jumpserver Exec Terminal';
layer.open({
type: 2,
title: title,
maxmin: true,
area: ['725px', '600px'],
shade: false,
content: new_url
});
return false
}
$(".iframe").on('click', function(){
var asset_id_all = getIDall();
if (asset_id_all == ''){
alert("请至少选择一行!");
return false;
}
var url= $(this).attr("value") + '?asset_id_all=' + asset_id_all;
parent.layer.open({
type: 2,
title: 'JumpServer - 批量修改主机',
maxmin: true,
shift: 'top',
border: [2, 0.3, '#1AB394'],
shade: [0.5, '#000000'],
area: ['800px', '600px'],
shadeClose: true,
content: url,
cancel: function(){
location.replace(location.href);
}
});
});
$('.search-btn-excel').unbind('click').bind('click',function(){
var url= $(this).attr("href");
$.ajax({
type: "GET",
url: url,
data: $("#asset_form").serialize(),
success: function (data) {
$("#export").html(data);
}
});
});
$('#asset_del').click(function () {
var asset_id_all = getIDall();
if (asset_id_all == ''){
alert("请至少选择一行!");
return false;
}
if (confirm("确定删除?")) {
$.ajax({
type: "post",
data: {asset_id_all: asset_id_all},
url: "{% url 'asset_del' %}?arg=batch",
success: function () {
parent.location.reload();
}
});
}
});
$('#asset_update').click(function () {
var asset_id_all = getIDall();
if (asset_id_all == ''){
if (confirm("更新全部资产信息?")) {
layer.msg('玩命更新中...', {time: 200000});
$.ajax({
type: "post",
url: "{% url 'asset_update_batch' %}?arg=all",
success: function () {
parent.location.reload();
}
});
}
}
else {
layer.msg('玩命更新中...', {time: 200000});
$.ajax({
type: "post",
data: {asset_id_all: asset_id_all},
url: "{% url 'asset_update_batch' %}",
success: function () {
parent.location.reload();
}
});
}
});
$('#zbx_update').click(function () {
var asset_id_all = getIDall();
{# alert(asset_id_all);#}
layer.msg('玩命更新中...', {time: 200000});
$.ajax({
type: "post",
data: {asset_id_all: asset_id_all},
url: "{% url 'zabbix_update_batch' %}",
success: function () {
parent.location.reload();
}
});
});
{# $('#asset_update_all').click(function () {#}
{# layer.msg('玩命更新中...', {time: 200000});#}
{# $.ajax({#}
{# type: "post",#}
{# url: "/jasset/asset_update_batch/?arg=all",#}
{# success: function () {#}
{# parent.location.reload();#}
{# }#}
{# });#}
{# });#}
function change_info(){
var args = $("#asset_form").serialize();
window.location = "{% url 'asset_list' %}?" + args
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
change_info()
}
});
</script> {% endblock %}
重启服务:
./service.sh restart
根据models.py的配置添加mysql字段:
#登录数据库
[root@test-node1 jumpserver]# mysql -uroot -p
#进入jumpserver库
mysql> use jumpserver
#查看表
mysql> show tables;
#在jasset_asset表中添加字段
alter table jasset_asset add zbx_hostid varchar(32) NULL;
访问jumpserver页面:http://10.0.0.56:8000/
添加资产:
注意:只是添加了主机,没有添加模板,模板还需要自己手动添加
【二次开发jumpserver】——整合jumpserver与zabbix推送主机功能的更多相关文章
- iOS开发三步搞定百度推送
iOS开发三步搞定百度推送 百度推送很简单,准备工作:在百度云推送平台注册应用,上传证书. 步骤一: 百度云推送平台 http://push.baidu.com/sdk/push_client_s ...
- 【NFS项目实战二】NFS共享数据的时时同步推送备份
[NFS项目实战二]NFS共享数据的时时同步推送备份 标签(空格分隔): Linux服务搭建-陈思齐 ---本教学笔记是本人学习和工作生涯中的摘记整理而成,此为初稿(尚有诸多不完善之处),为原创作品, ...
- 【WP 8.1开发】手机客户端应用接收推送通知
上一篇文章中,已经完成了用于发送通知的服务器端,接下来我们就用这个服务端来测试一下. 在开始测试之前,我们要做一个接收通知的WP应用. 1.启动VS Express for Windows,新建项目, ...
- C#微信公众号开发系列教程(接收事件推送与消息排重)
微信服务器在5秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次.这样的话,问题就来了.有这样一个场景:当用户关注微信账号时,获取当前用户信息,然后将信息写到数据库中.类似于pc端网站的注册.可 ...
- IM推送保障及网络优化详解(二):如何做长连接加推送组合方案
对于移动APP来说,IM功能正变得越来越重要,它能够创建起人与人之间的连接.社交类产品中,用户与用户之间的沟通可以产生出更好的用户粘性. 在复杂的 Android 生态环境下,多种因素都会造成消息推送 ...
- Asp.net MVC企业级开发(04)---SignalR消息推送
Asp.net SignalR是微软为实现实时通信而开发的一个类库.可以适用于以下场景: 聊天室,如在线客服系统,IM系统等 股票价格实时更新 消息的推送服务 游戏中人物位置的实时推送 SignalR ...
- zabbix推送内存监控单应用shell
利用top方式获取指定第三方的内存使用率 #!/bin/bash process=$1 if [ ! -z $process ];then cd /zabbix/zabbix-agent/script ...
- 夺命雷公狗---微信开发17----自定义菜单的事件推送,响应菜单的CLICK
废话不多说,index.php 代码如下所示: <?php /** * wechat php test */ //define your token require_once "com ...
- laravel整合workerman做消息推送系统
官方建议分离 workerman和mvc框架的结合,我去,这不是有点脑缺氧吗? 大量的业务逻辑,去独立增加方法和类库在写一次,实际业务中是不现实和不实际的 gateway增加一些这方面的工作,但是我看 ...
随机推荐
- MVC通过递归+部分视图实现评论
前一个项目里有一个关于评论系统的需求.感觉这个评论的实现还是蛮好玩的,所以记录下这个系统的实现相关内容. 功能需求: 1.用户可以再视屏下方留言. 2.用户可以再别的用户留言下方回复. 3.用户可以删 ...
- 简单总结几种常见web攻击手段及其防御方式
web攻击手段有几种,本文简单介绍几种常见的攻击手段及其防御方式 XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS XSS 概念 全称是跨站脚本攻击(Cross Site Scr ...
- VB6之借助zlib实现gzip解压缩
这是个简版的,可以拿来做下网页gzip的解压缩,整好我的webserver还不支持这个,有时间了就加上. zlib.dll下载请点击我! 模块zlib.bas的代码如下: 'code by lichm ...
- Django学习(二)---使用模板Templates
学会使用渲染模板的方法来显示html内容. 一.Templates是什么: HTML文件 使用了Django模板语言(Django Tamplate Language DTL) 可以使用第三方模板 二 ...
- KMP算法(研究总结,字符串)
KMP算法(研究总结,字符串) 前段时间学习KMP算法,感觉有些复杂,不过好歹是弄懂啦,简单地记录一下,方便以后自己回忆. 引入 首先我们来看一个例子,现在有两个字符串A和B,问你在A中是否有B,有几 ...
- Python 批量翻译 使用有道api;
妹子是做翻译相关的,遇到个问题,要求得到句子中的所有单词的 音标; 有道翻译只能对单个单词翻译音标,不能对多个单词或者句子段落翻译音标; 手工一个一个翻的话那就要累死人了.....于是就让我写个翻译音 ...
- 机器学习 —— 基础整理(八)循环神经网络的BPTT算法步骤整理;梯度消失与梯度爆炸
网上有很多Simple RNN的BPTT(Backpropagation through time,随时间反向传播)算法推导.下面用自己的记号整理一下. 我之前有个习惯是用下标表示样本序号,这里不能再 ...
- 用runtime封装归档(encoding)
runtime一套比较基层的c语言的API(库) 归档(OC对象-->字典—>2进制—>写入沙盒 || 目的.数据持久化) #import <UIKit/UIKit.h&g ...
- tomato dualwan /root目录的特殊用途
测试发现tomato dualwan /root目录下存储的文件重启后会自动清掉.利用这个特性可以把测试生成的临时文件丢到这里. root下本应该存在的.vimrc 文件 采用如下方法生成: 在/op ...
- 小白浅论JAVA数组中“for加强版”
代码: /*String[] s=new String[]{"sdsfd","fgd","sdf"}; for(String a:s) Sy ...