mirror of https://github.com/jumpserver/jumpserver
asset update batch and crontab
parent
b8cb6f4246
commit
5a3c11f619
|
@ -1,459 +0,0 @@
|
||||||
# -*- 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
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import xlsxwriter
|
||||||
from django.db.models import AutoField
|
from django.db.models import AutoField
|
||||||
from jumpserver.api import *
|
from jumpserver.api import *
|
||||||
from jasset.models import ASSET_STATUS, ASSET_TYPE, ASSET_ENV, IDC, AssetRecord
|
from jasset.models import ASSET_STATUS, ASSET_TYPE, ASSET_ENV, IDC, AssetRecord
|
||||||
|
from jperm.ansible_api import MyRunner
|
||||||
|
from jperm.perm_api import gen_resource
|
||||||
|
|
||||||
|
|
||||||
def group_add_asset(group, asset_id=None, asset_ip=None):
|
def group_add_asset(group, asset_id=None, asset_ip=None):
|
||||||
|
@ -406,3 +408,64 @@ def excel_to_db(excel_file):
|
||||||
asset.group = group_instance
|
asset.group = group_instance
|
||||||
asset.save()
|
asset.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_ansible_asset_info(asset_ip, setup_info):
|
||||||
|
disk_all = setup_info.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")
|
||||||
|
|
||||||
|
all_ip = setup_info.get("ansible_all_ipv4_addresses")
|
||||||
|
other_ip_list = all_ip.remove(asset_ip) if asset_ip in all_ip else []
|
||||||
|
other_ip = ','.join(other_ip_list) if other_ip_list else ''
|
||||||
|
# hostname = setup_info.get("ansible_hostname")
|
||||||
|
# ip = setup_info.get("ansible_default_ipv4").get("address")
|
||||||
|
mac = setup_info.get("ansible_default_ipv4").get("macaddress")
|
||||||
|
brand = setup_info.get("ansible_product_name")
|
||||||
|
cpu_type = setup_info.get("ansible_processor")[1]
|
||||||
|
cpu_cores = setup_info.get("ansible_processor_count")
|
||||||
|
cpu = cpu_type + ' * ' + unicode(cpu_cores)
|
||||||
|
memory = setup_info.get("ansible_memtotal_mb")
|
||||||
|
disk = disk_need
|
||||||
|
system_type = setup_info.get("ansible_distribution")
|
||||||
|
system_version = setup_info.get("ansible_distribution_version")
|
||||||
|
# asset_type = setup_info.get("ansible_system")
|
||||||
|
sn = setup_info.get("ansible_product_serial")
|
||||||
|
asset_info = [other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand]
|
||||||
|
|
||||||
|
return asset_info
|
||||||
|
|
||||||
|
|
||||||
|
def asset_ansible_update(obj_list, name=''):
|
||||||
|
resource = gen_resource(obj_list)
|
||||||
|
ansible_instance = MyRunner(resource)
|
||||||
|
ansible_asset_info = ansible_instance.run(module_name='setup', pattern='*')
|
||||||
|
for asset in obj_list:
|
||||||
|
try:
|
||||||
|
setup_info = ansible_asset_info['contacted'][asset.hostname]['ansible_facts']
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
asset_info = get_ansible_asset_info(asset.ip, setup_info)
|
||||||
|
other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand = asset_info
|
||||||
|
asset_dic = {"other_ip": other_ip,
|
||||||
|
"mac": mac,
|
||||||
|
"cpu": cpu,
|
||||||
|
"memory": memory,
|
||||||
|
"disk": disk,
|
||||||
|
"sn": sn,
|
||||||
|
"system_type": system_type,
|
||||||
|
"system_version": system_version,
|
||||||
|
"brand": brand
|
||||||
|
}
|
||||||
|
|
||||||
|
ansible_record(asset, asset_dic, name)
|
||||||
|
|
||||||
|
|
||||||
|
def asset_ansible_update_all():
|
||||||
|
name = u'定时更新'
|
||||||
|
asset_all = Asset.objects.all()
|
||||||
|
asset_ansible_update(asset_all, name)
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ class Asset(models.Model):
|
||||||
memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存')
|
memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存')
|
||||||
disk = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'硬盘')
|
disk = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'硬盘')
|
||||||
system_type = models.CharField(max_length=32, 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_version = models.CharField(max_length=8, blank=True, null=True, verbose_name=u"系统版本号")
|
||||||
cabinet = models.CharField(max_length=32, 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'机器位置')
|
position = models.IntegerField(blank=True, null=True, verbose_name=u'机器位置')
|
||||||
number = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'资产编号')
|
number = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'资产编号')
|
||||||
|
|
|
@ -11,6 +11,7 @@ urlpatterns = patterns('',
|
||||||
url(r"^asset_detail/$", asset_detail),
|
url(r"^asset_detail/$", asset_detail),
|
||||||
url(r'^asset_edit/$', asset_edit),
|
url(r'^asset_edit/$', asset_edit),
|
||||||
url(r'^asset_update/$', asset_update),
|
url(r'^asset_update/$', asset_update),
|
||||||
|
url(r'^asset_update_batch/$', asset_update_batch),
|
||||||
# url(r'^search/$', host_search),
|
# url(r'^search/$', host_search),
|
||||||
# url(r"^show_all_ajax/$", show_all_ajax),
|
# url(r"^show_all_ajax/$", show_all_ajax),
|
||||||
url(r'^group_add/$', group_add),
|
url(r'^group_add/$', group_add),
|
||||||
|
|
|
@ -6,7 +6,8 @@ from jumpserver.api import *
|
||||||
from jumpserver.models import Setting
|
from jumpserver.models import Setting
|
||||||
from jasset.forms import AssetForm, IdcForm
|
from jasset.forms import AssetForm, IdcForm
|
||||||
from jasset.models import Asset, IDC, AssetGroup, ASSET_TYPE, ASSET_STATUS
|
from jasset.models import Asset, IDC, AssetGroup, ASSET_TYPE, ASSET_STATUS
|
||||||
from ansible_api import Tasks
|
from jperm.ansible_api import Tasks, MyRunner
|
||||||
|
from jperm.perm_api import gen_resource
|
||||||
|
|
||||||
|
|
||||||
@require_role('admin')
|
@require_role('admin')
|
||||||
|
@ -197,7 +198,7 @@ def asset_edit(request):
|
||||||
header_title, path1, path2 = u'修改资产', u'资产管理', u'修改资产'
|
header_title, path1, path2 = u'修改资产', u'资产管理', u'修改资产'
|
||||||
|
|
||||||
asset_id = request.GET.get('id', '')
|
asset_id = request.GET.get('id', '')
|
||||||
username = request.session.get('username', 'admin')
|
username = request.user.username
|
||||||
asset = get_object(Asset, id=asset_id)
|
asset = get_object(Asset, id=asset_id)
|
||||||
if asset:
|
if asset:
|
||||||
password_old = asset.password
|
password_old = asset.password
|
||||||
|
@ -311,7 +312,7 @@ def asset_list(request):
|
||||||
@require_role('admin')
|
@require_role('admin')
|
||||||
def asset_edit_batch(request):
|
def asset_edit_batch(request):
|
||||||
af = AssetForm()
|
af = AssetForm()
|
||||||
name = request.session.get('username', 'admin')
|
name = request.user.username
|
||||||
asset_group_all = AssetGroup.objects.all()
|
asset_group_all = AssetGroup.objects.all()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -409,55 +410,30 @@ def asset_update(request):
|
||||||
"""
|
"""
|
||||||
asset_id = request.GET.get('id', '')
|
asset_id = request.GET.get('id', '')
|
||||||
asset = get_object(Asset, id=asset_id)
|
asset = get_object(Asset, id=asset_id)
|
||||||
name = request.session.get('username', 'admin')
|
name = request.user.username
|
||||||
if not asset:
|
if not asset:
|
||||||
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||||
if asset.use_default_auth:
|
|
||||||
default = Setting.objects.all()
|
|
||||||
if default:
|
|
||||||
default = default[0]
|
|
||||||
username = default.default_user
|
|
||||||
password = CRYPTOR.decrypt(default.default_password)
|
|
||||||
port = default.default_port
|
|
||||||
else:
|
|
||||||
return HttpResponse(u'没有设置默认用户名和密码!')
|
|
||||||
else:
|
else:
|
||||||
username = asset.username
|
asset_ansible_update(asset_list, name)
|
||||||
password = CRYPTOR.decrypt(asset.password)
|
|
||||||
port = asset.port
|
|
||||||
|
|
||||||
resource = [{"hostname": asset.ip, "port": 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')
|
|
||||||
all_ip = asset_info.get('other_ip')
|
|
||||||
other_ip_list = all_ip.remove(asset.ip) if asset.ip in all_ip else []
|
|
||||||
other_ip = ','.join(other_ip_list) if other_ip_list else ''
|
|
||||||
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)
|
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||||
|
|
||||||
|
|
||||||
|
@require_role('admin')
|
||||||
|
def asset_update_batch(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
asset_list = []
|
||||||
|
name = unicode(request.user.username) + ' - ' + u'自动更新'
|
||||||
|
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')
|
@require_role('admin')
|
||||||
def idc_add(request):
|
def idc_add(request):
|
||||||
"""
|
"""
|
||||||
|
@ -478,9 +454,7 @@ def idc_add(request):
|
||||||
return HttpResponseRedirect("/jasset/idc_list/")
|
return HttpResponseRedirect("/jasset/idc_list/")
|
||||||
else:
|
else:
|
||||||
idc_form = IdcForm()
|
idc_form = IdcForm()
|
||||||
return render_to_response('jasset/idc_add.html',
|
return my_render('jasset/idc_add.html', locals(), request)
|
||||||
locals(),
|
|
||||||
context_instance=RequestContext(request))
|
|
||||||
|
|
||||||
|
|
||||||
@require_role('admin')
|
@require_role('admin')
|
||||||
|
@ -496,9 +470,7 @@ def idc_list(request):
|
||||||
else:
|
else:
|
||||||
posts = IDC.objects.exclude(name='ALL').order_by('id')
|
posts = IDC.objects.exclude(name='ALL').order_by('id')
|
||||||
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
|
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
|
||||||
return render_to_response('jasset/idc_list.html',
|
return my_render('jasset/idc_list.html', locals(), request)
|
||||||
locals(),
|
|
||||||
context_instance=RequestContext(request))
|
|
||||||
|
|
||||||
|
|
||||||
@require_role('admin')
|
@require_role('admin')
|
||||||
|
|
|
@ -66,6 +66,7 @@ INSTALLED_APPS = (
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'django.contrib.humanize',
|
'django.contrib.humanize',
|
||||||
|
'django_crontab',
|
||||||
'bootstrapform',
|
'bootstrapform',
|
||||||
'jumpserver',
|
'jumpserver',
|
||||||
'juser',
|
'juser',
|
||||||
|
@ -149,3 +150,7 @@ USE_TZ = False
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
BOOTSTRAP_COLUMN_COUNT = 10
|
BOOTSTRAP_COLUMN_COUNT = 10
|
||||||
|
|
||||||
|
CRONJOBS = [
|
||||||
|
('0 1 * * *', 'jasset.asset_api.asset_ansible_update_all')
|
||||||
|
]
|
||||||
|
|
|
@ -11,9 +11,15 @@
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span class="text text-primary"><b>{{ asset.ip }}</b></span>
|
<span class="text text-primary"><b>{{ asset.ip }}</b></span>
|
||||||
<div class="ibox-tools">
|
<div class="ibox-tools">
|
||||||
|
<a class="" href="/jasset/asset_update/?id={{ asset.id }}">
|
||||||
|
<i class="fa fa-refresh"></i>
|
||||||
|
</a>
|
||||||
<a class="collapse-link">
|
<a class="collapse-link">
|
||||||
<i class="fa fa-chevron-up"></i>
|
<i class="fa fa-chevron-up"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-user">
|
<ul class="dropdown-menu dropdown-user">
|
||||||
</ul>
|
</ul>
|
||||||
<a class="close-link">
|
<a class="close-link">
|
||||||
|
|
|
@ -96,6 +96,12 @@
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
{{ af.memory|bootstrap_horizontal }}
|
{{ af.memory|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>
|
<div class="hr-line-dashed"></div>
|
||||||
{{ af.disk|bootstrap_horizontal }}
|
{{ af.disk|bootstrap_horizontal }}
|
||||||
|
|
||||||
|
|
|
@ -54,29 +54,17 @@
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<div class="radio i-checks">
|
<div class="radio i-checks">
|
||||||
<label>
|
<label>
|
||||||
<<<<<<< HEAD
|
|
||||||
<input type="radio" checked="" value="no_action" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
|
|
||||||
=======
|
|
||||||
<input type="radio" checked="" value="" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
|
<input type="radio" checked="" value="" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
|
||||||
>>>>>>> cmdb
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio i-checks">
|
<div class="radio i-checks">
|
||||||
<label>
|
<label>
|
||||||
<<<<<<< HEAD
|
|
||||||
<input type="radio" id="default" name="use_default_auth" class="auth"><span> 使用默认 </span>
|
|
||||||
=======
|
|
||||||
<input type="radio" id="default" name="use_default_auth" class="auth" value="default"><span> 使用默认 </span>
|
<input type="radio" id="default" name="use_default_auth" class="auth" value="default"><span> 使用默认 </span>
|
||||||
>>>>>>> cmdb
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio i-checks">
|
<div class="radio i-checks">
|
||||||
<label>
|
<label>
|
||||||
<<<<<<< HEAD
|
|
||||||
<input type="radio" id="pass" name="use_default_auth" class="auth"><span> 用户名密码 </span>
|
|
||||||
=======
|
|
||||||
<input type="radio" id="pass" name="use_default_auth" class="auth" value="user_passwd"><span> 用户名密码 </span>
|
<input type="radio" id="pass" name="use_default_auth" class="auth" value="user_passwd"><span> 用户名密码 </span>
|
||||||
>>>>>>> cmdb
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -138,21 +126,6 @@
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
<<<<<<< HEAD
|
|
||||||
$('#host_edit').click(function () {
|
|
||||||
var args = {};
|
|
||||||
var match = null;
|
|
||||||
var uuid = decodeURIComponent(location.search.substring(1));
|
|
||||||
var reg = /(?:([^&]+)=([^&]+))/g;
|
|
||||||
while((match = reg.exec(uuid))!==null){
|
|
||||||
args[match[1]] = match[2];
|
|
||||||
}
|
|
||||||
var ids = args['uuid'];
|
|
||||||
$('#uuid').val(ids)
|
|
||||||
});
|
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> cmdb
|
|
||||||
$('.auth').click(function(){
|
$('.auth').click(function(){
|
||||||
if ($(this).attr('id') == 'pass'){
|
if ($(this).attr('id') == 'pass'){
|
||||||
$('#admin_account').css('display', 'block')
|
$('#admin_account').css('display', 'block')
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<a href="/jasset/asset_detail/?id={{ asset.id }}" class="btn btn-xs btn-primary">详情</a>
|
<a href="/jasset/asset_detail/?id={{ asset.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||||
{% ifnotequal session_role_id 0 %}
|
{% ifnotequal session_role_id 0 %}
|
||||||
<a href="/jasset/asset_edit/?id={{ asset.id }}" class="btn btn-xs btn-info">编辑</a>
|
<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>
|
<a value="/jasset/asset_del/?id={{ asset.id }}" class="btn btn-xs btn-danger asset_del">删除</a>
|
||||||
{% endifnotequal %}
|
{% endifnotequal %}
|
||||||
</td>
|
</td>
|
||||||
|
@ -142,7 +141,7 @@
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input type="button" id="asset_del" class="btn btn-danger btn-sm" name="del_button" value="删除"/>
|
<input type="button" id="asset_del" class="btn btn-danger btn-sm" name="del_button" value="删除"/>
|
||||||
<a value="/jasset/asset_edit_batch/" type="button" class="btn btn-sm btn-warning iframe">修改</a>
|
<a value="/jasset/asset_edit_batch/" type="button" class="btn btn-sm btn-warning iframe">修改</a>
|
||||||
<a value="/jasset/asset_update_batch/" type="button" class="btn btn-sm btn-info">更新</a>
|
<input type="button" id="asset_update" class="btn btn-info btn-sm" name="update_button" value="更新"/>
|
||||||
</div>
|
</div>
|
||||||
{% include 'paginator.html' %}
|
{% include 'paginator.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -156,23 +155,10 @@
|
||||||
|
|
||||||
{% block self_footer_js %}
|
{% block self_footer_js %}
|
||||||
<script>
|
<script>
|
||||||
$('table td').on('change', function(env, id){
|
|
||||||
var url = "/jasset/show_all_ajax/?env=" + env + "&id=" + id;
|
|
||||||
console.log(url);
|
|
||||||
$.ajax({
|
|
||||||
type: "GET",
|
|
||||||
url: url,
|
|
||||||
// data: $("#search_form").serialize(),
|
|
||||||
success: function (data) {
|
|
||||||
$("#j_dept_"+id).html(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$('.asset_del').click(function(){
|
$('.asset_del').click(function(){
|
||||||
var row = $(this).closest('tr');
|
var row = $(this).closest('tr');
|
||||||
if (confirm("确定删除")) {
|
if (confirm("确定删除?")) {
|
||||||
$.get(
|
$.get(
|
||||||
$(this).attr('value'),
|
$(this).attr('value'),
|
||||||
{},
|
{},
|
||||||
|
@ -222,12 +208,11 @@
|
||||||
|
|
||||||
$('#asset_del').click(function () {
|
$('#asset_del').click(function () {
|
||||||
var asset_id_all = getIDall();
|
var asset_id_all = getIDall();
|
||||||
console.log(asset_id_all);
|
|
||||||
if (asset_id_all == ''){
|
if (asset_id_all == ''){
|
||||||
alert("请至少选择一行!");
|
alert("请至少选择一行!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (confirm("确定删除")) {
|
if (confirm("确定删除?")) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "post",
|
type: "post",
|
||||||
data: {asset_id_all: asset_id_all},
|
data: {asset_id_all: asset_id_all},
|
||||||
|
@ -239,6 +224,23 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#asset_update').click(function () {
|
||||||
|
var asset_id_all = getIDall();
|
||||||
|
if (asset_id_all == ''){
|
||||||
|
alert("请至少选择一行!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
layer.msg('玩命更新中...', {time: 200000});
|
||||||
|
$.ajax({
|
||||||
|
type: "post",
|
||||||
|
data: {asset_id_all: asset_id_all},
|
||||||
|
url: "/jasset/asset_update_batch/",
|
||||||
|
success: function () {
|
||||||
|
parent.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function change_info(){
|
function change_info(){
|
||||||
var args = $("#asset_form").serialize();
|
var args = $("#asset_form").serialize();
|
||||||
|
@ -250,19 +252,6 @@
|
||||||
change_info()
|
change_info()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function show_all(env, id) {
|
|
||||||
var url = "/jasset/show_all_ajax/?env=" + env + "&id=" + id;
|
|
||||||
console.log(url);
|
|
||||||
$.ajax({
|
|
||||||
type: "GET",
|
|
||||||
url: url,
|
|
||||||
success: function (data) {
|
|
||||||
$("#j_group_" + id).html(data);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
Loading…
Reference in New Issue