mirror of https://github.com/jumpserver/jumpserver
asset add batch
parent
ec7b543bf2
commit
0f29745bfa
|
@ -0,0 +1,459 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ansible.inventory.group import Group
|
||||
from ansible.inventory.host import Host
|
||||
from ansible.inventory import Inventory
|
||||
from ansible.runner import Runner
|
||||
from ansible.playbook import PlayBook
|
||||
|
||||
from ansible import callbacks
|
||||
from ansible import utils
|
||||
from passlib.hash import sha512_crypt
|
||||
|
||||
# from utils import get_rand_pass
|
||||
|
||||
import random
|
||||
import os.path
|
||||
API_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
ANSIBLE_DIR = os.path.join(API_DIR, 'playbooks')
|
||||
|
||||
def get_rand_pass():
|
||||
"""
|
||||
get a reandom password.
|
||||
"""
|
||||
lower = [chr(i) for i in range(97,123)]
|
||||
upper = [chr(i).upper() for i in range(97,123)]
|
||||
digit = [str(i) for i in range(10)]
|
||||
password_pool = []
|
||||
password_pool.extend(lower)
|
||||
password_pool.extend(upper)
|
||||
password_pool.extend(digit)
|
||||
pass_list = [random.choice(password_pool) for i in range(1,14)]
|
||||
pass_list.insert(random.choice(range(1,14)), '@')
|
||||
pass_list.insert(random.choice(range(1,14)), random.choice(digit))
|
||||
password = ''.join(pass_list)
|
||||
return password
|
||||
|
||||
class AnsibleError(StandardError):
|
||||
"""
|
||||
the base AnsibleError which contains error(required),
|
||||
data(optional) and message(optional).
|
||||
存储所有Ansible 异常对象
|
||||
"""
|
||||
def __init__(self, error, data='', message=''):
|
||||
super(AnsibleError, self).__init__(message)
|
||||
self.error = error
|
||||
self.data = data
|
||||
self.message = message
|
||||
|
||||
|
||||
class CommandValueError(AnsibleError):
|
||||
"""
|
||||
indicate the input value has error or invalid.
|
||||
the data specifies the error field of input form.
|
||||
输入不合法 异常对象
|
||||
"""
|
||||
def __init__(self, field, message=''):
|
||||
super(CommandValueError, self).__init__('value:invalid', field, message)
|
||||
|
||||
|
||||
class MyInventory(object):
|
||||
"""
|
||||
this is my ansible inventory object.
|
||||
"""
|
||||
def __init__(self, resource):
|
||||
"""
|
||||
resource的数据格式是一个列表字典,比如
|
||||
{
|
||||
"group1": {
|
||||
"hosts": [{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...],
|
||||
"vars": {"var1": value1, "var2": value2, ...}
|
||||
}
|
||||
}
|
||||
|
||||
如果你只传入1个列表,这默认该列表内的所有主机属于my_group组,比如
|
||||
[{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...]
|
||||
"""
|
||||
self.resource = resource
|
||||
self.inventory = Inventory()
|
||||
self.gen_inventory()
|
||||
|
||||
def add_group(self, hosts, groupname, groupvars=None):
|
||||
"""
|
||||
add hosts to a group
|
||||
"""
|
||||
my_group = Group(name=groupname)
|
||||
|
||||
# if group variables exists, add them to group
|
||||
if groupvars:
|
||||
for key, value in groupvars.iteritems():
|
||||
my_group.set_variable(key, value)
|
||||
|
||||
# add hosts to group
|
||||
for host in hosts:
|
||||
# set connection variables
|
||||
hostname = host.get("hostname")
|
||||
hostport = host.get("port")
|
||||
username = host.get("username")
|
||||
password = host.get("password")
|
||||
my_host = Host(name=hostname, port=hostport)
|
||||
my_host.set_variable('ansible_ssh_host', hostname)
|
||||
my_host.set_variable('ansible_ssh_port', hostport)
|
||||
my_host.set_variable('ansible_ssh_user', username)
|
||||
my_host.set_variable('ansible_ssh_pass', password)
|
||||
# set other variables
|
||||
for key, value in host.iteritems():
|
||||
if key not in ["hostname", "port", "username", "password"]:
|
||||
my_host.set_variable(key, value)
|
||||
# add to group
|
||||
my_group.add_host(my_host)
|
||||
|
||||
self.inventory.add_group(my_group)
|
||||
|
||||
def gen_inventory(self):
|
||||
"""
|
||||
add hosts to inventory.
|
||||
"""
|
||||
if isinstance(self.resource, list):
|
||||
self.add_group(self.resource, 'my_group')
|
||||
elif isinstance(self.resource, dict):
|
||||
for groupname, hosts_and_vars in self.resource.iteritems():
|
||||
self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
|
||||
|
||||
|
||||
class Command(MyInventory):
|
||||
"""
|
||||
this is a command object for parallel execute command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Command, self).__init__(*args, **kwargs)
|
||||
self.results = ''
|
||||
|
||||
def run(self, command, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
if module_name not in ["raw", "command", "shell"]:
|
||||
raise CommandValueError("module_name",
|
||||
"module_name must be of the 'raw, command, shell'")
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=command,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
)
|
||||
self.results = hoc.run()
|
||||
|
||||
if self.stdout:
|
||||
return {"ok": self.stdout}
|
||||
else:
|
||||
msg = []
|
||||
if self.stderr:
|
||||
msg.append(self.stderr)
|
||||
if self.dark:
|
||||
msg.append(self.dark)
|
||||
return {"failed": msg}
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
"""
|
||||
get the ansible raw results.
|
||||
"""
|
||||
return self.results
|
||||
|
||||
@property
|
||||
def exec_time(self):
|
||||
"""
|
||||
get the command execute time.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
"start": value.get("start"),
|
||||
"end" : value.get("end"),
|
||||
"delta": value.get("delta"),}
|
||||
return result
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
"""
|
||||
get the comamnd standard output.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = value.get("stdout")
|
||||
return result
|
||||
|
||||
@property
|
||||
def stderr(self):
|
||||
"""
|
||||
get the command standard error.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
"stderr": value.get("stderr"),
|
||||
"warnings": value.get("warnings"),}
|
||||
return result
|
||||
|
||||
@property
|
||||
def dark(self):
|
||||
"""
|
||||
get the dark results.
|
||||
"""
|
||||
return self.results.get("dark")
|
||||
|
||||
|
||||
class Tasks(Command):
|
||||
"""
|
||||
this is a tasks object for include the common command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Tasks, self).__init__(*args, **kwargs)
|
||||
|
||||
def __run(self, module_args, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=module_args,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
)
|
||||
|
||||
self.results = hoc.run()
|
||||
|
||||
@property
|
||||
def msg(self):
|
||||
"""
|
||||
get the contacted and dark msg
|
||||
"""
|
||||
msg = {}
|
||||
for result in ["contacted", "dark"]:
|
||||
all = self.results.get(result)
|
||||
for key, value in all.iteritems():
|
||||
if value.get("msg"):
|
||||
msg[key] = value.get("msg")
|
||||
return msg
|
||||
|
||||
def push_key(self, user, key_path):
|
||||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}"' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def del_key(self, user, key_path):
|
||||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state="absent"' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_user(self, username, password):
|
||||
"""
|
||||
add a host user.
|
||||
"""
|
||||
encrypt_pass = sha512_crypt.encrypt(password)
|
||||
module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass)
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_multi_user(self, *args):
|
||||
"""
|
||||
add multi user
|
||||
:param args:
|
||||
user
|
||||
:return:
|
||||
"""
|
||||
results = {}
|
||||
users = {}
|
||||
action = results["action_info"] = {}
|
||||
for user in args:
|
||||
users[user] = get_rand_pass()
|
||||
for user, password in users.iteritems():
|
||||
ret = self.add_user(user, password)
|
||||
action[user] = ret
|
||||
results["user_info"] = users
|
||||
|
||||
return results
|
||||
|
||||
def del_user(self, username):
|
||||
"""
|
||||
delete a host user.
|
||||
"""
|
||||
module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % (username)
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_init_users(self):
|
||||
"""
|
||||
add initail users: SA, DBA, DEV
|
||||
"""
|
||||
results = {}
|
||||
action = results["action_info"] = {}
|
||||
users = {"SA": get_rand_pass(), "DBA": get_rand_pass(), "DEV": get_rand_pass()}
|
||||
for user, password in users.iteritems():
|
||||
ret = self.add_user(user, password)
|
||||
action[user] = ret
|
||||
results["user_info"] = users
|
||||
|
||||
return results
|
||||
|
||||
def del_init_users(self):
|
||||
"""
|
||||
delete initail users: SA, DBA, DEV
|
||||
"""
|
||||
results = {}
|
||||
action = results["action_info"] = {}
|
||||
for user in ["SA", "DBA", "DEV"]:
|
||||
ret = self.del_user(user)
|
||||
action[user] = ret
|
||||
return results
|
||||
|
||||
def get_host_info(self):
|
||||
"""
|
||||
use the setup module get host informations
|
||||
:return:
|
||||
all_ip is list
|
||||
processor_count is int
|
||||
system_dist_version is string
|
||||
system_type is string
|
||||
disk is dict (device_name: device_size}
|
||||
system_dist is string
|
||||
processor_type is string
|
||||
default_ip is string
|
||||
hostname is string
|
||||
product_sn is string
|
||||
memory_total is int (MB)
|
||||
default_mac is string
|
||||
product_name is string
|
||||
"""
|
||||
self.__run('', 'setup')
|
||||
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
setup =value.get("ansible_facts")
|
||||
# get disk informations
|
||||
disk_all = setup.get("ansible_devices")
|
||||
disk_need = {}
|
||||
for disk_name, disk_info in disk_all.iteritems():
|
||||
if disk_name.startswith('sd') or disk_name.startswith('hd') or disk_name.startswith('vd'):
|
||||
disk_need[disk_name] = disk_info.get("size")
|
||||
|
||||
result[key] = {
|
||||
"other_ip": setup.get("ansible_all_ipv4_addresses"),
|
||||
"hostname": setup.get("ansible_hostname" ),
|
||||
"ip": setup.get("ansible_default_ipv4").get("address"),
|
||||
"mac": setup.get("ansible_default_ipv4").get("macaddress"),
|
||||
"brand": setup.get("ansible_product_name"),
|
||||
"cpu_type": setup.get("ansible_processor"),
|
||||
"cpu_cores": setup.get("ansible_processor_count"),
|
||||
"memory": setup.get("ansible_memtotal_mb"),
|
||||
"disk": disk_need,
|
||||
"system_type": setup.get("ansible_distribution"),
|
||||
"system_version": setup.get("ansible_distribution_version"),
|
||||
"asset_type": setup.get("ansible_system"),
|
||||
"sn": setup.get("ansible_product_serial")
|
||||
}
|
||||
|
||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result}
|
||||
|
||||
|
||||
class CustomAggregateStats(callbacks.AggregateStats):
|
||||
"""
|
||||
Holds stats about per-host activity during playbook runs.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(CustomAggregateStats, self).__init__()
|
||||
self.results = []
|
||||
|
||||
def compute(self, runner_results, setup=False, poll=False,
|
||||
ignore_errors=False):
|
||||
"""
|
||||
Walk through all results and increment stats.
|
||||
"""
|
||||
super(CustomAggregateStats, self).compute(runner_results, setup, poll,
|
||||
ignore_errors)
|
||||
|
||||
self.results.append(runner_results)
|
||||
|
||||
|
||||
def summarize(self, host):
|
||||
"""
|
||||
Return information about a particular host
|
||||
"""
|
||||
summarized_info = super(CustomAggregateStats, self).summarize(host)
|
||||
|
||||
# Adding the info I need
|
||||
summarized_info['result'] = self.results
|
||||
|
||||
return summarized_info
|
||||
|
||||
|
||||
class MyPlaybook(MyInventory):
|
||||
"""
|
||||
this is my playbook object for execute playbook.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyPlaybook, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def run(self, playbook_relational_path, extra_vars=None):
|
||||
"""
|
||||
run ansible playbook,
|
||||
only surport relational path.
|
||||
"""
|
||||
stats = callbacks.AggregateStats()
|
||||
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
|
||||
runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
|
||||
playbook_path = os.path.join(ANSIBLE_DIR, playbook_relational_path)
|
||||
|
||||
pb = PlayBook(
|
||||
playbook = playbook_path,
|
||||
stats = stats,
|
||||
callbacks = playbook_cb,
|
||||
runner_callbacks = runner_cb,
|
||||
inventory = self.inventory,
|
||||
extra_vars = extra_vars,
|
||||
check=False)
|
||||
|
||||
self.results = pb.run()
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
"""
|
||||
get the raw results after playbook run.
|
||||
"""
|
||||
return self.results
|
||||
|
||||
|
||||
class App(MyPlaybook):
|
||||
"""
|
||||
this is a app object for inclue the common playbook.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(App, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# coding: utf-8
|
||||
import ast
|
||||
import xlrd
|
||||
import xlsxwriter
|
||||
from django.db.models import AutoField
|
||||
from jumpserver.api import *
|
||||
|
@ -226,7 +226,7 @@ def asset_diff(before, after):
|
|||
|
||||
def asset_diff_one(before, after):
|
||||
print before.__dict__, after.__dict__
|
||||
fields = Asset._meta.get_all_field_names()
|
||||
fields = Asset._meta.get_all_field_names()
|
||||
for field in fields:
|
||||
print before.field, after.field
|
||||
|
||||
|
@ -270,7 +270,7 @@ def db_asset_alert(asset, username, alert_dic):
|
|||
else:
|
||||
name = asset.username
|
||||
alert_info = [field_name, u'默认', name] if unicode(value[0]) == 'True' else \
|
||||
[field_name, name, u'默认']
|
||||
[field_name, name, u'默认']
|
||||
|
||||
elif field in ['username', 'password']:
|
||||
continue
|
||||
|
@ -281,7 +281,7 @@ def db_asset_alert(asset, username, alert_dic):
|
|||
continue
|
||||
else:
|
||||
alert_info = [u'是否激活', u'激活', u'禁用'] if unicode(value[0]) == 'True' else \
|
||||
[u'是否激活', u'禁用', u'激活']
|
||||
[u'是否激活', u'禁用', u'激活']
|
||||
|
||||
else:
|
||||
alert_info = [field_name, unicode(value[0]), unicode(value[1])]
|
||||
|
@ -310,8 +310,10 @@ def write_excel(asset_all):
|
|||
|
||||
group_all = '/'.join(group_list)
|
||||
status = asset.get_status_display()
|
||||
alter_dic = [asset.hostname, asset.ip, asset.idc.name, asset.mac, asset.remote_ip, asset.cpu, asset.memory,
|
||||
asset.disk, asset.system_type, asset.cabinet, group_all, status, asset.comment]
|
||||
idc_name = asset.idc.name if asset.idc else u''
|
||||
alter_dic = [asset.hostname, asset.ip, idc_name, asset.mac, asset.remote_ip, asset.cpu, asset.memory,
|
||||
asset.disk, (asset.system_type + asset.system_version), asset.cabinet, group_all, status,
|
||||
asset.comment]
|
||||
data.append(alter_dic)
|
||||
format = workbook.add_format()
|
||||
format.set_border(1)
|
||||
|
@ -342,6 +344,62 @@ def write_excel(asset_all):
|
|||
def copy_model_instance(obj):
|
||||
initial = dict([(f.name, getattr(obj, f.name))
|
||||
for f in obj._meta.fields
|
||||
if not isinstance(f, AutoField) and\
|
||||
not f in obj._meta.parents.values()])
|
||||
return obj.__class__(**initial)
|
||||
if not isinstance(f, AutoField) and \
|
||||
not f in obj._meta.parents.values()])
|
||||
return obj.__class__(**initial)
|
||||
|
||||
|
||||
def ansible_record(asset, ansible_dic, username):
|
||||
alert_dic = {}
|
||||
asset_dic = asset.__dict__
|
||||
for field, value in ansible_dic.items():
|
||||
old = asset_dic.get(field)
|
||||
new = ansible_dic.get(field)
|
||||
if unicode(old) != unicode(new):
|
||||
print old, new, type(old), type(new)
|
||||
setattr(asset, field, value)
|
||||
asset.save()
|
||||
alert_dic[field] = [old, new]
|
||||
|
||||
db_asset_alert(asset, username, alert_dic)
|
||||
|
||||
|
||||
def excel_to_db(excel_file):
|
||||
"""
|
||||
Asset add batch function
|
||||
"""
|
||||
try:
|
||||
data = xlrd.open_workbook(filename=None, file_contents=excel_file.read())
|
||||
except Exception, e:
|
||||
return False
|
||||
|
||||
else:
|
||||
table = data.sheets()[0]
|
||||
rows = table.nrows
|
||||
group_instance = []
|
||||
for row_num in range(1, rows):
|
||||
row = table.row_values(row_num)
|
||||
if row:
|
||||
ip, port, hostname, use_default_auth, username, password, group = row
|
||||
print ip
|
||||
use_default_auth = 1 if use_default_auth == u'默认' else 0
|
||||
if get_object(Asset, ip=ip):
|
||||
continue
|
||||
if ip and port:
|
||||
asset = Asset(ip=ip,
|
||||
port=port,
|
||||
use_default_auth=use_default_auth,
|
||||
username=username,
|
||||
password=password
|
||||
)
|
||||
asset.save()
|
||||
group_list = group.split('/')
|
||||
for group_name in group_list:
|
||||
group = get_object(AssetGroup, name=group_name)
|
||||
if group:
|
||||
group_instance.append(group)
|
||||
if group_instance:
|
||||
print group_instance
|
||||
asset.group = group_instance
|
||||
asset.save()
|
||||
return True
|
||||
|
|
|
@ -80,7 +80,7 @@ class Asset(models.Model):
|
|||
status = models.IntegerField(max_length=2, choices=ASSET_STATUS, blank=True, null=True, default=1, verbose_name=u"机器状态")
|
||||
asset_type = models.IntegerField(max_length=2, choices=ASSET_TYPE, blank=True, null=True, verbose_name=u"主机类型")
|
||||
env = models.IntegerField(max_length=2, choices=ASSET_ENV, blank=True, null=True, verbose_name=u"运行环境")
|
||||
sn = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"SN编号")
|
||||
sn = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"SN编号")
|
||||
date_added = models.DateTimeField(auto_now=True, default=datetime.datetime.now(), null=True)
|
||||
is_active = models.BooleanField(default=True, verbose_name=u"是否激活")
|
||||
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
import datetime
|
||||
from django.db import models
|
||||
from juser.models import User, UserGroup
|
||||
|
||||
|
||||
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
|
||||
|
||||
def get_asset(self):
|
||||
return self.asset_set.all()
|
||||
|
||||
def get_asset_info(self, printable=False):
|
||||
assets = self.get_asset()
|
||||
ip_comment = {}
|
||||
for asset in assets:
|
||||
ip_comment[asset.ip] = asset.comment
|
||||
|
||||
for ip in sorted(ip_comment):
|
||||
if ip_comment[ip]:
|
||||
print '%-15s -- %s' % (ip, ip_comment[ip])
|
||||
else:
|
||||
print '%-15s' % ip
|
||||
print ''
|
||||
|
||||
def get_asset_num(self):
|
||||
return len(self.get_asset())
|
||||
|
||||
def get_user_group(self):
|
||||
perm_list = self.perm_set.all()
|
||||
user_group_list = []
|
||||
for perm in perm_list:
|
||||
user_group_list.append(perm.user_group)
|
||||
return user_group_list
|
||||
|
||||
def get_user(self):
|
||||
user_list = []
|
||||
user_group_list = self.get_user_group()
|
||||
for user_group in user_group_list:
|
||||
user_list.extend(user_group.user_set.all())
|
||||
return user_list
|
||||
|
||||
def is_permed(self, user=None, user_group=None):
|
||||
if user:
|
||||
if user in self.get_user():
|
||||
return True
|
||||
|
||||
if user_group:
|
||||
if user_group in self.get_user_group():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class IDC(models.Model):
|
||||
name = models.CharField(max_length=32, unique=True)
|
||||
bandwidth = models.CharField(max_length=32, blank=True, null=True)
|
||||
linkman = models.CharField(max_length=16, blank=True, null=True)
|
||||
phone = models.CharField(max_length=32, blank=True, null=True)
|
||||
address = models.CharField(max_length=128, blank=True, null=True)
|
||||
network = models.TextField(blank=True, null=True)
|
||||
date_added = models.DateField(auto_now=True, default=datetime.datetime.now())
|
||||
operator = models.IntegerField(max_length=32, blank=True, null=True)
|
||||
comment = models.CharField(max_length=128, blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Asset(models.Model):
|
||||
"""
|
||||
asset modle
|
||||
"""
|
||||
ENVIRONMENT = (
|
||||
(0, U'生产环境'),
|
||||
(1, U'测试环境')
|
||||
)
|
||||
SERVER_STATUS = (
|
||||
(0, u"已使用"),
|
||||
(1, u"未使用"),
|
||||
(2, u"报废")
|
||||
)
|
||||
ASSET_TYPE = (
|
||||
(0, u"服务器"),
|
||||
(2, u"网络设备"),
|
||||
(3, u"其他")
|
||||
)
|
||||
|
||||
ip = models.IPAddressField(unique=True)
|
||||
second_ip = models.CharField(max_length=255, blank=True, null=True)
|
||||
hostname = models.CharField(max_length=64, blank=True, null=True)
|
||||
port = models.IntegerField(max_length=6)
|
||||
group = models.ManyToManyField(AssetGroup, blank=True, null=True)
|
||||
username = models.CharField(max_length=16, blank=True, null=True)
|
||||
password = models.CharField(max_length=64, blank=True, null=True)
|
||||
use_default_auth = models.BooleanField(default=True)
|
||||
idc = models.ForeignKey(IDC, blank=True, null=True, on_delete=models.SET_NULL)
|
||||
mac = models.CharField(max_length=20, blank=True, null=True)
|
||||
remote_ip = models.IPAddressField(unique=True, blank=True, null=True)
|
||||
brand = models.CharField(max_length=64, blank=True, null=True)
|
||||
cpu = models.CharField(max_length=64, blank=True, null=True)
|
||||
memory = models.CharField(max_length=128, blank=True, null=True)
|
||||
disk = models.CharField(max_length=128, blank=True, null=True)
|
||||
system_type = models.CharField(max_length=32, blank=True, null=True)
|
||||
system_version = models.CharField(max_length=8, blank=True, null=True)
|
||||
cabinet = models.CharField(max_length=32, blank=True, null=True)
|
||||
position = models.IntegerField(max_length=2, blank=True, null=True)
|
||||
number = models.CharField(max_length=32, blank=True, null=True)
|
||||
status = models.IntegerField(max_length=2, choices=SERVER_STATUS, default=1)
|
||||
asset_type = models.IntegerField(max_length=2, choices=ASSET_TYPE, blank=True, null=True)
|
||||
env = models.CharField(max_length=32, choices=ENVIRONMENT, blank=True, null=True)
|
||||
sn = models.CharField(max_length=32, blank=True, null=True)
|
||||
date_added = models.DateTimeField(auto_now=True, default=datetime.datetime.now())
|
||||
is_active = models.BooleanField(default=True)
|
||||
comment = models.CharField(max_length=128, blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.ip
|
||||
|
||||
def get_user(self):
|
||||
perm_list = []
|
||||
asset_group_all = self.bis_group.all()
|
||||
for asset_group in asset_group_all:
|
||||
perm_list.extend(asset_group.perm_set.all())
|
||||
|
||||
user_group_list = []
|
||||
for perm in perm_list:
|
||||
user_group_list.append(perm.user_group)
|
||||
|
||||
user_permed_list = []
|
||||
for user_group in user_group_list:
|
||||
user_permed_list.extend(user_group.user_set.all())
|
||||
user_permed_list = list(set(user_permed_list))
|
||||
return user_permed_list
|
||||
|
||||
|
||||
class AssetAlias(models.Model):
|
||||
user = models.ForeignKey(User)
|
||||
asset = models.ForeignKey(Asset)
|
||||
alias = models.CharField(max_length=100, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.alias
|
|
@ -4,15 +4,14 @@ from jasset.views import *
|
|||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^asset_add/$', asset_add),
|
||||
# url(r"^host_add_multi/$", host_add_batch),
|
||||
url(r"^asset_add_batch/$", asset_add_batch),
|
||||
url(r'^group_del/$', group_del),
|
||||
url(r'^asset_list/$', asset_list),
|
||||
url(r'^asset_del/$', asset_del),
|
||||
url(r"^asset_detail/$", asset_detail),
|
||||
url(r'^asset_edit/$', asset_edit),
|
||||
url(r'^asset_update/$', asset_update),
|
||||
# url(r'^search/$', host_search),
|
||||
# url(r"^host_detail/$", host_detail),
|
||||
# url(r"^dept_host_ajax/$", dept_host_ajax),
|
||||
# url(r"^show_all_ajax/$", show_all_ajax),
|
||||
url(r'^group_add/$', group_add),
|
||||
url(r'^group_list/$', group_list),
|
||||
|
@ -27,4 +26,5 @@ urlpatterns = patterns('',
|
|||
url(r'^idc_detail/$', idc_detail),
|
||||
url(r'^idc_edit/$', idc_edit),
|
||||
url(r'^idc_del/$', idc_del),
|
||||
url(r'^upload/$', asset_upload),
|
||||
)
|
|
@ -1,14 +1,13 @@
|
|||
# coding:utf-8
|
||||
|
||||
import ast
|
||||
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from jasset.asset_api import *
|
||||
from jumpserver.api import *
|
||||
from jasset.forms import AssetForm, IdcForm
|
||||
from jasset.models import Asset, IDC, AssetGroup, ASSET_TYPE, ASSET_STATUS
|
||||
from ansible_api import Tasks
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -175,6 +174,12 @@ def asset_add(request):
|
|||
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):
|
||||
"""
|
||||
|
@ -207,8 +212,6 @@ def asset_edit(request):
|
|||
|
||||
asset_id = request.GET.get('id', '')
|
||||
username = request.session.get('username', 'admin')
|
||||
# if not asset_id:
|
||||
# return HttpResponse('没有该主机')
|
||||
asset = get_object(Asset, id=asset_id)
|
||||
asset_old = copy_model_instance(asset)
|
||||
af = AssetForm(instance=asset)
|
||||
|
@ -231,8 +234,8 @@ def asset_edit(request):
|
|||
af_save.password = ''
|
||||
af_save.save()
|
||||
af_post.save_m2m()
|
||||
asset_new = get_object(Asset, id=asset_id)
|
||||
asset_diff_one(asset_old, asset_new)
|
||||
# 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)
|
||||
|
||||
|
@ -306,7 +309,7 @@ def asset_edit_batch(request):
|
|||
@require_role('admin')
|
||||
def asset_detail(request):
|
||||
"""
|
||||
主机详情
|
||||
Asset detail view
|
||||
"""
|
||||
header_title, path1, path2 = u'主机详细信息', u'资产管理', u'主机详情'
|
||||
asset_id = request.GET.get('id', '')
|
||||
|
@ -316,6 +319,53 @@ def asset_detail(request):
|
|||
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)
|
||||
if not asset:
|
||||
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||
name = request.session.get('username', 'admin')
|
||||
if asset.use_default_auth:
|
||||
username = 'root'
|
||||
password = '123456'
|
||||
else:
|
||||
username = asset.username
|
||||
password = asset.password
|
||||
|
||||
resource = [{"hostname": asset.ip, "port": asset.port,
|
||||
"username": username, "password": password}]
|
||||
|
||||
ansible_instance = Tasks(resource)
|
||||
ansible_asset_info = ansible_instance.get_host_info()
|
||||
if ansible_asset_info['status'] == 'ok':
|
||||
asset_info = ansible_asset_info['result'][asset.ip]
|
||||
if asset_info:
|
||||
hostname = asset_info.get('hostname')
|
||||
other_ip = ','.join(asset_info.get('other_ip'))
|
||||
cpu_type = asset_info.get('cpu_type')[1]
|
||||
cpu_cores = asset_info.get('cpu_cores')
|
||||
cpu = cpu_type + ' * ' + unicode(cpu_cores)
|
||||
memory = asset_info.get('memory')
|
||||
disk = asset_info.get('disk')
|
||||
sn = asset_info.get('sn')
|
||||
brand = asset_info.get('brand')
|
||||
system_type = asset_info.get('system_type')
|
||||
system_version = asset_info.get('system_version')
|
||||
|
||||
asset_dic = {"hostname": hostname, "other_ip": other_ip, "cpu": cpu,
|
||||
"memory": memory, "disk": disk, "system_type": system_type,
|
||||
"system_version": system_version, "brand": brand, "sn": sn
|
||||
}
|
||||
|
||||
ansible_record(asset, asset_dic, name)
|
||||
|
||||
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def idc_add(request):
|
||||
"""
|
||||
|
@ -343,6 +393,9 @@ def idc_add(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', '')
|
||||
|
@ -358,6 +411,10 @@ def idc_list(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':
|
||||
|
@ -372,7 +429,9 @@ def idc_edit(request):
|
|||
|
||||
@require_role('admin')
|
||||
def idc_detail(request):
|
||||
""" IDC详情 """
|
||||
"""
|
||||
IDC detail view
|
||||
"""
|
||||
header_title, path1, path2 = u'IDC详情', u'资产管理', u'IDC详情'
|
||||
idc_id = request.GET.get('id', '')
|
||||
idc = get_object(IDC, id=idc_id)
|
||||
|
@ -384,7 +443,25 @@ def idc_detail(request):
|
|||
|
||||
@require_role('admin')
|
||||
def idc_del(request):
|
||||
"""
|
||||
IDC delete view
|
||||
"""
|
||||
uuid = request.GET.get('uuid', '')
|
||||
idc = get_object_or_404(IDC, uuid=uuid)
|
||||
idc.delete()
|
||||
return HttpResponseRedirect('/jasset/idc_list/')
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def asset_upload(request):
|
||||
"""
|
||||
Upload 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)
|
||||
|
|
|
@ -415,12 +415,29 @@ def str_to_list(info):
|
|||
"""
|
||||
str to list
|
||||
"""
|
||||
print ast.literal_eval(info), type(ast.literal_eval(info))
|
||||
return ast.literal_eval(info)
|
||||
|
||||
|
||||
@register.filter(name='str_to_dic')
|
||||
def str_to_dic(info):
|
||||
"""
|
||||
str to list
|
||||
"""
|
||||
return ast.literal_eval(info).iteritems()
|
||||
|
||||
|
||||
@register.filter(name='str_to_code')
|
||||
def str_to_code(char_str):
|
||||
if char_str:
|
||||
return char_str
|
||||
else:
|
||||
return u'空'
|
||||
|
||||
|
||||
@register.filter(name='ip_str_to_list')
|
||||
def ip_str_to_list(ip_str):
|
||||
"""
|
||||
ip str to list
|
||||
"""
|
||||
return ip_str.split(',')
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="/jasset/asset_add/" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
|
||||
<li><a href="/jasset/host_add_multi" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>
|
||||
<li><a href="/jasset/asset_add_batch" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% include 'nav_cat_bar.html' %}
|
||||
<style>
|
||||
.file-box{ position:relative;width:340px}
|
||||
.txt{ height:22px; border:1px solid #cdcdcd; width:180px;}
|
||||
.file{ position:absolute; top:0; right:80px; height:24px; filter:alpha(opacity:0);opacity: 0;width:260px }
|
||||
</style>
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-lg-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>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ibox-content">
|
||||
<div class="panel blank-panel">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="/jasset/asset_add/" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
|
||||
<li class="active"><a href="/jasset/asset_add_batch/" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="tab-2" class="ibox float-e-margins tab-pane active">
|
||||
{% if emg %}
|
||||
<div class="alert alert-warning text-center">{{ emg }}</div>
|
||||
{% endif %}
|
||||
{% if smg %}
|
||||
<div class="alert alert-success text-center">{{ smg }}</div>
|
||||
{% endif %}
|
||||
<p>请下载Excel文件, 按照格式填写主机信息, 上传导入. <a href="/static/files/excels/asset.xlsx">点击下载模板</a></p>
|
||||
<form action="/jasset/upload/" method="POST" enctype="multipart/form-data">
|
||||
<div class="file-box">
|
||||
<input id='textfield' />
|
||||
<input type="button" class="btn btn-info btn-sm" name="file_name" value="点击选择文件">
|
||||
<input type="file" name="file_name" class="file" id="fileField" size="28" onchange="document.getElementById('textfield').value=this.value" />
|
||||
<button class="btn btn-primary btn-sm" type="submit">上传文件</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -37,6 +37,20 @@
|
|||
<td class="text-navy">主机名</td>
|
||||
<td>{{ asset.hostname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">其他IP</td>
|
||||
<td>
|
||||
<table class="table">
|
||||
{% if asset.other_ip %}
|
||||
{% for ip in asset.other_ip|ip_str_to_list %}
|
||||
<tr>
|
||||
<td>{{ ip }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">远控IP</td>
|
||||
<td>{{ asset.remote_ip }}</td>
|
||||
|
@ -77,11 +91,21 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">内存</td>
|
||||
<td>{{ asset.memory }}</td>
|
||||
<td>{{ asset.memory }}M</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">硬盘</td>
|
||||
<td>{{ asset.disk }}</td>
|
||||
<td>
|
||||
<table class="table">
|
||||
{% if asset.disk %}
|
||||
{% for disk, value in asset.disk|str_to_dic %}
|
||||
<tr>
|
||||
<td><span class="text-navy">{{ disk }}</span>     {{ value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">资产编号</td>
|
||||
|
@ -95,6 +119,10 @@
|
|||
<td class="text-navy">主机类型</td>
|
||||
<td>{{ asset.get_asset_type_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">系统版本</td>
|
||||
<td>{{ asset.system_type }} {{ asset.system_version }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">运行环境</td>
|
||||
<td>{{ asset.get_env_display }}</td>
|
||||
|
|
|
@ -107,7 +107,8 @@
|
|||
<th class="text-center"> 主机名 </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"> 操作系统 </th>
|
||||
<th class="text-center"> 使用默认管理 </th>
|
||||
<th class="text-center"> 操作 </th>
|
||||
</tr>
|
||||
|
@ -122,12 +123,14 @@
|
|||
<td class="text-center"> {{ asset.hostname }} </td>
|
||||
<td class="text-center"> {{ asset.idc.name }} </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.cpu }}|{{ asset.memory }}|{{ asset.disk }}</td>#}
|
||||
<td class="text-center">{{ asset.system_type }}{{ asset.system_version }}</td>
|
||||
<td class="text-center"> {{ asset.use_default_auth|bool2str }} </td>
|
||||
<td class="text-center" data-editable='false'>
|
||||
<a href="/jasset/asset_detail/?id={{ asset.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
{% ifnotequal session_role_id 0 %}
|
||||
<a href="/jasset/asset_edit/?id={{ asset.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
<a href="/jasset/asset_update/?id={{ asset.id }}" class="btn btn-xs btn-info">更新</a>
|
||||
<a value="/jasset/asset_del/?id={{ asset.id }}" class="btn btn-xs btn-danger asset_del">删除</a>
|
||||
{% endifnotequal %}
|
||||
</td>
|
||||
|
|
Loading…
Reference in New Issue