mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' of git.coding.net:jumpserver/jumpserver into dev
commit
8ac369b925
|
@ -43,7 +43,7 @@ class CommandValueError(AnsibleError):
|
||||||
super(CommandValueError, self).__init__('value:invalid', field, message)
|
super(CommandValueError, self).__init__('value:invalid', field, message)
|
||||||
|
|
||||||
|
|
||||||
class MyInventory(object):
|
class MyInventory(Inventory):
|
||||||
"""
|
"""
|
||||||
this is my ansible inventory object.
|
this is my ansible inventory object.
|
||||||
"""
|
"""
|
||||||
|
@ -64,7 +64,7 @@ class MyInventory(object):
|
||||||
self.inventory = Inventory(host_list=[])
|
self.inventory = Inventory(host_list=[])
|
||||||
self.gen_inventory()
|
self.gen_inventory()
|
||||||
|
|
||||||
def add_group(self, hosts, groupname, groupvars=None):
|
def my_add_group(self, hosts, groupname, groupvars=None):
|
||||||
"""
|
"""
|
||||||
add hosts to a group
|
add hosts to a group
|
||||||
"""
|
"""
|
||||||
|
@ -90,6 +90,7 @@ class MyInventory(object):
|
||||||
my_host.set_variable('ansible_ssh_user', username)
|
my_host.set_variable('ansible_ssh_user', username)
|
||||||
my_host.set_variable('ansible_ssh_pass', password)
|
my_host.set_variable('ansible_ssh_pass', password)
|
||||||
my_host.set_variable('ansible_ssh_private_key_file', ssh_key)
|
my_host.set_variable('ansible_ssh_private_key_file', ssh_key)
|
||||||
|
|
||||||
# set other variables
|
# set other variables
|
||||||
for key, value in host.iteritems():
|
for key, value in host.iteritems():
|
||||||
if key not in ["hostname", "port", "username", "password"]:
|
if key not in ["hostname", "port", "username", "password"]:
|
||||||
|
@ -104,10 +105,10 @@ class MyInventory(object):
|
||||||
add hosts to inventory.
|
add hosts to inventory.
|
||||||
"""
|
"""
|
||||||
if isinstance(self.resource, list):
|
if isinstance(self.resource, list):
|
||||||
self.add_group(self.resource, 'default_group')
|
self.my_add_group(self.resource, 'default_group')
|
||||||
elif isinstance(self.resource, dict):
|
elif isinstance(self.resource, dict):
|
||||||
for groupname, hosts_and_vars in self.resource.iteritems():
|
for groupname, hosts_and_vars in self.resource.iteritems():
|
||||||
self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
|
self.my_add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
|
||||||
|
|
||||||
|
|
||||||
class MyRunner(MyInventory):
|
class MyRunner(MyInventory):
|
||||||
|
@ -168,6 +169,7 @@ class Command(MyInventory):
|
||||||
)
|
)
|
||||||
self.results = hoc.run()
|
self.results = hoc.run()
|
||||||
|
|
||||||
|
ret = {}
|
||||||
if self.stdout:
|
if self.stdout:
|
||||||
data['ok'] = self.stdout
|
data['ok'] = self.stdout
|
||||||
if self.stderr:
|
if self.stderr:
|
||||||
|
@ -177,6 +179,7 @@ class Command(MyInventory):
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def raw_results(self):
|
def raw_results(self):
|
||||||
"""
|
"""
|
||||||
|
@ -238,7 +241,14 @@ class Tasks(Command):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(Tasks, self).__init__(*args, **kwargs)
|
super(Tasks, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def __run(self, module_args, module_name="command", timeout=5, forks=10, group='default_group', pattern='*'):
|
def __run(self,
|
||||||
|
module_args,
|
||||||
|
module_name="command",
|
||||||
|
timeout=5,
|
||||||
|
forks=10,
|
||||||
|
group='default_group',
|
||||||
|
pattern='*',
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
run command from andible ad-hoc.
|
run command from andible ad-hoc.
|
||||||
command : 必须是一个需要执行的命令字符串, 比如
|
command : 必须是一个需要执行的命令字符串, 比如
|
||||||
|
@ -251,9 +261,11 @@ class Tasks(Command):
|
||||||
subset=group,
|
subset=group,
|
||||||
pattern=pattern,
|
pattern=pattern,
|
||||||
forks=forks,
|
forks=forks,
|
||||||
|
become=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.results = hoc.run()
|
self.results = hoc.run()
|
||||||
|
return {"msg": self.msg, "result": self.results}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def msg(self):
|
def msg(self):
|
||||||
|
@ -304,7 +316,7 @@ class Tasks(Command):
|
||||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state="absent"' % (user, key_path)
|
module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state="absent"' % (user, key_path)
|
||||||
self.__run(module_args, "authorized_key")
|
self.__run(module_args, "authorized_key")
|
||||||
|
|
||||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"}
|
||||||
|
|
||||||
def add_user(self, username, password):
|
def add_user(self, username, password):
|
||||||
"""
|
"""
|
||||||
|
@ -342,7 +354,8 @@ class Tasks(Command):
|
||||||
delete a host user.
|
delete a host user.
|
||||||
"""
|
"""
|
||||||
module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % (username)
|
module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % (username)
|
||||||
self.__run(module_args, "user")
|
self.__run(module_args,
|
||||||
|
"user",)
|
||||||
|
|
||||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||||
|
|
||||||
|
@ -418,8 +431,31 @@ class Tasks(Command):
|
||||||
"product_sn": setup.get("ansible_product_serial")
|
"product_sn": setup.get("ansible_product_serial")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result}
|
return {"failed": self.msg, "ok": result}
|
||||||
|
|
||||||
|
def push_sudo_file(self, file_path):
|
||||||
|
"""
|
||||||
|
use template to render pushed sudoers file
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
module_args1 = 'test'
|
||||||
|
ret1 = self.__run(module_args1, "script")
|
||||||
|
module_args2 = 'visudo -c | grep "parsed OK" &> /dev/null && echo "ok" || echo "failed"'
|
||||||
|
ret2 = self.__run(module_args2, "shell")
|
||||||
|
ret2_status = [host_value.get("stdout") for host_value in ret2["result"]["contacted"].values()]
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
if not ret1["msg"]:
|
||||||
|
result["step1"] = "ok"
|
||||||
|
else:
|
||||||
|
result["step1"] = "failed"
|
||||||
|
|
||||||
|
if not ret2["msg"] and "failed" not in ret2_status:
|
||||||
|
result["step2"] = "ok"
|
||||||
|
else:
|
||||||
|
result["step2"] = "failed"
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
class CustomAggregateStats(callbacks.AggregateStats):
|
class CustomAggregateStats(callbacks.AggregateStats):
|
||||||
"""
|
"""
|
||||||
|
@ -469,12 +505,12 @@ class MyPlaybook(MyInventory):
|
||||||
playbook_path = os.path.join(ANSIBLE_DIR, playbook_relational_path)
|
playbook_path = os.path.join(ANSIBLE_DIR, playbook_relational_path)
|
||||||
|
|
||||||
pb = PlayBook(
|
pb = PlayBook(
|
||||||
playbook = playbook_path,
|
playbook=playbook_path,
|
||||||
stats = stats,
|
stats=stats,
|
||||||
callbacks = playbook_cb,
|
callbacks=playbook_cb,
|
||||||
runner_callbacks = runner_cb,
|
runner_callbacks=runner_cb,
|
||||||
inventory = self.inventory,
|
inventory=self.inventory,
|
||||||
extra_vars = extra_vars,
|
extra_vars=extra_vars,
|
||||||
check=False)
|
check=False)
|
||||||
|
|
||||||
self.results = pb.run()
|
self.results = pb.run()
|
||||||
|
@ -504,9 +540,14 @@ if __name__ == "__main__":
|
||||||
# },
|
# },
|
||||||
# }
|
# }
|
||||||
|
|
||||||
resource = [{"hostname": "127.0.0.1", "port": "22", "username": "yumaojun", "password": "yusky0902"}]
|
resource = [{"hostname": "127.0.0.1", "port": "22", "username": "yumaojun", "password": "yusky0902",
|
||||||
command = Command(resource)
|
# "ansible_become": "yes",
|
||||||
print command.run("who")
|
# "ansible_become_method": "sudo",
|
||||||
|
# # "ansible_become_user": "root",
|
||||||
|
# "ansible_become_pass": "yusky0902",
|
||||||
|
}]
|
||||||
|
cmd = Command(resource)
|
||||||
|
print cmd.run('ls')
|
||||||
|
|
||||||
# resource = [{"hostname": "192.168.10.148", "port": "22", "username": "root", "password": "xxx"}]
|
# resource = [{"hostname": "192.168.10.148", "port": "22", "username": "root", "password": "xxx"}]
|
||||||
# task = Tasks(resource)
|
# task = Tasks(resource)
|
||||||
|
|
|
@ -5,12 +5,37 @@ from jasset.models import Asset, AssetGroup
|
||||||
from juser.models import User, UserGroup
|
from juser.models import User, UserGroup
|
||||||
|
|
||||||
|
|
||||||
|
class PermLog(models.Model):
|
||||||
|
datetime = models.DateTimeField(auto_now_add=True)
|
||||||
|
action = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||||
|
results = models.CharField(max_length=1000, null=True, blank=True, default='')
|
||||||
|
is_success = models.BooleanField(default=False)
|
||||||
|
is_finish = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
class SysUser(models.Model):
|
||||||
|
username = models.CharField(max_length=100)
|
||||||
|
password = models.CharField(max_length=100)
|
||||||
|
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||||
|
|
||||||
|
|
||||||
|
class PermSudo(models.Model):
|
||||||
|
name = models.CharField(max_length=100, unique=True)
|
||||||
|
date_added = models.DateTimeField(auto_now=True)
|
||||||
|
commands = models.TextField()
|
||||||
|
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class PermRole(models.Model):
|
class PermRole(models.Model):
|
||||||
name = models.CharField(max_length=100, unique=True)
|
name = models.CharField(max_length=100, unique=True)
|
||||||
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||||
password = models.CharField(max_length=100)
|
password = models.CharField(max_length=100)
|
||||||
key_path = models.CharField(max_length=100)
|
key_path = models.CharField(max_length=100)
|
||||||
date_added = models.DateTimeField(auto_now=True)
|
date_added = models.DateTimeField(auto_now=True)
|
||||||
|
sudo = models.ManyToManyField(PermSudo, related_name='perm_role')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -28,3 +53,13 @@ class PermRule(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class PermPush(models.Model):
|
||||||
|
date_added = models.DateTimeField(auto_now=True)
|
||||||
|
asset = models.ManyToManyField(Asset, related_name='perm_push')
|
||||||
|
asset_group = models.ManyToManyField(AssetGroup, related_name='perm_push')
|
||||||
|
role = models.ManyToManyField(PermRole, related_name='perm_push')
|
||||||
|
is_public_key = models.BooleanField(default=False)
|
||||||
|
is_password = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
|
@ -266,6 +266,40 @@ def get_role_info(role_id, type="all"):
|
||||||
return u"不支持的查询"
|
return u"不支持的查询"
|
||||||
|
|
||||||
|
|
||||||
|
def get_role_push_host(role):
|
||||||
|
"""
|
||||||
|
get the role push host
|
||||||
|
:return: the asset object
|
||||||
|
"""
|
||||||
|
# 计算该role 所有push记录 总共推送的主机
|
||||||
|
assets = []
|
||||||
|
asset_groups = []
|
||||||
|
for push in role.perm_push.all():
|
||||||
|
assets.extend(push.asset.all())
|
||||||
|
asset_groups.extend(push.asset_group.all())
|
||||||
|
group_assets = []
|
||||||
|
for asset_group in asset_groups:
|
||||||
|
group_assets.extend(asset_group.asset_set.all())
|
||||||
|
cacl_assets = set(assets) | set(group_assets)
|
||||||
|
|
||||||
|
# 计算所有主机 在push记录里面的 使用密码和使用秘钥状况
|
||||||
|
result = []
|
||||||
|
for asset in cacl_assets:
|
||||||
|
all_push = asset.perm_push.all()
|
||||||
|
if True in [push.is_password for push in all_push if role in push.role.all()]:
|
||||||
|
is_password = u"是"
|
||||||
|
else:
|
||||||
|
is_password = u"否"
|
||||||
|
if True in [push.is_public_key for push in all_push if role in push.role.all()]:
|
||||||
|
is_public_key = u"是"
|
||||||
|
else:
|
||||||
|
is_public_key = u"否"
|
||||||
|
result.append({"ip": asset.ip,
|
||||||
|
"group": ','.join([group.name for group in asset.group.all()]),
|
||||||
|
"password": is_password,
|
||||||
|
"pubkey": is_public_key})
|
||||||
|
return result
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print get_role_info(1)
|
print get_role_info(1)
|
||||||
|
|
||||||
|
|
|
@ -13,4 +13,9 @@ urlpatterns = patterns('jperm.views',
|
||||||
(r'^role/perm_role_detail/$', perm_role_detail),
|
(r'^role/perm_role_detail/$', perm_role_detail),
|
||||||
(r'^role/perm_role_edit/$', perm_role_edit),
|
(r'^role/perm_role_edit/$', perm_role_edit),
|
||||||
(r'^role/perm_role_push/$', perm_role_push),
|
(r'^role/perm_role_push/$', perm_role_push),
|
||||||
|
(r'^sudo/$', perm_sudo_list),
|
||||||
|
(r'^sudo/perm_sudo_add/$', perm_sudo_add),
|
||||||
|
(r'^sudo/perm_sudo_delete/$', perm_sudo_delete),
|
||||||
|
(r'^sudo/perm_sudo_edit/$', perm_sudo_edit),
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,6 +8,12 @@ from paramiko.rsakey import RSAKey
|
||||||
from jumpserver.api import mkdir
|
from jumpserver.api import mkdir
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from jumpserver.api import CRYPTOR
|
from jumpserver.api import CRYPTOR
|
||||||
|
from os import makedirs
|
||||||
|
|
||||||
|
from django.template.loader import get_template
|
||||||
|
from django.template import Context
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
|
|
||||||
from jumpserver.settings import KEY_DIR
|
from jumpserver.settings import KEY_DIR
|
||||||
|
|
||||||
|
@ -66,6 +72,47 @@ def gen_keys(key="", key_path_dir=""):
|
||||||
return key_path_dir
|
return key_path_dir
|
||||||
|
|
||||||
|
|
||||||
|
def gen_sudo(role_custom, role_name, role_chosen):
|
||||||
|
"""
|
||||||
|
生成sudo file, 仅测试了cenos7
|
||||||
|
role_custom: 自定义支持的sudo 命令 格式: 'CMD1, CMD2, CMD3, ...'
|
||||||
|
role_name: role name
|
||||||
|
role_chosen: 选择那些sudo的命令别名:
|
||||||
|
NETWORKING, SOFTWARE, SERVICES, STORAGE,
|
||||||
|
DELEGATING, PROCESSES, LOCATE, DRIVERS
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sudo_file_basename = os.path.join(os.path.dirname(KEY_DIR), 'role_sudo_file')
|
||||||
|
makedirs(sudo_file_basename)
|
||||||
|
sudo_file_path = os.path.join(sudo_file_basename, role_name)
|
||||||
|
|
||||||
|
t = get_template('role_sudo.j2')
|
||||||
|
content = t.render(Context({"role_custom": role_custom,
|
||||||
|
"role_name": role_name,
|
||||||
|
"role_chosen": role_chosen,
|
||||||
|
}))
|
||||||
|
with open(sudo_file_path, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
return sudo_file_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_add_sudo_script(sudo_chosen_aliase, sudo_chosen_obj):
|
||||||
|
"""
|
||||||
|
get the sudo file
|
||||||
|
:param kwargs:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sudo_j2 = get_template('jperm/role_sudo.j2')
|
||||||
|
sudo_content = sudo_j2.render(Context({"sudo_chosen_aliase": sudo_chosen_aliase,
|
||||||
|
"sudo_chosen_obj": sudo_chosen_obj}))
|
||||||
|
sudo_file = NamedTemporaryFile(delete=False)
|
||||||
|
sudo_file.write(sudo_content)
|
||||||
|
sudo_file.close()
|
||||||
|
|
||||||
|
return sudo_file.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print gen_keys()
|
print gen_keys()
|
||||||
|
|
||||||
|
|
261
jperm/views.py
261
jperm/views.py
|
@ -5,15 +5,14 @@ from paramiko import SSHException
|
||||||
from jperm.perm_api import *
|
from jperm.perm_api import *
|
||||||
from juser.user_api import gen_ssh_key
|
from juser.user_api import gen_ssh_key
|
||||||
|
|
||||||
|
|
||||||
from juser.models import User, UserGroup
|
from juser.models import User, UserGroup
|
||||||
from jasset.models import Asset, AssetGroup
|
from jasset.models import Asset, AssetGroup
|
||||||
from jperm.models import PermRole, PermRule
|
from jperm.models import PermRole, PermRule, PermSudo, PermPush
|
||||||
from jumpserver.models import Setting
|
from jumpserver.models import Setting
|
||||||
|
|
||||||
from jperm.utils import updates_dict, gen_keys, get_rand_pass
|
from jperm.utils import updates_dict, gen_keys, get_rand_pass, get_add_sudo_script
|
||||||
from jperm.ansible_api import Tasks
|
from jperm.ansible_api import Tasks
|
||||||
from jperm.perm_api import get_role_info
|
from jperm.perm_api import get_role_info, get_role_push_host
|
||||||
|
|
||||||
from jumpserver.api import my_render, get_object, CRYPTOR
|
from jumpserver.api import my_render, get_object, CRYPTOR
|
||||||
|
|
||||||
|
@ -256,37 +255,36 @@ def perm_role_add(request):
|
||||||
# 渲染数据
|
# 渲染数据
|
||||||
header_title, path1, path2 = "系统角色", "角色管理", "添加角色"
|
header_title, path1, path2 = "系统角色", "角色管理", "添加角色"
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "GET":
|
||||||
# 获取参数: name, comment
|
default_password = get_rand_pass()
|
||||||
name = request.POST.get("role_name", "")
|
sudos = PermSudo.objects.all()
|
||||||
comment = request.POST.get("role_comment", "")
|
return my_render('jperm/perm_role_add.html', locals(), request)
|
||||||
password = request.POST.get("role_password", "")
|
|
||||||
key_content = request.POST.get("role_key", "")
|
elif request.method == "POST":
|
||||||
try:
|
# 获取参数: name, comment, sudo
|
||||||
if get_object(PermRole, name=name):
|
name = request.POST.get("role_name")
|
||||||
raise ServerError('已经存在该用户 %s' % name)
|
comment = request.POST.get("role_comment")
|
||||||
|
password = request.POST.get("role_password")
|
||||||
|
sudos_name = request.POST.getlist("sudo_name")
|
||||||
|
sudos_obj = [PermSudo.objects.get(name=sudo_name) for sudo_name in sudos_name]
|
||||||
|
encrypt_pass = CRYPTOR.encrypt(password)
|
||||||
|
# 生成随机密码,生成秘钥对
|
||||||
|
|
||||||
|
key_path = gen_keys()
|
||||||
|
role = PermRole(name=name, comment=comment, password=encrypt_pass, key_path=key_path)
|
||||||
|
role.save()
|
||||||
|
role.sudo = sudos_obj
|
||||||
|
role.save()
|
||||||
|
|
||||||
|
msg = u"添加角色: %s" % name
|
||||||
|
# 渲染 刷新数据
|
||||||
|
header_title, path1, path2 = "系统角色", "角色管理", "查看角色"
|
||||||
|
roles_list = PermRole.objects.all()
|
||||||
|
# TODO: 搜索和分页
|
||||||
|
keyword = request.GET.get('search', '')
|
||||||
|
if keyword:
|
||||||
|
roles_list = roles_list.filter(Q(name=keyword))
|
||||||
|
|
||||||
if '' == password and '' == key_content:
|
|
||||||
raise ServerError('账号和密码必填一项')
|
|
||||||
if password:
|
|
||||||
encrypt_pass = CRYPTOR.encrypt(password)
|
|
||||||
else:
|
|
||||||
encrypt_pass = CRYPTOR.encrypt(CRYPTOR.gen_rand_pass(20))
|
|
||||||
# 生成随机密码,生成秘钥对
|
|
||||||
if key_content:
|
|
||||||
try:
|
|
||||||
key_path = gen_keys(key=key_content)
|
|
||||||
except SSHException:
|
|
||||||
raise ServerError('输入的密钥不合法')
|
|
||||||
else:
|
|
||||||
key_path = gen_keys()
|
|
||||||
logger.debug('generate role key: %s' % key_path)
|
|
||||||
role = PermRole(name=name, comment=comment, password=encrypt_pass, key_path=key_path)
|
|
||||||
role.save()
|
|
||||||
msg = u"添加角色: %s" % name
|
|
||||||
return HttpResponseRedirect('/jperm/role/')
|
|
||||||
except ServerError, e:
|
|
||||||
error = e
|
|
||||||
|
|
||||||
return my_render('jperm/perm_role_add.html', locals(), request)
|
return my_render('jperm/perm_role_add.html', locals(), request)
|
||||||
|
|
||||||
|
@ -337,6 +335,7 @@ def perm_role_detail(request):
|
||||||
asset_groups = role_info.get("asset_groups")
|
asset_groups = role_info.get("asset_groups")
|
||||||
users = role_info.get("users")
|
users = role_info.get("users")
|
||||||
user_groups = role_info.get("user_groups")
|
user_groups = role_info.get("user_groups")
|
||||||
|
push_info = get_role_push_host(PermRole.objects.get(id=role_id))
|
||||||
|
|
||||||
return my_render('jperm/perm_role_detail.html', locals(), request)
|
return my_render('jperm/perm_role_detail.html', locals(), request)
|
||||||
|
|
||||||
|
@ -351,13 +350,20 @@ def perm_role_edit(request):
|
||||||
|
|
||||||
# 渲染数据
|
# 渲染数据
|
||||||
role_id = request.GET.get("id")
|
role_id = request.GET.get("id")
|
||||||
role = get_object(PermRole, id=role_id)
|
role = PermRole.objects.get(id=role_id)
|
||||||
|
role_pass = CRYPTOR.decrypt(role.password)
|
||||||
|
role_sudos = role.sudo.all()
|
||||||
|
if request.method == "GET":
|
||||||
|
return my_render('jperm/perm_role_edit.html', locals(), request)
|
||||||
|
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
# 获取 POST 数据
|
# 获取 POST 数据
|
||||||
role_name = request.POST.get("role_name")
|
role_name = request.POST.get("role_name")
|
||||||
role_password = request.POST.get("role_password")
|
role_password = request.POST.get("role_password")
|
||||||
role_comment = request.POST.get("role_comment")
|
role_comment = request.POST.get("role_comment")
|
||||||
|
role_sudo_names = request.POST.getlist("sudo_name")
|
||||||
|
role_sudos = [PermSudo.objects.get(name=sudo_name) for sudo_name in role_sudo_names]
|
||||||
key_content = request.POST.get("role_key", "")
|
key_content = request.POST.get("role_key", "")
|
||||||
try:
|
try:
|
||||||
if not role:
|
if not role:
|
||||||
|
@ -375,7 +381,9 @@ def perm_role_edit(request):
|
||||||
logger.debug('Recreate role key: %s' % role.key_path)
|
logger.debug('Recreate role key: %s' % role.key_path)
|
||||||
# 写入数据库
|
# 写入数据库
|
||||||
role.name = role_name
|
role.name = role_name
|
||||||
|
role.password = encrypt_role_pass
|
||||||
role.comment = role_comment
|
role.comment = role_comment
|
||||||
|
role.sudo = role_sudos
|
||||||
|
|
||||||
role.save()
|
role.save()
|
||||||
msg = u"更新系统角色: %s" % role.name
|
msg = u"更新系统角色: %s" % role.name
|
||||||
|
@ -386,6 +394,7 @@ def perm_role_edit(request):
|
||||||
return my_render('jperm/perm_role_edit.html', locals(), request)
|
return my_render('jperm/perm_role_edit.html', locals(), request)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@require_role('admin')
|
@require_role('admin')
|
||||||
def perm_role_push(request):
|
def perm_role_push(request):
|
||||||
"""
|
"""
|
||||||
|
@ -445,22 +454,184 @@ def perm_role_push(request):
|
||||||
key_push = request.POST.get("use_publicKey")
|
key_push = request.POST.get("use_publicKey")
|
||||||
task = Tasks(push_resource)
|
task = Tasks(push_resource)
|
||||||
ret = {}
|
ret = {}
|
||||||
ret_failed = []
|
ret_failed = {}
|
||||||
|
|
||||||
# 因为要先建立用户,所以password 是必选项,
|
# 因为要先建立用户,所以password 是必选项,而push key是在 password也完成的情况下的 可选项
|
||||||
# 而push key是在 password也完成的情况下的 可选项
|
# 1. 以password 方式推送角色
|
||||||
ret["password_push"] = task.add_multi_user(**role_pass)
|
if password_push:
|
||||||
if ret["password_push"].get("status") != "success":
|
ret["password_push"] = task.add_multi_user(**role_pass)
|
||||||
ret_failed.append(1)
|
if ret["password_push"].get("status") != "success":
|
||||||
|
ret_failed["step1"] == "failed"
|
||||||
|
|
||||||
|
# 2. 以秘钥 方式推送角色
|
||||||
if key_push:
|
if key_push:
|
||||||
|
ret["password_push"] = task.add_multi_user(**role_pass)
|
||||||
|
if ret["password_push"].get("status") != "success":
|
||||||
|
ret_failed["step2-1"] = "failed"
|
||||||
ret["key_push"] = task.push_multi_key(**role_key)
|
ret["key_push"] = task.push_multi_key(**role_key)
|
||||||
if ret["key_push"].get("status") != "success":
|
if ret["key_push"].get("status") != "success":
|
||||||
ret_failed.append(1)
|
ret_failed["step2-2"] = "failed"
|
||||||
|
|
||||||
print ret
|
# 3. 推送sudo配置文件
|
||||||
|
sudo_chosen_aliase = {}
|
||||||
|
sudo_alias = []
|
||||||
|
for role in roles_obj:
|
||||||
|
role_alias = [sudo.name for sudo in role.sudo.all()]
|
||||||
|
sudo_alias.extend(role_alias)
|
||||||
|
sudo_chosen_aliase[role.name] = ','.join(role_alias)
|
||||||
|
sudo_chosen_obj = [PermSudo.objects.get(name=sudo_name) for sudo_name in set(sudo_alias)]
|
||||||
|
|
||||||
|
add_sudo_script = get_add_sudo_script(sudo_chosen_aliase, sudo_chosen_obj)
|
||||||
|
ret_sudo = task.push_sudo_file(add_sudo_script)
|
||||||
|
|
||||||
|
if ret_sudo["step1"] != "ok" or ret_sudo["step2"] != "ok":
|
||||||
|
ret_failed["step3"] = "failed"
|
||||||
|
os.remove(add_sudo_script)
|
||||||
|
|
||||||
|
|
||||||
|
# 结果汇总统计
|
||||||
if ret_failed:
|
if ret_failed:
|
||||||
return HttpResponse(u"推送失败")
|
# 推送失败
|
||||||
|
error = u"推送失败, 原因: %s 失败" % ','.join(ret_failed.keys())
|
||||||
else:
|
else:
|
||||||
return HttpResponse(u"推送系统角色: %s" % ','.join(role_names))
|
# 推送成功 回写push表
|
||||||
|
msg = u"推送系统角色: %s" % ','.join(role_names)
|
||||||
|
push = PermPush(is_public_key=bool(key_push), is_password=bool(password_push))
|
||||||
|
push.save()
|
||||||
|
push.asset_group = asset_groups_obj
|
||||||
|
push.asset = calc_assets
|
||||||
|
push.role = roles_obj
|
||||||
|
push.save()
|
||||||
|
|
||||||
|
# 渲染 刷新数据
|
||||||
|
header_title, path1, path2 = "系统角色", "角色管理", "查看角色"
|
||||||
|
roles_list = PermRole.objects.all()
|
||||||
|
# TODO: 搜索和分页
|
||||||
|
keyword = request.GET.get('search', '')
|
||||||
|
if keyword:
|
||||||
|
roles_list = roles_list.filter(Q(name=keyword))
|
||||||
|
|
||||||
|
roles_list, p, roles, page_range, current_page, show_first, show_end = pages(roles_list, request)
|
||||||
|
return my_render('jperm/perm_role_list.html', locals(), request)
|
||||||
|
|
||||||
|
|
||||||
|
@require_role('admin')
|
||||||
|
def perm_sudo_list(request):
|
||||||
|
"""
|
||||||
|
list sudo commands alias
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# 渲染数据
|
||||||
|
header_title, path1, path2 = "Sudo命令", "别名管理", "查看别名"
|
||||||
|
|
||||||
|
# 获取所有sudo 命令别名
|
||||||
|
sudos_list = PermSudo.objects.all()
|
||||||
|
|
||||||
|
# TODO: 搜索和分页
|
||||||
|
keyword = request.GET.get('search', '')
|
||||||
|
if keyword:
|
||||||
|
sudos_list = sudos_list.filter(Q(name=keyword))
|
||||||
|
|
||||||
|
sudos_list, p, sudos, page_range, current_page, show_first, show_end = pages(sudos_list, request)
|
||||||
|
|
||||||
|
return my_render('jperm/perm_sudo_list.html', locals(), request)
|
||||||
|
|
||||||
|
|
||||||
|
@require_role('admin')
|
||||||
|
def perm_sudo_add(request):
|
||||||
|
"""
|
||||||
|
list sudo commands alias
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# 渲染数据
|
||||||
|
header_title, path1, path2 = "Sudo命令", "别名管理", "添加别名"
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
return my_render('jperm/perm_sudo_add.html', locals(), request)
|
||||||
|
|
||||||
|
elif request.method == "POST":
|
||||||
|
# 获取参数: name, comment
|
||||||
|
name = request.POST.get("sudo_name")
|
||||||
|
comment = request.POST.get("sudo_comment")
|
||||||
|
commands = request.POST.get("sudo_commands")
|
||||||
|
|
||||||
|
sudo = PermSudo(name=name.strip(), comment=comment, commands=commands.strip())
|
||||||
|
sudo.save()
|
||||||
|
|
||||||
|
msg = u"添加Sudo命令别名: %s" % name
|
||||||
|
# 渲染数据
|
||||||
|
header_title, path1, path2 = "Sudo命令", "别名管理", "查看别名"
|
||||||
|
# 获取所有sudo 命令别名
|
||||||
|
sudos_list = PermSudo.objects.all()
|
||||||
|
|
||||||
|
# TODO: 搜索和分页
|
||||||
|
keyword = request.GET.get('search', '')
|
||||||
|
if keyword:
|
||||||
|
roles_list = sudos_list.filter(Q(name=keyword))
|
||||||
|
|
||||||
|
sudos_list, p, sudos, page_range, current_page, show_first, show_end = pages(sudos_list, request)
|
||||||
|
|
||||||
|
return my_render('jperm/perm_sudo_list.html', locals(), request)
|
||||||
|
else:
|
||||||
|
return HttpResponse(u"不支持该操作")
|
||||||
|
|
||||||
|
|
||||||
|
@require_role('admin')
|
||||||
|
def perm_sudo_edit(request):
|
||||||
|
"""
|
||||||
|
list sudo commands alias
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# 渲染数据
|
||||||
|
header_title, path1, path2 = "Sudo命令", "别名管理", "编辑别名"
|
||||||
|
|
||||||
|
sudo_id = request.GET.get("id")
|
||||||
|
sudo = PermSudo.objects.get(id=sudo_id)
|
||||||
|
if request.method == "GET":
|
||||||
|
return my_render('jperm/perm_sudo_edit.html', locals(), request)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
name = request.POST.get("sudo_name")
|
||||||
|
commands = request.POST.get("sudo_commands")
|
||||||
|
comment = request.POST.get("sudo_comment")
|
||||||
|
sudo.name = name.strip()
|
||||||
|
sudo.commands = commands.strip()
|
||||||
|
sudo.comment = comment
|
||||||
|
sudo.save()
|
||||||
|
|
||||||
|
msg = u"更新命令别名: %s" % name
|
||||||
|
# 渲染数据
|
||||||
|
header_title, path1, path2 = "Sudo命令", "别名管理", "查看别名"
|
||||||
|
# 获取所有sudo 命令别名
|
||||||
|
sudos_list = PermSudo.objects.all()
|
||||||
|
# TODO: 搜索和分页
|
||||||
|
keyword = request.GET.get('search', '')
|
||||||
|
if keyword:
|
||||||
|
sudos_list = sudos_list.filter(Q(name=keyword))
|
||||||
|
sudos_list, p, sudos, page_range, current_page, show_first, show_end = pages(sudos_list, request)
|
||||||
|
return my_render('jperm/perm_sudo_list.html', locals(), request)
|
||||||
|
|
||||||
|
|
||||||
|
@require_role('admin')
|
||||||
|
def perm_sudo_delete(request):
|
||||||
|
"""
|
||||||
|
list sudo commands alias
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if request.method == "POST":
|
||||||
|
# 获取参数删除的role对象
|
||||||
|
sudo_id = request.POST.get("id")
|
||||||
|
sudo = PermSudo.objects.get(id=sudo_id)
|
||||||
|
# 数据库里删除记录
|
||||||
|
sudo.delete()
|
||||||
|
return HttpResponse(u"删除角色: %s" % sudo.name)
|
||||||
|
else:
|
||||||
|
return HttpResponse(u"不支持该操作")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -250,3 +250,12 @@ def check_role(asset_id, user):
|
||||||
"""
|
"""
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(name='role_contain_which_sudos')
|
||||||
|
def role_contain_which_sudos(role):
|
||||||
|
"""
|
||||||
|
get role sudo commands
|
||||||
|
"""
|
||||||
|
sudo_names = [sudo.name for sudo in role.sudo.all()]
|
||||||
|
return ','.join(sudo_names)
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo" class="col-sm-2 control-label">角色Sudo命令<span class="red-fonts">*</span></label>
|
||||||
|
<div class="col-sm-8" id="sudo_name">
|
||||||
|
<select name="sudo_name" data-placeholder="请选择Sudo别名" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||||
|
{% for sudo in sudos %}
|
||||||
|
<option >{{ sudo.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include 'nav_cat_bar.html' %}
|
{% include 'nav_cat_bar.html' %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
|
@ -51,8 +50,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
|
@ -97,8 +96,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
|
@ -143,8 +142,60 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div class="ibox-title">
|
||||||
|
<span class="label label-primary"><b>推送主机</b></span>
|
||||||
|
<div class="ibox-tools">
|
||||||
|
<a class="collapse-link">
|
||||||
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-user">
|
||||||
|
<li><a href="#"></a>
|
||||||
|
</li>
|
||||||
|
<li><a href="#"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<a class="close-link">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ibox-content">
|
||||||
|
<div>
|
||||||
|
<div class="text-left">
|
||||||
|
<table class="table table-striped" id="ugedit" >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">主机</th>
|
||||||
|
<th class="text-center">主机组</th>
|
||||||
|
<th class="text-center">使用密码</th>
|
||||||
|
<th class="text-center">使用秘钥</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for host in push_info %}
|
||||||
|
<tr class="gradeX">
|
||||||
|
<td class="text-center"> {{ host.ip }} </td>
|
||||||
|
<td class="text-center"> {{ host.group }} </td>
|
||||||
|
<td class="text-center"> {{ host.password }} </td>
|
||||||
|
<td class="text-center"> {{ host.pubkey }} </td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo" class="col-sm-2 control-label">角色Sudo命令<span class="red-fonts">*</span></label>
|
||||||
|
<div class="col-sm-8" id="sudo_name">
|
||||||
|
<select name="sudo_name" data-placeholder="请选择Sudo别名" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||||
|
{% for sudo in role_sudos %}
|
||||||
|
<option selected >{{ sudo.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
<th class="text-center">名称 </th>
|
<th class="text-center">名称 </th>
|
||||||
<th class="text-center">备注</th>
|
<th class="text-center">备注</th>
|
||||||
<th class="text-center">创建时间</th>
|
<th class="text-center">创建时间</th>
|
||||||
|
<th class="text-center">sudo别名</th>
|
||||||
<th class="text-center">操作</th>
|
<th class="text-center">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
<td class="text-center"> {{ role.name }} </td>
|
<td class="text-center"> {{ role.name }} </td>
|
||||||
<td class="text-center"> {{ role.comment }} </td>
|
<td class="text-center"> {{ role.comment }} </td>
|
||||||
<td class="text-center"> {{ role.date_added | date:"Y-m-d H:i:s"}} </td>
|
<td class="text-center"> {{ role.date_added | date:"Y-m-d H:i:s"}} </td>
|
||||||
|
<td class="text-center"> {{ role | role_contain_which_sudos }} </td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="/jperm/role/perm_role_detail/?id={{ role.id }}" class="btn btn-xs btn-primary">详情</a>
|
<a href="/jperm/role/perm_role_detail/?id={{ role.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||||
<a href="/jperm/role/perm_role_edit/?id={{ role.id }}" class="btn btn-xs btn-info">编辑</a>
|
<a href="/jperm/role/perm_role_edit/?id={{ role.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||||
|
@ -98,6 +100,7 @@ function remove_role(role_id){
|
||||||
del_row.remove()
|
del_row.remove()
|
||||||
},
|
},
|
||||||
error: function (msg) {
|
error: function (msg) {
|
||||||
|
console.log(msg)
|
||||||
alert("失败: " + msg)
|
alert("失败: " + msg)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -77,6 +77,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="j_group" class="col-sm-2 control-label">使用密码</label>
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<div class="radio i-checks">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" value="1" id="use_password" name="use_password">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="rulename" class="col-sm-2 control-label">授权名称<span class="red-fonts">*</span></label>
|
<label for="rulename" class="col-sm-2 control-label">授权名称<span class="red-fonts">*</span></label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input id="rulename" name="rulename" placeholder="Rule Name" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
<input id="rulename" name="rulename" placeholder="Rule Name" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
|
@ -44,8 +44,9 @@
|
||||||
<label for="user" class="col-sm-2 control-label">用户</label>
|
<label for="user" class="col-sm-2 control-label">用户</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<select name="user" id="user" data-placeholder="用户名" class="chosen-select form-control m-b" multiple tabindex="2">
|
<select name="user" id="user" data-placeholder="用户名" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||||
|
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
<option value="{{ user.name }}">{{ user.name }}</option>
|
<option>{{ user.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<span class="help-block m-b-none">用户和用户组必选一个</span>
|
<span class="help-block m-b-none">用户和用户组必选一个</span>
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
<label for="usergroup" class="col-sm-2 control-label">用户组</label>
|
<label for="usergroup" class="col-sm-2 control-label">用户组</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<select name="usergroup" id="usergroup" data-placeholder="请选择用户组" class="chosen-select form-control m-b" multiple tabindex="2">
|
<select name="usergroup" id="usergroup" data-placeholder="请选择用户组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||||
|
|
||||||
{% for user_group in user_groups %}
|
{% for user_group in user_groups %}
|
||||||
<option value="{{ user_group.name }}">{{ user_group.name }}</option>
|
<option value="{{ user_group.name }}">{{ user_group.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -86,7 +88,7 @@
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8" id="role_name">
|
||||||
<select name="role" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
<select name="role" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||||
{% for role in roles %}
|
{% for role in roles %}
|
||||||
<option value="{{ role.name }}">{{ role.name }}</option>
|
<option value="{{ role.name }}">{{ role.name }}</option>
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block self_head_css_js %}
|
||||||
|
<link href="/static/css/plugins/datapicker/datepicker3.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/plugins/chosen/chosen.css" rel="stylesheet">
|
||||||
|
<script src="/static/js/plugins/chosen/chosen.jquery.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
{% load mytags %}
|
||||||
|
{% block content %}
|
||||||
|
{% include 'nav_cat_bar.html' %}
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div class="ibox-title">
|
||||||
|
<h5>填写基本信息</h5>
|
||||||
|
<div class="ibox-tools">
|
||||||
|
<a class="collapse-link">
|
||||||
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
|
<a class="close-link">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ibox-content">
|
||||||
|
<form method="post" id="sudoForm" class="form-horizontal" action="">
|
||||||
|
{% if error %}
|
||||||
|
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if msg %}
|
||||||
|
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo_name" class="col-sm-2 control-label">命令别名<span class="red-fonts">*</span></label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input id="sudo_name" name="sudo_name" placeholder="Sudo Command Alias" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo_commands_label" class="col-sm-2 control-label">系统命令<span class="red-fonts">*</span></label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<textarea id="sudo_commands" name="sudo_commands" class="form-control" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo_comment" class="col-sm-2 control-label">备注</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input id="sudo_comment" name="sudo_comment" placeholder="Sudo Comment" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
<button class="btn btn-white" type="reset">取消</button>
|
||||||
|
<button id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block self_footer_js %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("input.role").click(function(){
|
||||||
|
if($("input.role[value=GA]").is( ":checked" )){
|
||||||
|
$("#admin_groups").css("display", 'none');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$("#admin_groups").css("display", 'block');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#use_password').click(function(){
|
||||||
|
if ($(this).is(':checked')){
|
||||||
|
$('#admin_account_password').css('display', 'block')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$('#admin_account_password').css('display', 'none')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#use_publicKey').click(function(){
|
||||||
|
if ($(this).is(':checked')){
|
||||||
|
|
||||||
|
$('#admin_account_publicKey').css('display', 'block')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#admin_account_publicKey').css('display', 'none')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
'.chosen-select' : {},
|
||||||
|
'.chosen-select-deselect' : {allow_single_deselect:true},
|
||||||
|
'.chosen-select-no-single' : {disable_search_threshold:10},
|
||||||
|
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
|
||||||
|
'.chosen-select-width' : {width:"95%"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var selector in config) {
|
||||||
|
$(selector).chosen(config[selector]);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||||
|
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block self_head_css_js %}
|
||||||
|
<link href="/static/css/plugins/datapicker/datepicker3.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/plugins/chosen/chosen.css" rel="stylesheet">
|
||||||
|
<script src="/static/js/plugins/chosen/chosen.jquery.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
{% load mytags %}
|
||||||
|
{% block content %}
|
||||||
|
{% include 'nav_cat_bar.html' %}
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div class="ibox-title">
|
||||||
|
<h5>填写基本信息</h5>
|
||||||
|
<div class="ibox-tools">
|
||||||
|
<a class="collapse-link">
|
||||||
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
|
<a class="close-link">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ibox-content">
|
||||||
|
<form method="post" id="sudoForm" class="form-horizontal" action="">
|
||||||
|
{% if error %}
|
||||||
|
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if msg %}
|
||||||
|
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo_name" class="col-sm-2 control-label">命令别名<span class="red-fonts">*</span></label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input id="sudo_name" name="sudo_name" placeholder="Sudo Command Alias" type="text" class="form-control" value={{ sudo.name }}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo_commands_label" class="col-sm-2 control-label">系统命令<span class="red-fonts">*</span></label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<textarea id="sudo_commands" name="sudo_commands" class="form-control" rows="3">{{ sudo.commands }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sudo_comment" class="col-sm-2 control-label">备注</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input id="sudo_comment" name="sudo_comment" placeholder="Sudo Comment" type="text" class="form-control" value={{ sudo.commnet }}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
<button class="btn btn-white" type="reset">取消</button>
|
||||||
|
<button id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block self_footer_js %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("input.role").click(function(){
|
||||||
|
if($("input.role[value=GA]").is( ":checked" )){
|
||||||
|
$("#admin_groups").css("display", 'none');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$("#admin_groups").css("display", 'block');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#use_password').click(function(){
|
||||||
|
if ($(this).is(':checked')){
|
||||||
|
$('#admin_account_password').css('display', 'block')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$('#admin_account_password').css('display', 'none')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#use_publicKey').click(function(){
|
||||||
|
if ($(this).is(':checked')){
|
||||||
|
|
||||||
|
$('#admin_account_publicKey').css('display', 'block')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#admin_account_publicKey').css('display', 'none')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
'.chosen-select' : {},
|
||||||
|
'.chosen-select-deselect' : {allow_single_deselect:true},
|
||||||
|
'.chosen-select-no-single' : {disable_search_threshold:10},
|
||||||
|
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
|
||||||
|
'.chosen-select-width' : {width:"95%"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var selector in config) {
|
||||||
|
$(selector).chosen(config[selector]);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||||
|
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load mytags %}
|
||||||
|
{% block content %}
|
||||||
|
{% include 'nav_cat_bar.html' %}
|
||||||
|
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div>
|
||||||
|
{% if error %}
|
||||||
|
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if msg %}
|
||||||
|
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="ibox-title">
|
||||||
|
<h5> 所有Sudo命令别名</h5>
|
||||||
|
<div class="ibox-tools">
|
||||||
|
<a class="collapse-link">
|
||||||
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
|
<a class="close-link">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ibox-content">
|
||||||
|
<div class="">
|
||||||
|
<a href="/jperm/sudo/perm_sudo_add/" class="btn btn-sm btn-primary "> 添加别名 </a>
|
||||||
|
<a id="del_btn" class="btn btn-sm btn-danger "> 删除所选 </a>
|
||||||
|
<form id="search_form" method="get" action="" class="pull-right mail-search">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control input-sm" id="search_input" name="search" placeholder="Search">
|
||||||
|
<div class="input-group-btn">
|
||||||
|
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||||
|
- 搜索 -
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-striped table-bordered table-hover " id="editable" >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">命令别名 </th>
|
||||||
|
<th class="text-center">系统命令</th>
|
||||||
|
<th class="text-center">创建时间</th>
|
||||||
|
<th class="text-center">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="edittbody">
|
||||||
|
{% for sudo in sudos %}
|
||||||
|
<tr class="gradeX" id={{ sudo.id }}>
|
||||||
|
<td class="text-center"> {{ sudo.name }} </td>
|
||||||
|
<td class="text-center"> {{ sudo.commands }} </td>
|
||||||
|
<td class="text-center"> {{ sudo.date_added | date:"Y-m-d H:i:s"}} </td>
|
||||||
|
<td class="text-center">
|
||||||
|
{# <a href="/jperm/sudo/perm_sudo_detail/?id={{ sudo.id }}" class="btn btn-xs btn-primary">详情</a>#}
|
||||||
|
<a href="/jperm/sudo/perm_sudo_edit/?id={{ sudo.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||||
|
<button onclick="remove_sudo({{ sudo.id }})" class="btn btn-xs btn-danger">删除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="dataTables_info" id="editable_info" role="status" aria-live="polite">
|
||||||
|
Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'paginator.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function remove_sudo(sudo_id){
|
||||||
|
if (confirm("确认删除")) {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "/jperm/sudo/perm_sudo_delete/",
|
||||||
|
data: "id=" + sudo_id,
|
||||||
|
success: function(msg){
|
||||||
|
alert( "成功: " + msg );
|
||||||
|
var del_row = $('tbody#edittbody>tr#' + sudo_id);
|
||||||
|
del_row.remove()
|
||||||
|
},
|
||||||
|
error: function (msg) {
|
||||||
|
alert("失败: " + msg)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
sudo_file=/etc/sudoers
|
||||||
|
|
||||||
|
|
||||||
|
# Add Command Aliases
|
||||||
|
add_cmd_alias() {
|
||||||
|
{% for sudo in sudo_chosen_obj %}
|
||||||
|
if $(grep '^Cmnd_Alias {{ sudo.name }}' ${sudo_file} &> /dev/null); then
|
||||||
|
sed -i 's@^Cmnd_Alias.*{{ sudo.name }}.*@Cmnd_Alias {{ sudo.name }} = {{ sudo.commands }}@g' ${sudo_file}
|
||||||
|
else
|
||||||
|
echo "Cmnd_Alias {{ sudo.name }} = {{ sudo.commands }}" >> ${sudo_file}
|
||||||
|
fi
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
add_role_chosen() {
|
||||||
|
{% for role, alias in sudo_chosen_aliase.items %}
|
||||||
|
if $(grep '^{{ role }}' ${sudo_file} &> /dev/null); then
|
||||||
|
sed -i 's@^{{ role }}.*@{{ role }} ALL = {{ alias }}@g' ${sudo_file}
|
||||||
|
else
|
||||||
|
echo "{{ role }} ALL = {{ alias }}" >> ${sudo_file}
|
||||||
|
fi
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
add_cmd_alias
|
||||||
|
add_role_chosen
|
|
@ -28,9 +28,15 @@
|
||||||
<a href="/jperm/rule/">授权规则</a>
|
<a href="/jperm/rule/">授权规则</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="role">
|
<li class="sudo_list sudo_edit sudo_add cmd_list cmd_edit cmd_add sudo_detail">
|
||||||
<a href="/jperm/role/">系统角色</a>
|
<a href="/jperm/role/">系统角色</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="sudo_list sudo_edit sudo_add cmd_list cmd_edit cmd_add sudo_detail">
|
||||||
|
<a href="/jperm/sudo/">Sudo命令</a>
|
||||||
|
</li>
|
||||||
|
<li class="apply_show online"><a href="/jperm/apply_show/online/">权限审批</a></li>
|
||||||
|
<li class="apply_show online"><a href="/jperm/log/">授权记录</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li id="jlog">
|
<li id="jlog">
|
||||||
|
|
Loading…
Reference in New Issue