From 7d412e4c180c0411d12c4239bd245606405cdbe5 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 28 Oct 2015 22:30:34 +0800 Subject: [PATCH 01/25] update configure file --- jumpserver.conf | 12 ++++-------- jumpserver/settings.py | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/jumpserver.conf b/jumpserver.conf index 94ee1653f..dd6d3fca7 100644 --- a/jumpserver.conf +++ b/jumpserver.conf @@ -1,19 +1,17 @@ #coding: utf8 [base] -url = http://192.168.244.129 +url = http://192.168.10.148 key = 88aaaf7ffe3c6c04 log = debug - [db] -host = 127.0.0.1 +host = 192.168.10.148 port = 3306 user = jumpserver -password = mysql234 +password =mysql1234 database = jumpserver - [ldap] ldap_enable = 1 host_url = ldap://127.0.0.1:389 @@ -21,10 +19,8 @@ base_dn = dc=jumpserver, dc=org root_dn = cn=admin,dc=jumpserver,dc=org root_pw = secret234 - [websocket] -web_socket_host = 192.168.40.140:3000 - +web_socket_host = 192.168.10.148:3000 [mail] mail_enable = 1 diff --git a/jumpserver/settings.py b/jumpserver/settings.py index 0a5a69bee..db02336dc 100644 --- a/jumpserver/settings.py +++ b/jumpserver/settings.py @@ -62,7 +62,7 @@ INSTALLED_APPS = ( 'juser', 'jasset', 'jperm', - # 'jlog', + 'jlog', ) MIDDLEWARE_CLASSES = ( From 9e0d1a7285c28c06bcd9ed7e4a09b6a3b2b4fabf Mon Sep 17 00:00:00 2001 From: root Date: Thu, 29 Oct 2015 16:32:02 +0800 Subject: [PATCH 02/25] add ansible_api module --- jperm/README.md | 10 ++++ jperm/ansible_api.py | 138 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 jperm/README.md create mode 100644 jperm/ansible_api.py diff --git a/jperm/README.md b/jperm/README.md new file mode 100644 index 000000000..9dbd9c329 --- /dev/null +++ b/jperm/README.md @@ -0,0 +1,10 @@ +# Jperm App + +--- + +### 模块 ansible_api + +> 使用说明 + ++ 依赖安装包: ansible、 sshpass ++ 关于ansible配置: 需要启用配置文件(/etc/ansible/ansible.cfg)的 host_key_checking = False diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py new file mode 100644 index 000000000..b9a45e9fb --- /dev/null +++ b/jperm/ansible_api.py @@ -0,0 +1,138 @@ +# -*- 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 + + +class MyAnsible(object): + """ + this is my ansible object + """ + def __init__(self, resource): + """ + resource : + 必须是一个字典列表,比如 + [{"hostname": "10.10.10.10", "port": "22", + "username": "test", "password": "mypass"}, ...] + """ + self.resource = resource + self._gen_inventory() + + + def _gen_inventory(self): + """ + add hosts to inventory + """ + my_group = Group(name='my_group') + + for host in self.resource: + hostname = host.get("hostname") + hostport = host.get("hostport") + 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) + my_group.add_host(my_host) + + my_inventory = Inventory() + my_inventory.add_group(my_group) + my_inventory.subset('my_group') + + self.inventory = my_inventory + + + def run_command(self, command, module_name="command", timeout=5, forks=10): + """ + run command from andible ad-hoc + command : 必须是一个需要执行的命令字符串, 比如 + 'uname -a' + """ + hoc = Runner(module_name=module_name, + module_args=command, + timeout=timeout, + inventory=self.inventory, + subset='my_group', + forks=forks + ) + + self.results = hoc.run() + + + @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") + + + +if __name__ == "__main__": + resource = [{"hostname": "127.0.0.1", "port": "22", "username": "root", "password": "xxx"}, + {"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] + myansible = MyAnsible(resource) + myansible.run_command("uname -a") + print myansible.stdout + + + + + + + + From b88c4211b2badd8876368c7661439f200c492159 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 30 Oct 2015 08:25:22 +0800 Subject: [PATCH 03/25] update ansible_api.py --- jperm/ansible_api.py | 98 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 15 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index b9a45e9fb..797694f6a 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -8,9 +8,32 @@ from ansible.runner import Runner from ansible.playbook import PlayBook -class MyAnsible(object): +class AnsibleError(StandardError): """ - this is my ansible object + 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): """ @@ -21,11 +44,11 @@ class MyAnsible(object): """ self.resource = resource self._gen_inventory() - + def _gen_inventory(self): """ - add hosts to inventory + add hosts to inventory. """ my_group = Group(name='my_group') @@ -46,14 +69,25 @@ class MyAnsible(object): my_inventory.subset('my_group') self.inventory = my_inventory - - def run_command(self, command, module_name="command", timeout=5, forks=10): + +class Command(MyInventory): + """ + this is a command object for parallel execute command. + """ + def __init__(self, *args, **kwargs): + super(Command, self).__init__(*args, **kwargs) + + + def run(self, command, module_name="command", timeout=5, forks=10): """ - run command from andible ad-hoc + 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, @@ -68,7 +102,7 @@ class MyAnsible(object): @property def raw_results(self): """ - get the ansible raw results + get the ansible raw results. """ return self.results @@ -76,7 +110,7 @@ class MyAnsible(object): @property def exec_time(self): """ - get the command execute time + get the command execute time. """ result = {} all = self.results.get("contacted") @@ -91,7 +125,7 @@ class MyAnsible(object): @property def stdout(self): """ - get the comamnd standard output + get the comamnd standard output. """ result = {} all = self.results.get("contacted") @@ -103,7 +137,7 @@ class MyAnsible(object): @property def stderr(self): """ - get the command standard error + get the command standard error. """ result = {} all = self.results.get("contacted") @@ -116,18 +150,52 @@ class MyAnsible(object): @property def dark(self): """ - get the dark results + 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) + + +class MyPlaybook(MyInventory): + """ + this is my playbook object for execute playbook. + """ + def __init__(self, *args, **kwargs): + super(MyPlaybook, self).__init__(*args, **kwargs) + + + def deploy(self): + """ + use ansible playbook to deploy a application. + """ + pass + + +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__": resource = [{"hostname": "127.0.0.1", "port": "22", "username": "root", "password": "xxx"}, {"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] - myansible = MyAnsible(resource) - myansible.run_command("uname -a") - print myansible.stdout + command = Command(resource) + command.run("uname -a", "copy") + print command.stdout + print command.stderr + print command.dark + From fe23e6103648e1547f08c3b664e7052e8bd90b07 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 30 Oct 2015 23:08:45 +0800 Subject: [PATCH 04/25] Task add method push_key --- jperm/ansible_api.py | 65 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 797694f6a..407d5cf8a 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -97,6 +97,7 @@ class Command(MyInventory): ) self.results = hoc.run() + return self.stdout @property @@ -163,6 +164,60 @@ class Tasks(Command): super(Tasks, self).__init__(*args, **kwargs) + def __run(self, module_args, module_name="command", timeout=5, forks=10): + """ + 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='my_group', + forks=forks + ) + + self.results = hoc.run() + + + 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") + + 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") + + if not msg: + return {"status": "ok"} + else: + return {"status": "failed","msg": msg} + + + def add_user(self, user): + """ + add a host user. + """ + pass + + + def del_user(self, user): + """ + delete a host user. + """ + pass + + + + + class MyPlaybook(MyInventory): """ this is my playbook object for execute playbook. @@ -188,13 +243,9 @@ class App(MyPlaybook): if __name__ == "__main__": - resource = [{"hostname": "127.0.0.1", "port": "22", "username": "root", "password": "xxx"}, - {"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] - command = Command(resource) - command.run("uname -a", "copy") - print command.stdout - print command.stderr - print command.dark + resource = [ {"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] + task = Tasks(resource) + print task.push_key('root', '/root/.ssh/id_rsa.pub') From dd4ac4e6d6972aaa8aa28abedbb29997e924d83f Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Fri, 30 Oct 2015 23:14:45 +0800 Subject: [PATCH 05/25] Task add method push_key --- jperm/ansible_api.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 407d5cf8a..ccaf17efe 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -195,10 +195,7 @@ class Tasks(Command): if value.get("msg"): msg[key] = value.get("msg") - if not msg: - return {"status": "ok"} - else: - return {"status": "failed","msg": msg} + return {"status": "ok"} if msg else {"status": "failed","msg": msg} def add_user(self, user): From df9d879f227ccb820b55886b7b2f5a06303201e2 Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Sat, 31 Oct 2015 11:55:19 +0800 Subject: [PATCH 06/25] ansible api base complete... --- jperm/ansible_api.py | 166 +++++++++++++++++++++++++++++++------------ 1 file changed, 120 insertions(+), 46 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index ccaf17efe..13a3783d1 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -7,6 +7,14 @@ 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 + +import os.path +JPERM_DIR = os.path.dirname(os.path.abspath(__file__)) +ANSIBLE_DIR = os.path.join(JPERM_DIR, 'playbooks') + class AnsibleError(StandardError): """ @@ -38,21 +46,28 @@ class MyInventory(object): def __init__(self, resource): """ resource : - 必须是一个字典列表,比如 - [{"hostname": "10.10.10.10", "port": "22", - "username": "test", "password": "mypass"}, ...] + resource的数据格式是一个列表字典,比如 + { + "group1": [{"hostname": "10.10.10.10", "port": "22", + "username": "test", "password": "mypass"}, ...], + "group2": [{"hostname": "10.10.10.10", "port": "22", + "username": "test", "password": "mypass"}, ...] + } + 如果你只传入1个列表,这默认该列表内的所有主机属于my_group组,比如 + [{"hostname": "10.10.10.10", "port": "22", + "username": "test", "password": "mypass"}, ...] + """ self.resource = resource - self._gen_inventory() + self.inventory = Inventory() + self.gen_inventory() - - def _gen_inventory(self): + def add_group(self, hosts, groupname): """ - add hosts to inventory. + add hosts to a group """ - my_group = Group(name='my_group') - - for host in self.resource: + my_group = Group(name=groupname) + for host in hosts: hostname = host.get("hostname") hostport = host.get("hostport") username = host.get("username") @@ -64,11 +79,17 @@ class MyInventory(object): my_host.set_variable('ansible_ssh_pass', password) my_group.add_host(my_host) - my_inventory = Inventory() - my_inventory.add_group(my_group) - my_inventory.subset('my_group') + self.inventory.add_group(my_group) - self.inventory = my_inventory + 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 in self.resource.iteritems(): + self.add_group(hosts, groupname) class Command(MyInventory): @@ -77,7 +98,6 @@ class Command(MyInventory): """ def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) - def run(self, command, module_name="command", timeout=5, forks=10): """ @@ -99,7 +119,6 @@ class Command(MyInventory): self.results = hoc.run() return self.stdout - @property def raw_results(self): """ @@ -107,7 +126,6 @@ class Command(MyInventory): """ return self.results - @property def exec_time(self): """ @@ -121,7 +139,6 @@ class Command(MyInventory): "end" : value.get("end"), "delta": value.get("delta"),} return result - @property def stdout(self): @@ -133,7 +150,6 @@ class Command(MyInventory): for key, value in all.iteritems(): result[key] = value.get("stdout") return result - @property def stderr(self): @@ -163,7 +179,6 @@ class Tasks(Command): def __init__(self, *args, **kwargs): super(Tasks, self).__init__(*args, **kwargs) - def __run(self, module_args, module_name="command", timeout=5, forks=10): """ run command from andible ad-hoc. @@ -180,6 +195,18 @@ class Tasks(Command): 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): """ @@ -188,33 +215,61 @@ class Tasks(Command): module_args = 'user="%s" key="{{ lookup("file", "%s") }}"' % (user, key_path) self.__run(module_args, "authorized_key") - 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 {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"} - return {"status": "ok"} if msg else {"status": "failed","msg": msg} - - - def add_user(self, user): + def add_user(self, username, password): """ add a host user. """ - pass + 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 del_user(self, user): + def del_user(self, username): """ delete a host user. """ - pass + 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"} + +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. @@ -223,11 +278,32 @@ class MyPlaybook(MyInventory): super(MyPlaybook, self).__init__(*args, **kwargs) - def deploy(self): + def run(self, playbook_relational_path): """ - use ansible playbook to deploy a application. + run ansible playbook, + only surport relational path. """ - pass + stats = CustomAggregateStats() + 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, + check=True) + + self.results = pb.run() + + @property + def raw_results(self): + """ + get the raw results after playbook run. + """ + return self.results class App(MyPlaybook): @@ -240,15 +316,13 @@ class App(MyPlaybook): if __name__ == "__main__": - resource = [ {"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] - task = Tasks(resource) - print task.push_key('root', '/root/.ssh/id_rsa.pub') - - - - - - + resource = {"test": [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}]} + playbook = MyPlaybook(resource) + playbook.run('test.yml') + print playbook.raw_results +# print task.add_user('test', 'mypass') +# print task.del_user('test') +# print task.push_key('root', '/root/.ssh/id_rsa.pub') From 6572e6f10ee7c52683c40bd9696ed2f6df5cdc9a Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Mon, 2 Nov 2015 23:03:41 +0800 Subject: [PATCH 07/25] update ansible_api, and update perm_list_user view --- jperm/{views.py => views.py.back} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename jperm/{views.py => views.py.back} (100%) diff --git a/jperm/views.py b/jperm/views.py.back similarity index 100% rename from jperm/views.py rename to jperm/views.py.back From c26594a3ec093ad9ac4b8a2a2f8bda395acddb2a Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Mon, 2 Nov 2015 23:05:19 +0800 Subject: [PATCH 08/25] update ansible_api, and update perm_list_user view --- jperm/README.md | 4 +- jperm/ansible_api.py | 63 ++++++++++++-- jperm/views.py | 197 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 jperm/views.py diff --git a/jperm/README.md b/jperm/README.md index 9dbd9c329..a5a7e026c 100644 --- a/jperm/README.md +++ b/jperm/README.md @@ -6,5 +6,7 @@ > 使用说明 -+ 依赖安装包: ansible、 sshpass ++ 依赖rpm安装包: ansible、 sshpass ++ 依赖pip安装包: passlib + 关于ansible配置: 需要启用配置文件(/etc/ansible/ansible.cfg)的 host_key_checking = False + diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 13a3783d1..474677b34 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -11,11 +11,16 @@ from ansible import callbacks from ansible import utils from passlib.hash import sha512_crypt +from utils import get_rand_pass + import os.path JPERM_DIR = os.path.dirname(os.path.abspath(__file__)) ANSIBLE_DIR = os.path.join(JPERM_DIR, 'playbooks') + + + class AnsibleError(StandardError): """ the base AnsibleError which contains error(required), @@ -217,6 +222,15 @@ class Tasks(Command): 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. @@ -235,7 +249,31 @@ class Tasks(Command): 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 @@ -316,13 +354,28 @@ class App(MyPlaybook): if __name__ == "__main__": - resource = {"test": [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}]} - playbook = MyPlaybook(resource) - playbook.run('test.yml') - print playbook.raw_results + resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "yusky0902"}] +# playbook = MyPlaybook(resource) +# playbook.run('test.yml') +# print playbook.raw_results + command = Command(resource) + command.run("who") + print command.stdout + + +# task = Tasks(resource) # print task.add_user('test', 'mypass') # print task.del_user('test') # print task.push_key('root', '/root/.ssh/id_rsa.pub') +# print task.del_key('root', '/root/.ssh/id_rsa.pub') + + +# task = Tasks(resource) +# print task.add_init_users() +# print task.del_init_users() + + + diff --git a/jperm/views.py b/jperm/views.py new file mode 100644 index 000000000..bc0ea2d8e --- /dev/null +++ b/jperm/views.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- + + +from django.db.models import Q +from jumpserver.api import * +from jperm.perm_api import * +from jperm.models import PermLog as Log +from jperm.models import SysUser +from juser.user_api import gen_ssh_key + + +from django.shortcuts import render_to_response + + +@require_role('admin') +def perm_user_list(request): + """ + 用户授权视图: + 该视图的模板包含2部分: + 1. block 部分:{% block content %} + rander_content 为渲染数据 + 2. include 部分:{% include 'nav_cat_bar.html' %} + rander_nav 为渲染数据 + """ + render_data = {} + data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "用户授权"} + # 获取所有用户 + users_list = User.objects.all() + + # 搜索和分页 + keyword = request.GET.get('search', '') + if keyword: + users_list = users_list.filter(Q(name=keyword) | Q(username=keyword)) + users_list, p, users, page_range, current_page, show_first, show_end = pages(users_list, request) + + data_content = {"users": users} + for data in [data_nav, data_content]: + render_data.update(data) + + return render_to_response('jperm/perm_user_list.html', render_data) + + +@require_role('admin') +def perm_user_edit(request): + """ + TODO: + """ + header_title, path1, path2 = '用户授权', '授权管理', '授权更改' + user_id = request.GET.get('id', '') + user = get_object(User, id=user_id) + asset_all = Asset.objects.all() # 获取所有资产 + asset_group_all = AssetGroup.objects.all() # 获取所有资产组 + asset_permed = user.asset.all() # 获取授权的资产对象列表 + asset_group_permed = user.asset_group.all() # 获取授权的资产组对象列表 + if request.method == 'GET' and user: + assets = [asset for asset in asset_all if asset not in asset_permed] # 获取没有授权的资产对象列表 + asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed] # 同理 + return my_render('jperm/perm_user_edit.html', locals(), request) + elif request.method == 'POST' and user: + asset_id_select = request.POST.getlist('asset_select', []) # 获取选择的资产id列表 + asset_group_id_select = request.POST.getlist('asset_groups_select', []) # 获取选择的资产组id列表 + asset_select = get_object_list(Asset, asset_id_select) + asset_group_select = get_object_list(AssetGroup, asset_group_id_select) + asset_new = list(set(asset_select) - set(asset_permed)) # 计算的得到新授权的资产对象列表 + asset_del = list(set(asset_permed) - set(asset_select)) # 计算得到回收权限的资产对象列表 + asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) # 新授权的资产组对象列表 + asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) # 回收的资产组对象列表 + for asset_group in asset_group_new: + asset_new.extend(asset_group.asset_set.all()) + for asset_group in asset_group_del: + asset_del.extend(asset_group.asset_set.all()) + perm_info = { + 'action': 'perm user edit: ' + user.name, + 'del': {'users': [user], 'assets': asset_del}, + 'new': {'users': [user], 'assets': asset_new} + } + print perm_info + try: + results = perm_user_api(perm_info) # 通过API授权或回收 + except ServerError, e: + return HttpResponse(e) + unreachable_asset = [] + failures_asset = [] + for ip in results.get('unreachable'): + unreachable_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) + for ip in results.get('failures'): + failures_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) + failures_asset.extend(unreachable_asset) # 失败的授权要统计 + for asset in failures_asset: + if asset in asset_select: + asset_select.remove(asset) + else: + asset_select.append(asset) + user.asset = asset_select + user.asset_group = asset_group_select + user.save() # 保存到数据库 + return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json") + else: + return HttpResponse('输入错误') + + +@require_role('admin') +def perm_group_list(request): + header_title, path1, path2 = '用户组授权', '授权管理', '用户组授权' + keyword = request.GET.get('search', '') + user_groups_list = UserGroup.objects.all() + if keyword: + request = user_groups_list.filter(Q(name=keyword) | Q(comment=keyword)) + user_groups_list, p, user_groups, page_range, current_page, show_first, show_end = pages(user_groups_list, request) + return my_render('jperm/perm_group_list.html', locals(), request) + + + +@require_role('admin') +def perm_group_edit(request): + header_title, path1, path2 = '用户组授权', '授权管理', '授权更改' + user_group_id = request.GET.get('id', '') + user_group = get_object(UserGroup, id=user_group_id) + asset_all = Asset.objects.all() + asset_group_all = AssetGroup.objects.all() + asset_permed = user_group.asset.all() # 获取授权的资产对象列表 + asset_group_permed = user_group.asset_group.all() # 获取授权的资产组对象列表 + if request.method == 'GET' and user_group: + assets = [asset for asset in asset_all if asset not in asset_permed] + asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed] + return my_render('jperm/perm_group_edit.html', locals(), request) + elif request.method == 'POST' and user_group: + asset_id_select = request.POST.getlist('asset_select', []) + asset_group_id_select = request.POST.getlist('asset_groups_select', []) + asset_select = get_object_list(Asset, asset_id_select) + asset_group_select = get_object_list(AssetGroup, asset_group_id_select) + asset_new = list(set(asset_select) - set(asset_permed)) # 计算的得到新授权的资产对象列表 + asset_del = list(set(asset_permed) - set(asset_select)) # 计算得到回收权限的资产对象列表 + asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) # 新授权的资产组对象列表 + asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) # 回收的资产组对象列表 + users = user_group.user_set.all() + perm_info = { + 'action': 'perm group edit: ' + user_group.name, + 'del': {'users': users, 'assets': asset_del}, + 'new': {'users': users, 'assets': asset_new} + } + results = perm_user_api(perm_info) + unreachable_asset = [] + failures_asset = [] + for ip in results.get('unreachable'): + unreachable_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) + for ip in results.get('failures'): + failures_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) + failures_asset.extend(unreachable_asset) # 失败的授权要统计 + for asset in failures_asset: + if asset in asset_select: + asset_select.remove(asset) + else: + asset_select.append(asset) + user_group.asset = asset_select + user_group.asset_group = asset_group_select + user_group.save() # 保存到数据库 + return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json") + else: + return HttpResponse('输入错误') + + +def log(request): + header_title, path1, path2 = '授权记录', '授权管理', '授权记录' + log_all = Log.objects.all().order_by('-datetime') + log_all, p, logs, page_range, current_page, show_first, show_end = pages(log_all, request) + return my_render('jperm/perm_log.html', locals(), request) + + +def sys_user_add(request): + asset_group_all = AssetGroup.objects.all() + if request.method == 'POST': + username = request.POST.get('username', '') + password = request.POST.get('password', '') + asset_groups_id = request.POST.getlist('asset_groups_select', []) + comment = request.POST.get('comment') + sys_user = SysUser(username=username, password=password, comment=comment) + sys_user.save() + gen_ssh_key(username, key_dir=os.path.join(SSH_KEY_DIR, 'sysuser'), authorized_keys=False) + results = push_user(sys_user, asset_groups_id) + return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json") + return my_render('jperm/sys_user_add.html', locals(), request) + + +def sys_user_list(request): + users_list = SysUser.objects.all() + users_list, p, users, page_range, current_page, show_first, show_end = pages(users_list, request) + return my_render('jperm/sys_user_list.html', locals(), request) + + +def sys_user_edit(request): + pass + + +def sys_user_del(request): + pass + From c49a02d1c574489da16097695ae1a0d4867bafdb Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Mon, 2 Nov 2015 23:07:04 +0800 Subject: [PATCH 09/25] update ansible_api, and update perm_list_user view --- jperm/ansible_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 474677b34..0bc21c6d2 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -354,7 +354,7 @@ class App(MyPlaybook): if __name__ == "__main__": - resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "yusky0902"}] + resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] # playbook = MyPlaybook(resource) # playbook.run('test.yml') # print playbook.raw_results From 26e3634814efc304967af4e86355a54ef9fc7f18 Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Thu, 5 Nov 2015 22:47:45 +0800 Subject: [PATCH 10/25] mapping model --- jasset/__init__.pyc | Bin 0 -> 122 bytes jasset/admin.pyc | Bin 0 -> 179 bytes jasset/asset_api.pyc | Bin 0 -> 1762 bytes jasset/models.pyc | Bin 0 -> 1799 bytes jasset/urls.pyc | Bin 0 -> 672 bytes jasset/views.pyc | Bin 0 -> 6695 bytes jlog/__init__.pyc | Bin 0 -> 120 bytes jlog/admin.pyc | Bin 0 -> 177 bytes jlog/models.pyc | Bin 0 -> 1293 bytes jperm/__init__.pyc | Bin 0 -> 121 bytes jperm/admin.pyc | Bin 0 -> 178 bytes jperm/models.py | 26 +++++- jperm/models.pyc | Bin 0 -> 2230 bytes jperm/perm_api.pyc | Bin 0 -> 7863 bytes jperm/playbooks/add_init_users/add_users.yml | 12 +++ jperm/playbooks/test.yml | 9 +++ jperm/urls.py | 1 + jperm/urls.pyc | Bin 0 -> 783 bytes jperm/utils.py | 36 +++++++++ jperm/utils.pyc | Bin 0 -> 1062 bytes jperm/views.py | 80 ++++++++++++++----- jperm/views.pyc | Bin 0 -> 9056 bytes jumpserver/__init__.pyc | Bin 0 -> 126 bytes jumpserver/api.pyc | Bin 0 -> 20982 bytes jumpserver/context_processors.pyc | Bin 0 -> 965 bytes jumpserver/models.pyc | Bin 0 -> 840 bytes jumpserver/settings.pyc | Bin 0 -> 4006 bytes jumpserver/tasks.py | 5 +- jumpserver/tasks.pyc | Bin 0 -> 1506 bytes jumpserver/templatetags/__init__.pyc | Bin 0 -> 170 bytes jumpserver/templatetags/mytags.pyc | Bin 0 -> 4204 bytes jumpserver/urls.pyc | Bin 0 -> 1568 bytes jumpserver/views.pyc | Bin 0 -> 7901 bytes jumpserver/wsgi.pyc | Bin 0 -> 589 bytes juser/__init__.pyc | Bin 0 -> 121 bytes juser/admin.pyc | Bin 0 -> 178 bytes juser/models.py | 8 +- juser/models.pyc | Bin 0 -> 2190 bytes juser/urls.pyc | Bin 0 -> 1280 bytes juser/user_api.pyc | Bin 0 -> 6597 bytes juser/views.pyc | Bin 0 -> 15721 bytes logs/jumpserver.log | 0 templates/jperm/perm_user_detail.html | 30 +++++++ templates/jperm/perm_user_list.html | 2 +- 44 files changed, 179 insertions(+), 30 deletions(-) create mode 100644 jasset/__init__.pyc create mode 100644 jasset/admin.pyc create mode 100644 jasset/asset_api.pyc create mode 100644 jasset/models.pyc create mode 100644 jasset/urls.pyc create mode 100644 jasset/views.pyc create mode 100644 jlog/__init__.pyc create mode 100644 jlog/admin.pyc create mode 100644 jlog/models.pyc create mode 100644 jperm/__init__.pyc create mode 100644 jperm/admin.pyc create mode 100644 jperm/models.pyc create mode 100644 jperm/perm_api.pyc create mode 100644 jperm/playbooks/add_init_users/add_users.yml create mode 100644 jperm/playbooks/test.yml create mode 100644 jperm/urls.pyc create mode 100644 jperm/utils.py create mode 100644 jperm/utils.pyc create mode 100644 jperm/views.pyc create mode 100644 jumpserver/__init__.pyc create mode 100644 jumpserver/api.pyc create mode 100644 jumpserver/context_processors.pyc create mode 100644 jumpserver/models.pyc create mode 100644 jumpserver/settings.pyc create mode 100644 jumpserver/tasks.pyc create mode 100644 jumpserver/templatetags/__init__.pyc create mode 100644 jumpserver/templatetags/mytags.pyc create mode 100644 jumpserver/urls.pyc create mode 100644 jumpserver/views.pyc create mode 100644 jumpserver/wsgi.pyc create mode 100644 juser/__init__.pyc create mode 100644 juser/admin.pyc create mode 100644 juser/models.pyc create mode 100644 juser/urls.pyc create mode 100644 juser/user_api.pyc create mode 100644 juser/views.pyc create mode 100644 logs/jumpserver.log create mode 100644 templates/jperm/perm_user_detail.html diff --git a/jasset/__init__.pyc b/jasset/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8640fe38d542671124d32eedd80caa580e81dbf5 GIT binary patch literal 122 zcmZSn%*$1D#2_r00SXv_v;zZE2u2t04lP{%}*)KNwou6Rt&@p04CBVKL7v# literal 0 HcmV?d00001 diff --git a/jasset/asset_api.pyc b/jasset/asset_api.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e8434612d4b7cdb670977895f3386dc4797cdd5 GIT binary patch literal 1762 zcmbW1&ubG=5Xa~3CaI0B=?|+1r7S42C^W@`2#WZlC@AEx6$^zDw%xTPO_OcjYpsx+ zS`dVuRJ?fb=1K9Q)|TQw;xUch{R8wn^U_}wM7!+HzL}jjvu{3cp8Kmed*%D+qZ#U4 zF5Wls=&KMBZbcQMhf#+3c4*b1NrxhrR*5EEic&I2QIwWJn%&0zE=(@{#^o!F42z31 z96Hr`?%=KOLo^iC&yW!(d+OhSM=NT&mxt22t6evP)1`6saoy(nV5^ zt*=33JzPIOt+qDa{n%V>f7#rA{?@AU<(Ag5@n-9_#l#Dv$P2xYE%MDcm|u$QD=A1! zlZ9Ii4{l4OL>8Zj5AZ5%UeN5Ap0Ac9In4*sc@e?o$#8B-4GkkO+MqqkO$q zGx_r3e4^v}Qe4lM#Vc=9g-K~7d1`WSlmtcOEXpU&srhFqol!&1fRj-(qCs$R9^lan z5L`h)i}E!U^TC4ms*j4p0dTqQ1Q-CI=h+ALHKL{_f@^ap;Yyv(1g>Wj>V(>>SKHD!}i9D*82NH01Ypu8qUY22LoFb z9aq4n;AdbF55utaB0pDZd@-3+)5<`beac~??K9|n$+_@)VeO3n?IN)7udLe9z zQdF#zv$qy75xF0b~Bwbs^~?PpuCh@(_h)~f?P2MRvdFW_|tyuP5H1@C6V^|n2xW!B?T z#l&?P#>*zIMnXgo2Ln8T+1MV~VZ*y$c7-+DT_Ih!<7Z>Q?SC6?2Ok%LA)Z5sU3>rs ze7$N&^;>*=j_~%Ap37r!7@s}FI&DV^kStIIP~$#N))yeW*0&GsmtX&0YOhmU-pBiD zdy3W55K_d&1U(k}{A*IbBkyFU#XDI_VWSpc(#(^boa(gU321w#*a!|T>AFI#YP&8t o35Vb;i(!bpo|4hOABDW3uFuz^#Y%jG7pK{fb#o`W`?@dv0ie^HIRF3v literal 0 HcmV?d00001 diff --git a/jasset/models.pyc b/jasset/models.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb530951eaa10dbe9e3548b13b0ee2c52a1ba038 GIT binary patch literal 1799 zcmbtV-)|E~5S}|bP8<>v0;TYhst*-@B9HAuTh)O;BNedLE)o{f>F{pCne&}{w+BVy zjs7A1SNb=hKDXaD8#@+x31HpL&Cbm3{Q73y`mnwE+dn@%oygg*h3_wT>sKHaPb9g> zIPkILk<4Nl#}e6=xLBqwIf=x!@^!Hrl-q95w#JZbGO+Q6m|<@l=XwS+@bon>$4~pCBbD_18YKPU@Mxsr&C)-U z+!d$(Wj5e0M&A_KAC1fY=9<R_6(U5uEnwq zR7B$dSw*6ah0s>ysFtXpJ)qK+_mPY@bqS;aZvf9n##<{|9QcuTTeVkp7J};?mFy}M z;S|2E$rR5X0wa3QVz_=`)mP8Hr&_jZWPS$`rOVvF;>o za<45<8($_x`6ffDqI5Viqf3$3VR) zE30Q8mSyhJBA}Zo!ZcYFj)C4!y&GjS7c6*~g~UVRIb$fPP7#GkYOS+6F@LYT*c>iYCq4?dO0gB#UVE`z>% literal 0 HcmV?d00001 diff --git a/jasset/urls.pyc b/jasset/urls.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d12635a887e981670775d88e82f9f04530339b7c GIT binary patch literal 672 zcmZ8eyH3ME5ZpWGWyb*uN+cQzi^8U&LWnP*2#CT(kd<2^M}En74x-LK@OAtJ9{{^{ zE;jfvp4(a9&e+cP!n^&td0E5Z@ag$LxBethbP31+asjb`TtX}%cOZ5^uqGiJ!7~a_ z4xj^S1UQDhZ21^)V)+DcYWWm!X88=zwcG{tEcXECmd^ow=6e_71t=e$f(2Pif9MDt zVrE8ACB|S~XftK4SZ9qw!)jA!f#5ENYeN8i$y?SOEX;=4936^=RD)iH$eNb3^}MDo^(z4yUBEbNJ w=u28gby=Ed+vJtTdWUt?*^W3>Sbem=>@F`=li@u_)8_;i!jlu>OJDToFIG^TQvd(} literal 0 HcmV?d00001 diff --git a/jasset/views.pyc b/jasset/views.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0bb65fb630ece88919323e536a29754d3ab7b427 GIT binary patch literal 6695 zcmbVRU2jy!8J;=2UfXN0*B_WdqmV@n?KY$~O;MV(2}vL+Nu?4xwhBS1R*TO8cG)k^ zoP}8RUbH4DC5nooNNpt~f?C@2qCrBcLZMZDKreb<_0l%`(yHaDRzgKem9;8+7_(|6)dFr44EN6$l0_C|Dm+j=RQ}*qjb9obi9DRF%%?$N@zdrnn_Dv zSi~U}aUD6-#RP(%VMx9Klg{DqCEw2#tqr2w>9F2xh;QYSyUUk9y#MEmOLzWo@9stM zHM4kPO+j-QzIL^buiv}!PLzb>=<74Ha#1T*1H>6KWDS9wKWgqo(bDa^D_8HJ zltpe_E0?Y;U%qB1QCgPXre#WnqVG?giK>-6VYsPzJgAbyO|tAIhD)a4lF>$NxLBz~ zDg0v2XX?ITI*K1jD|PW(DcLAuX3hlR`5=5H4C^7*F`n3RD;*r>a!BO-lbk|9CWFjD z7xRTMsQE!C9aidd#fr_dUFj%v=#fXy1VvOUM5U+_$k-dj=*%~}S5HZEZe=ij!||H| z8g?Vq0vY5eZe2AO(g^UB*;Vc7Jj#?9o5R&~Sg%LZwT4t{ShX^QK2VMb#Nfzvvr{kvGp5KoJT71Q)$-5pJP421Zrr>2Znt1P z9vP;y!Tg1K=o?k#gFd5%LgU!vJTLzXa) z(d1}$!$fQISP;qm!XYh|;#QEzehOi+2Jmt$bIlOIiwbm0xjj?AP&iczfd;}xZh_3L zLP9uzcrQp)*%E_5Oib!=e6n6j=e@_ZY;|xWo{lypWCaBfkcQJ?$ac(-d5oUl?SBehyVV~@493x zISd$Kdv7NkgZrc;=JF+0btIi;OR3>Q5{DJ9=Vj+KI~x}~B- zC_4I;{ZGsfQbN}d58aw+@eIX0L*f}`z{{xVZZoPjuKZCxOFJw!qvoICzE6>rVLpLr zMDH-!!e=$)n24Pb6=l`J2-|h)$cde-h@Brm>*#au>*K(!(@PLD3+MphK$2q4;8V;E zY6>AkXfP`b0wc?yn*l0U=_D)s4DE^D#+m1sqevkxnf*G9lp8iK1Ugs8nJhhpT< za^ZnBfvBwiEsW23hw5^9V~Hg?Shb>Bjyj z8n92ph~&{(A^6>TmmUYnlkD-q6+Vzbk96fv3NqZIhHiq6-EEV z4WP0mQPfsSj(flX*h+vXC!bbJBkmi*F>Q_XThU0U159>w5wC$p(M!}wWzY^9jXhZt z-Uf~d#tkHs02=6t!It^fgKbYTS%GL=E#1HVQ4F@CJRC~a!&a06BiNG*k}Q&WrAAK* znXj<>m>zN~yG9QQtTyVhSFR_xZlUfPlOB>Zn_gFj*D8tHF2FIayW4VVG8D6Ldlpq1yJ=C|^GoMp+P-I-??W zu8Gw73{nR&MFQmTjC%#DQMi7+6O$`hC8PU9Vp<{wKDxe$$x&2T~Ez{Uy8q~l4m!ZIaD)V^AO@AT4fI@0i1UtjE$k;CXnx(`$#Jzlx?UXRQ)hZ&FTl#&Oa^ zp|e`{Wc8relRo24{Aiy2?9#*dP3tlDy2ZCbsvlvs*Kh%_JXq{>&u@WDkGSP~1mAAS zV#F|Hi)HlU-{|Hb@*_p6MM3^i&&mY zw2x5YX&XC4;i5iFCwT@WmY%)L>>ZIv6+&)}N|uB%$561H6{UnR%Hd@$q^El_eZNRW`Z#DWy57b|ABgftUdRlM@#G literal 0 HcmV?d00001 diff --git a/jlog/admin.pyc b/jlog/admin.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8903548ba0f4bf64ce60341e59a482c0decbeb31 GIT binary patch literal 177 zcmZSn%*$1D#2_r00ScIav;z16frJG6De2@+DsY literal 0 HcmV?d00001 diff --git a/jlog/models.pyc b/jlog/models.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ffaf3b1397c60206df84b52c3924853b55e64056 GIT binary patch literal 1293 zcmbVMOK%e~5FTffG)Ws8%0u+Tbx#c^PN;$uMM8oeOohZ=tR;3fj=T@8y$B?3@CUi` zFZcm4Guwtm5fbV?X2+k$GoEk88~vP4p8k09ZUxs@gx}}*`XvgDj{pad3rGYA-2)?F z+k>?L9l#_{fvb2vmBrJBO7uue+NaOis|K*YRX3Zzt#<~Yd-DTRw0heJtbVT|Hplh#XX zoaXed>c+6rU`SRrr4MXao4gE0*@{QnRDoSf>V_~y@iGnO%I2o^M)dfQ)y%Xcv;dW$L`){H#}NTUfs_IvnH7CM`53u)`=vQ)mt%iSR!h z{x^}5io-Q{h{{kr!u#a!yBBC%FC3DxI|h^iAA@sL_KyLzBOW+B7z1wEVW-hYbTG}B zkqPx2MVC}N?leiRC1EkuSW=Rbip6D<+<9b@`%F^RC0TK`m}}x`VY4pX@&TDqdbi={ z6xUHldHN{~nVHL&>rR`}+qB5aGyS1$D#G8;kArEIwDuM;1LgdzZP#>i literal 0 HcmV?d00001 diff --git a/jperm/models.py b/jperm/models.py index b86ddd433..e5c7c1774 100644 --- a/jperm/models.py +++ b/jperm/models.py @@ -1,8 +1,8 @@ import datetime from django.db import models -from juser.models import User, UserGroup from jasset.models import Asset, AssetGroup +from juser.models import User, UserGroup class PermLog(models.Model): @@ -19,3 +19,27 @@ class SysUser(models.Model): comment = models.CharField(max_length=100, null=True, blank=True, default='') +class PermRole(models.Model): + name = models.CharField(max_length=100) + comment = models.CharField(max_length=100) + + +class UserMapping(models.Model): + role = models.ForeignKey(PermRole, related_name='user_mapping') + user = models.ForeignKey(User, related_name='user_mapping') + asset = models.ForeignKey(Asset, related_name='user_mapping') + asset_group = models.ForeignKey(AssetGroup, related_name='user_mapping', null=True, blank=True) + + +class GroupMapping(models.Model): + role = models.ForeignKey(PermRole, related_name='group_mapping') + usergroup = models.ForeignKey(UserGroup, related_name='group_mapping', null=True, blank=True) + asset = models.ForeignKey(Asset, related_name='group_mapping') + asset_group = models.ForeignKey(AssetGroup, related_name='group_mapping', null=True, blank=True) + + + + + + + diff --git a/jperm/models.pyc b/jperm/models.pyc new file mode 100644 index 0000000000000000000000000000000000000000..441355de3870effd0e3ce2637479d7d290584ed2 GIT binary patch literal 2230 zcmbVNU2hvj6us;3I8G^*8WDkjqJsQ@k{{3t(SpK5DXJy~3BRni-ifnjKdhZuN}f~o zzwu9a=Lf(!ckH!QsAR>?PG;_%nZ4(nd#}5HAB~?aAN?|y^{0#f-{Nt9Vo329NiH%A z^N!?^6djp$B%-e?c~^>_%z9GvW!4YYp5y~5hB6yUF_PH`*1p(|EDz)|l5`+%L~cZW zosA_O?l?xR<51Fr9mlwJOe8(raZFmrk)%gEjytX64iQ{TKLDESAAEkAMwt2mhN4Ps z?xr2C`xu@$XT2Y9Wb84^@7Xh2117s;y?MjU)-n-uF&!ZkKf#bR zzKYB0b)2NB0xgn1;@p-Cf0ZFV@dR2nd9HlC%9HXp1)18*q{+R9SF*p5BGV)8=Dl%T zCWVb-y)KTyX_I4VxYcvl_ldVJv%;QdHc#~hFYCtY*%U4hm(u#(RZ@pN)FzqxtSa^8 zwRL#6Qvgq^Dz`})_EEF*B!_6!EOW7I=5yhHEbTdpAESxAV})wSW(MCW+(Ai5Vl#P?pL@myRx=E8p!e}TR4C=Q9KIK+kGngeS~ z$bpRoX<(5L$OMc?hWf6!H9OKJDCmWfUq3OP1K!f4Kpk)f!gLMn^enA4OBQTLXg}1&*Fuq^re2Ozv z%8|=KbYH&;MjPvU8D|69pK`U~-#zo6PI4Vyv0NpTJ1xD5bpAdkbZ$T!SE W$FL`zyU}rU+&vkc3{Ltd!+!yEDw7QW literal 0 HcmV?d00001 diff --git a/jperm/perm_api.pyc b/jperm/perm_api.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e23e897553b79c08f9704b9b014e7adc196189d1 GIT binary patch literal 7863 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 literal 0 HcmV?d00001 diff --git a/jperm/utils.py b/jperm/utils.py new file mode 100644 index 000000000..76a0a8489 --- /dev/null +++ b/jperm/utils.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +import random + +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 + +def updates_dict(*args): + """ + surport update multi dict + """ + result = {} + for d in args: + result.update(d) + return result + + + +if __name__ == "__main__": + pass + + diff --git a/jperm/utils.pyc b/jperm/utils.pyc new file mode 100644 index 0000000000000000000000000000000000000000..535aa36930640206fca7b322231d5527dd7fec59 GIT binary patch literal 1062 zcmaJ7dKzh*k z`9Ss`P(EaeZL8m?8_)*95jjcm*>*L+=ph%Y{~-FZjcm$LJ)(S%DN)^Ft0A36do12# zm`RAS%3PR)O_r3pT8DLF?Pb;Ih2%^El=;GD!UlqqxeWt>ajoc%C>rycFQrLJkooY^ z^F|_VU1yC%tZUp5ne57Cr4|=(>?m$}UYRr#*OV3|E&w*KOd0Ww%Wg&(i|R6KmYkKP zHY?-Y49i{Paa~n~~zs@*CRZn1J=6=X6 zunH9L;pR$|isN-+$~cZ#u{7EmVZ3;+arDaE^~C)2)MSGp~-SKO^+r`~uz IzBN_909Jj#g#Z8m literal 0 HcmV?d00001 diff --git a/jperm/views.py b/jperm/views.py index bc0ea2d8e..675ed2858 100644 --- a/jperm/views.py +++ b/jperm/views.py @@ -9,7 +9,12 @@ from jperm.models import SysUser from juser.user_api import gen_ssh_key -from django.shortcuts import render_to_response +from juser.models import User +from jasset.models import Asset, AssetGroup + +from jperm.utils import updates_dict + +from jumpserver.api import my_render, get_object @require_role('admin') @@ -22,8 +27,8 @@ def perm_user_list(request): 2. include 部分:{% include 'nav_cat_bar.html' %} rander_nav 为渲染数据 """ - render_data = {} data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "用户授权"} + # 获取所有用户 users_list = User.objects.all() @@ -32,39 +37,72 @@ def perm_user_list(request): if keyword: users_list = users_list.filter(Q(name=keyword) | Q(username=keyword)) users_list, p, users, page_range, current_page, show_first, show_end = pages(users_list, request) - data_content = {"users": users} - for data in [data_nav, data_content]: - render_data.update(data) - - return render_to_response('jperm/perm_user_list.html', render_data) + render_data = updates_dict(data_nav, data_content) + + return my_render('jperm/perm_user_list.html', render_data, request) + + +@require_role('admin') +def perm_user_detail(request): + """ + 用户详情视图: + 该视图的模板包含2部分: + 1. block 部分:{% block content %} + rander_content 为渲染数据 + 2. include 部分:{% include 'nav_cat_bar.html' %} + rander_nav 为渲染数据 + """ + data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "用户详情"} + + # 待实现 + render_data = updates_dict(data_nav) + + return my_render('jperm/perm_user_detail.html', render_data, request) + @require_role('admin') def perm_user_edit(request): """ TODO: """ - header_title, path1, path2 = '用户授权', '授权管理', '授权更改' + data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "授权更改"} + + # 获取user对象 user_id = request.GET.get('id', '') user = get_object(User, id=user_id) - asset_all = Asset.objects.all() # 获取所有资产 - asset_group_all = AssetGroup.objects.all() # 获取所有资产组 - asset_permed = user.asset.all() # 获取授权的资产对象列表 - asset_group_permed = user.asset_group.all() # 获取授权的资产组对象列表 + + # 获取所有 资产 和 资产组 + asset_all = Asset.objects.all() + asset_group_all = AssetGroup.objects.all() + + # 获取授权的 资产对象列表 和 资产组对象列表 + asset_permed = user.asset.all() + asset_group_permed = user.asset_group.all() + + # 获取未授权的 资产对象列表 和 资产组对象列表 if request.method == 'GET' and user: - assets = [asset for asset in asset_all if asset not in asset_permed] # 获取没有授权的资产对象列表 - asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed] # 同理 - return my_render('jperm/perm_user_edit.html', locals(), request) + assets = [asset for asset in asset_all if asset not in asset_permed] + asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed] + data_content = {"assets": assets, "asset_groups": asset_groups, "user": user} + + render_data = updates_dict(data_nav, data_content) + return my_render('jperm/perm_user_edit.html', render_data, request) + elif request.method == 'POST' and user: - asset_id_select = request.POST.getlist('asset_select', []) # 获取选择的资产id列表 - asset_group_id_select = request.POST.getlist('asset_groups_select', []) # 获取选择的资产组id列表 + # 获取选择的资产列表 和 资产组列表 + asset_id_select = request.POST.getlist('asset_select', []) + asset_group_id_select = request.POST.getlist('asset_groups_select', []) asset_select = get_object_list(Asset, asset_id_select) asset_group_select = get_object_list(AssetGroup, asset_group_id_select) - asset_new = list(set(asset_select) - set(asset_permed)) # 计算的得到新授权的资产对象列表 - asset_del = list(set(asset_permed) - set(asset_select)) # 计算得到回收权限的资产对象列表 - asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) # 新授权的资产组对象列表 - asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) # 回收的资产组对象列表 + + # 新授权的资产对象列表, 回收权限的资产对象列表, 新授权的资产组对象列表, 回收的资产组对象列表 + asset_new = list(set(asset_select) - set(asset_permed)) + asset_del = list(set(asset_permed) - set(asset_select)) + asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) + asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) + for asset_group in asset_group_new: asset_new.extend(asset_group.asset_set.all()) for asset_group in asset_group_del: diff --git a/jperm/views.pyc b/jperm/views.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7e90e65382ec383d408f8b870eb7fe4076aeefa GIT binary patch literal 9056 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 IL`Tbi0F2e*8UO$Q literal 0 HcmV?d00001 diff --git a/jumpserver/__init__.pyc b/jumpserver/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84249321965d97edd465910209d425e6f945c3d3 GIT binary patch literal 126 zcmZSn%*$1D#2_r00SXv_v;zl13CMf)YvbkVsu#iv+<#CPBJEiPDJjcre`n2AE6J zGX&wKsw|PZY+bQs%aUbDw9eQTNoBp(LCLD5Hm*uixz@E+N$gZADGmT;v&n9yDo3Tt z&i8$A?`+@t+l_apP59G_|99XM6q}9l@aLGUF^MSe zn1oZSZ!(D{<(o`4W^yr;h#4mw(`*vWYKxg{i^;W`L~GPG$0X*ct=VMfnp~Snw3%GH zNwh~j=9$F2+A19;(NW8HnnY(UKi?$g*YaH^(N)WLn?!dlf0;>KR?GL8L{BZhz$6yb z@(WF3VJ*MNBo-;(VzP@(?sAj3+~k&+#1fNRY7$HB{#s3TnaM3TiRC7@!X#GM+BqhB zg~?rM5?9*tT$8=Z2+q-DJGW z%n8RhzGKF=niIx2dB@!28#A`ejNNR)%qTiM_KC2li*jDr%l8~=7Q_N7|4KQjJp z#_KUBn(X9uI$OJdwTUk`bp5jN7OL`&hDwZIq{{7@dWZ2A8}D+}^cla|jP2CI{SB>4 z)Vixyv($LYRI|IGX1QwiT)dFo(q7}OFemXacN*^s<6UV^fEEX znX6fY$G$f)V7!&J+H0cP1IAlr{DbPdI;#Du@vhZWuJP6wuUGRAD!*3wL&m#K9quwd z>aW*G?BQZb9x^lkHkgwDW};TKl}K+eCtFP7zR%QeRQ(a-ZPGmV8xNGS z#dtSrp0642Ce&tH6<%<+<2p1d_H=( z{sR?1C}U@3tZGL#qy8>zQL8YsyHuzYZCeZ4wg;H4++NGsRy|}?w>_Il1@%YVR~WIw zdobw0(3qbt?=1MiK%v}!EEAN=m!o=rC0ouEv%YN(T)$i?<$cdivJf2_AI9~)ObN5t zR?b@T^PXQymJ7*J_`tS}a0}3u%%w8f;5L+&-?!5D=&hji^)GxIY;vGn4}GI1Os_zf#Jof%_9CnMwNj)KJzhb17dHqlKWHtYFDB zAx$)J$v%97Ge|Nmri_Kf09%=ZI%_h@#f%rTIjFH_n`<#%i`n|1qd~34YbEJE*kq1F zCe8_GLXE?j=92i>95csbY(5TI*=~-5D79iJe^wBH?!z)+D=x5g~8sr z-1rV8?Q#5+gzR`K4sgYXGg&`g5Rs^H>eUaXo;p4C%(K(4e>ijcm(w4gMz5(SzFU3j ztlG;2hUX7eETl8};eu#=B2~&~@*`^YOC?~Di>6DNaweV1ihk>e3T{T*>fTh4E@yK7 z+919@zPgt?$)}=X)<5cJ8_GF92*7S@gI*$CYhq_$QM=~O{vCJi7Hann>^h*#;qC5# z_S5gW2VCu^&)s`yZ{PNPVm9#dKFk2t6MRtOlA?-T*vp<&-phu3dFQ?ZyOX>2?&}v3 zVW1}1RVd|B09j8|pA^%%+N&4aG^p2)jyR+HDvSEaVI=*E^j~m(z{U3Vb^8 zn<0^>xhAPRqV%t#0P2H)T>|PJZ#Jc6D#y%{JjlE`Bw@5)4)Pp_RJfHS%`)0i1sVpO zq6)N#?w5mh2L+12#nd9FB2cPK_3=k9och!M_R*6wpFCIn;mcDm{cP%Ir)=f)izlaE z`eya)Gw3k&y|dNF&$9UXTeafzGpF9x92sssgOADZVf0v5E)o8vR36frU4#h>b!vfh zr386a76x*ee3E;zh14+>W)JypOv`DKSqNOnNJ`hIP#4flHZ5@{-XwSv>D+=O%l|=! z@RIQiSV2NeUS-OTL;!diKm>Hb*0OT|+{5|HO*2THmey`VOA9!O8QN5M#BysWU?2u4 z3@~A{nOvaCxuJM?umzK>#UyP8EIJG_TA)O}~)1qmK$QCo+VoE<30koRD z z;YuEoqL7cTs|haxcTErqu6VfuRn|a8)kl6d{oLEt$36zRL?jgvQ}xUTGw+_NK5}CE z+(}C}8m z4v=eV6Gey&-7lfqw7frq-sVOk)D^o#pamn%((BHr;_w;3L7u`iS%n9di=J7>#dGJ@TO91QcmZ^&q-t zW#A9CC^MI8l|$O76`5%_-dts%C)lFT6PQ?N_GHJwE-@Gca60O4ZXZPd|Nj=98DFo_-?;Myua>a_02e>c`)k zdj5^-C(mnWnkeUo4@XP{6uzDqJ6U69a6!@<0FsnRq-a7Vm;&|4;8_irg2Xt`DNBrF{Xii_ zUBupp_8#cleR%J{U;~VG@7NEz~4)WL1BOC z3De{p&R+(d6q7dENo_=x2E>MV&11?4^q0gdsJ;Q07ooR?#|He$%&pa58ozv;Q9m;> zS{5FKhKY<<9+jRLkXhk+=;R(iB65Id1SlopHcDLgA4~g1Dlyyl5W5M58EZ*YX7b^6%;8`OY5;miOb*b#6-Q$dtV-fJPt zfpy7jVnv{f8EA6ZA?ys*Z<}nUu}REKgu|FX+D5fM95ahyc|@yH^jQN1j9%Lc4Fjx= z*<~|;%VCL(b(ja?A)!wvxAh>*7UU7mgE`S=7Gs-ZU2GWZR&#r;8FRH?+#I@2^UUOY zQ@)I52nK`j)`0MOM0i_3cTO4MKI|Oh9hyg6;bBLn5G<+kLfS4+F5G1YEUBw8c##H= z)ds_LYi%4>Mi^tBKmm;fmkoP`#)7*BEj8a9M`f2L?Kbe!$MA7h z5OuVw4VKi@iw$+B^g!+N&Rhr2NK+fJrsj@ z>R2UyJU&wLi}BS#Ew}!ttvMb~O^nCa{BgWkf^`*NwJrYO8W|T8qlH>ujk>toP3#uK z{Jm@2gAMrKSMpP3p9>7bzxTa$@q<|(v4D84;AMs<*-)fB4+1dc21&$Ju%$i_`;}w- zMMg`ZN>npyAYL!|xkA}bLL0YXP7i#al!~VQ#MCg-%A=AIK{-__C+P$Wn#GJ4T!ub_ ztd6rf4yCm^XzyK)T4{JJLGh{?m>DYoP;?^#|ZiHCDT&%!9zkroi1;vQUH_%b5XOTZNhNjO>>QxVScQU{L0-{OCaiZETq% zH3fIO_kgvLDTXBVApU%9l4#5qCbZ-P!Uxve2~tOWIsWb;j*tc|Ptvp1x|#+L1$gF) zNkLWc<*W@wE)W)}xH!5NbpYRD-h!8!Od`aTN3<)NytARJQ0G2?8W)nsO7LRY8t0j! z+&w)`ZEB$vh1m;pnpT_zfww}*`}ZgX8Iz%5AnWC zc6X<^Vppf3W+ZF|^pBTZ%m)P)IS<_Ih~IIghvS|LNJ z`8y>;->GSSI}nP4=HoVJ^6TML6#Ui~MifnA6WjA(HZ+;ij5!E1fs1vUF-T8E%ABx_ zvjPf9JaW{+f~`LMz&58Da(`@LT@9e>o^U!C=yoH+1~fCa_#!~iYL&+N^mZm3ZYPA% z<+bfRFl_L5_%PHL;lCuDi}|Hei8vRtyM%L7UPkFYhBE~tg`$=fdJ+H{$~bw2DPO4! zq6Q6}*%W8}*wyN7Eh*AN@GT^fxW5bXv6w2Qa+&c$oc=}L&q6Z}C9{M7jLJm0nrRuX!!;ez&ht)^kIRD}6=Rf>T^`p8K z4RWwQ83v(bXj$`0ao&DtC^E1WiM=b))%`w`dyz=cmeUYd2*{P(ud#|kD=2%JyqjZ@ zVhYw#DK+7Kon=Zxl+!~HXXACV4OLu)<}@YNp;E;Uhh`xZ+))m-LNI;QrSIw{nLNRI zt~i{n1fzCDAw7=C2Sq&(a>R^`T3I@C9~eW$y9?|}OlyFbqEoH?B> zpc_RWr0p=guwc};a(GuNixvt&U=2abdMi1f@px{)CAJk@kPvmBL(%;n5^b@NMK9Q@ zG!RQlCzSebn#1s!UGS0nMEoLiEQxJqv%g0%*vVO1dLY1J&SLy_H?<+R0fMW!iNOQ5 zG$S<0pyYh~pM%=vs#_jgDsk2ZH?zkIHA0YJ>BA>z#kR>^_;VPJfUcx-fg)^8NCg^g zwg)5`dhApWdD^gW>pehk9E45?F(8l+J2;#cR;cw~U#G&NA=}Wjlp?b>8#v7_3>6d( zRt#;p*$hULK~hjm{f}A?NIw|Qc4GS+9ii3DAlctCBcBv@vK|pqVz5_?{Q`gzF*d#2 zRA~gpP=N-Y82Z+DrnoN7)0TBI1gY^+M!;agiw4s3edhZ%+Hv8fZ_d2=5ZJo<%)>UU zcK(A`s%PJw`oWp0m!7JA>lEh$f5SP(f7y&PKYz3O%zKEDRL?v*{pv%}w82{JZsyDz z=ifg!_0oqkKmO@7CVuYi_#PNHG|gc1g)5_Y-^zU}*Tq-vUwQvPFAV@i zOvIjGKD#sbBEKYbbL7>CoFmraXS)Y6F!9zHWAeKBoU79SG>n0n~ zp&5h+sQm_Ck=$LM3sw(=(R(z(m0cG?gT1Ro#f##OO21q5YjJ3ivQ-y&n_8k*?{G`V;IW)kP4FL>2$NEK^31Fm?%SP;8(3$NvFxA2 zT)|B3CfR`;?tsY8qcm8Bp7ZH0vfHm|YOq;m0-IaRJ=n+~oWH?dX$pclqTt=NxKS`# zVKRCE2J}Au9BgY*F6#Nm~DMQvX- zdq7NsS^KgXY({o=wvh6Yj9vM;q>fs3U`rndYAh+YEI$&pB#Q+c0!#uuI1R6q3)?;K zpsgVjg#_%r#C6#PVcDc#3%2O6`(ijmffz-|v9YMaGW4sM!;K?R5YehiBHwbG*qvAa zS!u1=v)+6RY+yYQ&TcZ^5>%U(CC(MG4%qDrpbpnU`SGN#yGcw(Wk*1Z={`ax)Nn8d z!E)paX+P+|#i1^Oaja7~HXy))yv|%~sFhsQjL4f#V!#(m5qWDyPeh(mt!8qWVy-Z( z6?x?higSR+=G5$RpdFkAK7{sh!h-B^huxv`U}UoznvCW)_|WFSW#MTL?`=f9Qlmg? zYSzt5tA8Td9rf3F=E1>DUs`kDk;)y=8%GY`e`HmBO}mbl({T7pxA|!V4%YkeHAgmX z*>c~O%{eRV(b+>JeM7uIKUSC|HLHDNZcV%EV^0};j62L6#a*ZZgnLHL-Cr^Bkcfsd z`J;t#IF__?tRX4Fv=%e~0OV#y5IPpS4(?@)xNnb}>1batwhqDHBwhW)<7>ur1dkh{U{6n2x z@X7n|32147*6hWZfB}XG2mUcXT|uNJokREtN))klojF7urk;3f=G2qbzxVO^bFW90 z19tmdsQ$E=V%AS3H5%^WkNI$%(zHlp3))EqUXn?v;$#xxp9;+5q{bzaULl=Kx_4oS z@QAnpge77zqXkdcwK$TKAskWGS=}X`9nE zzinRI%C_}w%i9*UU8Nl!ob024kVZ%SkSKQG6VT-VonG>|%*V+QPRzuWxID=Nw3vaZ z0w%@vNfvc<#v-DP_(Ojjo#AE|e0O_vHV@{G)p~odkkFiz>e z`;&b;`s73brS=Y%mDKE6$H^B(2T9-w(hpbTftL14E@p-HO5B49AXx!j7&jwUn&OCi z(i}sGLpBf~y##>WdH)L8H1aiIphNh=PC*0yoCnsL!^aXFfZm_eSqpar`RZbuUFAkLw^LM}pBRDa>cXJC|1KljSi<4s$)-F(Z&)KJ>LezEFGsr^=P16UQdMv3*D1&i-Ay_w2p% zEBp2j960z@cks|%cOSmz-b7O85m(=_YW3Hyy{>m{Qdc$@Neg8kk4hymQ$<7@J!S1q zm4!6Vq$j4O$;hIr#e4{ z5JDijDnx^M#LpxA1bq{Xrf%A_nFcp*V11T|E&19`795`5tkQP3~KK4A`Ui+{iV7$UvkR+*EU_zUKCAQ43$ zg5xb0M#jCh7wj4?=}}U|+8`u$8~<>B!_h>NC<0y(k(Dk~!V5pR*eBLcXNse|1Z0MpWnNd9uzVGMqCH_b=*3*v%1B%4IEB2z`;f&^hLetTrA+Ypn8 z8bg4h>wD z&%E^-SdBMjo_*3@qOo*f)d~Vf(Lnbvv6}l|kl2_cU|~Lu#y@3UjLBaiksybX!J$(_ zV1xi73f#YDhTK=orWkVhgV4ei|BPti0g-7TN|rjEP0h}Lz5VqsQS1IICjXiV5#sWk z-F=IR=y8U*|IB272@&mb+B%IW_eE`!Ut=iHXaX_~OvR?Q=9ts9pldFE7l^9UXwVNq zNXl2d+;6ZCVa~BlN1Q?cZvw@ky)${RRn1ve%gkdxsh)oE{0C1|KYF&Zi;TX!xeNF&0SdU%@9hg5($uG9do&0wy zQ!+Z{DLJ{&;~;533R04xRhLCb!KGjT-cpp{L{%u)h#Nf|%vn%&dIm48u!Buecv z9@}vCh|?6wD$%pV4DH#hD197vsz(AyNpkdic>fd{*Xe@85krcBEM zSSxc8;p+jVw>mlx7FviBe#n8r0wj-N(*p3L06A1gqmml0;)vIfJRT9$^`V01 zy?-g!;JZ3S5YY|hN7dDa^^*-<ef7!lxLICQ{E;C$fHUdwy58oVw^fx3?nui9#XAmdS z6zEC3a543I5*qsOMTG=s8M)< z7YvakQ2sJnr=_b?y1qtyedrlb7UC5c5Gtr`E5sN4x~sEcikHJapuf>;7ZGeQ}4Vsed@Ft zMM0uGk&%lVkM{Dt8zZzFB;n<_W|r4uc|~faF6%@jl*xk=Wu~%tZxKIAz9@KkK!URw zO%Og1g;y|_GeMEB!XabC;)JxIO!tDi#Ddatw(dj#th@Js$9C_r4m{0oYgHMC;0J&Q zm`cN_j3^3kT;X3B-DIdxP=e5fvPD3=oI?n_cG1*=Iv)?2%K}>`Zeh*&_usK%5W?-k ziMKC2ZzY@id(11qi)*jR$bljwWV`{f%QctyvC-^07HBBB|BK20WgM0!l_m@;Gd@Q4a{+Iu;n94B@Mi{JP$DJ?gr>1x7aQ_{P0zRAV=^dZmr7+dt|DSN@`&r8(E@w zn*8+Pqc`;$Ar66J)q80hg$T?ntMmwWXF zQ9I$JO#s-y8jx*ti6%v20a|;|8TM?Vyrdj~bO(4LW46Lzg%acqTbUL-Mumf}c%Hoh zJ>b5H#p|+H+MRp1)*_G80>y7#3dII4{~H$nCpS*1=phD{!J9Qw;bQ^bO63E3eA&{a z?O=~1M3)Oms|%1QT!a^z1aXc@^5XLBA?tw*ar{H1+^sAgbV4M&C7XlM=C_)!Pp^(jLMPicaR00>KL_8=pXa!1Lan9cCD z!&@S_;nkaVK&`zgO=-h*X}<_=|CC4*+(3B%-BN~x@dDRYhIv4|U~d$u#n3(;V*^cw zJcb~){i1pypsZ`)xQaaj;+|`ct>P6ng}D(f!mSm=jXxdvx@yBUeiyBQ zhZ=JDw3x)M(Wy1&YmLt6IdC1|63-EL^ctn@v}=gP!!>Y&UC$Z(s-McT*l6y* zK_AgGVlwtW8p+wXSX~)nPZlIpS)c(tlnLtdw4p-Bg`8D(VJ~S{s!-mlhN{2yZs_RP z0k)DBmV}m1HRDn};H?{o2$ZZaSHA!^J;Ht1#o-)jm`YkH8WGg@%wF7L)P@%Y!cxN~ z0$sdosG#em_@KtA!Omm*u$98D-a30xK(N+uzl%~}2P#ZUH&oS9+?qo$5jkE5UOuam zqz8Rv>H$fQ|L}K`9&U^ z;&UYlZX)Yq5h(F^S0k6N1D9hBD@p9rM3N*QtpQ2$8?6BeVb|!EB)LqIq}xi89&;Sc zU8MHoJ&kKT>l}uqup6y#T(FoGDRwb^`3gbzo7!S{)x{cb19d@Q?JH7&dkJaaUP%dY z70H6C1~FC~)4Al!1~cPo_F2i~8YZ&eRxw9`;l`O;&EzE%^@55uey?Sn%Pwn}BXhfS zv&Gl$TI9r5b)gVMvME{PYnPYUWT{w#@&*<+GP$0~CMKJiK*2RcWWT7B$!EqrXuLx* zLAIl(Vi2>xnC;>)W9m#8|J#@lN6qY;#*S!7)YUfOZ%s%DHK=Wikwt)8OS9gp424mAc}_B1?H3Ud*$s2E(S~_`26BK$`Z?PsiQA*Y zi#P4=0JQ6lq_*qlMid|ozinjpTjyfhx>o#<8z(Cmh=_>d2`s^y_g}DSQmt%rK%C?Y zxHpBYJ|J@jcN}?|g*UHpMJb;S@4HAu(>|%w2`*IP@T=^*W2lx;o&6JV#@r;{JK|UT zd{T$JUKQx|IdO#v-?4Bfnc!oOOW{KE1XWVGk2jYJ8~SucYR_mdupg;!2rp6x=}gAO z?BV&|dFCEt@^6{k3e>nCF^8{^Gwu;4|Afh_On!t!Xd2Gr_&+_WOQqfzzTl&PF9<66 z8=~(<(6==-e9;0GRoIbOlAG&tOETiZmI#Ujg@|#CI%k89W&*3uIFX)nOjcd3jV7*3 zN6n?hDRni52z;%X?l|56jrO3;M(1yVOXhQFWXgB6rmTG|d~rjmjH`BmD}Ixa+wj2r z)*^Qy2QDV$u3_$8COIV9#@-xnm+L6p>VT{dBbl@bL0EPrmFV=Rh624@$UMZ3-UK9o zl6qARSLayRv3;;VxpS|p@qGsdcDdg~t?uOrFZ{Y3G`s6itJQJMHu;tQdsVrfm1JL3 zs5i)l@RcsY$h`x}f$jV4SMA*8?$h}F+xPBE_77~|v9DhyxyrlT1N+@$TzD&!+nF%H zEz86na_OR-`)jt0GC9e_hTsS%x#_ZUx>@XDvW&?9`(44@jZAK4Lg6ea>h5H2HyAMgbP9-?md{oAs5ToTUg8X2Jg6PrQ}qejOXAj zcmVij9g`rA*xs4l&-44uhCfe})sN>N3)(*c^cyVq5~9SXs3vL@traOb2UG{tgtQKa zb4YbWmt{oXh}JQcF}+_*;A?*2St#r{g81NcH=JUe-a4mwIEuxyLgWl9#CnJ2zC&z@ zDtto~1h{co zUa+~=X8r(NJp|;mbH=vW=yHsWuCN_KvgN$a+P?9w-erjAF){mM9cO==dFWuaNMPnG z+oxuk!)MJY)bPW8s&v85|H$i_Wr~IETV@&dm8n^G>7Qv|cD-f^iZN&UW@EbBg^YLT zUVrVi<5Y5_ayL@>l?oZD_@qJ_h5>HcE1Q+3SYS_HxEI)+ch>TG)i)b(dab+TZDCv1 zH=J!cTYyH}x#i~86W!*G_OKM}o=Qk{rp|&#O5P{YJV?}Z|0dyuzr=hWR+W&tY;37( vHxP0vXfAhngnj2i_Mxg}zA@=zK!@u8r-d0Jy+RRvtzSzvCvD8tTqWUepb^p4 literal 0 HcmV?d00001 diff --git a/jumpserver/models.pyc b/jumpserver/models.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54dd681613bf2e44c4af19f51b516fba52763191 GIT binary patch literal 840 zcmbVKOK;Oa5T3OYrwI?Cs^{J+`9i{p6G8|iBo67pK}hvwwP7cYo%KWZ7`5jh^-uO+ z@B`?~x=I6wO0f2Pp557bd@~Mzy_mhdd-Lr(JgktvA6UBA43=L74xm(!Do{26R8R!4 zQD8&(39tvaN<*+CSjA)Z$ba*S6>AhRl(j|I(S+3%66IBPNF-+;S-M*W1c{FU6dcPZ z-GfR;f1F72v7}|(LzqV1I`Q{M@VE8kN#7}04#mFFfy4}wReZv=(2Sup*VX{@_bRnBjxZ@r|Z#iO!B(nl{%v zywQ!JtuN}4jo1ExlC)Ba?_>&*I#uWL1edW4%JZ;=sj_-**8?@_!BYOlL|p$nv7gAh NVLtC=e7>iz!h2ikss#W5 literal 0 HcmV?d00001 diff --git a/jumpserver/settings.pyc b/jumpserver/settings.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c0a9757b40074f213366270634aade6b41b339e GIT binary patch literal 4006 zcmeHKTXPyW6h44WV&Z$!#7)waG&gebVyCX-q)8iW)-Dqa9v0W>K6Gb60+#HBtVCS< zH8cH{{S%$OcBVZ#Yhax)|-&n&)Q;!pgY0AK(n zwh3TKa1&r+C+a7`Ob+@fFjK%&(4Bzy012LiZc_EkN#F_SrlET-);SOF6Y6VD0iT3! zW+wIFR8*aWai1(`F%JxfTMkU2sko^yoE#}G7wQVTI;ijc(tk^y#s zkc%;7nvhE|WQLG0V#q8ZmkGH74E4+rvIJ}%%rAjo1@juU*MTiS8>jjeuthL$0DA%E z*T8-NGYjl4m^Xpl1M?ej65ynP<$&FXb-oDf0lwyeJ;c`nut)fs0k({~2R{`thjSlIQ)>o(OC}Lx4LO0YP9P+8dO;X< z`WO&-9!Wi0h{GUcG+?&08#Ycu33;~T$_#e6>RF^?G$c*R?1*ZS(u=3Dq5hd6j%=26 zg?Nm}%{wpT#%e!keHV5-*>mpZj>8vke{I>FTerFIA1yaudgAbS?Ww!=xVsXpJzW-4 zD7K=}li#3Glo!mBxP-K5q+%dLr=i)*b9|w^`jF6<9dYerTnTbt%A+0^;>yQ#fiNzX zu`~~9b{m_kW8@?*vZh*EV?{fC&-R^T9wnmNt<9;&Y9%cdq9yd|IF$UUc(&mfFj&X4i*tq;Ix`@G!39gTf#$9xs=9{kFe1jE1 zd%Ydn9nd5%&~^nKnvVwLi3KqTUV+q z=#`yPMW@(T3cFEf-_UE6eSh**6Q+{Qp{U+-<9Iw$jGTc(lY%` zT3C*n7>FPgnyps!?KnRsatt5ijec9)I-Aj1-SGd5LXR`Y7I)58C}A-P|L!5n`O~e2(LiXh;QN5$Z7A{AzpxL3Lq5E%6`vs z1DoNsNL6ku8puW!xo68xRFR!f6%H!imZc7IRISpvSuk{~SgH|w$ZbZQZs7Pbh2%CK z#HykfH!UjjN8j>cp8%NYg zqq+dau%Tupiq15Gz~#0tRk4fM&=0F#HprBrZ`Jg=^-BMRW>ydToURr{eRF?DstQoo zclXMLI);HDs+r|-^*}F@hmo4iTJ@D)v-WFck||Y;dZAoKmcrhiAs122ZmC!->j#CJ zZf%wEeAEp}Ppw+5E3vI=Wm~E;b71V0lvKI2Rj8M$6{_Qd=onHR+(VC0sII@RTYI(Y zmTnl;nnAN1(lK!cDMfGUrLFB!SvOQRBers(va?^#> XRN~z5nVmc>m7Z8iFHI_~^rZg>> Success" % hostname - return results_r \ No newline at end of file + return results_r + diff --git a/jumpserver/tasks.pyc b/jumpserver/tasks.pyc new file mode 100644 index 0000000000000000000000000000000000000000..492bcb3900bdcc0855d375686cb45757ebca42b1 GIT binary patch literal 1506 zcmb7DO>fgc5S_J?Hc4AZ3N2JzdZ1EHt+-S|po;Gn4h1Du5d{=E_9k`W*ulH5sFa-A z6GwgrLi{&=0K6GDO)7*CPIf#y^LBP--q`)QRC(~@-l0zyPXX^oSmq%_fWM-MXrSmw zk>b5WkwXKQj$9fP=%@f|fiC_oox?H5+h)Cp0O2n@bp_3qAl^jY>60Ys*B!Q$A$%{2 z+MeGxmf@KVBjdBSh_#0G6w7==087+UbVf8Titcb`)}>wnMm3%jW06M18M{*Bc^Wyi zJ94oKScIi$cMrz&JHgDdz|taXhX4p%0)z`fs5w3!Ac#vriIG8>MnG0*G*7{TT(?LT z`Vs}#kjcVWQGEX|(f)C^gtNH1SCTSuT?v_nE_IRAb=u}vHGkD;dt9c^Um4OXGyK`d zbNb-WxI$xOwLrZJp9z-f43)lDqcU&Tdhk`~jG4T_+UoA!r*(A!uTJ1!1YW%Yzc~X( ztlAal%GCK5H#O_4U~L~=Av)1%J26_gK2D5nMWL}W3q#C88?zw9capSkLMGlWK%{z* zSl!BuPG|SSB(=5*|1b?tJOKLowABeC-H-`mPnyNCPFq*U%2>}D5KPq8elpM!GgtFF zc<9q4vEs<$RD1rh*N(I#+VR3DOSO@DOy>LAn2-n9EJJLV^_`ua^_fFvX=;9fvpO)> zrj}+Npw0uHr_IjC-EOM8D5)u_)?ngqh5Pe#@`W@mKbphmjVG_0FAv_?TQk6hls<*S zMV2c&NHdKuMVces4y_&-v2?YSzIel-jsr$!4UI;ftyvWXZmJycxpN0%M@@o52twrL26O0sN2qpT81|F$8XWOYApj*RCm-G z@HOZnotj!w`*jW~1M0;l#QbbdZfx*HQs{+8sLvT?iuRLOH#VS5OZ(6IN;v#*kOWzz NcbIF#VXJD@{SAyqNd*7^ literal 0 HcmV?d00001 diff --git a/jumpserver/templatetags/__init__.pyc b/jumpserver/templatetags/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e92dc2cb53192d09839aab48cb0c7a2e57b7978 GIT binary patch literal 170 zcmZSn%*$1D#2_r00SXv_v;z(v-|pKMjz&5|Ens z_{7qZjQpbbcnu(r0YMa-0J-`_`S~UKS*5uJ#i>PQsYS@llGNOSoWzpUlEn04{rLFI eyv&mLc)fzk5)Pn7o80`A(wtN~kUhmf%m4uMIVP##vy^Qq;(RxT0yZxq=X8kDN(4>50NX)k^+{fwe}3|Y-e}P z+`AE$5~-2{4YY1d3vEb4QYs(_RcQ(c(nP3#gpb~reC`iupXc0Ndn^!AyR3a@&b{Z( zopYY^I{v>$hmL-E=x2+n^Yd|k3d5{vr9%8`l_)j0NozHyyX&5s^Mv+P;;Twd&E=Hl zGrmgt)H9@VD(P310W~+Ebd*!&LA8q0cBp8FDi5i!Plf$h(cyr)pwuc3AI`A2S%*8i ztdR_BNLa&N)@X(`BCOFaYiEYFQ&?kN)>wu$F0A{ytnmzMLRh=Htot&o`-Qc;%bLir z_6X~NE^AkY^`Nl!s_-FoL5tS+XSjLcKCHrhUG8pLp;-71%o6_xzu5w8qwF9rQDr$P z*~qPM`4LABfjnVMWKSe<$=DpG)lwz010dq6J#1{c$n6{+#z_prhpbZP#1ut2$mFp$ zG>IRcnrwgZx8~YkH*VjV#PhQ1-bSy%iktLda<-JzqXGye7jqcYOj@hinR30dY@+mR zlxE4U9=5b(W-2SZO)swm6nhNAP(;-yDlbKLKCLB@h|d>ulZgKeh}b7sp{I_9pmMm0 zj~zX)shI_9!0D&Yd+MC0($ngkR%K6FpVM-V_P{f%o+{#23$0g%vD=@$(z=O7-F*}5SuOs z%l#69AEEuqT7d^weENkk1?xF0{oGS8eU~OG(!7~nFg47z|0|nMbMu}e(oC^H84Xnx z3pH-N>R^T`8W;c6e)q#o@9sJ`oJo8}sYyeLr_AK^^mGhL#nfWf;mch~R24MKwYVB^ zp}-AW>dz;!v6jYJA{xB|z6(c9VTfR=Z$cmR>^SCP+!7;yez8`sS_u>S1BE)t2cE+P zxR&vc?4tx+&;ll>o_hH)#=_GtOsVsT3SXsD0>99R5ce2x)h|sc{67o5U>;h<<%~!1 z2En-fuQwZizLpJ+joWvdSMRj0Txh;^>)x*~$*uyi6>LOqaph8y*kLR?O$0N`ZPCj% zsya7zEGQc62BSb7g9%(@pD>MOsAY~Y!Nc5&(OX{Hivtc}7@n{C#`Kss3V+|{**%zN zOdx`146!ZU(uB_Ufhh0?_*)oGgZa%EB7jMe>t?nXOaO=H6K5FkEnW z{W|B_QOqk*Wg$vU#vqJRdXC8a7>G`lK*FIlw97o506>WNw31WDhdO-JurRmoUT-7M zOHn{V*|`0i=EZg7eCOr?U0L$Rtn*X)jpX7p$iAnT5u~<>=fI;S7$kgM8X3fP=Sp!H zJcvo}5FNxRKgBRSTlq}aqn?xsTbpOAAc|swrNJPOSsg5#|Ee zdv7Oc=T!08>Y&nEBV`w#L!vH9B{L70#|_NjLzI z)pa|Hba`>I$3c8Um%=&+y*mEKc7?4-fmSm6aFLT8VvS3e(TcTi{J#C##||`sYFi7z zpgJVW+d2*|KW@IRM4EJP*JQ1sx$-)r;XcdjrHF;Bpuy&@6*QWC2<&er7KTi z1=XFIS!zA|*ctOu-1r4k|=s6P2G};tCAv z%6V7y5u4Ik0RRT5#4@6F2~ms{^u$`3W6~Kv#Sgh6R8KRC|8}z3qfIf|^obwU_ohja=7)9*<(#7@t}cCM=h#OSJ%$vW%gvub=7Cax68e zEd9xJr4~ks37Bvtshy4&(o(u2Ag0k0y2mID_zfZ-MFCwmU;`1b7YX+BLiB=zyin(W zkrdE%0xGZtgHVQy|NVq&H+erCRh%ZSFGH|`DTac{)W59W8~hx22&59WvR MBl!XJNBv{^zddg5djJ3c literal 0 HcmV?d00001 diff --git a/jumpserver/urls.pyc b/jumpserver/urls.pyc new file mode 100644 index 0000000000000000000000000000000000000000..806161a2798dac027691af4a5d04ded8a2927312 GIT binary patch literal 1568 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 literal 0 HcmV?d00001 diff --git a/jumpserver/wsgi.pyc b/jumpserver/wsgi.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90dfb9052b06aabdac1e8d8e8d99992972b3cd26 GIT binary patch literal 589 zcmYjO!H&}~5Vg~7K>?(d7IC)3r3Z-NgoF@c(JoaHbS1ig)JtlTY3j)FME11Hp7+=I z3VwqRfN=|KE&F9WFZ1S&Joxn>4?muLsl?wk;O`qg@hw9w#DYkT=)?2huLgIX<@rth7t3|aKc zCF{N8MjZxF)^pEpM=10xZlhXR2TxQ4$k#-De5rMfRV?b(_y+%Zs<6}G_4DF|UgH&^ zuAz5$-GL{46&tH_`N*XyA=4X4d^N76wB4HG8;#9%-6mBqT;EGr1@#r uIQt+kVQ*z=02+^1{pwbkr6Qug`wDo(j*WDjx-`kc* z+!{d-NE8X7iW3|vaUw?!Ulzy<{agjqa;*i z&QYB?%0exOZo5W%gn!eo?T}_GB;r)*$XIyxjLx>RG#}5vRmr+ZkJ%=n1u$t>jA(xb z3V0=g4~w~eH>P9hFIk&#XYb{KvL8{p(g_;Ieo@31bD zxE%$_9a|zT$)l(b*wd#&xVi;Bp;pAcCwf#xPmGv5stTg$G8dJoG_%*p;!yogEmgKqFvZkRU{z;JeJ*BEsB>V3 zS^{H1g~d5Q5$3^MpW1ZoW*tmU_tH<2Gs^TzVYiEzG9jZ~9Al63$rmF8jqb3mHbqF|$ zf)3NLuMO);?+1Bg!(YhhgUe@TFX#X&f?3R9A2t53+(4FfdZv^GNFN;bmr1mFc>&Aj zY`KCZ?yCJFGzyGseUTgaZegEly~%j9N$wGJ8!0x zB}j_=JmZWE`Zm0)?Gm})4XoY`V_om*JZm8RyjKf!hCkZD_L>Ofj9;FE#j zS_9FM!q7An^%ni|MCq($hq?tiwfbpd>B3ullN>Pl`iJ8OKRx~O=+`HYCqI5adHC7n z+rz>*d2;y2&tDur_=Xf1+57aXN5_wjemi5g)hI{?>AJejJ;ijt gfe&-BH$y>+=h>S(@~z^#^fpSwH@{rEym~qM2Nd?UFaQ7m literal 0 HcmV?d00001 diff --git a/juser/urls.pyc b/juser/urls.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f7b7b6883f36257febe2eec95d6d4dc9bc19b63 GIT binary patch literal 1280 zcmZuw%Z}Pm40V#>4KobtvYo!D6wQKk)m2sX3%W?FE?7(yaSep#rF(A%&AQ*zzv*A} z16tb&5Kt4i*gk$7`x@`hWccCt`|m4go@ey?nZD*19g026Pza!?!UwV9xB-^K>jIBkT8{1jP(Pl1PZ?O^z8m7|d0a#Yq}zwEBtSZrQBSppDAdn0=v{f;g`W zy*W2uAB#}OlqHy3t}A6~ON)mvm4P*QTK6GZ!+OXGOI@s!6e$@Gw9$;zT5aQegHe*N zi>6k~Vx}Ceaf5ke%r^Rg)R4^n%vMucZ8woFqzd2RL9Ibm?DHm^!Grq6cS)<6w0aEY zVTbHBc$&NP8+MP#d2b>2*2>rFgYt3J8vI{R;ot~MxdV9$mX_TvcJh=+YA{>s?(hfoNrls4?nn)EQP|+rDv8u{ mz%yBtPr~wJR;Vh)PdpvN;m@6^GjzM1fphtKjz=~=`TYla%sAx$ literal 0 HcmV?d00001 diff --git a/juser/user_api.pyc b/juser/user_api.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba53cb1533e9b033d9f98264f9b14a351015e71d GIT binary patch literal 6597 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 Q9Y+D!+m}kGR;4=r1DEB7jQ{`u literal 0 HcmV?d00001 diff --git a/juser/views.pyc b/juser/views.pyc new file mode 100644 index 0000000000000000000000000000000000000000..803949f571f73d185f55ba24cc55630e98111e09 GIT binary patch literal 15721 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%0A)LI4 z0s$PKE3mj$>JUs z#Jc`tEKaldI*X@RJjdeuEM8@Ck;Pjqe#GL(EZ$}D_b94suG$~`Gsruz0waas3$!oc zttguD1IXso5|m3)P2SpcV^hb*j<$})9iQ&#?pV>Ws$+5c(#H12bsgP}b&U=9Zuvik ChF|dj literal 0 HcmV?d00001 diff --git a/logs/jumpserver.log b/logs/jumpserver.log new file mode 100644 index 000000000..e69de29bb diff --git a/templates/jperm/perm_user_detail.html b/templates/jperm/perm_user_detail.html new file mode 100644 index 000000000..8fec3ba31 --- /dev/null +++ b/templates/jperm/perm_user_detail.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} +{% load mytags %} +{% block content %} +{% include 'nav_cat_bar.html' %} + +
+
+
+
+
+
还未实现...
+ +
+ +
+
+
+
+ +{% endblock %} diff --git a/templates/jperm/perm_user_list.html b/templates/jperm/perm_user_list.html index 84fdc5678..dc503fecc 100644 --- a/templates/jperm/perm_user_list.html +++ b/templates/jperm/perm_user_list.html @@ -78,4 +78,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} From 8e2f3fdecda37c4997c5b57e1a2afee39e456dd7 Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Thu, 5 Nov 2015 22:52:02 +0800 Subject: [PATCH 11/25] update --- jasset/__init__.pyc | Bin 122 -> 0 bytes jasset/admin.pyc | Bin 179 -> 0 bytes jasset/asset_api.pyc | Bin 1762 -> 0 bytes jasset/models.pyc | Bin 1799 -> 0 bytes jasset/urls.pyc | Bin 672 -> 0 bytes jasset/views.pyc | Bin 6695 -> 0 bytes jlog/__init__.pyc | Bin 120 -> 0 bytes jlog/admin.pyc | Bin 177 -> 0 bytes jlog/models.pyc | Bin 1293 -> 0 bytes jperm/__init__.pyc | Bin 121 -> 0 bytes jperm/admin.pyc | Bin 178 -> 0 bytes jperm/models.pyc | Bin 2230 -> 0 bytes jperm/perm_api.pyc | Bin 7863 -> 0 bytes jperm/urls.pyc | Bin 783 -> 0 bytes jperm/utils.pyc | Bin 1062 -> 0 bytes jperm/views.pyc | Bin 9056 -> 0 bytes jumpserver/__init__.pyc | Bin 126 -> 0 bytes jumpserver/api.pyc | Bin 20982 -> 0 bytes jumpserver/context_processors.pyc | Bin 965 -> 0 bytes jumpserver/models.pyc | Bin 840 -> 0 bytes jumpserver/settings.pyc | Bin 4006 -> 0 bytes jumpserver/tasks.pyc | Bin 1506 -> 0 bytes jumpserver/urls.pyc | Bin 1568 -> 0 bytes jumpserver/views.pyc | Bin 7901 -> 0 bytes jumpserver/wsgi.pyc | Bin 589 -> 0 bytes 25 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 jasset/__init__.pyc delete mode 100644 jasset/admin.pyc delete mode 100644 jasset/asset_api.pyc delete mode 100644 jasset/models.pyc delete mode 100644 jasset/urls.pyc delete mode 100644 jasset/views.pyc delete mode 100644 jlog/__init__.pyc delete mode 100644 jlog/admin.pyc delete mode 100644 jlog/models.pyc delete mode 100644 jperm/__init__.pyc delete mode 100644 jperm/admin.pyc delete mode 100644 jperm/models.pyc delete mode 100644 jperm/perm_api.pyc delete mode 100644 jperm/urls.pyc delete mode 100644 jperm/utils.pyc delete mode 100644 jperm/views.pyc delete mode 100644 jumpserver/__init__.pyc delete mode 100644 jumpserver/api.pyc delete mode 100644 jumpserver/context_processors.pyc delete mode 100644 jumpserver/models.pyc delete mode 100644 jumpserver/settings.pyc delete mode 100644 jumpserver/tasks.pyc delete mode 100644 jumpserver/urls.pyc delete mode 100644 jumpserver/views.pyc delete mode 100644 jumpserver/wsgi.pyc diff --git a/jasset/__init__.pyc b/jasset/__init__.pyc deleted file mode 100644 index 8640fe38d542671124d32eedd80caa580e81dbf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122 zcmZSn%*$1D#2_r00SXv_v;zZE2u2t04lP{%}*)KNwou6Rt&@p04CBVKL7v# diff --git a/jasset/asset_api.pyc b/jasset/asset_api.pyc deleted file mode 100644 index 4e8434612d4b7cdb670977895f3386dc4797cdd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1762 zcmbW1&ubG=5Xa~3CaI0B=?|+1r7S42C^W@`2#WZlC@AEx6$^zDw%xTPO_OcjYpsx+ zS`dVuRJ?fb=1K9Q)|TQw;xUch{R8wn^U_}wM7!+HzL}jjvu{3cp8Kmed*%D+qZ#U4 zF5Wls=&KMBZbcQMhf#+3c4*b1NrxhrR*5EEic&I2QIwWJn%&0zE=(@{#^o!F42z31 z96Hr`?%=KOLo^iC&yW!(d+OhSM=NT&mxt22t6evP)1`6saoy(nV5^ zt*=33JzPIOt+qDa{n%V>f7#rA{?@AU<(Ag5@n-9_#l#Dv$P2xYE%MDcm|u$QD=A1! zlZ9Ii4{l4OL>8Zj5AZ5%UeN5Ap0Ac9In4*sc@e?o$#8B-4GkkO+MqqkO$q zGx_r3e4^v}Qe4lM#Vc=9g-K~7d1`WSlmtcOEXpU&srhFqol!&1fRj-(qCs$R9^lan z5L`h)i}E!U^TC4ms*j4p0dTqQ1Q-CI=h+ALHKL{_f@^ap;Yyv(1g>Wj>V(>>SKHD!}i9D*82NH01Ypu8qUY22LoFb z9aq4n;AdbF55utaB0pDZd@-3+)5<`beac~??K9|n$+_@)VeO3n?IN)7udLe9z zQdF#zv$qy75xF0b~Bwbs^~?PpuCh@(_h)~f?P2MRvdFW_|tyuP5H1@C6V^|n2xW!B?T z#l&?P#>*zIMnXgo2Ln8T+1MV~VZ*y$c7-+DT_Ih!<7Z>Q?SC6?2Ok%LA)Z5sU3>rs ze7$N&^;>*=j_~%Ap37r!7@s}FI&DV^kStIIP~$#N))yeW*0&GsmtX&0YOhmU-pBiD zdy3W55K_d&1U(k}{A*IbBkyFU#XDI_VWSpc(#(^boa(gU321w#*a!|T>AFI#YP&8t o35Vb;i(!bpo|4hOABDW3uFuz^#Y%jG7pK{fb#o`W`?@dv0ie^HIRF3v diff --git a/jasset/models.pyc b/jasset/models.pyc deleted file mode 100644 index fb530951eaa10dbe9e3548b13b0ee2c52a1ba038..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1799 zcmbtV-)|E~5S}|bP8<>v0;TYhst*-@B9HAuTh)O;BNedLE)o{f>F{pCne&}{w+BVy zjs7A1SNb=hKDXaD8#@+x31HpL&Cbm3{Q73y`mnwE+dn@%oygg*h3_wT>sKHaPb9g> zIPkILk<4Nl#}e6=xLBqwIf=x!@^!Hrl-q95w#JZbGO+Q6m|<@l=XwS+@bon>$4~pCBbD_18YKPU@Mxsr&C)-U z+!d$(Wj5e0M&A_KAC1fY=9<R_6(U5uEnwq zR7B$dSw*6ah0s>ysFtXpJ)qK+_mPY@bqS;aZvf9n##<{|9QcuTTeVkp7J};?mFy}M z;S|2E$rR5X0wa3QVz_=`)mP8Hr&_jZWPS$`rOVvF;>o za<45<8($_x`6ffDqI5Viqf3$3VR) zE30Q8mSyhJBA}Zo!ZcYFj)C4!y&GjS7c6*~g~UVRIb$fPP7#GkYOS+6F@LYT*c>iYCq4?dO0gB#UVE`z>% diff --git a/jasset/urls.pyc b/jasset/urls.pyc deleted file mode 100644 index d12635a887e981670775d88e82f9f04530339b7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 672 zcmZ8eyH3ME5ZpWGWyb*uN+cQzi^8U&LWnP*2#CT(kd<2^M}En74x-LK@OAtJ9{{^{ zE;jfvp4(a9&e+cP!n^&td0E5Z@ag$LxBethbP31+asjb`TtX}%cOZ5^uqGiJ!7~a_ z4xj^S1UQDhZ21^)V)+DcYWWm!X88=zwcG{tEcXECmd^ow=6e_71t=e$f(2Pif9MDt zVrE8ACB|S~XftK4SZ9qw!)jA!f#5ENYeN8i$y?SOEX;=4936^=RD)iH$eNb3^}MDo^(z4yUBEbNJ w=u28gby=Ed+vJtTdWUt?*^W3>Sbem=>@F`=li@u_)8_;i!jlu>OJDToFIG^TQvd(} diff --git a/jasset/views.pyc b/jasset/views.pyc deleted file mode 100644 index 0bb65fb630ece88919323e536a29754d3ab7b427..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6695 zcmbVRU2jy!8J;=2UfXN0*B_WdqmV@n?KY$~O;MV(2}vL+Nu?4xwhBS1R*TO8cG)k^ zoP}8RUbH4DC5nooNNpt~f?C@2qCrBcLZMZDKreb<_0l%`(yHaDRzgKem9;8+7_(|6)dFr44EN6$l0_C|Dm+j=RQ}*qjb9obi9DRF%%?$N@zdrnn_Dv zSi~U}aUD6-#RP(%VMx9Klg{DqCEw2#tqr2w>9F2xh;QYSyUUk9y#MEmOLzWo@9stM zHM4kPO+j-QzIL^buiv}!PLzb>=<74Ha#1T*1H>6KWDS9wKWgqo(bDa^D_8HJ zltpe_E0?Y;U%qB1QCgPXre#WnqVG?giK>-6VYsPzJgAbyO|tAIhD)a4lF>$NxLBz~ zDg0v2XX?ITI*K1jD|PW(DcLAuX3hlR`5=5H4C^7*F`n3RD;*r>a!BO-lbk|9CWFjD z7xRTMsQE!C9aidd#fr_dUFj%v=#fXy1VvOUM5U+_$k-dj=*%~}S5HZEZe=ij!||H| z8g?Vq0vY5eZe2AO(g^UB*;Vc7Jj#?9o5R&~Sg%LZwT4t{ShX^QK2VMb#Nfzvvr{kvGp5KoJT71Q)$-5pJP421Zrr>2Znt1P z9vP;y!Tg1K=o?k#gFd5%LgU!vJTLzXa) z(d1}$!$fQISP;qm!XYh|;#QEzehOi+2Jmt$bIlOIiwbm0xjj?AP&iczfd;}xZh_3L zLP9uzcrQp)*%E_5Oib!=e6n6j=e@_ZY;|xWo{lypWCaBfkcQJ?$ac(-d5oUl?SBehyVV~@493x zISd$Kdv7NkgZrc;=JF+0btIi;OR3>Q5{DJ9=Vj+KI~x}~B- zC_4I;{ZGsfQbN}d58aw+@eIX0L*f}`z{{xVZZoPjuKZCxOFJw!qvoICzE6>rVLpLr zMDH-!!e=$)n24Pb6=l`J2-|h)$cde-h@Brm>*#au>*K(!(@PLD3+MphK$2q4;8V;E zY6>AkXfP`b0wc?yn*l0U=_D)s4DE^D#+m1sqevkxnf*G9lp8iK1Ugs8nJhhpT< za^ZnBfvBwiEsW23hw5^9V~Hg?Shb>Bjyj z8n92ph~&{(A^6>TmmUYnlkD-q6+Vzbk96fv3NqZIhHiq6-EEV z4WP0mQPfsSj(flX*h+vXC!bbJBkmi*F>Q_XThU0U159>w5wC$p(M!}wWzY^9jXhZt z-Uf~d#tkHs02=6t!It^fgKbYTS%GL=E#1HVQ4F@CJRC~a!&a06BiNG*k}Q&WrAAK* znXj<>m>zN~yG9QQtTyVhSFR_xZlUfPlOB>Zn_gFj*D8tHF2FIayW4VVG8D6Ldlpq1yJ=C|^GoMp+P-I-??W zu8Gw73{nR&MFQmTjC%#DQMi7+6O$`hC8PU9Vp<{wKDxe$$x&2T~Ez{Uy8q~l4m!ZIaD)V^AO@AT4fI@0i1UtjE$k;CXnx(`$#Jzlx?UXRQ)hZ&FTl#&Oa^ zp|e`{Wc8relRo24{Aiy2?9#*dP3tlDy2ZCbsvlvs*Kh%_JXq{>&u@WDkGSP~1mAAS zV#F|Hi)HlU-{|Hb@*_p6MM3^i&&mY zw2x5YX&XC4;i5iFCwT@WmY%)L>>ZIv6+&)}N|uB%$561H6{UnR%Hd@$q^El_eZNRW`Z#DWy57b|ABgftUdRlM@#G diff --git a/jlog/admin.pyc b/jlog/admin.pyc deleted file mode 100644 index 8903548ba0f4bf64ce60341e59a482c0decbeb31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmZSn%*$1D#2_r00ScIav;z16frJG6De2@+DsY diff --git a/jlog/models.pyc b/jlog/models.pyc deleted file mode 100644 index ffaf3b1397c60206df84b52c3924853b55e64056..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1293 zcmbVMOK%e~5FTffG)Ws8%0u+Tbx#c^PN;$uMM8oeOohZ=tR;3fj=T@8y$B?3@CUi` zFZcm4Guwtm5fbV?X2+k$GoEk88~vP4p8k09ZUxs@gx}}*`XvgDj{pad3rGYA-2)?F z+k>?L9l#_{fvb2vmBrJBO7uue+NaOis|K*YRX3Zzt#<~Yd-DTRw0heJtbVT|Hplh#XX zoaXed>c+6rU`SRrr4MXao4gE0*@{QnRDoSf>V_~y@iGnO%I2o^M)dfQ)y%Xcv;dW$L`){H#}NTUfs_IvnH7CM`53u)`=vQ)mt%iSR!h z{x^}5io-Q{h{{kr!u#a!yBBC%FC3DxI|h^iAA@sL_KyLzBOW+B7z1wEVW-hYbTG}B zkqPx2MVC}N?leiRC1EkuSW=Rbip6D<+<9b@`%F^RC0TK`m}}x`VY4pX@&TDqdbi={ z6xUHldHN{~nVHL&>rR`}+qB5aGyS1$D#G8;kArEIwDuM;1LgdzZP#>i diff --git a/jperm/models.pyc b/jperm/models.pyc deleted file mode 100644 index 441355de3870effd0e3ce2637479d7d290584ed2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2230 zcmbVNU2hvj6us;3I8G^*8WDkjqJsQ@k{{3t(SpK5DXJy~3BRni-ifnjKdhZuN}f~o zzwu9a=Lf(!ckH!QsAR>?PG;_%nZ4(nd#}5HAB~?aAN?|y^{0#f-{Nt9Vo329NiH%A z^N!?^6djp$B%-e?c~^>_%z9GvW!4YYp5y~5hB6yUF_PH`*1p(|EDz)|l5`+%L~cZW zosA_O?l?xR<51Fr9mlwJOe8(raZFmrk)%gEjytX64iQ{TKLDESAAEkAMwt2mhN4Ps z?xr2C`xu@$XT2Y9Wb84^@7Xh2117s;y?MjU)-n-uF&!ZkKf#bR zzKYB0b)2NB0xgn1;@p-Cf0ZFV@dR2nd9HlC%9HXp1)18*q{+R9SF*p5BGV)8=Dl%T zCWVb-y)KTyX_I4VxYcvl_ldVJv%;QdHc#~hFYCtY*%U4hm(u#(RZ@pN)FzqxtSa^8 zwRL#6Qvgq^Dz`})_EEF*B!_6!EOW7I=5yhHEbTdpAESxAV})wSW(MCW+(Ai5Vl#P?pL@myRx=E8p!e}TR4C=Q9KIK+kGngeS~ z$bpRoX<(5L$OMc?hWf6!H9OKJDCmWfUq3OP1K!f4Kpk)f!gLMn^enA4OBQTLXg}1&*Fuq^re2Ozv z%8|=KbYH&;MjPvU8D|69pK`U~-#zo6PI4Vyv0NpTJ1xD5bpAdkbZ$T!SE W$FL`zyU}rU+&vkc3{Ltd!+!yEDw7QW diff --git a/jperm/perm_api.pyc b/jperm/perm_api.pyc deleted file mode 100644 index e23e897553b79c08f9704b9b014e7adc196189d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7863 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 diff --git a/jperm/utils.pyc b/jperm/utils.pyc deleted file mode 100644 index 535aa36930640206fca7b322231d5527dd7fec59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1062 zcmaJ7dKzh*k z`9Ss`P(EaeZL8m?8_)*95jjcm*>*L+=ph%Y{~-FZjcm$LJ)(S%DN)^Ft0A36do12# zm`RAS%3PR)O_r3pT8DLF?Pb;Ih2%^El=;GD!UlqqxeWt>ajoc%C>rycFQrLJkooY^ z^F|_VU1yC%tZUp5ne57Cr4|=(>?m$}UYRr#*OV3|E&w*KOd0Ww%Wg&(i|R6KmYkKP zHY?-Y49i{Paa~n~~zs@*CRZn1J=6=X6 zunH9L;pR$|isN-+$~cZ#u{7EmVZ3;+arDaE^~C)2)MSGp~-SKO^+r`~uz IzBN_909Jj#g#Z8m diff --git a/jperm/views.pyc b/jperm/views.pyc deleted file mode 100644 index b7e90e65382ec383d408f8b870eb7fe4076aeefa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9056 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 IL`Tbi0F2e*8UO$Q diff --git a/jumpserver/__init__.pyc b/jumpserver/__init__.pyc deleted file mode 100644 index 84249321965d97edd465910209d425e6f945c3d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 zcmZSn%*$1D#2_r00SXv_v;zl13CMf)YvbkVsu#iv+<#CPBJEiPDJjcre`n2AE6J zGX&wKsw|PZY+bQs%aUbDw9eQTNoBp(LCLD5Hm*uixz@E+N$gZADGmT;v&n9yDo3Tt z&i8$A?`+@t+l_apP59G_|99XM6q}9l@aLGUF^MSe zn1oZSZ!(D{<(o`4W^yr;h#4mw(`*vWYKxg{i^;W`L~GPG$0X*ct=VMfnp~Snw3%GH zNwh~j=9$F2+A19;(NW8HnnY(UKi?$g*YaH^(N)WLn?!dlf0;>KR?GL8L{BZhz$6yb z@(WF3VJ*MNBo-;(VzP@(?sAj3+~k&+#1fNRY7$HB{#s3TnaM3TiRC7@!X#GM+BqhB zg~?rM5?9*tT$8=Z2+q-DJGW z%n8RhzGKF=niIx2dB@!28#A`ejNNR)%qTiM_KC2li*jDr%l8~=7Q_N7|4KQjJp z#_KUBn(X9uI$OJdwTUk`bp5jN7OL`&hDwZIq{{7@dWZ2A8}D+}^cla|jP2CI{SB>4 z)Vixyv($LYRI|IGX1QwiT)dFo(q7}OFemXacN*^s<6UV^fEEX znX6fY$G$f)V7!&J+H0cP1IAlr{DbPdI;#Du@vhZWuJP6wuUGRAD!*3wL&m#K9quwd z>aW*G?BQZb9x^lkHkgwDW};TKl}K+eCtFP7zR%QeRQ(a-ZPGmV8xNGS z#dtSrp0642Ce&tH6<%<+<2p1d_H=( z{sR?1C}U@3tZGL#qy8>zQL8YsyHuzYZCeZ4wg;H4++NGsRy|}?w>_Il1@%YVR~WIw zdobw0(3qbt?=1MiK%v}!EEAN=m!o=rC0ouEv%YN(T)$i?<$cdivJf2_AI9~)ObN5t zR?b@T^PXQymJ7*J_`tS}a0}3u%%w8f;5L+&-?!5D=&hji^)GxIY;vGn4}GI1Os_zf#Jof%_9CnMwNj)KJzhb17dHqlKWHtYFDB zAx$)J$v%97Ge|Nmri_Kf09%=ZI%_h@#f%rTIjFH_n`<#%i`n|1qd~34YbEJE*kq1F zCe8_GLXE?j=92i>95csbY(5TI*=~-5D79iJe^wBH?!z)+D=x5g~8sr z-1rV8?Q#5+gzR`K4sgYXGg&`g5Rs^H>eUaXo;p4C%(K(4e>ijcm(w4gMz5(SzFU3j ztlG;2hUX7eETl8};eu#=B2~&~@*`^YOC?~Di>6DNaweV1ihk>e3T{T*>fTh4E@yK7 z+919@zPgt?$)}=X)<5cJ8_GF92*7S@gI*$CYhq_$QM=~O{vCJi7Hann>^h*#;qC5# z_S5gW2VCu^&)s`yZ{PNPVm9#dKFk2t6MRtOlA?-T*vp<&-phu3dFQ?ZyOX>2?&}v3 zVW1}1RVd|B09j8|pA^%%+N&4aG^p2)jyR+HDvSEaVI=*E^j~m(z{U3Vb^8 zn<0^>xhAPRqV%t#0P2H)T>|PJZ#Jc6D#y%{JjlE`Bw@5)4)Pp_RJfHS%`)0i1sVpO zq6)N#?w5mh2L+12#nd9FB2cPK_3=k9och!M_R*6wpFCIn;mcDm{cP%Ir)=f)izlaE z`eya)Gw3k&y|dNF&$9UXTeafzGpF9x92sssgOADZVf0v5E)o8vR36frU4#h>b!vfh zr386a76x*ee3E;zh14+>W)JypOv`DKSqNOnNJ`hIP#4flHZ5@{-XwSv>D+=O%l|=! z@RIQiSV2NeUS-OTL;!diKm>Hb*0OT|+{5|HO*2THmey`VOA9!O8QN5M#BysWU?2u4 z3@~A{nOvaCxuJM?umzK>#UyP8EIJG_TA)O}~)1qmK$QCo+VoE<30koRD z z;YuEoqL7cTs|haxcTErqu6VfuRn|a8)kl6d{oLEt$36zRL?jgvQ}xUTGw+_NK5}CE z+(}C}8m z4v=eV6Gey&-7lfqw7frq-sVOk)D^o#pamn%((BHr;_w;3L7u`iS%n9di=J7>#dGJ@TO91QcmZ^&q-t zW#A9CC^MI8l|$O76`5%_-dts%C)lFT6PQ?N_GHJwE-@Gca60O4ZXZPd|Nj=98DFo_-?;Myua>a_02e>c`)k zdj5^-C(mnWnkeUo4@XP{6uzDqJ6U69a6!@<0FsnRq-a7Vm;&|4;8_irg2Xt`DNBrF{Xii_ zUBupp_8#cleR%J{U;~VG@7NEz~4)WL1BOC z3De{p&R+(d6q7dENo_=x2E>MV&11?4^q0gdsJ;Q07ooR?#|He$%&pa58ozv;Q9m;> zS{5FKhKY<<9+jRLkXhk+=;R(iB65Id1SlopHcDLgA4~g1Dlyyl5W5M58EZ*YX7b^6%;8`OY5;miOb*b#6-Q$dtV-fJPt zfpy7jVnv{f8EA6ZA?ys*Z<}nUu}REKgu|FX+D5fM95ahyc|@yH^jQN1j9%Lc4Fjx= z*<~|;%VCL(b(ja?A)!wvxAh>*7UU7mgE`S=7Gs-ZU2GWZR&#r;8FRH?+#I@2^UUOY zQ@)I52nK`j)`0MOM0i_3cTO4MKI|Oh9hyg6;bBLn5G<+kLfS4+F5G1YEUBw8c##H= z)ds_LYi%4>Mi^tBKmm;fmkoP`#)7*BEj8a9M`f2L?Kbe!$MA7h z5OuVw4VKi@iw$+B^g!+N&Rhr2NK+fJrsj@ z>R2UyJU&wLi}BS#Ew}!ttvMb~O^nCa{BgWkf^`*NwJrYO8W|T8qlH>ujk>toP3#uK z{Jm@2gAMrKSMpP3p9>7bzxTa$@q<|(v4D84;AMs<*-)fB4+1dc21&$Ju%$i_`;}w- zMMg`ZN>npyAYL!|xkA}bLL0YXP7i#al!~VQ#MCg-%A=AIK{-__C+P$Wn#GJ4T!ub_ ztd6rf4yCm^XzyK)T4{JJLGh{?m>DYoP;?^#|ZiHCDT&%!9zkroi1;vQUH_%b5XOTZNhNjO>>QxVScQU{L0-{OCaiZETq% zH3fIO_kgvLDTXBVApU%9l4#5qCbZ-P!Uxve2~tOWIsWb;j*tc|Ptvp1x|#+L1$gF) zNkLWc<*W@wE)W)}xH!5NbpYRD-h!8!Od`aTN3<)NytARJQ0G2?8W)nsO7LRY8t0j! z+&w)`ZEB$vh1m;pnpT_zfww}*`}ZgX8Iz%5AnWC zc6X<^Vppf3W+ZF|^pBTZ%m)P)IS<_Ih~IIghvS|LNJ z`8y>;->GSSI}nP4=HoVJ^6TML6#Ui~MifnA6WjA(HZ+;ij5!E1fs1vUF-T8E%ABx_ zvjPf9JaW{+f~`LMz&58Da(`@LT@9e>o^U!C=yoH+1~fCa_#!~iYL&+N^mZm3ZYPA% z<+bfRFl_L5_%PHL;lCuDi}|Hei8vRtyM%L7UPkFYhBE~tg`$=fdJ+H{$~bw2DPO4! zq6Q6}*%W8}*wyN7Eh*AN@GT^fxW5bXv6w2Qa+&c$oc=}L&q6Z}C9{M7jLJm0nrRuX!!;ez&ht)^kIRD}6=Rf>T^`p8K z4RWwQ83v(bXj$`0ao&DtC^E1WiM=b))%`w`dyz=cmeUYd2*{P(ud#|kD=2%JyqjZ@ zVhYw#DK+7Kon=Zxl+!~HXXACV4OLu)<}@YNp;E;Uhh`xZ+))m-LNI;QrSIw{nLNRI zt~i{n1fzCDAw7=C2Sq&(a>R^`T3I@C9~eW$y9?|}OlyFbqEoH?B> zpc_RWr0p=guwc};a(GuNixvt&U=2abdMi1f@px{)CAJk@kPvmBL(%;n5^b@NMK9Q@ zG!RQlCzSebn#1s!UGS0nMEoLiEQxJqv%g0%*vVO1dLY1J&SLy_H?<+R0fMW!iNOQ5 zG$S<0pyYh~pM%=vs#_jgDsk2ZH?zkIHA0YJ>BA>z#kR>^_;VPJfUcx-fg)^8NCg^g zwg)5`dhApWdD^gW>pehk9E45?F(8l+J2;#cR;cw~U#G&NA=}Wjlp?b>8#v7_3>6d( zRt#;p*$hULK~hjm{f}A?NIw|Qc4GS+9ii3DAlctCBcBv@vK|pqVz5_?{Q`gzF*d#2 zRA~gpP=N-Y82Z+DrnoN7)0TBI1gY^+M!;agiw4s3edhZ%+Hv8fZ_d2=5ZJo<%)>UU zcK(A`s%PJw`oWp0m!7JA>lEh$f5SP(f7y&PKYz3O%zKEDRL?v*{pv%}w82{JZsyDz z=ifg!_0oqkKmO@7CVuYi_#PNHG|gc1g)5_Y-^zU}*Tq-vUwQvPFAV@i zOvIjGKD#sbBEKYbbL7>CoFmraXS)Y6F!9zHWAeKBoU79SG>n0n~ zp&5h+sQm_Ck=$LM3sw(=(R(z(m0cG?gT1Ro#f##OO21q5YjJ3ivQ-y&n_8k*?{G`V;IW)kP4FL>2$NEK^31Fm?%SP;8(3$NvFxA2 zT)|B3CfR`;?tsY8qcm8Bp7ZH0vfHm|YOq;m0-IaRJ=n+~oWH?dX$pclqTt=NxKS`# zVKRCE2J}Au9BgY*F6#Nm~DMQvX- zdq7NsS^KgXY({o=wvh6Yj9vM;q>fs3U`rndYAh+YEI$&pB#Q+c0!#uuI1R6q3)?;K zpsgVjg#_%r#C6#PVcDc#3%2O6`(ijmffz-|v9YMaGW4sM!;K?R5YehiBHwbG*qvAa zS!u1=v)+6RY+yYQ&TcZ^5>%U(CC(MG4%qDrpbpnU`SGN#yGcw(Wk*1Z={`ax)Nn8d z!E)paX+P+|#i1^Oaja7~HXy))yv|%~sFhsQjL4f#V!#(m5qWDyPeh(mt!8qWVy-Z( z6?x?higSR+=G5$RpdFkAK7{sh!h-B^huxv`U}UoznvCW)_|WFSW#MTL?`=f9Qlmg? zYSzt5tA8Td9rf3F=E1>DUs`kDk;)y=8%GY`e`HmBO}mbl({T7pxA|!V4%YkeHAgmX z*>c~O%{eRV(b+>JeM7uIKUSC|HLHDNZcV%EV^0};j62L6#a*ZZgnLHL-Cr^Bkcfsd z`J;t#IF__?tRX4Fv=%e~0OV#y5IPpS4(?@)xNnb}>1batwhqDHBwhW)<7>ur1dkh{U{6n2x z@X7n|32147*6hWZfB}XG2mUcXT|uNJokREtN))klojF7urk;3f=G2qbzxVO^bFW90 z19tmdsQ$E=V%AS3H5%^WkNI$%(zHlp3))EqUXn?v;$#xxp9;+5q{bzaULl=Kx_4oS z@QAnpge77zqXkdcwK$TKAskWGS=}X`9nE zzinRI%C_}w%i9*UU8Nl!ob024kVZ%SkSKQG6VT-VonG>|%*V+QPRzuWxID=Nw3vaZ z0w%@vNfvc<#v-DP_(Ojjo#AE|e0O_vHV@{G)p~odkkFiz>e z`;&b;`s73brS=Y%mDKE6$H^B(2T9-w(hpbTftL14E@p-HO5B49AXx!j7&jwUn&OCi z(i}sGLpBf~y##>WdH)L8H1aiIphNh=PC*0yoCnsL!^aXFfZm_eSqpar`RZbuUFAkLw^LM}pBRDa>cXJC|1KljSi<4s$)-F(Z&)KJ>LezEFGsr^=P16UQdMv3*D1&i-Ay_w2p% zEBp2j960z@cks|%cOSmz-b7O85m(=_YW3Hyy{>m{Qdc$@Neg8kk4hymQ$<7@J!S1q zm4!6Vq$j4O$;hIr#e4{ z5JDijDnx^M#LpxA1bq{Xrf%A_nFcp*V11T|E&19`795`5tkQP3~KK4A`Ui+{iV7$UvkR+*EU_zUKCAQ43$ zg5xb0M#jCh7wj4?=}}U|+8`u$8~<>B!_h>NC<0y(k(Dk~!V5pR*eBLcXNse|1Z0MpWnNd9uzVGMqCH_b=*3*v%1B%4IEB2z`;f&^hLetTrA+Ypn8 z8bg4h>wD z&%E^-SdBMjo_*3@qOo*f)d~Vf(Lnbvv6}l|kl2_cU|~Lu#y@3UjLBaiksybX!J$(_ zV1xi73f#YDhTK=orWkVhgV4ei|BPti0g-7TN|rjEP0h}Lz5VqsQS1IICjXiV5#sWk z-F=IR=y8U*|IB272@&mb+B%IW_eE`!Ut=iHXaX_~OvR?Q=9ts9pldFE7l^9UXwVNq zNXl2d+;6ZCVa~BlN1Q?cZvw@ky)${RRn1ve%gkdxsh)oE{0C1|KYF&Zi;TX!xeNF&0SdU%@9hg5($uG9do&0wy zQ!+Z{DLJ{&;~;533R04xRhLCb!KGjT-cpp{L{%u)h#Nf|%vn%&dIm48u!Buecv z9@}vCh|?6wD$%pV4DH#hD197vsz(AyNpkdic>fd{*Xe@85krcBEM zSSxc8;p+jVw>mlx7FviBe#n8r0wj-N(*p3L06A1gqmml0;)vIfJRT9$^`V01 zy?-g!;JZ3S5YY|hN7dDa^^*-<ef7!lxLICQ{E;C$fHUdwy58oVw^fx3?nui9#XAmdS z6zEC3a543I5*qsOMTG=s8M)< z7YvakQ2sJnr=_b?y1qtyedrlb7UC5c5Gtr`E5sN4x~sEcikHJapuf>;7ZGeQ}4Vsed@Ft zMM0uGk&%lVkM{Dt8zZzFB;n<_W|r4uc|~faF6%@jl*xk=Wu~%tZxKIAz9@KkK!URw zO%Og1g;y|_GeMEB!XabC;)JxIO!tDi#Ddatw(dj#th@Js$9C_r4m{0oYgHMC;0J&Q zm`cN_j3^3kT;X3B-DIdxP=e5fvPD3=oI?n_cG1*=Iv)?2%K}>`Zeh*&_usK%5W?-k ziMKC2ZzY@id(11qi)*jR$bljwWV`{f%QctyvC-^07HBBB|BK20WgM0!l_m@;Gd@Q4a{+Iu;n94B@Mi{JP$DJ?gr>1x7aQ_{P0zRAV=^dZmr7+dt|DSN@`&r8(E@w zn*8+Pqc`;$Ar66J)q80hg$T?ntMmwWXF zQ9I$JO#s-y8jx*ti6%v20a|;|8TM?Vyrdj~bO(4LW46Lzg%acqTbUL-Mumf}c%Hoh zJ>b5H#p|+H+MRp1)*_G80>y7#3dII4{~H$nCpS*1=phD{!J9Qw;bQ^bO63E3eA&{a z?O=~1M3)Oms|%1QT!a^z1aXc@^5XLBA?tw*ar{H1+^sAgbV4M&C7XlM=C_)!Pp^(jLMPicaR00>KL_8=pXa!1Lan9cCD z!&@S_;nkaVK&`zgO=-h*X}<_=|CC4*+(3B%-BN~x@dDRYhIv4|U~d$u#n3(;V*^cw zJcb~){i1pypsZ`)xQaaj;+|`ct>P6ng}D(f!mSm=jXxdvx@yBUeiyBQ zhZ=JDw3x)M(Wy1&YmLt6IdC1|63-EL^ctn@v}=gP!!>Y&UC$Z(s-McT*l6y* zK_AgGVlwtW8p+wXSX~)nPZlIpS)c(tlnLtdw4p-Bg`8D(VJ~S{s!-mlhN{2yZs_RP z0k)DBmV}m1HRDn};H?{o2$ZZaSHA!^J;Ht1#o-)jm`YkH8WGg@%wF7L)P@%Y!cxN~ z0$sdosG#em_@KtA!Omm*u$98D-a30xK(N+uzl%~}2P#ZUH&oS9+?qo$5jkE5UOuam zqz8Rv>H$fQ|L}K`9&U^ z;&UYlZX)Yq5h(F^S0k6N1D9hBD@p9rM3N*QtpQ2$8?6BeVb|!EB)LqIq}xi89&;Sc zU8MHoJ&kKT>l}uqup6y#T(FoGDRwb^`3gbzo7!S{)x{cb19d@Q?JH7&dkJaaUP%dY z70H6C1~FC~)4Al!1~cPo_F2i~8YZ&eRxw9`;l`O;&EzE%^@55uey?Sn%Pwn}BXhfS zv&Gl$TI9r5b)gVMvME{PYnPYUWT{w#@&*<+GP$0~CMKJiK*2RcWWT7B$!EqrXuLx* zLAIl(Vi2>xnC;>)W9m#8|J#@lN6qY;#*S!7)YUfOZ%s%DHK=Wikwt)8OS9gp424mAc}_B1?H3Ud*$s2E(S~_`26BK$`Z?PsiQA*Y zi#P4=0JQ6lq_*qlMid|ozinjpTjyfhx>o#<8z(Cmh=_>d2`s^y_g}DSQmt%rK%C?Y zxHpBYJ|J@jcN}?|g*UHpMJb;S@4HAu(>|%w2`*IP@T=^*W2lx;o&6JV#@r;{JK|UT zd{T$JUKQx|IdO#v-?4Bfnc!oOOW{KE1XWVGk2jYJ8~SucYR_mdupg;!2rp6x=}gAO z?BV&|dFCEt@^6{k3e>nCF^8{^Gwu;4|Afh_On!t!Xd2Gr_&+_WOQqfzzTl&PF9<66 z8=~(<(6==-e9;0GRoIbOlAG&tOETiZmI#Ujg@|#CI%k89W&*3uIFX)nOjcd3jV7*3 zN6n?hDRni52z;%X?l|56jrO3;M(1yVOXhQFWXgB6rmTG|d~rjmjH`BmD}Ixa+wj2r z)*^Qy2QDV$u3_$8COIV9#@-xnm+L6p>VT{dBbl@bL0EPrmFV=Rh624@$UMZ3-UK9o zl6qARSLayRv3;;VxpS|p@qGsdcDdg~t?uOrFZ{Y3G`s6itJQJMHu;tQdsVrfm1JL3 zs5i)l@RcsY$h`x}f$jV4SMA*8?$h}F+xPBE_77~|v9DhyxyrlT1N+@$TzD&!+nF%H zEz86na_OR-`)jt0GC9e_hTsS%x#_ZUx>@XDvW&?9`(44@jZAK4Lg6ea>h5H2HyAMgbP9-?md{oAs5ToTUg8X2Jg6PrQ}qejOXAj zcmVij9g`rA*xs4l&-44uhCfe})sN>N3)(*c^cyVq5~9SXs3vL@traOb2UG{tgtQKa zb4YbWmt{oXh}JQcF}+_*;A?*2St#r{g81NcH=JUe-a4mwIEuxyLgWl9#CnJ2zC&z@ zDtto~1h{co zUa+~=X8r(NJp|;mbH=vW=yHsWuCN_KvgN$a+P?9w-erjAF){mM9cO==dFWuaNMPnG z+oxuk!)MJY)bPW8s&v85|H$i_Wr~IETV@&dm8n^G>7Qv|cD-f^iZN&UW@EbBg^YLT zUVrVi<5Y5_ayL@>l?oZD_@qJ_h5>HcE1Q+3SYS_HxEI)+ch>TG)i)b(dab+TZDCv1 zH=J!cTYyH}x#i~86W!*G_OKM}o=Qk{rp|&#O5P{YJV?}Z|0dyuzr=hWR+W&tY;37( vHxP0vXfAhngnj2i_Mxg}zA@=zK!@u8r-d0Jy+RRvtzSzvCvD8tTqWUepb^p4 diff --git a/jumpserver/models.pyc b/jumpserver/models.pyc deleted file mode 100644 index 54dd681613bf2e44c4af19f51b516fba52763191..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 840 zcmbVKOK;Oa5T3OYrwI?Cs^{J+`9i{p6G8|iBo67pK}hvwwP7cYo%KWZ7`5jh^-uO+ z@B`?~x=I6wO0f2Pp557bd@~Mzy_mhdd-Lr(JgktvA6UBA43=L74xm(!Do{26R8R!4 zQD8&(39tvaN<*+CSjA)Z$ba*S6>AhRl(j|I(S+3%66IBPNF-+;S-M*W1c{FU6dcPZ z-GfR;f1F72v7}|(LzqV1I`Q{M@VE8kN#7}04#mFFfy4}wReZv=(2Sup*VX{@_bRnBjxZ@r|Z#iO!B(nl{%v zywQ!JtuN}4jo1ExlC)Ba?_>&*I#uWL1edW4%JZ;=sj_-**8?@_!BYOlL|p$nv7gAh NVLtC=e7>iz!h2ikss#W5 diff --git a/jumpserver/settings.pyc b/jumpserver/settings.pyc deleted file mode 100644 index 1c0a9757b40074f213366270634aade6b41b339e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4006 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 NcbIF#VXJD@{SAyqNd*7^ diff --git a/jumpserver/urls.pyc b/jumpserver/urls.pyc deleted file mode 100644 index 806161a2798dac027691af4a5d04ded8a2927312..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1568 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 diff --git a/jumpserver/wsgi.pyc b/jumpserver/wsgi.pyc deleted file mode 100644 index 90dfb9052b06aabdac1e8d8e8d99992972b3cd26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 589 zcmYjO!H&}~5Vg~7K>?(d7IC)3r3Z-NgoF@c(JoaHbS1ig)JtlTY3j)FME11Hp7+=I z3VwqRfN=|KE&F9WFZ1S&Joxn>4?muLsl?wk;O`qg@hw9w#DYkT=)?2huLgIX<@rth7t3|aKc zCF{N8MjZxF)^pEpM=10xZlhXR2TxQ4$k#-De5rMfRV?b(_y+%Zs<6}G_4DF|UgH&^ zuAz5$-GL{46&tH_`N*XyA=4X4d^N76wB4HG8;#9%-6mBqT;EGr1@#r u Date: Thu, 5 Nov 2015 22:53:19 +0800 Subject: [PATCH 12/25] update --- juser/__init__.pyc | Bin 121 -> 0 bytes juser/admin.pyc | Bin 178 -> 0 bytes juser/models.pyc | Bin 2190 -> 0 bytes juser/urls.pyc | Bin 1280 -> 0 bytes juser/user_api.pyc | Bin 6597 -> 0 bytes juser/views.pyc | Bin 15721 -> 0 bytes 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 juser/__init__.pyc delete mode 100644 juser/admin.pyc delete mode 100644 juser/models.pyc delete mode 100644 juser/urls.pyc delete mode 100644 juser/user_api.pyc delete mode 100644 juser/views.pyc diff --git a/juser/__init__.pyc b/juser/__init__.pyc deleted file mode 100644 index fac421385b1e45f5db5aad6c06d4190c14655f62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmZSn%*$1D#2_r00SXv_v;zIQt+kVQ*z=02+^1{pwbkr6Qug`wDo(j*WDjx-`kc* z+!{d-NE8X7iW3|vaUw?!Ulzy<{agjqa;*i z&QYB?%0exOZo5W%gn!eo?T}_GB;r)*$XIyxjLx>RG#}5vRmr+ZkJ%=n1u$t>jA(xb z3V0=g4~w~eH>P9hFIk&#XYb{KvL8{p(g_;Ieo@31bD zxE%$_9a|zT$)l(b*wd#&xVi;Bp;pAcCwf#xPmGv5stTg$G8dJoG_%*p;!yogEmgKqFvZkRU{z;JeJ*BEsB>V3 zS^{H1g~d5Q5$3^MpW1ZoW*tmU_tH<2Gs^TzVYiEzG9jZ~9Al63$rmF8jqb3mHbqF|$ zf)3NLuMO);?+1Bg!(YhhgUe@TFX#X&f?3R9A2t53+(4FfdZv^GNFN;bmr1mFc>&Aj zY`KCZ?yCJFGzyGseUTgaZegEly~%j9N$wGJ8!0x zB}j_=JmZWE`Zm0)?Gm})4XoY`V_om*JZm8RyjKf!hCkZD_L>Ofj9;FE#j zS_9FM!q7An^%ni|MCq($hq?tiwfbpd>B3ullN>Pl`iJ8OKRx~O=+`HYCqI5adHC7n z+rz>*d2;y2&tDur_=Xf1+57aXN5_wjemi5g)hI{?>AJejJ;ijt gfe&-BH$y>+=h>S(@~z^#^fpSwH@{rEym~qM2Nd?UFaQ7m diff --git a/juser/urls.pyc b/juser/urls.pyc deleted file mode 100644 index 6f7b7b6883f36257febe2eec95d6d4dc9bc19b63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1280 zcmZuw%Z}Pm40V#>4KobtvYo!D6wQKk)m2sX3%W?FE?7(yaSep#rF(A%&AQ*zzv*A} z16tb&5Kt4i*gk$7`x@`hWccCt`|m4go@ey?nZD*19g026Pza!?!UwV9xB-^K>jIBkT8{1jP(Pl1PZ?O^z8m7|d0a#Yq}zwEBtSZrQBSppDAdn0=v{f;g`W zy*W2uAB#}OlqHy3t}A6~ON)mvm4P*QTK6GZ!+OXGOI@s!6e$@Gw9$;zT5aQegHe*N zi>6k~Vx}Ceaf5ke%r^Rg)R4^n%vMucZ8woFqzd2RL9Ibm?DHm^!Grq6cS)<6w0aEY zVTbHBc$&NP8+MP#d2b>2*2>rFgYt3J8vI{R;ot~MxdV9$mX_TvcJh=+YA{>s?(hfoNrls4?nn)EQP|+rDv8u{ mz%yBtPr~wJR;Vh)PdpvN;m@6^GjzM1fphtKjz=~=`TYla%sAx$ diff --git a/juser/user_api.pyc b/juser/user_api.pyc deleted file mode 100644 index ba53cb1533e9b033d9f98264f9b14a351015e71d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6597 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 Q9Y+D!+m}kGR;4=r1DEB7jQ{`u diff --git a/juser/views.pyc b/juser/views.pyc deleted file mode 100644 index 803949f571f73d185f55ba24cc55630e98111e09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15721 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%0A)LI4 z0s$PKE3mj$>JUs z#Jc`tEKaldI*X@RJjdeuEM8@Ck;Pjqe#GL(EZ$}D_b94suG$~`Gsruz0waas3$!oc zttguD1IXso5|m3)P2SpcV^hb*j<$})9iQ&#?pV>Ws$+5c(#H12bsgP}b&U=9Zuvik ChF|dj From 82286ea7ed59d942ae5102b9a2856603fc3acc6a Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Fri, 6 Nov 2015 11:32:59 +0800 Subject: [PATCH 13/25] fix set host vars and add set group vars --- jperm/ansible_api.py | 117 +++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 55 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 0bc21c6d2..fe3b020a4 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -7,17 +7,16 @@ from ansible.inventory import Inventory from ansible.runner import Runner from ansible.playbook import PlayBook -from ansible import callbacks -from ansible import utils +from ansible import callbacks +from ansible import utils from passlib.hash import sha512_crypt from utils import get_rand_pass + import os.path -JPERM_DIR = os.path.dirname(os.path.abspath(__file__)) -ANSIBLE_DIR = os.path.join(JPERM_DIR, 'playbooks') - - +API_DIR = os.path.dirname(os.path.abspath(__file__)) +ANSIBLE_DIR = os.path.join(API_DIR, 'playbooks') @@ -50,38 +49,48 @@ class MyInventory(object): """ def __init__(self, resource): """ - resource : - resource的数据格式是一个列表字典,比如 - { - "group1": [{"hostname": "10.10.10.10", "port": "22", - "username": "test", "password": "mypass"}, ...], - "group2": [{"hostname": "10.10.10.10", "port": "22", - "username": "test", "password": "mypass"}, ...] - } - 如果你只传入1个列表,这默认该列表内的所有主机属于my_group组,比如 - [{"hostname": "10.10.10.10", "port": "22", - "username": "test", "password": "mypass"}, ...] - + 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): + 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: - hostname = host.get("hostname") - hostport = host.get("hostport") - username = host.get("username") - password = host.get("password") + # set connection variables + hostname = host.pop("hostname") + hostport = host.pop("port") + username = host.pop("username") + password = host.pop("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_user', username) my_host.set_variable('ansible_ssh_pass', password) + # set other variables + for key, value in host.iteritems(): + my_host.set_variable(key, value) + # add to group my_group.add_host(my_host) self.inventory.add_group(my_group) @@ -93,8 +102,8 @@ class MyInventory(object): if isinstance(self.resource, list): self.add_group(self.resource, 'my_group') elif isinstance(self.resource, dict): - for groupname, hosts in self.resource.iteritems(): - self.add_group(hosts, groupname) + 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): @@ -120,7 +129,7 @@ class Command(MyInventory): subset='my_group', forks=forks ) - + self.results = hoc.run() return self.stdout @@ -197,7 +206,7 @@ class Tasks(Command): subset='my_group', forks=forks ) - + self.results = hoc.run() @property @@ -235,7 +244,7 @@ class Tasks(Command): """ add a host user. """ - encrypt_pass = sha512_crypt.encrypt(password) + encrypt_pass = sha512_crypt.encrypt(password) module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass) self.__run(module_args, "user") @@ -263,7 +272,7 @@ class Tasks(Command): results["user_info"] = users return results - + def del_init_users(self): """ delete initail users: SA, DBA, DEV @@ -284,7 +293,7 @@ class CustomAggregateStats(callbacks.AggregateStats): def __init__(self): super(CustomAggregateStats, self).__init__() self.results = [] - + def compute(self, runner_results, setup=False, poll=False, ignore_errors=False): """ @@ -292,21 +301,21 @@ class CustomAggregateStats(callbacks.AggregateStats): """ 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): """ @@ -316,23 +325,24 @@ class MyPlaybook(MyInventory): super(MyPlaybook, self).__init__(*args, **kwargs) - def run(self, playbook_relational_path): + def run(self, playbook_relational_path, extra_vars=None): """ run ansible playbook, only surport relational path. """ - stats = CustomAggregateStats() - playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY) + 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, - check=True) + 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() @@ -351,16 +361,17 @@ class App(MyPlaybook): def __init__(self, *args, **kwargs): super(App, self).__init__(*args, **kwargs) - + if __name__ == "__main__": - resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "xxx"}] + pass +# resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "yusky0902"}] # playbook = MyPlaybook(resource) # playbook.run('test.yml') # print playbook.raw_results - command = Command(resource) - command.run("who") - print command.stdout +# command = Command(resource) +# command.run("who") +# print command.raw_results # task = Tasks(resource) @@ -375,7 +386,3 @@ if __name__ == "__main__": # print task.del_init_users() - - - - From a2f84e943a7c5353adc921dea964b901bf07f725 Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Tue, 10 Nov 2015 17:46:44 +0800 Subject: [PATCH 14/25] update ansible api --- jperm/ansible_api.py | 23 +++++----- jperm/views.py | 100 +++++++++++++++++++------------------------ 2 files changed, 55 insertions(+), 68 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index fe3b020a4..7cbc19342 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -78,18 +78,19 @@ class MyInventory(object): # add hosts to group for host in hosts: # set connection variables - hostname = host.pop("hostname") - hostport = host.pop("port") - username = host.pop("username") - password = host.pop("password") + 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 + # set other variables for key, value in host.iteritems(): - my_host.set_variable(key, value) + if key not in ["hostname", "port", "username", "password"]: + my_host.set_variable(key, value) # add to group my_group.add_host(my_host) @@ -364,14 +365,14 @@ class App(MyPlaybook): if __name__ == "__main__": - pass -# resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "yusky0902"}] + resource = [{"hostname": "192.168.10.161", "port": "22", "username": "yumaojun", "password": "yusky0902"}] # playbook = MyPlaybook(resource) # playbook.run('test.yml') # print playbook.raw_results -# command = Command(resource) -# command.run("who") -# print command.raw_results + command = Command(resource) + command.run("who") + print command.raw_results + print command.resource # task = Tasks(resource) diff --git a/jperm/views.py b/jperm/views.py index 675ed2858..32e6843b3 100644 --- a/jperm/views.py +++ b/jperm/views.py @@ -9,8 +9,9 @@ from jperm.models import SysUser from juser.user_api import gen_ssh_key -from juser.models import User +from juser.models import User, UserGroup from jasset.models import Asset, AssetGroup +from jperm.models import PermRole, PermRule from jperm.utils import updates_dict @@ -69,72 +70,57 @@ def perm_user_edit(request): """ data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "授权更改"} - # 获取user对象 user_id = request.GET.get('id', '') user = get_object(User, id=user_id) - # 获取所有 资产 和 资产组 - asset_all = Asset.objects.all() - asset_group_all = AssetGroup.objects.all() - - # 获取授权的 资产对象列表 和 资产组对象列表 - asset_permed = user.asset.all() - asset_group_permed = user.asset_group.all() - - # 获取未授权的 资产对象列表 和 资产组对象列表 if request.method == 'GET' and user: - assets = [asset for asset in asset_all if asset not in asset_permed] - asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed] - data_content = {"assets": assets, "asset_groups": asset_groups, "user": user} + # 获取所有 用户,用户组,资产,资产组,用户角色, 用于添加授权规则 + users = User.objects.all() + user_groups = UserGroup.objects.all() + assets = Asset.objects.all() + asset_groups = AssetGroup.objects.all() + roles = PermRole.objects.all() + data_content = {"users": users, "user_groups": user_groups, + "assets": assets, "asset_groups": asset_groups, + "roles": roles} render_data = updates_dict(data_nav, data_content) - return my_render('jperm/perm_user_edit.html', render_data, request) + return my_render('jperm/rule_add.html', render_data, request) elif request.method == 'POST' and user: - # 获取选择的资产列表 和 资产组列表 - asset_id_select = request.POST.getlist('asset_select', []) - asset_group_id_select = request.POST.getlist('asset_groups_select', []) - asset_select = get_object_list(Asset, asset_id_select) - asset_group_select = get_object_list(AssetGroup, asset_group_id_select) + # 获取用户选择的 用户,用户组,资产,资产组,用户角色 + users_select = request.POST.getlist('user', []) + user_groups_select = request.POST.getlist('usergroup', []) + assets_select = request.POST.getlist('asset', []) + asset_groups_select = request.POST.getlist('assetgroup', []) + roles_select = request.POST.getlist('role', []) - # 新授权的资产对象列表, 回收权限的资产对象列表, 新授权的资产组对象列表, 回收的资产组对象列表 - asset_new = list(set(asset_select) - set(asset_permed)) - asset_del = list(set(asset_permed) - set(asset_select)) - asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) - asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) + # 获取需要授权的主机列表 + assets_obj = [Asset.objects.get(ip=asset) for asset in assets_select] + asset_groups_obj = [AssetGroup.objects.get(name=group) for group in asset_groups_select] + + group_assets_obj = [ asset for assets in [group.user_set.all() for group in asset_groups_obj]] + - for asset_group in asset_group_new: - asset_new.extend(asset_group.asset_set.all()) - for asset_group in asset_group_del: - asset_del.extend(asset_group.asset_set.all()) - perm_info = { - 'action': 'perm user edit: ' + user.name, - 'del': {'users': [user], 'assets': asset_del}, - 'new': {'users': [user], 'assets': asset_new} - } - print perm_info - try: - results = perm_user_api(perm_info) # 通过API授权或回收 - except ServerError, e: - return HttpResponse(e) - unreachable_asset = [] - failures_asset = [] - for ip in results.get('unreachable'): - unreachable_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) - for ip in results.get('failures'): - failures_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) - failures_asset.extend(unreachable_asset) # 失败的授权要统计 - for asset in failures_asset: - if asset in asset_select: - asset_select.remove(asset) - else: - asset_select.append(asset) - user.asset = asset_select - user.asset_group = asset_group_select - user.save() # 保存到数据库 - return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json") - else: - return HttpResponse('输入错误') + + # 获取需要授权的用户列表 + users_obj = [User.objects.get(name=user) for user in users_select] + user_groups_obj = [UserGroup.objects.get(name=group) for group in user_groups_select] + + group_users_obj = [user for user in [group.user_set.all() for group in user_groups_obj]] + + + # 获取授予的角色列表 + roles_obj = [User.objects.get(name=role) for role in roles_select] + + + # 调用Ansible API 执行授权 + + + # 授权成功,写回数据库 + + print request.POST + return HttpResponse(request.POST) @require_role('admin') From 1c3d642be250026193bbdd9e2fe798e0197f5696 Mon Sep 17 00:00:00 2001 From: Zi Chuanxiu <719118794@qq.com> Date: Tue, 10 Nov 2015 19:55:12 +0800 Subject: [PATCH 15/25] fixed ansible command variables bug. --- jperm/ansible_api.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 7cbc19342..8f8243b88 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -114,7 +114,7 @@ class Command(MyInventory): def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) - def run(self, command, module_name="command", timeout=5, forks=10): + def run(self, command, module_name="command", timeout=5, forks=10, group='my_group'): """ run command from andible ad-hoc. command : 必须是一个需要执行的命令字符串, 比如 @@ -127,12 +127,20 @@ class Command(MyInventory): module_args=command, timeout=timeout, inventory=self.inventory, - subset='my_group', + subset=group, forks=forks ) self.results = hoc.run() - return self.stdout + 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): @@ -365,15 +373,23 @@ class App(MyPlaybook): if __name__ == "__main__": - resource = [{"hostname": "192.168.10.161", "port": "22", "username": "yumaojun", "password": "yusky0902"}] + pass +# resource = { +# "group1": { +# "hosts": [{"hostname": "127.0.0.1", "port": "22", "username": "root", "password": "xxx"},], +# "vars" : {"var1": "value1", "var2": "value2"}, +# }, +# } +# command = Command(resource) +# print command.run("who", group="group1") + +# resource = [{"hostname": "127.0.1.1", "port": "22", "username": "root", "password": "xxx"}] +# command = Command(resource) +# print command.run("who") + # playbook = MyPlaybook(resource) # playbook.run('test.yml') # print playbook.raw_results - command = Command(resource) - command.run("who") - print command.raw_results - print command.resource - # task = Tasks(resource) # print task.add_user('test', 'mypass') @@ -381,7 +397,6 @@ if __name__ == "__main__": # print task.push_key('root', '/root/.ssh/id_rsa.pub') # print task.del_key('root', '/root/.ssh/id_rsa.pub') - # task = Tasks(resource) # print task.add_init_users() # print task.del_init_users() From 6074bb033d753927aa83c85adab971a80bcddc3f Mon Sep 17 00:00:00 2001 From: yumaojun <719118794@qq.com> Date: Fri, 13 Nov 2015 00:31:27 +0800 Subject: [PATCH 16/25] ansible api add get_host_info in Class Tasks --- jperm/ansible_api.py | 128 ++++++-- jperm/template_filter.py | 0 jperm/views.py | 190 +++++++----- ...user_detail.html => perm_rule_detail.html} | 0 templates/jperm/perm_rule_edit.html | 284 ++++++++++++++++++ .../{perm_user_list.html => perm_rules.html} | 36 ++- templates/jperm/perm_user_edit.html | 122 -------- 7 files changed, 528 insertions(+), 232 deletions(-) create mode 100644 jperm/template_filter.py rename templates/jperm/{perm_user_detail.html => perm_rule_detail.html} (100%) create mode 100644 templates/jperm/perm_rule_edit.html rename templates/jperm/{perm_user_list.html => perm_rules.html} (61%) delete mode 100644 templates/jperm/perm_user_edit.html diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index fe3b020a4..4017cce16 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -78,18 +78,19 @@ class MyInventory(object): # add hosts to group for host in hosts: # set connection variables - hostname = host.pop("hostname") - hostport = host.pop("port") - username = host.pop("username") - password = host.pop("password") + 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 + # set other variables for key, value in host.iteritems(): - my_host.set_variable(key, value) + if key not in ["hostname", "port", "username", "password"]: + my_host.set_variable(key, value) # add to group my_group.add_host(my_host) @@ -112,8 +113,9 @@ class Command(MyInventory): """ def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) + self.results = '' - def run(self, command, module_name="command", timeout=5, forks=10): + def run(self, command, module_name="command", timeout=5, forks=10, group='my_group'): """ run command from andible ad-hoc. command : 必须是一个需要执行的命令字符串, 比如 @@ -126,12 +128,20 @@ class Command(MyInventory): module_args=command, timeout=timeout, inventory=self.inventory, - subset='my_group', + subset=group, forks=forks ) - self.results = hoc.run() - return self.stdout + + 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): @@ -193,7 +203,7 @@ class Tasks(Command): def __init__(self, *args, **kwargs): super(Tasks, self).__init__(*args, **kwargs) - def __run(self, module_args, module_name="command", timeout=5, forks=10): + def __run(self, module_args, module_name="command", timeout=5, forks=10, group='my_group'): """ run command from andible ad-hoc. command : 必须是一个需要执行的命令字符串, 比如 @@ -203,7 +213,7 @@ class Tasks(Command): module_args=module_args, timeout=timeout, inventory=self.inventory, - subset='my_group', + subset=group, forks=forks ) @@ -250,6 +260,25 @@ class Tasks(Command): 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. @@ -284,6 +313,56 @@ class Tasks(Command): 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 {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result} + + class CustomAggregateStats(callbacks.AggregateStats): @@ -362,25 +441,32 @@ class App(MyPlaybook): super(App, self).__init__(*args, **kwargs) - if __name__ == "__main__": pass -# resource = [{"hostname": "192.168.10.128", "port": "22", "username": "root", "password": "yusky0902"}] + +# resource = { +# "group1": { +# "hosts": [{"hostname": "127.0.0.1", "port": "22", "username": "root", "password": "xxx"},], +# "vars" : {"var1": "value1", "var2": "value2"}, +# }, +# } +# command = Command(resource) +# print command.run("who", group="group1") + + # resource = [{"hostname": "192.168.10.148", "port": "22", "username": "root", "password": "xxx"}] + # task = Tasks(resource) + # print task.get_host_info() + # playbook = MyPlaybook(resource) # playbook.run('test.yml') # print playbook.raw_results -# command = Command(resource) -# command.run("who") -# print command.raw_results - -# task = Tasks(resource) -# print task.add_user('test', 'mypass') +# task = Tasks(resource) + # print task.add_user('test', 'mypass') # print task.del_user('test') # print task.push_key('root', '/root/.ssh/id_rsa.pub') # print task.del_key('root', '/root/.ssh/id_rsa.pub') - # task = Tasks(resource) # print task.add_init_users() # print task.del_init_users() diff --git a/jperm/template_filter.py b/jperm/template_filter.py new file mode 100644 index 000000000..e69de29bb diff --git a/jperm/views.py b/jperm/views.py index 675ed2858..700ed444f 100644 --- a/jperm/views.py +++ b/jperm/views.py @@ -9,16 +9,18 @@ from jperm.models import SysUser from juser.user_api import gen_ssh_key -from juser.models import User -from jasset.models import Asset, AssetGroup +from juser.models import User, UserGroup +from jasset.models import Asset, AssetGroup +from jperm.models import PermRole, PermRule -from jperm.utils import updates_dict +from jperm.utils import updates_dict +from jperm.ansible_api import Tasks -from jumpserver.api import my_render, get_object +from jumpserver.api import my_render, get_object @require_role('admin') -def perm_user_list(request): +def perm_rules(request): """ 用户授权视图: 该视图的模板包含2部分: @@ -27,25 +29,27 @@ def perm_user_list(request): 2. include 部分:{% include 'nav_cat_bar.html' %} rander_nav 为渲染数据 """ - data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "用户授权"} + data_nav = {"header_title": "授权规则", "path1": "规则管理", "path2": "查看规则"} + + # 获取所有规则 + rules_list = PermRule.objects.all() - # 获取所有用户 - users_list = User.objects.all() - # 搜索和分页 + # TODO: 搜索和分页 keyword = request.GET.get('search', '') if keyword: - users_list = users_list.filter(Q(name=keyword) | Q(username=keyword)) - users_list, p, users, page_range, current_page, show_first, show_end = pages(users_list, request) - data_content = {"users": users} + rules_list = rules_list.filter(Q(name=keyword)) + + rules_list, p, rules, page_range, current_page, show_first, show_end = pages(rules_list, request) + data_content = {"rules": rules_list} render_data = updates_dict(data_nav, data_content) - return my_render('jperm/perm_user_list.html', render_data, request) + return my_render('jperm/perm_rules.html', render_data, request) @require_role('admin') -def perm_user_detail(request): +def perm_rule_detail(request): """ 用户详情视图: 该视图的模板包含2部分: @@ -59,82 +63,112 @@ def perm_user_detail(request): # 待实现 render_data = updates_dict(data_nav) - return my_render('jperm/perm_user_detail.html', render_data, request) + return my_render('jperm/perm_rule_detail.html', render_data, request) @require_role('admin') -def perm_user_edit(request): +def perm_rule_add(request): """ - TODO: - """ - data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "授权更改"} - # 获取user对象 + :param request: + :return: + """ + data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "添加授权规则"} + + if request.method == 'GET': + # 获取所有 用户,用户组,资产,资产组,用户角色, 用于添加授权规则 + users = User.objects.all() + user_groups = UserGroup.objects.all() + assets = Asset.objects.all() + asset_groups = AssetGroup.objects.all() + roles = PermRole.objects.all() + + data_content = {"users": users, "user_groups": user_groups, + "assets": assets, "asset_groups": asset_groups, + "roles": roles} + render_data = updates_dict(data_nav, data_content) + return my_render('jperm/perm_rule_add.html', render_data, request) + + elif request.method == 'POST': + # 获取用户选择的 用户,用户组,资产,资产组,用户角色 + users_select = request.POST.getlist('user', []) + user_groups_select = request.POST.getlist('usergroup', []) + assets_select = request.POST.getlist('asset', []) + asset_groups_select = request.POST.getlist('assetgroup', []) + roles_select = request.POST.getlist('role', []) + rule_name = request.POST.get('rulename') + rule_comment = request.POST.get('comment') + + # 获取需要授权的主机列表 + assets_obj = [Asset.objects.get(ip=asset) for asset in assets_select] + asset_groups_obj = [AssetGroup.objects.get(name=group) for group in asset_groups_select] + group_assets_obj = [asset for asset in [group.asset_set.all() for group in asset_groups_obj]] + calc_assets = set(group_assets_obj) | set(assets_obj) + + # 获取需要授权的用户列表 + users_obj = [User.objects.get(name=user) for user in users_select] + user_groups_obj = [UserGroup.objects.get(name=group) for group in user_groups_select] + group_users_obj = [user for user in [group.user_set.all() for group in user_groups_obj]] + calc_users = set(group_users_obj) | set(users_obj) + + # 获取授予的角色列表 + roles_obj = [PermRole.objects.get(name=role) for role in roles_select] + + # 调用Ansible API 执行授权 资源---Role---用户 + # 生成Inventory, 这里需要向CMDB 获取认证信息(1. password, 2, key) + hosts = [{"hostname": asset.ip, + "port": asset.port, + "username": asset.username, + "password": asset.password} for asset in calc_assets] + # 获取需要授权的角色名称 + roles = [role.name for role in roles_obj] + # 调用Ansible API 执行 password方式的授权 TODO: Surport sudo + tasks = Tasks(hosts) + ret = tasks.add_multi_user(*roles) + # TODO: 调用Ansible API 执行 key方式的授权 + + # 计算授权成功和授权失败的主机 TODO: 记录成功和失败 + perm_sucess = {} + perm_failed = {} + for role, status in ret.get('action_info').iteritems(): + if status['status'] == 'failed': + failed_ip = status['msg'].keys() + perm_sucess[role] = [asset for asset in calc_assets if asset.ip not in failed_ip] + perm_failed[role] = [asset for asset in calc_assets if asset.ip in failed_ip] + + if not perm_failed.values(): + # 仅授权成功的,写回数据库(授权规则,用户,用户组,资产,资产组,用户角色) + rule = PermRule(name=rule_name, comment=rule_comment) + rule.save() + rule.user = users_obj + rule.usergroup = user_groups_obj + rule.asset = assets_obj + rule.asset_group = asset_groups_obj + rule.role = roles_obj + rule.save() + return HttpResponse(ret) + else: + return HttpResponse("add rule failed") + +@require_role('admin') +def perm_rule_list(request): + """ + list rules + :param request: + :return: + """ + + data_nav = {"header_title": "用户授权", "path1": "授权管理", "path2": "查看授权规则"} + user_id = request.GET.get('id', '') user = get_object(User, id=user_id) - # 获取所有 资产 和 资产组 - asset_all = Asset.objects.all() - asset_group_all = AssetGroup.objects.all() - - # 获取授权的 资产对象列表 和 资产组对象列表 - asset_permed = user.asset.all() - asset_group_permed = user.asset_group.all() - - # 获取未授权的 资产对象列表 和 资产组对象列表 if request.method == 'GET' and user: - assets = [asset for asset in asset_all if asset not in asset_permed] - asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed] - data_content = {"assets": assets, "asset_groups": asset_groups, "user": user} + # 获取所有的rule对象 + rules = PermRule.obects.all() - render_data = updates_dict(data_nav, data_content) - return my_render('jperm/perm_user_edit.html', render_data, request) - elif request.method == 'POST' and user: - # 获取选择的资产列表 和 资产组列表 - asset_id_select = request.POST.getlist('asset_select', []) - asset_group_id_select = request.POST.getlist('asset_groups_select', []) - asset_select = get_object_list(Asset, asset_id_select) - asset_group_select = get_object_list(AssetGroup, asset_group_id_select) - # 新授权的资产对象列表, 回收权限的资产对象列表, 新授权的资产组对象列表, 回收的资产组对象列表 - asset_new = list(set(asset_select) - set(asset_permed)) - asset_del = list(set(asset_permed) - set(asset_select)) - asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) - asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) - - for asset_group in asset_group_new: - asset_new.extend(asset_group.asset_set.all()) - for asset_group in asset_group_del: - asset_del.extend(asset_group.asset_set.all()) - perm_info = { - 'action': 'perm user edit: ' + user.name, - 'del': {'users': [user], 'assets': asset_del}, - 'new': {'users': [user], 'assets': asset_new} - } - print perm_info - try: - results = perm_user_api(perm_info) # 通过API授权或回收 - except ServerError, e: - return HttpResponse(e) - unreachable_asset = [] - failures_asset = [] - for ip in results.get('unreachable'): - unreachable_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) - for ip in results.get('failures'): - failures_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip))) - failures_asset.extend(unreachable_asset) # 失败的授权要统计 - for asset in failures_asset: - if asset in asset_select: - asset_select.remove(asset) - else: - asset_select.append(asset) - user.asset = asset_select - user.asset_group = asset_group_select - user.save() # 保存到数据库 - return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json") - else: - return HttpResponse('输入错误') @require_role('admin') diff --git a/templates/jperm/perm_user_detail.html b/templates/jperm/perm_rule_detail.html similarity index 100% rename from templates/jperm/perm_user_detail.html rename to templates/jperm/perm_rule_detail.html diff --git a/templates/jperm/perm_rule_edit.html b/templates/jperm/perm_rule_edit.html new file mode 100644 index 000000000..591d1896a --- /dev/null +++ b/templates/jperm/perm_rule_edit.html @@ -0,0 +1,284 @@ +{% extends 'base.html' %} +{% load mytags %} +{% block content %} +{% include 'nav_cat_bar.html' %} + +
+
+
+
+
+
未授权资源和资源组
+ +
+ +
+
+{# 添加用户 #} + +
+ + + + + + + + + + {% for user in users.object_list %} + + + + + {% endfor %} + +
主机用户角色
192.168.10.128 +
+ +
+
+ +
+
+ +
+
+
+
+
+ Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries +
+
+ {% include 'paginator.html' %} +
+
+ +
+
+
+
授权资源和资源组
+ +
+ +
+
+ +
+ + + + + + + + + + {% for user in users.object_list %} + + + + + {% endfor %} + +
主机用户角色
{{ user.name }} + 详情 + 编辑 +
+
+
+
+ Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries +
+
+ {% include 'paginator.html' %} +
+
+ +
+
+
+
+
+
未授权资源和资源组
+ +
+ +
+
+{# 添加用户 #} + +
+ + + + + + + + + + {% for user in users.object_list %} + + + + + {% endfor %} + +
主机用户角色
192.168.10.128 +
+ +
+
+ +
+
+ +
+
+
+
+
+ Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries +
+
+ {% include 'paginator.html' %} +
+
+ +
+
+
+
授权资源和资源组
+ +
+ +
+
+ +
+ + + + + + + + + + {% for user in users.object_list %} + + + + + {% endfor %} + +
主机用户角色
{{ user.name }} + 详情 + 编辑 +
+
+
+
+ Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries +
+
+ {% include 'paginator.html' %} +
+
+ +
+
+
+
+ +{% endblock %} + diff --git a/templates/jperm/perm_user_list.html b/templates/jperm/perm_rules.html similarity index 61% rename from templates/jperm/perm_user_list.html rename to templates/jperm/perm_rules.html index dc503fecc..16694f3e2 100644 --- a/templates/jperm/perm_user_list.html +++ b/templates/jperm/perm_rules.html @@ -8,7 +8,7 @@
-
查看小组
+
所有规则
@@ -24,7 +24,8 @@
- 添加用户 + 添加规则 + 删除所选
+
+
+
+
+
+
+ 授权用户/用户组 +
+ + + + + + + + + + +
+
+
+
+
+ + + + + + + + + {% for user in users %} + + + + + {% endfor %} + +
用户用户组
{{ user.name }} {{ user | user_which_groups:"group" }}
+
+
+
+
+
+
+
+
+ 授权主机/主机组 +
+ + + + + + + + + + +
+
+
+
+
+ + + + + + + + + {% for asset in assets %} + + + + + {% endfor %} + +
主机主机组
{{ asset.ip }} {{ asset | asset_which_groups:"group" }}
+
+
+
+
+
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/templates/jperm/perm_role_edit.html b/templates/jperm/perm_role_edit.html new file mode 100644 index 000000000..23c7e7617 --- /dev/null +++ b/templates/jperm/perm_role_edit.html @@ -0,0 +1,113 @@ +{% extends 'base.html' %} +{% block self_head_css_js %} + + + +{% endblock %} +{% load mytags %} +{% block content %} + {% include 'nav_cat_bar.html' %} +
+
+
+
+
+
填写基本信息
+ +
+
+
+ {% if error %} +
{{ error }}
+ {% endif %} + {% if msg %} +
{{ msg }}
+ {% endif %} +
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} +{% block self_footer_js %} + + + +{% endblock %} + diff --git a/templates/jperm/perm_role_list.html b/templates/jperm/perm_role_list.html new file mode 100644 index 000000000..dfecbf09c --- /dev/null +++ b/templates/jperm/perm_role_list.html @@ -0,0 +1,105 @@ +{% extends 'base.html' %} +{% load mytags %} +{% block content %} +{% include 'nav_cat_bar.html' %} + +
+
+
+
+
+
所有系统角色
+ +
+ +
+
+ 添加角色 + 推送角色 + 删除所选 + +
+ + + + + + + + + + + + {% for role in roles %} + + + + + + + {% endfor %} + +
名称 备注创建时间操作
{{ role.name }} {{ role.comment }} {{ role.date_added | date:"Y-m-d H:i:s"}} + 详情 + 编辑 + +
+
+
+
+ Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries +
+
+ {% include 'paginator.html' %} +
+
+
+
+
+
+ + + + + +{% endblock %} + + diff --git a/templates/jperm/perm_role_push.html b/templates/jperm/perm_role_push.html new file mode 100644 index 000000000..6251ff441 --- /dev/null +++ b/templates/jperm/perm_role_push.html @@ -0,0 +1,139 @@ +{% extends 'base.html' %} +{% block self_head_css_js %} + + + +{% endblock %} +{% load mytags %} +{% block content %} + {% include 'nav_cat_bar.html' %} +
+
+
+
+
+
填写基本信息
+ +
+
+
+ {% if error %} +
{{ error }}
+ {% endif %} + {% if msg %} +
{{ msg }}
+ {% endif %} +
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} +{% block self_footer_js %} + + + +{% endblock %} + From 83c2704d537a31fe7d61a568f9ec24f3674f0da8 Mon Sep 17 00:00:00 2001 From: yumaojun <719118794@qq.com> Date: Sat, 14 Nov 2015 22:54:29 +0800 Subject: [PATCH 24/25] 1. update role push --- jperm/models.py | 2 +- jperm/views.py | 40 +++++++++++++++++++++++++++++ templates/jperm/perm_role_push.html | 29 ++++++++++++++++++--- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/jperm/models.py b/jperm/models.py index d273eeb9c..2bcea14e3 100644 --- a/jperm/models.py +++ b/jperm/models.py @@ -20,7 +20,7 @@ class SysUser(models.Model): class PermRole(models.Model): - name = models.CharField(max_length=100) + name = models.CharField(max_length=100, unique=True) comment = models.CharField(max_length=100, null=True, blank=True, default='') password = models.CharField(max_length=100) key_path = models.CharField(max_length=100) diff --git a/jperm/views.py b/jperm/views.py index bd3d32d9e..a9df09790 100644 --- a/jperm/views.py +++ b/jperm/views.py @@ -344,6 +344,46 @@ def perm_role_push(request): return my_render('jperm/perm_role_push.html', render_data, request) if request.method == "POST": + # 获取推荐角色的名称列表 + role_names = request.POST.getlist("roles") + + # 计算出需要推送的资产列表 + asset_ips = request.POST.getlist("assets") + asset_group_names = request.POST.getlist("asset_groups") + assets_obj = [Asset.objects.get(ip=asset_ip) for asset_ip in asset_ips] + asset_groups_obj = [AssetGroup.objects.get(name=asset_group_name) for asset_group_name in asset_group_names] + group_assets_obj = [] + for asset_group in asset_groups_obj: + group_assets_obj.extend(asset_group.asset_set.all()) + calc_assets = set(assets_obj) | set(group_assets_obj) + + # 生成Inventory + hosts = [{"hostname": asset.ip, + "port": asset.port, + "username": asset.username, + "password": asset.password} for asset in calc_assets] + + # 获取角色的推送方式,以及推送需要的信息 + roles_obj = [PermRole.objects.get(name=role_name) for role_name in role_names] + roles_info = {} + for role in roles_obj: + roles_info[role.name] = {"password": role.password, "key": role.key_path} + + # 推送 + password_push = request.POST.get("use_password") + key_push = request.POST.get("use_publicKey") + if password_push: + pass + if key_push: + pass + + + + + # 调用Ansible API 执行 password方式的授权 TODO: Surport sudo + # tasks = Tasks(hosts) + # ret = tasks.add_multi_user(*role_names) + return HttpResponse(u"未实现") diff --git a/templates/jperm/perm_role_push.html b/templates/jperm/perm_role_push.html index 6251ff441..a524d0cc2 100644 --- a/templates/jperm/perm_role_push.html +++ b/templates/jperm/perm_role_push.html @@ -36,7 +36,7 @@
- {% for asset in assets %} {% endfor %} @@ -47,7 +47,7 @@
- {% for asset_group in asset_groups %} {% endfor %} @@ -58,7 +58,7 @@
- {% for role in roles %} {% endfor %} @@ -66,6 +66,29 @@
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
From 95dc12a71b9fe2d7366400eb6bd8807d09380d48 Mon Sep 17 00:00:00 2001 From: yumaojun <719118794@qq.com> Date: Sat, 14 Nov 2015 23:17:05 +0800 Subject: [PATCH 25/25] update models --- jumpserver/templatetags/mytags.pyc | Bin 4204 -> 0 bytes juser/models.py | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 jumpserver/templatetags/mytags.pyc diff --git a/jumpserver/templatetags/mytags.pyc b/jumpserver/templatetags/mytags.pyc deleted file mode 100644 index db94f7a7838f55b9f4c97ddc1e5fcf6c6081af79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4204 zcmb_fZEqaa6~1?7{Sv>##vy^Qq;(RxT0yZxq=X8kDN(4>50NX)k^+{fwe}3|Y-e}P z+`AE$5~-2{4YY1d3vEb4QYs(_RcQ(c(nP3#gpb~reC`iupXc0Ndn^!AyR3a@&b{Z( zopYY^I{v>$hmL-E=x2+n^Yd|k3d5{vr9%8`l_)j0NozHyyX&5s^Mv+P;;Twd&E=Hl zGrmgt)H9@VD(P310W~+Ebd*!&LA8q0cBp8FDi5i!Plf$h(cyr)pwuc3AI`A2S%*8i ztdR_BNLa&N)@X(`BCOFaYiEYFQ&?kN)>wu$F0A{ytnmzMLRh=Htot&o`-Qc;%bLir z_6X~NE^AkY^`Nl!s_-FoL5tS+XSjLcKCHrhUG8pLp;-71%o6_xzu5w8qwF9rQDr$P z*~qPM`4LABfjnVMWKSe<$=DpG)lwz010dq6J#1{c$n6{+#z_prhpbZP#1ut2$mFp$ zG>IRcnrwgZx8~YkH*VjV#PhQ1-bSy%iktLda<-JzqXGye7jqcYOj@hinR30dY@+mR zlxE4U9=5b(W-2SZO)swm6nhNAP(;-yDlbKLKCLB@h|d>ulZgKeh}b7sp{I_9pmMm0 zj~zX)shI_9!0D&Yd+MC0($ngkR%K6FpVM-V_P{f%o+{#23$0g%vD=@$(z=O7-F*}5SuOs z%l#69AEEuqT7d^weENkk1?xF0{oGS8eU~OG(!7~nFg47z|0|nMbMu}e(oC^H84Xnx z3pH-N>R^T`8W;c6e)q#o@9sJ`oJo8}sYyeLr_AK^^mGhL#nfWf;mch~R24MKwYVB^ zp}-AW>dz;!v6jYJA{xB|z6(c9VTfR=Z$cmR>^SCP+!7;yez8`sS_u>S1BE)t2cE+P zxR&vc?4tx+&;ll>o_hH)#=_GtOsVsT3SXsD0>99R5ce2x)h|sc{67o5U>;h<<%~!1 z2En-fuQwZizLpJ+joWvdSMRj0Txh;^>)x*~$*uyi6>LOqaph8y*kLR?O$0N`ZPCj% zsya7zEGQc62BSb7g9%(@pD>MOsAY~Y!Nc5&(OX{Hivtc}7@n{C#`Kss3V+|{**%zN zOdx`146!ZU(uB_Ufhh0?_*)oGgZa%EB7jMe>t?nXOaO=H6K5FkEnW z{W|B_QOqk*Wg$vU#vqJRdXC8a7>G`lK*FIlw97o506>WNw31WDhdO-JurRmoUT-7M zOHn{V*|`0i=EZg7eCOr?U0L$Rtn*X)jpX7p$iAnT5u~<>=fI;S7$kgM8X3fP=Sp!H zJcvo}5FNxRKgBRSTlq}aqn?xsTbpOAAc|swrNJPOSsg5#|Ee zdv7Oc=T!08>Y&nEBV`w#L!vH9B{L70#|_NjLzI z)pa|Hba`>I$3c8Um%=&+y*mEKc7?4-fmSm6aFLT8VvS3e(TcTi{J#C##||`sYFi7z zpgJVW+d2*|KW@IRM4EJP*JQ1sx$-)r;XcdjrHF;Bpuy&@6*QWC2<&er7KTi z1=XFIS!zA|*ctOu-1r4k|=s6P2G};tCAv z%6V7y5u4Ik0RRT5#4@6F2~ms{^u$`3W6~Kv#Sgh6R8KRC|8}z3qfIf|^obwU_ohja=7)9*<(#7@t}cCM=h#OSJ%$vW%gvub=7Cax68e zEd9xJr4~ks37Bvtshy4&(o(u2Ag0k0y2mID_zfZ-MFCwmU;`1b7YX+BLiB=zyin(W zkrdE%0xGZtgHVQy|NVq&H+erCRh%ZSFGH|`DTac{)W59W8~hx22&59WvR MBl!XJNBv{^zddg5djJ3c diff --git a/juser/models.py b/juser/models.py index 70bc703e4..7ea4bc95b 100644 --- a/juser/models.py +++ b/juser/models.py @@ -24,9 +24,9 @@ class User(AbstractUser): role = models.CharField(max_length=2, choices=USER_ROLE_CHOICES, default='CU') group = models.ManyToManyField(UserGroup) ssh_key_pwd = models.CharField(max_length=200) - is_active = models.BooleanField(default=True) - last_login = models.DateTimeField(null=True) - date_joined = models.DateTimeField(null=True) + # is_active = models.BooleanField(default=True) + # last_login = models.DateTimeField(null=True) + # date_joined = models.DateTimeField(null=True)