From 34ccaeb10f7679d0d8745f58f8fdd7d420bddeee Mon Sep 17 00:00:00 2001 From: ibuler Date: Sat, 5 Dec 2015 12:03:18 +0800 Subject: [PATCH] fix push role bug --- jasset/views.py | 2 +- jperm/ansible_api.py | 155 +++++--------------------------- jperm/perm_api.py | 14 --- jperm/views.py | 84 ++++++++++------- jumpserver/views.py | 8 +- templates/jlog/file_detail.html | 140 +++++++++++++++++++++++++++++ 6 files changed, 218 insertions(+), 185 deletions(-) create mode 100644 templates/jlog/file_detail.html diff --git a/jasset/views.py b/jasset/views.py index ac8f166dc..7f7621892 100644 --- a/jasset/views.py +++ b/jasset/views.py @@ -7,7 +7,7 @@ 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 -from jperm.ansible_api import Tasks, MyRunner +from jperm.ansible_api import MyRunner from jperm.perm_api import gen_resource diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 422c65a03..57c01d158 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -119,8 +119,8 @@ class MyRunner(MyInventory): super(MyRunner, self).__init__(*args, **kwargs) self.results_raw = {} - def run(self, module_name='shell', module_args='', timeout=10, forks=10, pattern='', - sudo=False, sudo_user='root', sudo_pass=''): + def run(self, module_name='shell', module_args='', timeout=10, forks=10, pattern='*', + become=False, become_method='sudo', become_user='root', become_pass=''): """ run module from andible ad-hoc. module_name: ansible module_name @@ -132,10 +132,10 @@ class MyRunner(MyInventory): inventory=self.inventory, pattern=pattern, forks=forks, - become=sudo, - become_method='sudo', - become_user=sudo_user, - become_pass=sudo_pass + become=become, + become_method=become_method, + become_user=become_user, + become_pass=become_pass ) self.results_raw = hoc.run() return self.results_raw @@ -156,7 +156,7 @@ class MyRunner(MyInventory): for host, info in contacted.items(): if info.get('failed'): result['failed'][host] = info.get('msg') + info.get('stderr', '') - elif info.get('stderr'): + elif info.get('stderr') and info.get('module_name') in ['shell', 'command', 'raw']: result['failed'][host] = info.get('stderr') + str(info.get('warnings')) else: result['ok'][host] = info.get('stdout') @@ -265,60 +265,21 @@ class Command(MyInventory): return self.results_raw.get("dark") -class Tasks(Command): +class MyTask(MyRunner): """ 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='default_group', - pattern='*', - ): - """ - 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, - pattern=pattern, - forks=forks, - become=False, - ) - - self.results = hoc.run() - return {"msg": self.msg, "result": self.results} - - @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 + super(MyTask, self).__init__(*args, **kwargs) def push_key(self, user, key_path): """ push the ssh authorized key to target. """ module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state=present' % (user, key_path) - self.__run(module_args, "authorized_key") + self.run("authorized_key", module_args, become=True) - return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"} + return self.results def push_multi_key(self, **user_info): """ @@ -345,9 +306,9 @@ class Tasks(Command): 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") + self.run("authorized_key", module_args, become=True) - return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"} + return self.results def add_user(self, username, password=''): """ @@ -358,9 +319,9 @@ class Tasks(Command): module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass) else: module_args = 'name=%s shell=/bin/bash' % username - self.__run(module_args, "user") + self.run("user", module_args, become=True) - return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"} + return self.results def add_multi_user(self, **user_info): """ @@ -387,85 +348,10 @@ class Tasks(Command): """ delete a host user. """ - module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % (username) - self.__run(module_args, - "user",) + module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % username + self.run("user", module_args, become=True) - 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'): - disk_need[disk_name] = disk_info.get("size") - - result[key] = { - "all_ip": setup.get("ansible_all_ipv4_addresses"), - "hostname" : setup.get("ansible_hostname"), - "default_ip": setup.get("ansible_default_ipv4").get("address"), - "default_mac": setup.get("ansible_default_ipv4").get("macaddress"), - "product_name": setup.get("ansible_product_name"), - "processor_type": ' '.join(setup.get("ansible_processor")), - "processor_count": setup.get("ansible_processor_count"), - "memory_total": setup.get("ansible_memtotal_mb"), - "disk": disk_need, - "system_type": setup.get("ansible_system"), - "system_dist": setup.get("ansible_distribution"), - "system_dist_verion": setup.get("ansible_distribution_major_version"), - "product_sn": setup.get("ansible_product_serial") - } - - return {"failed": self.msg, "ok": result} + return self.results def push_sudo_file(self, file_path): """ @@ -473,8 +359,9 @@ class Tasks(Command): :return: """ module_args1 = file_path - ret = self.__run(module_args1, "script") - return ret + self.run("script", module_args1, become=True) + print self.results_raw + return self.results class CustomAggregateStats(callbacks.AggregateStats): diff --git a/jperm/perm_api.py b/jperm/perm_api.py index 11a26a079..224d6d2a5 100644 --- a/jperm/perm_api.py +++ b/jperm/perm_api.py @@ -302,20 +302,6 @@ def get_role_push_host(role): return asset_pushed, asset_no_push -@require_role('user') -def perm_role_get(request): - asset_id = request.GET.get('id', 0) - if asset_id: - asset = get_object(Asset, id=asset_id) - if asset: - role = user_have_perm(request.user, asset=asset) - return HttpResponse(','.join([i.name for i in role])) - else: - roles = get_group_user_perm(request.user).get('role').keys() - return HttpResponse(','.join(i.name for i in roles)) - return HttpResponse('error') - - if __name__ == "__main__": print get_role_info(1) diff --git a/jperm/views.py b/jperm/views.py index 110b36c76..9d8fdc281 100644 --- a/jperm/views.py +++ b/jperm/views.py @@ -11,9 +11,8 @@ from jperm.models import PermRole, PermRule, PermSudo, PermPush from jumpserver.models import Setting from jperm.utils import updates_dict, gen_keys, get_rand_pass, get_add_sudo_script -from jperm.ansible_api import Tasks +from jperm.ansible_api import MyTask from jperm.perm_api import get_role_info, get_role_push_host - from jumpserver.api import my_render, get_object, CRYPTOR @@ -211,8 +210,6 @@ def perm_rule_delete(request): # 根据rule_id 取得rule对象 rule_id = request.POST.get("id") rule_obj = PermRule.objects.get(id=rule_id) - print rule_id, rule_obj - print rule_obj.name rule_obj.delete() return HttpResponse(u"删除授权规则:%s" % rule_obj.name) else: @@ -423,25 +420,18 @@ def perm_role_push(request): # 调用Ansible API 进行推送 password_push = True if request.POST.get("use_password") else False key_push = True if request.POST.get("use_publicKey") else False - task = Tasks(push_resource) + task = MyTask(push_resource) ret = {} - ret_failed = {} # 因为要先建立用户,所以password 是必选项,而push key是在 password也完成的情况下的 可选项 - # 1. 以password 方式推送角色 - if password_push: - ret["password_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password)) - if ret["password_push"].get("status") != "success": - ret_failed = ret["password_push"].get('msg') - - # 2. 以秘钥 方式推送角色 + # 1. 以秘钥 方式推送角色 if key_push: - ret["password_push"] = task.add_user(role.name) - if ret["password_push"].get("status") != "ok": - ret_failed = ret["password_push"].get('msg') + ret["pass_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password)) ret["key_push"] = task.push_key(role.name, os.path.join(role.key_path, 'id_rsa.pub')) - if ret["key_push"].get("status") != "ok": - ret_failed = ret["key_push"].get('msg') + + # 2. 推送账号密码 + elif password_push: + ret["pass_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password)) # 3. 推送sudo配置文件 if password_push or key_push: @@ -451,16 +441,32 @@ def perm_role_push(request): role_chosen_aliase[role.name] = ','.join(sudo.name for sudo in sudo_alias if sudo.name) add_sudo_script = get_add_sudo_script(role_chosen_aliase, sudo_alias) ret['sudo'] = task.push_sudo_file(add_sudo_script) - - if ret['sudo'].get('msg'): - ret_failed = ret['sudo'].get('msg') os.remove(add_sudo_script) logger.debug('推送role结果: %s' % ret) - logger.debug('推送role错误: %s' % ret_failed) + success_asset = {} + failed_asset = {} + logger.debug(ret) + for push_type, result in ret.items(): + if result.get('failed'): + for hostname, info in result.get('failed').items(): + if hostname in failed_asset.keys(): + if info in failed_asset.get(hostname): + failed_asset[hostname] += info + else: + failed_asset[hostname] = info + + for push_type, result in ret.items(): + if result.get('ok'): + for hostname, info in result.get('ok').items(): + if hostname in failed_asset.keys(): + continue + elif hostname in success_asset.keys(): + if str(info) in success_asset.get(hostname, ''): + success_asset[hostname] += str(info) + else: + success_asset[hostname] = str(info) - success_asset = [] - failed_asset = [] # 推送成功 回写push表 for asset in calc_assets: push_check = PermPush.objects.filter(role=role, asset=asset) @@ -470,20 +476,18 @@ def perm_role_push(request): def func(**kwargs): PermPush(**kwargs).save() - if ret_failed.get(asset.hostname): - failed_asset.append(asset) + if failed_asset.get(asset.hostname): func(is_password=password_push, is_public_key=key_push, role=role, asset=asset, success=False, - result=ret_failed.get(asset.hostname)) + result=failed_asset.get(asset.hostname)) else: - success_asset.append(asset) func(is_password=password_push, is_public_key=key_push, role=role, asset=asset, success=True) if not failed_asset: - msg = u'角色 %s 推送成功[ %s ]' % (role.name, ','.join([asset.hostname for asset in success_asset])) + msg = u'角色 %s 推送成功[ %s ]' % (role.name, ','.join(success_asset.keys())) else: error = u'角色 %s 推送失败 [ %s ], 推送成功 [ %s ]' % (role.name, - ','.join([asset.hostname for asset in failed_asset]), - ','.join([asset.hostname for asset in success_asset])) + ','.join(failed_asset.keys()), + ','.join(success_asset.keys())) return my_render('jperm/perm_role_push.html', locals(), request) @@ -586,11 +590,29 @@ def perm_sudo_delete(request): def perm_role_recycle(request): role_id = request.GET.get('role_id') asset_ids = request.GET.get('asset_id').split(',') + assets = [] for asset_id in asset_ids: asset = get_object(Asset, id=asset_id) + assets.append(asset) role = get_object(PermRole, id=role_id) PermPush.objects.filter(asset=asset, role=role).delete() + + res = gen_resource(assets) + task = MyTask(res) + return HttpResponse('删除成功') +@require_role('user') +def perm_role_get(request): + asset_id = request.GET.get('id', 0) + if asset_id: + asset = get_object(Asset, id=asset_id) + if asset: + role = user_have_perm(request.user, asset=asset) + return HttpResponse(','.join([i.name for i in role])) + else: + roles = get_group_user_perm(request.user).get('role').keys() + return HttpResponse(','.join(i.name for i in roles)) + return HttpResponse('error') diff --git a/jumpserver/views.py b/jumpserver/views.py index dfa312819..ed144bdf6 100644 --- a/jumpserver/views.py +++ b/jumpserver/views.py @@ -302,8 +302,6 @@ def upload(request): illegal_asset = set(asset_select).issubset(set(assets)) return HttpResponse('没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset])) - - for upload_file in upload_files: file_path = '%s/%s' % (upload_dir, upload_file.name) with open(file_path, 'w') as f: @@ -320,11 +318,11 @@ def upload(request): filename=' '.join([f.name for f in upload_files]), type='upload', remote_ip=remote_ip, result=ret).save() if ret.get('failed'): - error = '上传目录: %s
上传失败: [ %s ]
上传成功 [ %s ]' % (upload_dir, + error = u'上传目录: %s
上传失败: [ %s ]
上传成功 [ %s ]' % (upload_dir, ', '.join(ret.get('failed').keys()), ', '.join(ret.get('ok').keys())) return HttpResponse(error, status=500) - msg = '上传目录: %s
传送成功 [ %s ]' % (upload_dir, ', '.join(ret.get('ok')).keys()) + msg = u'上传目录: %s
传送成功 [ %s ]' % (upload_dir, ', '.join(ret.get('ok').keys())) return HttpResponse(msg) return my_render('upload.html', locals(), request) @@ -345,7 +343,7 @@ def download(request): if not set(asset_select).issubset(set(assets)): illegal_asset = set(asset_select).issubset(set(assets)) - return HttpResponse('没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset])) + return HttpResponse(u'没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset])) res = gen_resource({'user': user, 'asset': asset_select}) runner = MyRunner(res) diff --git a/templates/jlog/file_detail.html b/templates/jlog/file_detail.html new file mode 100644 index 000000000..69a25880f --- /dev/null +++ b/templates/jlog/file_detail.html @@ -0,0 +1,140 @@ +{% extends 'base.html' %} +{% load mytags %} +{% block content %} + {% include 'nav_cat_bar.html' %} +
+
+
+
+
+ {{ log.id }} +
+ + + + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID{{ log.id }}
用户名{{ log.user }}
来源IP{{ log.remote_ip }}
类型{{ log.type }}
日期{{ log.datetime|date:"Y-m-d H:i:s" }}
文件 + + {% for file_name in file_list %} + {% if file_name %} + + + + {% endif %} + {% endfor %} +
{{ file_name }}
+
主机 + + {% for asset_name in assets_hostname %} + {% if asset_name %} + + + + {% endif %} + {% endfor %} +
{{ asset_name }}
+
+
+
+
+
+
+
+
+
+
结果
+
+ + + + + + + + + + +
+
+
+
+
+ + {% for result, info in result.items %} + {% for host, msg in info.items %} + {% ifequal result 'failed' %} + + + + + {% else %} + + + + + {% endifequal %} + {% endfor %} + {% endfor %} +
{{ host }}{{ msg }}
{{ host }}{{ msg }}
+
+
+
+
+
+ +
+
+ + + + +{% endblock %} \ No newline at end of file