From ab313aacd85d811dfff5a4892c6dd79e3dba7134 Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 20 Nov 2015 18:42:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9A=E4=B9=89Command=E5=89=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 99 ++++++++++------ jperm/ansible_api.py | 70 ++++++++---- jperm/models.py | 14 --- jperm/perm_api.py | 265 +------------------------------------------ jumpserver/api.py | 8 +- templates/nav.html | 4 +- 6 files changed, 126 insertions(+), 334 deletions(-) diff --git a/connect.py b/connect.py index 8558ed745..15f4c19b4 100644 --- a/connect.py +++ b/connect.py @@ -22,7 +22,7 @@ if django.get_version() != '1.6': from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object, mkdir from jumpserver.api import logger, Log, TtyLog from jumpserver.settings import LOG_DIR - +from jperm.ansible_api import Command login_user = get_object(User, username=getpass.getuser()) VIM_FLAG = False @@ -301,18 +301,24 @@ class Tty(object): ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: - if connect_info.get('role_pass'): - ssh.connect(connect_info.get('ip'), - port=connect_info.get('port'), - username=connect_info.get('role_name'), - password=connect_info.get('role_pass'), - look_for_keys=False) - else: - ssh.connect(connect_info.get('ip'), - port=connect_info.get('port'), - username=connect_info.get('role_name'), - key_filename=connect_info.get('role_key'), - look_for_keys=False) + role_key = connect_info.get('role_key') + if role_key and os.path.isfile(role_key): + try: + ssh.connect(connect_info.get('ip'), + port=connect_info.get('port'), + username=connect_info.get('role_name'), + key_filename=role_key, + look_for_keys=False) + self.ssh = ssh + return ssh + except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException: + pass + + ssh.connect(connect_info.get('ip'), + port=connect_info.get('port'), + username=connect_info.get('role_name'), + password=connect_info.get('role_pass'), + look_for_keys=False) except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException: raise ServerError('认证失败 Authentication Error.') @@ -458,23 +464,6 @@ class SshTty(Tty): channel.close() ssh.close() - def execute(self, cmd): - """ - execute cmd on the asset - 执行命令 - """ - pass - - -def print_user_asset_group_info(user): - asset_groups = AssetGroup.objects.all() - for asset_group in asset_groups: - if asset_group.comment: - print '[%-2s] %-10s %s' % (asset_group.id, asset_group.name, asset_group.comment) - else: - print '[%-2s] %-10s' % (asset_group.id, asset_group.name) - print - class Nav(object): def __init__(self, user): @@ -544,6 +533,52 @@ class Nav(object): print '[%-3s] %-15s' % (asset_group.id, asset_group.name) print + def exec_cmd(self): + self.search() + while True: + print "请输入主机名、IP或ansile支持的pattern, q退出" + try: + pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip() + if pattern == 'q': + break + else: + res = { + "group1": { + "hosts": [{"hostname": "127.0.0.1", "port": "22", "username": "lastimac", "password": "redhat"}, {"hostname": "192.168.244.129", "port": "22", "username": "root", "password": "redhat"}, {"hostname": "j", "port": "22", "username": "root", "password": "redhat"}], + "vars": {"var1": 'a', "var2": 'a'} + } + } + cmd = Command(res) + for inv in cmd.inventory.get_hosts(pattern=pattern): + print inv.name + confirm_host = raw_input("\033[1;32mIs that [y/n]>:\033[0m ").strip() + if confirm_host == 'y': + while True: + print "请输入执行的命令, 按q退出" + command = raw_input("\033[1;32mCmds>:\033[0m ").strip() + if command == 'q': + break + result = cmd.run(module_name='shell', command=command, pattern=pattern) + for k, v in result.items(): + if k == 'ok': + for host, output in v.items(): + color_print("%s => %s" % (host, 'Ok'), 'green') + print output + print + else: + for host, output in v.items(): + color_print("%s => %s" % (host, k), 'red') + color_print(output, 'red') + print + print "=" * 20 + print + else: + continue + + except EOFError: + print + break + def main(): """ @@ -575,8 +610,8 @@ def main(): nav.print_asset_group() continue elif option in ['E', 'e']: - # exec_cmd_servers(login_name) - pass + nav.exec_cmd() + continue elif option in ['Q', 'q', 'exit']: sys.exit() else: diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 4e66da246..f10d89576 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -107,43 +107,72 @@ class MyInventory(object): self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars")) +class MyRunner(MyInventory): + """ + This is a General object for parallel execute modules. + """ + def __init__(self, *args, **kwargs): + super(MyRunner, self).__init__(*args, **kwargs) + self.results = {} + + def run(self, module_name, module_args='', timeout=10, forks=10, pattern='', + sudo=False, sudo_user='root', sudo_pass=''): + """ + run module from andible ad-hoc. + module_name: ansible module_name + module_args: ansible module args + """ + hoc = Runner(module_name=module_name, + module_args=module_args, + timeout=timeout, + inventory=self.inventory, + pattern=pattern, + forks=forks, + become=sudo, + become_method='sudo', + become_user=sudo_user, + become_pass=sudo_pass + ) + self.results = hoc.run() + return self.results + + 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 = '' + self.results = {} - def run(self, command, module_name="command", timeout=10, forks=10, group='default_group', pattern='*'): + def run(self, command, module_name="command", timeout=10, forks=10, pattern='*'): """ run command from andible ad-hoc. command : 必须是一个需要执行的命令字符串, 比如 'uname -a' """ + data = {} 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, - pattern=pattern, - forks=forks, + "module_name must be of the 'raw, command, shell'") + hoc = MyRunner(module_name=module_name, + module_args=command, + timeout=timeout, + inventory=self.inventory, + pattern=pattern, + 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} + data['ok'] = self.stdout + if self.stderr: + data['err'] = self.stderr + if self.dark: + data['dark'] = self.dark + + return data @property def raw_results(self): @@ -174,7 +203,7 @@ class Command(MyInventory): result = {} all = self.results.get("contacted") for key, value in all.iteritems(): - result[key] = value.get("stdout") + result[key] = value.get("stdout") return result @property @@ -185,7 +214,8 @@ class Command(MyInventory): result = {} all = self.results.get("contacted") for key, value in all.iteritems(): - result[key] = { + if value.get("stderr") or value.get("warnings"): + result[key] = { "stderr": value.get("stderr"), "warnings": value.get("warnings"),} return result diff --git a/jperm/models.py b/jperm/models.py index dc8643b67..39bb9a3f5 100644 --- a/jperm/models.py +++ b/jperm/models.py @@ -5,20 +5,6 @@ from jasset.models import Asset, AssetGroup from juser.models import User, UserGroup -class PermLog(models.Model): - datetime = models.DateTimeField(auto_now_add=True) - action = models.CharField(max_length=100, null=True, blank=True, default='') - results = models.CharField(max_length=1000, null=True, blank=True, default='') - is_success = models.BooleanField(default=False) - is_finish = models.BooleanField(default=False) - - -class SysUser(models.Model): - username = models.CharField(max_length=100) - password = models.CharField(max_length=100) - comment = models.CharField(max_length=100, null=True, blank=True, default='') - - class PermRole(models.Model): name = models.CharField(max_length=100, unique=True) comment = models.CharField(max_length=100, null=True, blank=True, default='') diff --git a/jperm/perm_api.py b/jperm/perm_api.py index 1b363f547..5496020e5 100644 --- a/jperm/perm_api.py +++ b/jperm/perm_api.py @@ -4,12 +4,10 @@ from jumpserver.api import * import uuid import re -from jumpserver.tasks import playbook_run from jumpserver.models import Setting -from jperm.models import PermLog - from jperm.models import PermRole +from jperm.models import PermRule def get_object_list(model, id_list): @@ -22,267 +20,6 @@ def get_object_list(model, id_list): return object_list -def get_rand_file_path(base_dir=os.path.join(BASE_DIR, 'tmp')): - """获取随机文件路径""" - filename = uuid.uuid1().hex - return os.path.join(base_dir, filename) - - -def get_inventory(host_group): - """生成资产表库存清单""" - path = get_rand_file_path() - f = open(path, 'w') - for group, host_list in host_group.items(): - f.write('[%s]\n' % group) - for ip in host_list: - asset = get_object(Asset, ip=ip) - if asset.use_default: - f.write('%s\n' % ip) - else: - f.write('%s ansible_ssh_port=%s ansible_ssh_user=%s ansible_ssh_pass=%s\n' % - (ip, asset.port, asset.username, CRYPTOR.decrypt(asset.password))) - f.close() - return path - - -def get_playbook(template, var): - """根据playbook模板,生成playbook""" - str_playbook = open(template).read() - for k, v in var.items(): - str_playbook = re.sub(r'%s' % k, v, str_playbook) # 正则来替换传入的字符 - path = get_rand_file_path() - f = open(path, 'w') - f.write(str_playbook) - return path - - -def perm_user_api(perm_info): - """ - 用户授权api,通过调用ansible API完成用户新建等,传入参数必须如下,列表中可以是对象,也可以是用户名和ip - perm_info = {'del': {'users': [], - 'assets': [], - }, - 'new': {'users': [], - 'assets': []}} - """ - log = PermLog(action=perm_info.get('action', '')) - try: - new_users = perm_info.get('new', {}).get('users', []) - new_assets = perm_info.get('new', {}).get('assets', []) - del_users = perm_info.get('del', {}).get('users', []) - del_assets = perm_info.get('del', {}).get('assets', []) - print new_users, new_assets - except IndexError: - raise ServerError("Error: function perm_user_api传入参数错误") - - try: - new_ip = [asset.ip for asset in new_assets if isinstance(asset, Asset)] - del_ip = [asset.ip for asset in del_assets if isinstance(asset, Asset)] - new_username = [user.username for user in new_users] - del_username = [user.username for user in del_users] - except IndexError: - raise ServerError("Error: function perm_user_api传入参数类型错误") - - host_group = {'new': new_ip, 'del': del_ip} - inventory = get_inventory(host_group) - - the_new_users = ','.join(new_username) - the_del_users = ','.join(del_username) - - playbook = get_playbook(os.path.join(BASE_DIR, 'keys/../playbook', 'user_perm.yaml'), - {'the_new_group': 'new', 'the_del_group': 'del', - 'the_new_users': the_new_users, 'the_del_users': the_del_users, - 'KEY_DIR': os.path.join(SSH_KEY_DIR, 'sysuser')}) - - print playbook, inventory - - settings = get_object(Setting, name='default') - results = playbook_run(inventory, playbook, settings) - if not results.get('failures', 1) and not results.get('unreachable', ''): - is_success = True - else: - is_success = False - - log.results = results - log.is_finish = True - log.is_success = is_success - log.save() - return results - - -def user_group_permed(user_group): - assets = user_group.asset.all() - asset_groups = user_group.asset_group.all() - - for asset_group in asset_groups: - assets.extend(asset_group.asset.all()) - - return {'assets': assets, 'asset_groups': asset_groups} - - -def user_permed(user): - asset_groups = [] - assets = [] - user_groups = user.group.all() - asset_groups.extend(user.asset_group.all()) - assets.extend(user.asset.all()) - - for user_group in user_groups: - asset_groups.extend(user_group_permed(user_group).get('assets', [])) - assets.extend((user_group_permed(user_group).get('asset_groups', []))) - - return {'assets': assets, 'asset_groups': asset_groups} - - -def _public_perm_api(info): - """ - 公用的用户,用户组,主机,主机组编辑修改新建调用的api,用来完成授权 - info like that: - { - 'type': 'new_user', - 'user': 'a', - 'group': ['A', 'B'] - } - - { - 'type': 'edit_user', - 'user': 'a', - 'group': {'new': ['A'], 'del': []} - } - - { - 'type': 'del_user', - 'user': ['a', 'b'] - } - - { - 'type': 'edit_user_group', - 'group': 'A', - 'user': {'del': ['a', 'b'], 'new': ['c', 'd']} - } - - { - 'type': 'del_user_group', - 'group': ['A'] - } - - { - 'type': 'new_asset', - 'asset': 'a', - 'group': ['A', 'B'] - } - - { - 'type': 'edit_asset', - 'asset': 'a', - 'group': { - 'del': ['A', ['B'], - 'new': ['C', ['D']] - } - } - - { - 'type': 'del_asset', - 'asset': ['a', 'b'] - } - - { - 'type': 'edit_asset_group', - 'group': 'A', - 'asset': {'new': ['a', 'b'], 'del': ['c', 'd']} - } - - { - 'type': 'del_asset_group', - 'group': ['A', 'B'] - } - """ - - if info.get('type') == 'new_user': - new_assets = [] - user = info.get('user') - user_groups = info.get('group') - for user_group in user_groups: - new_assets.extend(user_group_permed(user_group).get('assets', [])) - - perm_info = { - 'action': 'new user: ' + user.name, - 'new': {'users': [user], 'assets': new_assets} - } - elif info.get('type') == 'edit_user': - new_assets = [] - del_assets = [] - user = info.get('user') - new_group = info.get('group').get('new') - del_group = info.get('group').get('del') - - for user_group in new_group: - new_assets.extend(user_group_permed(user_group).get('assets', [])) - - for user_group in del_group: - del_assets.extend((user_group_permed(user_group).get('assets', []))) - - perm_info = { - 'action': 'edit user: ' + user.name, - 'del': {'users': [user], 'assets': del_assets}, - 'new': {'users': [user], 'assets': new_assets} - } - - elif info.get('type') == 'del_user': - user = info.get('user') - del_assets = user_permed(user).get('assets', []) - perm_info = { - 'action': 'del user: ' + user.name, 'del': {'users': [user], 'assets': del_assets}, - } - - elif info.get('type') == 'edit_user_group': - user_group = info.get('group') - new_users = info.get('user').get('new') - del_users = info.get('user').get('del') - assets = user_group_permed(user_group).get('assets', []) - - perm_info = { - 'action': 'edit user group: ' + user_group.name, - 'new': {'users': new_users, 'assets': assets}, - 'del': {'users': del_users, 'assets': assets} - } - - elif info.get('type') == 'del_user_group': - user_group = info.get('group', []) - del_users = user_group.user_set.all() - assets = user_group_permed(user_group).get('assets', []) - - perm_info = { - 'action': "del user group: " + user_group.name, 'del': {'users': del_users, 'assets': assets} - } - else: - return - - try: - results = perm_user_api(perm_info) # 通过API授权或回收 - except ServerError, e: - return e - else: - return results - - -def push_user(user, asset_groups_id): - assets = [] - if not user: - return {'error': '没有该用户'} - for group_id in asset_groups_id: - asset_group = get_object(AssetGroup, id=group_id) - if asset_group: - assets.extend(asset_group.asset_set.all()) - perm_info = { - 'action': 'Push user:' + user.username, - 'new': {'users': [user], 'assets': assets} - } - - results = perm_user_api(perm_info) - return results - - def get_role_info(role_id, type="all"): """ 获取role对应的一些信息 diff --git a/jumpserver/api.py b/jumpserver/api.py index 6dc1a1602..f9285c166 100644 --- a/jumpserver/api.py +++ b/jumpserver/api.py @@ -14,7 +14,7 @@ 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 +from jlog.models import Log, TtyLog from jasset.models import Asset, AssetGroup from django.http import HttpResponseRedirect from django.shortcuts import render_to_response @@ -28,11 +28,15 @@ def set_log(level): return a log file object 根据提示设置log打印 """ + log_file = os.path.join(LOG_DIR, 'jumpserver.log') + 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(os.path.join(LOG_DIR, 'jumpserver.log')) + 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) diff --git a/templates/nav.html b/templates/nav.html index c5d46fb54..d6bc2cf43 100644 --- a/templates/nav.html +++ b/templates/nav.html @@ -29,11 +29,11 @@
  • 授权管理