【二次開發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/
添加資産:
注意:隻是添加了主機,沒有添加模闆,模闆還需要自己手動添加
發表于
2017-08-18 16:33
辣個提莫有毒
閱讀(4544)
評論(3)
編輯
收藏
舉報