mirror of https://github.com/jumpserver/jumpserver
[Feture] 使用信号解耦
parent
18fbfb449d
commit
17ddb3bbbd
|
@ -1 +0,0 @@
|
|||
from . import signals
|
|
@ -22,7 +22,7 @@ from django.shortcuts import get_object_or_404
|
|||
|
||||
from common.mixins import IDInFilterMixin
|
||||
from common.utils import get_object_or_none
|
||||
from .hands import IsSuperUser, IsAppUser, IsValidUser, \
|
||||
from .hands import IsSuperUser, IsAppUser, IsValidUser, IsSuperUserOrAppUser, \
|
||||
get_user_granted_assets, push_users
|
||||
from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser
|
||||
from . import serializers
|
||||
|
@ -156,7 +156,7 @@ class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
|
|||
class SystemUserAuthInfoApi(generics.RetrieveAPIView):
|
||||
"""Get system user auth info"""
|
||||
queryset = SystemUser.objects.all()
|
||||
permission_classes = (IsAppUser,)
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
system_user = self.get_object()
|
||||
|
@ -166,7 +166,6 @@ class SystemUserAuthInfoApi(generics.RetrieveAPIView):
|
|||
'username': system_user.username,
|
||||
'password': system_user.password,
|
||||
'private_key': system_user.private_key,
|
||||
'auth_method': system_user.auth_method,
|
||||
}
|
||||
return Response(data)
|
||||
|
||||
|
|
|
@ -8,5 +8,6 @@ class AssetsConfig(AppConfig):
|
|||
|
||||
def ready(self):
|
||||
from .signals import on_app_ready
|
||||
from . import tasks
|
||||
on_app_ready.send(self.__class__)
|
||||
super().ready()
|
||||
|
|
|
@ -2,4 +2,8 @@
|
|||
#
|
||||
|
||||
ADMIN_USER_CONN_CACHE_KEY_PREFIX = "ADMIN_USER_CONN_"
|
||||
SYSTEM_USER_CONN_CACHE_KEY_PREFIX = 'SYSTEM_USER_CONN_'
|
||||
SYSTEM_USER_CONN_CACHE_KEY_PREFIX = "SYSTEM_USER_CONN_"
|
||||
UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY = "UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY"
|
||||
TEST_ADMIN_USER_CONNECTABILITY_PEROID_KEY = "TEST_ADMIN_USER_CONNECTABILITY_KEY"
|
||||
TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY = "TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY"
|
||||
PUSH_SYSTEM_USER_PERIOD_KEY = "PUSH_SYSTEM_USER_PERIOD_KEY"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# coding:utf-8
|
||||
import uuid
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
@ -142,7 +143,7 @@ class ClusterForm(forms.ModelForm):
|
|||
class AdminUserForm(forms.ModelForm):
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(
|
||||
widget=forms.PasswordInput, max_length=100,
|
||||
widget=forms.PasswordInput, max_length=128,
|
||||
strip=True, required=False,
|
||||
help_text=_('If also set private key, use that first'),
|
||||
)
|
||||
|
@ -199,114 +200,46 @@ class SystemUserForm(forms.ModelForm):
|
|||
# Admin user assets define, let user select, save it in form not in view
|
||||
auto_generate_key = forms.BooleanField(initial=True, required=False)
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=100, strip=True)
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=128, strip=True)
|
||||
# Need use upload private key file except paste private key content
|
||||
private_key_file = forms.FileField(required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SystemUserForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
# Because we define custom field, so we need rewrite :method: `save`
|
||||
system_user = super(SystemUserForm, self).save(commit=commit)
|
||||
password = self.cleaned_data['password']
|
||||
system_user = super().save()
|
||||
password = self.cleaned_data.get('password', None)
|
||||
private_key_file = self.cleaned_data.get('private_key_file')
|
||||
auto_generate_key = self.cleaned_data.get('auto_generate_key')
|
||||
|
||||
if system_user.auth_method == 'P':
|
||||
if password:
|
||||
system_user.password = password
|
||||
elif system_user.auth_method == 'K':
|
||||
if self.cleaned_data['auto_generate_key']:
|
||||
private_key, public_key = ssh_key_gen(username=system_user.name)
|
||||
logger.info('Generate private key and public key')
|
||||
else:
|
||||
private_key = private_key_file.read().strip()
|
||||
public_key = ssh_pubkey_gen(private_key=private_key)
|
||||
system_user.private_key = private_key
|
||||
system_user.public_key = public_key
|
||||
system_user.save()
|
||||
return self.instance
|
||||
|
||||
def clean_private_key_file(self):
|
||||
if self.data['auth_method'] == 'K' and \
|
||||
not self.cleaned_data['auto_generate_key']:
|
||||
if not self.cleaned_data['private_key_file']:
|
||||
raise forms.ValidationError(_('Private key required'))
|
||||
else:
|
||||
key_string = self.cleaned_data['private_key_file'].read()
|
||||
self.cleaned_data['private_key_file'].seek(0)
|
||||
if not validate_ssh_private_key(key_string):
|
||||
raise forms.ValidationError(_('Invalid private key'))
|
||||
return self.cleaned_data['private_key_file']
|
||||
|
||||
def clean_password(self):
|
||||
if self.data['auth_method'] == 'P':
|
||||
if not self.cleaned_data.get('password'):
|
||||
raise forms.ValidationError(_('Password required'))
|
||||
return self.cleaned_data['password']
|
||||
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
fields = [
|
||||
'name', 'username', 'protocol', 'auto_generate_key', 'password',
|
||||
'private_key_file', 'auth_method', 'auto_push', 'sudo',
|
||||
'comment', 'shell', 'cluster'
|
||||
]
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||
'cluster': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _(' Select clusters')}),
|
||||
}
|
||||
help_texts = {
|
||||
'name': '* required',
|
||||
'username': '* required',
|
||||
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||
'auto_push': 'Auto push system user to asset',
|
||||
}
|
||||
|
||||
|
||||
class SystemUserUpdateForm(forms.ModelForm):
|
||||
# Admin user assets define, let user select, save it in form not in view
|
||||
auto_generate_key = forms.BooleanField(initial=False, required=False)
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=100, strip=True)
|
||||
# Need use upload private key file except paste private key content
|
||||
private_key_file = forms.FileField(required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SystemUserUpdateForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
# Because we define custom field, so we need rewrite :method: `save`
|
||||
system_user = super(SystemUserUpdateForm, self).save(commit=commit)
|
||||
password = self.cleaned_data['password']
|
||||
private_key_file = self.cleaned_data.get('private_key_file')
|
||||
|
||||
if system_user.auth_method == 'P' and password:
|
||||
system_user.password = password
|
||||
elif system_user.auth_method == 'K' and private_key_file:
|
||||
private_key = private_key_file.read().strip()
|
||||
if auto_generate_key:
|
||||
logger.info('Auto set system user auth')
|
||||
system_user.auto_gen_auth()
|
||||
else:
|
||||
private_key = private_key_file.read().strip().decode('utf-8')
|
||||
public_key = ssh_pubkey_gen(private_key=private_key)
|
||||
system_user.private_key = private_key
|
||||
system_user.public_key = public_key
|
||||
system_user.save()
|
||||
return self.instance
|
||||
system_user.set_auth(password=password, private_key=private_key, public_key=public_key)
|
||||
return system_user
|
||||
|
||||
def clean_private_key_file(self):
|
||||
if self.data['auth_method'] == 'K' and self.cleaned_data['private_key_file']:
|
||||
if self.cleaned_data.get('private_key_file'):
|
||||
key_string = self.cleaned_data['private_key_file'].read()
|
||||
self.cleaned_data['private_key_file'].seek(0)
|
||||
if not validate_ssh_private_key(key_string):
|
||||
raise forms.ValidationError(_('Invalid private key'))
|
||||
return self.cleaned_data['private_key_file']
|
||||
|
||||
def clean_password(self):
|
||||
if not self.cleaned_data.get('password') and \
|
||||
not self.cleaned_data.get('private_key_file') and \
|
||||
not self.cleaned_data.get('auto_generate_key'):
|
||||
raise forms.ValidationError(_('Auth info required, private_key or password'))
|
||||
return self.cleaned_data['password']
|
||||
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
fields = [
|
||||
'name', 'username', 'protocol',
|
||||
'auth_method', 'auto_push', 'sudo',
|
||||
'name', 'username', 'protocol', 'auto_generate_key',
|
||||
'password', 'private_key_file', 'auto_push', 'sudo',
|
||||
'comment', 'shell', 'cluster'
|
||||
]
|
||||
widgets = {
|
||||
|
@ -319,10 +252,64 @@ class SystemUserUpdateForm(forms.ModelForm):
|
|||
help_texts = {
|
||||
'name': '* required',
|
||||
'username': '* required',
|
||||
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||
'cluster': 'If auto push checked, system user will be create at cluster assets',
|
||||
'auto_push': 'Auto push system user to asset',
|
||||
}
|
||||
|
||||
|
||||
class SystemUserUpdateForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
fields = [
|
||||
'name', 'username', 'protocol',
|
||||
'sudo', 'comment', 'shell', 'cluster'
|
||||
]
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||
'cluster': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _(' Select clusters')}),
|
||||
}
|
||||
help_texts = {
|
||||
'name': '* required',
|
||||
'username': '* required',
|
||||
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||
}
|
||||
|
||||
|
||||
class SystemUserAuthForm(forms.Form):
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=128, strip=True)
|
||||
private_key_file = forms.FileField(required=False)
|
||||
|
||||
def clean_private_key_file(self):
|
||||
if self.cleaned_data.get('private_key_file'):
|
||||
key_string = self.cleaned_data['private_key_file'].read()
|
||||
self.cleaned_data['private_key_file'].seek(0)
|
||||
if not validate_ssh_private_key(key_string):
|
||||
raise forms.ValidationError(_('Invalid private key'))
|
||||
return self.cleaned_data['private_key_file']
|
||||
|
||||
def clean_password(self):
|
||||
if not self.cleaned_data.get('password') and \
|
||||
not self.cleaned_data.get('private_key_file'):
|
||||
msg = _('Auth info required, private_key or password')
|
||||
raise forms.ValidationError(msg)
|
||||
return self.cleaned_data['password']
|
||||
|
||||
def update(self, system_user):
|
||||
password = self.cleaned_data.get('password')
|
||||
private_key_file = self.cleaned_data.get('private_key_file')
|
||||
|
||||
if private_key_file:
|
||||
private_key = private_key_file.read().strip()
|
||||
public_key = ssh_pubkey_gen(private_key=private_key)
|
||||
else:
|
||||
private_key = None
|
||||
public_key = None
|
||||
system_user.set_auth(password=password, private_key=private_key, public_key=public_key)
|
||||
return system_user
|
||||
|
||||
|
||||
class FileForm(forms.Form):
|
||||
file = forms.FileField()
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
|
||||
from users.utils import AdminUserRequiredMixin
|
||||
from users.permissions import IsAppUser, IsSuperUser, IsValidUser
|
||||
from users.permissions import IsAppUser, IsSuperUser, IsValidUser, IsSuperUserOrAppUser
|
||||
from users.models import User, UserGroup
|
||||
from perms.utils import get_user_granted_assets
|
||||
from perms.tasks import push_users
|
|
@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
|
|||
class Cluster(models.Model):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||
admin_user = models.ForeignKey('assets.AdminUser', null=True, on_delete=models.SET_NULL, verbose_name=_("Admin user"))
|
||||
admin_user = models.ForeignKey('assets.AdminUser', null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_("Admin user"))
|
||||
bandwidth = models.CharField(max_length=32, blank=True, verbose_name=_('Bandwidth'))
|
||||
contact = models.CharField(max_length=128, blank=True, verbose_name=_('Contact'))
|
||||
phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone'))
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import logging
|
||||
import uuid
|
||||
|
@ -12,7 +11,7 @@ from django.db import models
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import signer, ssh_key_string_to_obj
|
||||
from common.utils import signer, ssh_key_string_to_obj, ssh_key_gen
|
||||
from .utils import private_key_validator
|
||||
|
||||
|
||||
|
@ -20,53 +19,41 @@ __all__ = ['AdminUser', 'SystemUser',]
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AdminUser(models.Model):
|
||||
"""
|
||||
A privileged user that ansible can use it to push system user and so on
|
||||
"""
|
||||
BECOME_METHOD_CHOICES = (
|
||||
('sudo', 'sudo'),
|
||||
('su', 'su'),
|
||||
)
|
||||
class AssetUser(models.Model):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
|
||||
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator,])
|
||||
become = models.BooleanField(default=True)
|
||||
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
|
||||
become_user = models.CharField(default='root', max_length=64)
|
||||
_become_pass = models.CharField(default='', max_length=128)
|
||||
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
|
||||
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, null=True)
|
||||
created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by'))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def password(self):
|
||||
if self._password:
|
||||
return signer.unsign(self._password)
|
||||
else:
|
||||
return ''
|
||||
return None
|
||||
|
||||
@password.setter
|
||||
def password(self, password_raw):
|
||||
self._password = signer.sign(password_raw)
|
||||
raise AttributeError("Using set_auth do that")
|
||||
# self._password = signer.sign(password_raw)
|
||||
|
||||
@property
|
||||
def private_key(self):
|
||||
if self._private_key:
|
||||
key_str = signer.unsign(self._private_key)
|
||||
return ssh_key_string_to_obj(key_str)
|
||||
return ssh_key_string_to_obj(key_str, password=self.password)
|
||||
else:
|
||||
return None
|
||||
|
||||
@private_key.setter
|
||||
def private_key(self, private_key_raw):
|
||||
self._private_key = signer.sign(private_key_raw)
|
||||
raise AttributeError("Using set_auth do that")
|
||||
# self._private_key = signer.sign(private_key_raw)
|
||||
|
||||
@property
|
||||
def private_key_file(self):
|
||||
|
@ -74,19 +61,62 @@ class AdminUser(models.Model):
|
|||
return None
|
||||
project_dir = settings.PROJECT_DIR
|
||||
tmp_dir = os.path.join(project_dir, 'tmp')
|
||||
key_name = md5(self._private_key.encode()).hexdigest()
|
||||
key_str = signer.unsign(self._private_key)
|
||||
key_name = md5(key_str.encode('utf-8')).hexdigest()
|
||||
key_path = os.path.join(tmp_dir, key_name)
|
||||
if not os.path.exists(key_path):
|
||||
self.private_key.write_private_key_file(key_path)
|
||||
with open(key_path, 'w') as f:
|
||||
f.write(key_str)
|
||||
os.chmod(key_path, 0o400)
|
||||
return key_path
|
||||
|
||||
@property
|
||||
def public_key(self):
|
||||
return signer.unsign(self._public_key)
|
||||
|
||||
@public_key.setter
|
||||
def public_key(self, public_key_raw):
|
||||
self._public_key = signer.sign(public_key_raw)
|
||||
def set_auth(self, password=None, private_key=None, public_key=None):
|
||||
update_fields = []
|
||||
if password:
|
||||
self._password = signer.sign(password)
|
||||
update_fields.append('_password')
|
||||
if private_key:
|
||||
self._private_key = signer.sign(private_key)
|
||||
update_fields.append('_private_key')
|
||||
if public_key:
|
||||
self._public_key = signer.sign(public_key)
|
||||
update_fields.append('_public_key')
|
||||
|
||||
if update_fields:
|
||||
self.save(update_fields=update_fields)
|
||||
|
||||
def auto_gen_auth(self):
|
||||
password = str(uuid.uuid4())
|
||||
private_key, public_key = ssh_key_gen(
|
||||
username=self.name, password=password
|
||||
)
|
||||
self.set_auth(password=password,
|
||||
private_key=private_key,
|
||||
public_key=public_key)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class AdminUser(AssetUser):
|
||||
"""
|
||||
A privileged user that ansible can use it to push system user and so on
|
||||
"""
|
||||
BECOME_METHOD_CHOICES = (
|
||||
('sudo', 'sudo'),
|
||||
('su', 'su'),
|
||||
)
|
||||
become = models.BooleanField(default=True)
|
||||
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
|
||||
become_user = models.CharField(default='root', max_length=64)
|
||||
_become_pass = models.CharField(default='', max_length=128)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def become_pass(self):
|
||||
|
@ -131,7 +161,7 @@ class AdminUser(models.Model):
|
|||
continue
|
||||
|
||||
|
||||
class SystemUser(models.Model):
|
||||
class SystemUser(AssetUser):
|
||||
PROTOCOL_CHOICES = (
|
||||
('ssh', 'ssh'),
|
||||
)
|
||||
|
@ -139,68 +169,15 @@ class SystemUser(models.Model):
|
|||
('P', 'Password'),
|
||||
('K', 'Public key'),
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
cluster = models.ManyToManyField('assets.Cluster', verbose_name=_("Cluster"))
|
||||
_password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
|
||||
protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
|
||||
_private_key = models.TextField(max_length=8192, blank=True, verbose_name=_('SSH private key'))
|
||||
_public_key = models.TextField(max_length=8192, blank=True, verbose_name=_('SSH public key'))
|
||||
auth_method = models.CharField(choices=AUTH_METHOD_CHOICES, default='K', max_length=1, verbose_name=_('Auth method'))
|
||||
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
|
||||
sudo = models.TextField(default='/sbin/ifconfig', verbose_name=_('Sudo'))
|
||||
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
|
||||
comment = models.TextField(max_length=128, blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def password(self):
|
||||
if self._password:
|
||||
return signer.unsign(self._password)
|
||||
return None
|
||||
|
||||
@password.setter
|
||||
def password(self, password_raw):
|
||||
self._password = signer.sign(password_raw)
|
||||
|
||||
@property
|
||||
def private_key(self):
|
||||
if self._private_key:
|
||||
return signer.unsign(self._private_key)
|
||||
return None
|
||||
|
||||
@private_key.setter
|
||||
def private_key(self, private_key_raw):
|
||||
self._private_key = signer.sign(private_key_raw)
|
||||
|
||||
@property
|
||||
def private_key_file(self):
|
||||
if not self.private_key:
|
||||
return None
|
||||
project_dir = settings.PROJECT_DIR
|
||||
tmp_dir = os.path.join(project_dir, 'tmp')
|
||||
key_name = md5(self._private_key.encode()).hexdigest()
|
||||
key_path = os.path.join(tmp_dir, key_name)
|
||||
if not os.path.exists(key_path):
|
||||
self.private_key.write_private_key_file(key_path)
|
||||
return key_path
|
||||
|
||||
@property
|
||||
def public_key(self):
|
||||
if self._public_key:
|
||||
return signer.unsign(self._public_key)
|
||||
else:
|
||||
return None
|
||||
|
||||
@public_key.setter
|
||||
def public_key(self, public_key_raw):
|
||||
self._public_key = signer.sign(public_key_raw)
|
||||
|
||||
def _to_secret_json(self):
|
||||
"""Push system user use it"""
|
||||
return {
|
||||
|
@ -228,7 +205,6 @@ class SystemUser(models.Model):
|
|||
'name': self.name,
|
||||
'username': self.username,
|
||||
'protocol': self.protocol,
|
||||
'auth_method': self.auth_method,
|
||||
'auto_push': self.auto_push,
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
|
|||
class AssetSystemUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
fields = ('id', 'name', 'username', 'protocol', 'auth_method', 'comment')
|
||||
fields = ('id', 'name', 'username', 'protocol', 'comment')
|
||||
|
||||
|
||||
class SystemUserUpdateAssetsSerializer(serializers.ModelSerializer):
|
||||
|
@ -202,7 +202,10 @@ class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
|||
|
||||
@staticmethod
|
||||
def get_admin_user_name(obj):
|
||||
return obj.admin_user.name
|
||||
try:
|
||||
return obj.admin_user.name
|
||||
except AttributeError:
|
||||
return ''
|
||||
|
||||
|
||||
class AssetGroupGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||
|
|
|
@ -1,31 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.dispatch import Signal
|
||||
|
||||
from django.dispatch import Signal, receiver
|
||||
|
||||
from common.utils import get_logger
|
||||
|
||||
logger = get_logger(__file__)
|
||||
on_asset_created = Signal(providing_args=['asset'])
|
||||
on_app_ready = Signal()
|
||||
|
||||
|
||||
@receiver(on_asset_created)
|
||||
def update_asset_info(sender, asset=None, **kwargs):
|
||||
from .tasks import update_assets_hardware_info
|
||||
logger.debug("Receive asset create signal, update asset hardware info")
|
||||
update_assets_hardware_info.delay([asset])
|
||||
|
||||
|
||||
@receiver(on_asset_created)
|
||||
def test_admin_user_connective(sender, asset=None, **kwargs):
|
||||
from .tasks import test_admin_user_connectability_manual
|
||||
logger.debug("Receive asset create signal, test admin user connectability")
|
||||
test_admin_user_connectability_manual.delay(asset)
|
||||
|
||||
|
||||
@receiver(on_app_ready)
|
||||
def test_admin_user_on_app_ready(sender, **kwargs):
|
||||
from .tasks import test_admin_user_connectability_period
|
||||
logger.debug("Receive app ready signal, test admin connectability")
|
||||
test_admin_user_connectability_period.delay()
|
||||
on_system_user_auth_changed = Signal(providing_args=['system_user'])
|
||||
|
|
|
@ -3,15 +3,23 @@ import json
|
|||
|
||||
from celery import shared_task
|
||||
from django.core.cache import cache
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_save
|
||||
|
||||
from common.utils import get_object_or_none, capacity_convert, sum_capacity, encrypt_password, get_logger
|
||||
from common.utils import get_object_or_none, capacity_convert, \
|
||||
sum_capacity, encrypt_password, get_logger
|
||||
from common.celery import app as celery_app
|
||||
from .models import SystemUser, AdminUser, Asset
|
||||
from .const import ADMIN_USER_CONN_CACHE_KEY_PREFIX, SYSTEM_USER_CONN_CACHE_KEY_PREFIX
|
||||
from .const import ADMIN_USER_CONN_CACHE_KEY_PREFIX, SYSTEM_USER_CONN_CACHE_KEY_PREFIX, \
|
||||
UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY, TEST_ADMIN_USER_CONNECTABILITY_PEROID_KEY, \
|
||||
TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY, PUSH_SYSTEM_USER_PERIOD_KEY
|
||||
from .signals import on_app_ready
|
||||
|
||||
|
||||
FORKS = 10
|
||||
TIMEOUT = 60
|
||||
logger = get_logger(__file__)
|
||||
CACHE_MAX_TIME = 60*60*60
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -75,7 +83,7 @@ def update_assets_hardware_info(assets):
|
|||
asset.save()
|
||||
|
||||
for hostname, task in summary['dark'].items():
|
||||
logger.warn("Update {} hardware info error: {}".format(
|
||||
logger.error("Update {} hardware info error: {}".format(
|
||||
hostname, task[name],
|
||||
))
|
||||
|
||||
|
@ -88,8 +96,15 @@ def update_assets_hardware_period():
|
|||
Update asset hardware period task
|
||||
:return:
|
||||
"""
|
||||
assets = Asset.objects.filter(type__in=['Server', 'VM'])
|
||||
update_assets_hardware_info(assets)
|
||||
if cache.get(UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY) == 1:
|
||||
logger.debug("Update asset hardware period task is running, passed")
|
||||
return {}
|
||||
try:
|
||||
cache.set(UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY, 1, CACHE_MAX_TIME)
|
||||
assets = Asset.objects.filter(type__in=['Server', 'VM'])
|
||||
return update_assets_hardware_info(assets)
|
||||
finally:
|
||||
cache.set(UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY, 0)
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -100,6 +115,7 @@ def test_admin_user_connectability(admin_user):
|
|||
:return:
|
||||
"""
|
||||
from ops.utils import run_adhoc
|
||||
|
||||
assets = admin_user.get_related_assets()
|
||||
hosts = [asset.hostname for asset in assets]
|
||||
tasks = [
|
||||
|
@ -117,16 +133,26 @@ def test_admin_user_connectability(admin_user):
|
|||
@shared_task
|
||||
def test_admin_user_connectability_period():
|
||||
# assets = Asset.objects.filter(type__in=['Server', 'VM'])
|
||||
admin_users = AdminUser.objects.all()
|
||||
for admin_user in admin_users:
|
||||
summary = test_admin_user_connectability(admin_user)
|
||||
if cache.get(TEST_ADMIN_USER_CONNECTABILITY_PEROID_KEY) == 1:
|
||||
logger.debug("Test admin user connectablity period task is running, passed")
|
||||
return
|
||||
|
||||
cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + admin_user.name, summary, 60*60*60)
|
||||
for i in summary['contacted']:
|
||||
cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + i, 1, 60*60*60)
|
||||
logger.debug("Test admin user connectablity period task start")
|
||||
try:
|
||||
cache.set(TEST_ADMIN_USER_CONNECTABILITY_PEROID_KEY, 1, CACHE_MAX_TIME)
|
||||
admin_users = AdminUser.objects.all()
|
||||
for admin_user in admin_users:
|
||||
summary = test_admin_user_connectability(admin_user)
|
||||
|
||||
for i in summary['dark']:
|
||||
cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + i, 0, 60*60*60)
|
||||
cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + admin_user.name, summary, 60*60*60)
|
||||
for i in summary['contacted']:
|
||||
cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + i, 1, 60*60*60)
|
||||
|
||||
for i, error in summary['dark'].items():
|
||||
cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + i, 0, 60*60*60)
|
||||
logger.error(error)
|
||||
finally:
|
||||
cache.set(TEST_ADMIN_USER_CONNECTABILITY_PEROID_KEY, 0)
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -175,9 +201,18 @@ def test_system_user_connectability(system_user):
|
|||
|
||||
@shared_task
|
||||
def test_system_user_connectability_period():
|
||||
for system_user in SystemUser.objects.all():
|
||||
summary = test_system_user_connectability(system_user)
|
||||
cache.set(SYSTEM_USER_CONN_CACHE_KEY_PREFIX + system_user.name, summary, 60*60*60)
|
||||
if cache.get(TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY) == 1:
|
||||
logger.debug("Test admin user connectablity period task is running, passed")
|
||||
return
|
||||
|
||||
logger.debug("Test system user connectablity period task start")
|
||||
try:
|
||||
cache.set(TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY, 1, CACHE_MAX_TIME)
|
||||
for system_user in SystemUser.objects.all():
|
||||
summary = test_system_user_connectability(system_user)
|
||||
cache.set(SYSTEM_USER_CONN_CACHE_KEY_PREFIX + system_user.name, summary, 60*60*60)
|
||||
finally:
|
||||
cache.set(TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY, 0)
|
||||
|
||||
|
||||
def get_push_system_user_tasks(system_user):
|
||||
|
@ -217,18 +252,18 @@ def get_push_system_user_tasks(system_user):
|
|||
return tasks
|
||||
|
||||
|
||||
PUSH_SYSTEM_USER_PERIOD_TASK_NAME = 'PUSH SYSTEM USER [{}] PERIOD...'
|
||||
PUSH_SYSTEM_USER_TASK_NAME = 'PUSH SYSTEM USER [{}] ASSETS'
|
||||
|
||||
|
||||
def push_system_user(system_user, assets, name):
|
||||
def push_system_user(system_user, assets, task_name=None):
|
||||
from ops.utils import get_task_by_name, run_adhoc_object, \
|
||||
create_task, create_adhoc
|
||||
|
||||
if system_user.auto_push and assets:
|
||||
task = get_task_by_name(name)
|
||||
if task_name is None:
|
||||
task_name = 'PUSH-SYSTEM-USER-{}'.format(system_user.name)
|
||||
|
||||
task = get_task_by_name(task_name)
|
||||
if not task:
|
||||
task = create_task(name, created_by="System")
|
||||
logger.debug("Doesn't get task {}, create it".format(task_name))
|
||||
task = create_task(task_name, created_by="System")
|
||||
task.save()
|
||||
tasks = get_push_system_user_tasks(system_user)
|
||||
hosts = [asset.hostname for asset in assets]
|
||||
|
@ -236,36 +271,124 @@ def push_system_user(system_user, assets, name):
|
|||
|
||||
adhoc = task.get_latest_adhoc()
|
||||
if not adhoc or adhoc.task != tasks or adhoc.hosts != hosts:
|
||||
logger.debug("Task {} not exit or changed, create new version".format(task_name))
|
||||
adhoc = create_adhoc(task=task, tasks=tasks, pattern='all',
|
||||
options=options, hosts=hosts, run_as_admin=True)
|
||||
return run_adhoc_object(adhoc)
|
||||
logger.debug("Task {} start execute".format(task_name))
|
||||
result = run_adhoc_object(adhoc)
|
||||
return result.results_summary
|
||||
else:
|
||||
msg = "Task {} does'nt execute, because not auto_push " \
|
||||
"is not True, or not assets".format(task_name)
|
||||
logger.debug(msg)
|
||||
return {}
|
||||
|
||||
|
||||
@shared_task
|
||||
def push_system_user_to_cluster_assets(system_user, task_name=None):
|
||||
logger.debug("{} task start".format(task_name))
|
||||
assets = system_user.get_clusters_assets()
|
||||
summary = push_system_user(system_user, assets, task_name)
|
||||
|
||||
for h in summary.get("contacted", []):
|
||||
logger.debug("Push system user {} to {} success".format(system_user.name, h))
|
||||
for h, msg in summary.get('dark', {}).items():
|
||||
logger.error('Push system user {} to {} failed: {}'.format(
|
||||
system_user.name, h, msg
|
||||
))
|
||||
return summary
|
||||
|
||||
|
||||
@shared_task
|
||||
def push_system_user_period():
|
||||
logger.debug("Push system user period")
|
||||
for s in SystemUser.objects.filter(auto_push=True):
|
||||
assets = s.get_clusters_assets()
|
||||
|
||||
name = PUSH_SYSTEM_USER_PERIOD_TASK_NAME.format(s.name)
|
||||
push_system_user(s, assets, name)
|
||||
|
||||
|
||||
def push_system_user_to_assets_if_need(system_user, assets=None, asset_groups=None):
|
||||
assets_to_push = []
|
||||
system_user_assets = system_user.assets.all()
|
||||
if assets:
|
||||
assets_to_push.extend(assets)
|
||||
if asset_groups:
|
||||
for group in asset_groups:
|
||||
assets_to_push.extend(group.assets.all())
|
||||
|
||||
assets_need_push = set(assets_to_push) - set(system_user_assets)
|
||||
if not assets_need_push:
|
||||
if cache.get(PUSH_SYSTEM_USER_PERIOD_KEY) == 1:
|
||||
logger.debug("push system user period task is running, passed")
|
||||
return
|
||||
logger.debug("Push system user {} to {} assets".format(
|
||||
system_user.name, ', '.join([asset.hostname for asset in assets_need_push])
|
||||
))
|
||||
result = push_system_user(system_user, assets_need_push, PUSH_SYSTEM_USER_TASK_NAME)
|
||||
system_user.assets.add(*tuple(assets_need_push))
|
||||
return result
|
||||
|
||||
logger.debug("Push system user period task start")
|
||||
try:
|
||||
cache.set(PUSH_SYSTEM_USER_PERIOD_KEY, 1, timeout=CACHE_MAX_TIME)
|
||||
for system_user in SystemUser.objects.filter(auto_push=True):
|
||||
task_name = 'PUSH-SYSTEM-USER-PERIOD'
|
||||
push_system_user_to_cluster_assets(system_user, task_name)
|
||||
finally:
|
||||
cache.set(PUSH_SYSTEM_USER_PERIOD_KEY, 0)
|
||||
|
||||
|
||||
# def push_system_user_to_assets_if_need(system_user, assets=None, asset_groups=None):
|
||||
# assets_to_push = []
|
||||
# system_user_assets = system_user.assets.all()
|
||||
# if assets:
|
||||
# assets_to_push.extend(assets)
|
||||
# if asset_groups:
|
||||
# for group in asset_groups:
|
||||
# assets_to_push.extend(group.assets.all())
|
||||
#
|
||||
# assets_need_push = set(assets_to_push) - set(system_user_assets)
|
||||
# if not assets_need_push:
|
||||
# return
|
||||
# logger.debug("Push system user {} to {} assets".format(
|
||||
# system_user.name, ', '.join([asset.hostname for asset in assets_need_push])
|
||||
# ))
|
||||
# result = push_system_user(system_user, assets_need_push, PUSH_SYSTEM_USER_TASK_NAME)
|
||||
# system_user.assets.add(*tuple(assets_need_push))
|
||||
# return result
|
||||
|
||||
|
||||
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
|
||||
def update_asset_info(sender, instance=None, created=False, **kwargs):
|
||||
if instance and created:
|
||||
logger.debug("Receive asset create signal, update asset hardware info")
|
||||
update_assets_hardware_info.delay([instance])
|
||||
|
||||
|
||||
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
|
||||
def test_admin_user_connective(sender, instance=None, created=False, **kwargs):
|
||||
if instance and created:
|
||||
logger.debug("Receive asset create signal, test admin user connectability")
|
||||
test_admin_user_connectability_manual.delay(instance)
|
||||
|
||||
|
||||
@receiver(post_save, sender=SystemUser)
|
||||
def push_system_user_on_change(sender, instance=None, created=False, **kwargs):
|
||||
if instance and instance.auto_push:
|
||||
logger.debug("System user `{}` auth changed, push it".format(instance.name))
|
||||
task_name = "PUSH-SYSTEM-USER-ON-CREATED-{}".format(instance.name)
|
||||
push_system_user_to_cluster_assets.delay(instance, task_name)
|
||||
|
||||
|
||||
@receiver(post_save, sender=SystemUser)
|
||||
def push_system_user_on_change(sender, instance=None, update_fields=None, **kwargs):
|
||||
fields_check = {'_password', '_private_key', '_public_key'}
|
||||
auth_changed = update_fields & fields_check if update_fields else None
|
||||
if instance and instance.auto_push and auth_changed:
|
||||
logger.debug("System user `{}` auth changed, push it".format(instance.name))
|
||||
task_name = "PUSH-SYSTEM-USER-ON-CREATED-{}".format(instance.name)
|
||||
push_system_user_to_cluster_assets.delay(instance, task_name)
|
||||
|
||||
|
||||
@receiver(on_app_ready, dispatch_uid="my_unique_identifier")
|
||||
def test_admin_user_on_app_ready(sender, **kwargs):
|
||||
logger.debug("Receive app ready signal, test admin connectability")
|
||||
test_admin_user_connectability_period.delay()
|
||||
|
||||
|
||||
celery_app.conf['CELERYBEAT_SCHEDULE'].update(
|
||||
{
|
||||
'update_assets_hardware_period': {
|
||||
'task': 'assets.tasks.update_assets_hardware_period',
|
||||
'schedule': 60*60*24,
|
||||
'args': (),
|
||||
},
|
||||
'test-admin-user-connectability_period': {
|
||||
'task': 'assets.tasks.test_admin_user_connectability_period',
|
||||
'schedule': 60*60,
|
||||
'args': (),
|
||||
},
|
||||
'push_system_user_period': {
|
||||
'task': 'assets.tasks.push_system_user_period',
|
||||
'schedule': 60*60,
|
||||
'args': (),
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -39,30 +39,29 @@
|
|||
{% bootstrap_field form.username layout="horizontal" %}
|
||||
{% bootstrap_field form.protocol layout="horizontal" %}
|
||||
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||
<h3>{% trans 'Auth' %}</h3>
|
||||
{% bootstrap_field form.auth_method layout="horizontal" %}
|
||||
|
||||
{% block auth %}
|
||||
<div class="password-auth hidden">
|
||||
{% bootstrap_field form.password layout="horizontal" %}
|
||||
</div>
|
||||
<div class="public-key-auth">
|
||||
<h3>{% trans 'Auth' %}</h3>
|
||||
<div class="auto-generate">
|
||||
<div class="form-group">
|
||||
<label for="{{ form.auto_generate_key.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto generate key' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.auto_generate_key}}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{% bootstrap_field form.private_key_file layout="horizontal" %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="auth-fields">
|
||||
{% bootstrap_field form.private_key_file layout="horizontal" %}
|
||||
{% bootstrap_field form.password layout="horizontal" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.as_push.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto push' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.auto_push}}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
{% bootstrap_field form.sudo layout="horizontal" %}
|
||||
{% bootstrap_field form.shell layout="horizontal" %}
|
||||
|
@ -82,41 +81,20 @@
|
|||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
var auth_method = '#'+'{{ form.auth_method.id_for_label }}';
|
||||
var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}';
|
||||
function authMethodDisplay() {
|
||||
if ($(auth_method).val() == 'P') {
|
||||
$('.password-auth').removeClass('hidden');
|
||||
$('.public-key-auth').addClass('hidden');
|
||||
$('#'+'{{ form.password.id_for_label }}').attr('required', 'required');
|
||||
$('#'+'{{ form.password.id_for_label }}').removeAttr('disabled');
|
||||
$('#'+'{{ form.private_key_file.id_for_label }}').removeAttr('required');
|
||||
|
||||
} else if ($(auth_method).val() == 'K') {
|
||||
$('.password-auth').addClass('hidden');
|
||||
$('.public-key-auth').removeClass('hidden');
|
||||
$('#'+'{{ form.password.id_for_label }}').removeAttr('required');
|
||||
$('#'+'{{ form.password.id_for_label }}').attr('disabled', 'disabled');
|
||||
|
||||
if ($(auto_generate_key).prop('checked')){
|
||||
$('#'+'{{ form.private_key_file.id_for_label }}').closest('.form-group').addClass('hidden');
|
||||
} else {
|
||||
$('#'+'{{ form.private_key_file.id_for_label }}').closest('.form-group').removeClass('hidden');
|
||||
$('#'+'{{ form.private_key_file.id_for_label }}').closest('.form-group input').attr('required', 'required');
|
||||
}
|
||||
function authFieldsDisplay() {
|
||||
if ($(auto_generate_key).prop('checked')) {
|
||||
$('.auth-fields').addClass('hidden');
|
||||
} else {
|
||||
$('.auth-fields').removeClass('hidden');
|
||||
}
|
||||
}
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
authMethodDisplay();
|
||||
$(auth_method).change(function () {
|
||||
authMethodDisplay();
|
||||
});
|
||||
authFieldsDisplay();
|
||||
$(auto_generate_key).change(function () {
|
||||
authMethodDisplay();
|
||||
authFieldsDisplay();
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -86,10 +86,10 @@
|
|||
<table class="table">
|
||||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="50%">{% trans 'Reset auth' %}:</td>
|
||||
<td width="50%">{% trans 'Test auth all assets manual' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Run' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -97,6 +97,42 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Using this as cluster admin user' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit" id="add-asset2group">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Select cluster' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for cluster in cluster_remain %}
|
||||
<option value="{{ cluster.id }}" id="opt_{{ cluster.id }}" >{{ cluster.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-sm" id="btn_add_user_group">{% trans 'Confirm' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for cluster in admin_user.cluster_set.all %}
|
||||
<tr>
|
||||
<td ><b class="bdg_group" data-gid={{ cluster.id }}>{{ cluster.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn-leave-group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -192,6 +228,7 @@ function adminUserDelete(name, url) {
|
|||
jumpserver.assets_selected = {};
|
||||
jumpserver.asset_groups_selected = {};
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
})
|
||||
.on('click', '.btn-delete-admin-user', function () {
|
||||
var $this = $(this);
|
||||
|
|
|
@ -236,7 +236,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,8 +16,18 @@
|
|||
<li>
|
||||
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
|
||||
</li>
|
||||
<li class="active"><a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Attached assets' %}</a>
|
||||
<li>
|
||||
<a href="{% url 'assets:system-user-auth' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Auth' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-default" href="{% url 'assets:system-user-update' pk=system_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -131,7 +141,7 @@ function initAssetsTable() {
|
|||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}?system_user_id={{ system_user.id }}',
|
||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "is_online" }],
|
||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "is_connective" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li>
|
||||
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="{% url 'assets:system-user-auth' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Auth' %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Attached assets' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-default" href="{% url 'assets:system-user-update' pk=system_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-12" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ system_user.name }}</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">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form enctype="multipart/form-data" method="post" class="form-horizontal" action="" >
|
||||
{% csrf_token %}
|
||||
{% bootstrap_field form.password layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
{% bootstrap_field form.private_key_file layout="horizontal" %}
|
||||
<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">{% trans 'Reset' %}</button>
|
||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -17,6 +17,11 @@
|
|||
<li class="active">
|
||||
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'assets:system-user-auth' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Auth' %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Attached assets' %}
|
||||
|
@ -61,10 +66,6 @@
|
|||
<td>{% trans 'Protocol' %}:</td>
|
||||
<td><b>{{ system_user.protocol }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Auto push' %}:</td>
|
||||
<td><b>{{ system_user.auto_push|yesno:"Yes,No,Unknown" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Sudo' %}:</td>
|
||||
<td><b>{{ system_user.sudo }}</b></td>
|
||||
|
@ -129,14 +130,50 @@
|
|||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{# <tr>#}
|
||||
{# <td width="50%">{% trans 'Change auth period' %}:</td>#}
|
||||
{# <td>#}
|
||||
{# <span style="float: right">#}
|
||||
{# <button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>#}
|
||||
{# </span>#}
|
||||
{# </td>#}
|
||||
{# </tr>#}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Clusters' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit" id="add-asset2group">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Add to cluster' %}" id="" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for cluster in cluster_remain %}
|
||||
<option value="{{ cluster.id }}" id="opt_{{ cluster.id }}" >{{ cluster.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-sm" id="btn_add_user_group">{% trans 'Confirm' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for cluster in system_user.cluster.all %}
|
||||
<tr>
|
||||
<td width="50%">{% trans 'Reset auth' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
<td ><b class="bdg_group" data-gid={{ cluster.id }}>{{ cluster.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn-leave-group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -150,6 +187,7 @@
|
|||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
// Todo: 添加自动推送的js
|
||||
{# function switch_user_status(obj) {#}
|
||||
{# var status = $(obj).prop('checked');#}
|
||||
{##}
|
||||
|
|
|
@ -50,6 +50,7 @@ urlpatterns = [
|
|||
url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.SystemUserUpdateView.as_view(), name='system-user-update'),
|
||||
url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/delete/$', views.SystemUserDeleteView.as_view(), name='system-user-delete'),
|
||||
url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/asset/$', views.SystemUserAssetView.as_view(), name='system-user-asset'),
|
||||
url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/auth/$', views.SystemUserAuthView.as_view(), name='system-user-auth'),
|
||||
# url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/asset-group$', views.SystemUserAssetGroupView.as_view(),
|
||||
# name='system-user-asset-group'),
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class AdminUserListView(AdminUserRequiredMixin, TemplateView):
|
|||
'action': _('Admin user list'),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AdminUserListView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AdminUserCreateView(AdminUserRequiredMixin,
|
||||
|
@ -45,7 +45,7 @@ class AdminUserCreateView(AdminUserRequiredMixin,
|
|||
'action': 'Create admin user'
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AdminUserCreateView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
success_message = _(
|
||||
|
@ -56,9 +56,6 @@ class AdminUserCreateView(AdminUserRequiredMixin,
|
|||
))
|
||||
return success_message
|
||||
|
||||
def form_invalid(self, form):
|
||||
return super(AdminUserCreateView, self).form_invalid(form)
|
||||
|
||||
|
||||
class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = AdminUser
|
||||
|
@ -71,7 +68,7 @@ class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|||
'action': 'Update admin user'
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AdminUserUpdateView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
success_url = reverse_lazy('assets:admin-user-detail',
|
||||
|
@ -79,38 +76,28 @@ class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|||
return success_url
|
||||
|
||||
|
||||
class AdminUserDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
class AdminUserDetailView(AdminUserRequiredMixin, DetailView):
|
||||
model = AdminUser
|
||||
template_name = 'assets/admin_user_detail.html'
|
||||
context_object_name = 'admin_user'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=AdminUser.objects.all())
|
||||
return super(AdminUserDetailView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = []
|
||||
for cluster in self.object.cluster_set.all():
|
||||
queryset.extend(list(cluster.assets.all()))
|
||||
return queryset
|
||||
object = None
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
asset_groups = AssetGroup.objects.all()
|
||||
assets = self.get_queryset()
|
||||
cluster_remain = Cluster.objects.exclude(admin_user=self.object)
|
||||
context = {
|
||||
'app': 'assets',
|
||||
'action': 'Admin user detail',
|
||||
'assets_remain': [asset for asset in Asset.objects.all() if asset not in assets],
|
||||
'asset_groups': asset_groups,
|
||||
'cluster_remain': cluster_remain,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AdminUserDetailView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
template_name = 'assets/admin_user_assets.html'
|
||||
context_object_name = 'admin_user'
|
||||
object = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=AdminUser.objects.all())
|
||||
|
|
|
@ -28,7 +28,6 @@ from .. import forms
|
|||
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
||||
from ..hands import AdminUserRequiredMixin
|
||||
from ..tasks import update_assets_hardware_info
|
||||
from ..signals import on_asset_created
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
@ -79,7 +78,6 @@ class AssetCreateView(AdminUserRequiredMixin, CreateView):
|
|||
asset.created_by = self.request.user.username or 'Admin'
|
||||
asset.date_created = timezone.now()
|
||||
asset.save()
|
||||
on_asset_created.send(sender=self.__class__, asset=asset)
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -90,10 +88,6 @@ class AssetCreateView(AdminUserRequiredMixin, CreateView):
|
|||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
# update_assets_hardware_info.delay([self.asset._to_secret_json()])
|
||||
return super().get_success_url()
|
||||
|
||||
|
||||
class AssetModalListView(AdminUserRequiredMixin, ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import redirect, reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.views.generic import TemplateView, ListView
|
||||
from django.views.generic import TemplateView, ListView, FormView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
from django.urls import reverse_lazy
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||
|
||||
from ..forms import SystemUserForm, SystemUserUpdateForm
|
||||
from ..models import Asset, AssetGroup, SystemUser
|
||||
from ..forms import SystemUserForm, SystemUserUpdateForm, SystemUserAuthForm
|
||||
from ..models import SystemUser, Cluster
|
||||
from ..hands import AdminUserRequiredMixin
|
||||
from perms.utils import associate_system_users_and_assets
|
||||
|
||||
|
||||
__all__ = ['SystemUserCreateView', 'SystemUserUpdateView',
|
||||
'SystemUserDetailView', 'SystemUserDeleteView',
|
||||
'SystemUserAssetView', 'SystemUserListView',
|
||||
'SystemUserAuthView',
|
||||
]
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ class SystemUserListView(AdminUserRequiredMixin, TemplateView):
|
|||
'action': _('System user list'),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(SystemUserListView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||
|
@ -50,11 +50,10 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
|
|||
'action': _('Create system user'),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(SystemUserCreateView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
url = reverse_lazy('assets:system-user-detail',
|
||||
kwargs={'pk': self.object.pk}),
|
||||
url = reverse('assets:system-user-detail', kwargs={'pk': self.object.pk})
|
||||
success_message = _(
|
||||
'Create system user <a href="{url}">{name}</a> '
|
||||
'successfully.'.format(url=url, name=self.object.name)
|
||||
|
@ -74,15 +73,7 @@ class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|||
'action': _('Update system user')
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(SystemUserUpdateView, self).get_context_data(**kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super(SystemUserUpdateView, self).form_valid(form)
|
||||
system_user = self.object
|
||||
assets = system_user.assets.all()
|
||||
asset_groups = system_user.asset_groups.all()
|
||||
associate_system_users_and_assets([system_user], assets, asset_groups, force=True)
|
||||
return response
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
success_url = reverse_lazy('assets:system-user-detail',
|
||||
|
@ -96,12 +87,14 @@ class SystemUserDetailView(AdminUserRequiredMixin, DetailView):
|
|||
model = SystemUser
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
cluster_remain = Cluster.objects.exclude(systemuser=self.object)
|
||||
context = {
|
||||
'app': _('Assets'),
|
||||
'action': _('System user detail')
|
||||
'action': _('System user detail'),
|
||||
'cluster_remain': cluster_remain,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(SystemUserDetailView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class SystemUserDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||
|
@ -121,5 +114,36 @@ class SystemUserAssetView(AdminUserRequiredMixin, DetailView):
|
|||
'action': 'System user asset',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(SystemUserAssetView, self).get_context_data(**kwargs)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class SystemUserAuthView(AdminUserRequiredMixin, SingleObjectMixin,
|
||||
SuccessMessageMixin, FormView):
|
||||
model = SystemUser
|
||||
template_name = 'assets/system_user_auth.html'
|
||||
context_object_name = 'system_user'
|
||||
form_class = SystemUserAuthForm
|
||||
success_message = _("Update auth info success")
|
||||
object = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
instance = form.update(self.object)
|
||||
success_url = reverse('assets:system-user-detail', kwargs={"pk": instance.id})
|
||||
messages.success(self.request, self.success_message)
|
||||
return redirect(success_url)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'assets',
|
||||
'action': 'System user auth',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
from celery import Celery
|
||||
from celery.schedules import crontab
|
||||
|
||||
# set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings')
|
||||
|
@ -21,20 +18,5 @@ app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in setti
|
|||
|
||||
app.conf.update(
|
||||
CELERYBEAT_SCHEDULE={
|
||||
'refresh-asset-hardware-info': {
|
||||
'task': 'assets.tasks.update_assets_hardware_period',
|
||||
'schedule': 60*60*60*24,
|
||||
'args': (),
|
||||
},
|
||||
'test-admin-user-connectability_periode': {
|
||||
'task': 'assets.tasks.test_admin_user_connectability_period',
|
||||
'schedule': 60*60*60,
|
||||
'args': (),
|
||||
},
|
||||
'clean_terminal_history': {
|
||||
'task': 'terminal.tasks.clean_terminal_history',
|
||||
'schedule': 60*60*60,
|
||||
'args': (),
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -14,7 +14,7 @@ import hashlib
|
|||
from email.utils import formatdate
|
||||
import calendar
|
||||
import threading
|
||||
from six import StringIO
|
||||
from io import StringIO
|
||||
import uuid
|
||||
|
||||
import paramiko
|
||||
|
@ -180,15 +180,15 @@ def timesince(dt, since='', default="just now"):
|
|||
return default
|
||||
|
||||
|
||||
def ssh_key_string_to_obj(text):
|
||||
def ssh_key_string_to_obj(text, password=None):
|
||||
key = None
|
||||
try:
|
||||
key = paramiko.RSAKey.from_private_key( StringIO(text) )
|
||||
key = paramiko.RSAKey.from_private_key(StringIO(text), password=password)
|
||||
except paramiko.SSHException:
|
||||
pass
|
||||
|
||||
try:
|
||||
key = paramiko.DSSKey.from_private_key( StringIO(text) )
|
||||
key = paramiko.DSSKey.from_private_key(StringIO(text), password=password)
|
||||
except paramiko.SSHException:
|
||||
pass
|
||||
return key
|
||||
|
@ -222,7 +222,6 @@ def ssh_key_gen(length=2048, type='rsa', password=None, username='jumpserver', h
|
|||
hostname = os.uname()[1]
|
||||
|
||||
f = StringIO()
|
||||
|
||||
try:
|
||||
if type == 'rsa':
|
||||
private_key_obj = paramiko.RSAKey.generate(length)
|
||||
|
|
|
@ -1 +1 @@
|
|||
[{"model": "users.usergroup", "pk": "2e0b2a25-b32f-44a0-b087-f0f17de66e26", "fields": {"is_discard": false, "discard_time": null, "name": "Default", "comment": "Default user group", "date_created": "2017-12-07T08:20:09.593Z", "created_by": "System"}}, {"model": "assets.cluster", "pk": "c0df1aa0-bde7-4226-a69a-d02976888456", "fields": {"name": "Default", "bandwidth": "", "contact": "", "phone": "", "address": "", "intranet": "", "extranet": "", "date_created": "2017-12-07T08:20:09.606Z", "operator": "", "created_by": "System", "comment": "Default Cluster"}}, {"model": "assets.assetgroup", "pk": "881a0460-7989-42af-a588-957efe57fb8e", "fields": {"name": "Default", "created_by": "", "date_created": "2017-12-07T08:20:09.610Z", "comment": "Default asset group", "system_users": []}}, {"model": "users.user", "pk": "edc529d5-0377-4456-831f-ec42cf5b34d2", "fields": {"password": "pbkdf2_sha256$36000$3VcSL8Ap6zHd$14Y4+uZHRU8gwFgEXdIEZZ2+NWV15sRBV2YWgWbdyhY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-12-07T08:20:09.494Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2087-11-20T08:20:09.494Z", "created_by": "System", "user_permissions": [], "groups": ["2e0b2a25-b32f-44a0-b087-f0f17de66e26"]}}]
|
||||
[{"model": "users.usergroup", "pk": "f3c6b021-59a9-43e7-b022-c2e9bfac84d7", "fields": {"is_discard": false, "discard_time": null, "name": "Default", "comment": "Default user group", "date_created": "2017-12-12T08:13:20.906Z", "created_by": "System"}}, {"model": "users.loginlog", "pk": "328c7d0f-214d-4665-8c7b-f3063718530e", "fields": {"username": "admin", "type": "ST", "ip": "127.0.0.1", "city": "Unknown", "user_agent": "", "datetime": "2017-12-12T08:10:28.973Z"}}, {"model": "users.loginlog", "pk": "a72fa02e-3b2c-40a0-8cb1-0c2f98d8f248", "fields": {"username": "admin", "type": "ST", "ip": "127.0.0.1", "city": "Unknown", "user_agent": "", "datetime": "2017-12-12T08:10:28.980Z"}}, {"model": "assets.cluster", "pk": "a950b8aa-073b-45ab-b72e-5bdfbb614653", "fields": {"name": "Default", "admin_user": null, "bandwidth": "", "contact": "", "phone": "", "address": "", "intranet": "", "extranet": "", "date_created": "2017-12-12T08:13:20.919Z", "operator": "", "created_by": "System", "comment": "Default Cluster"}}, {"model": "assets.assetgroup", "pk": "d742a7be-faf1-4c29-ae0a-e6aa640ab395", "fields": {"name": "Default", "created_by": "", "date_created": "2017-12-12T08:13:20.923Z", "comment": "Default asset group"}}, {"model": "captcha.captchastore", "pk": 1, "fields": {"challenge": "EQEI", "response": "eqei", "hashkey": "c993e8e245252eb8ca40a57c67a63ee9c61dce5c", "expiration": "2017-12-12T08:17:50.235Z"}}, {"model": "users.user", "pk": "61c39c1f-5b57-4268-8180-b6dda235aadd", "fields": {"password": "pbkdf2_sha256$36000$yhYWUEo4DNqj$SpxtdIOm9nwRG+X76jUUlGvdDcLaMBl7Z+rJ8sfSMcU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-12-12T08:13:20.827Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2087-11-25T08:13:20.827Z", "created_by": "System", "user_permissions": [], "groups": ["f3c6b021-59a9-43e7-b022-c2e9bfac84d7"]}}]
|
|
@ -34,8 +34,8 @@ th a {
|
|||
}
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #1ab394 !important;
|
||||
color: white;
|
||||
background-color: #d2d2d2 !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
.select2-selection--single,
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
{% load i18n %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/dataTables/datatables.min.css" %}" rel="stylesheet">
|
||||
{# <link href="{% static "css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css" %}" rel="stylesheet">#}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<script src="{% static "js/plugins/dataTables/dataTables.min.js" %}"></script>
|
||||
|
@ -48,7 +47,6 @@
|
|||
{% endblock %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
{# {% block tags_list %}{% endblock %}#}
|
||||
</div>
|
||||
{% block table_container %}
|
||||
<table class="table table-striped table-bordered table-hover" id="editable" >
|
||||
|
@ -64,7 +62,6 @@
|
|||
{% endblock %}
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
{# Update batch #}
|
||||
{% block content_bottom_left %} {% endblock %}
|
||||
</div>
|
||||
{% block table_pagination %}
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
{% load i18n %}
|
||||
{% block first_login_message %}
|
||||
{% if user.is_authenticated and user.is_first_login %}
|
||||
<div class="alert alert-danger help-message">
|
||||
{% url 'users:user-first-login' as first_login_url %}
|
||||
{% blocktrans %}
|
||||
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block update_public_key_message %}
|
||||
{% if user.is_authenticated and not user.is_public_key_valid %}
|
||||
<div class="alert alert-danger help-message">
|
||||
{% url 'users:user-pubkey-update' as user_pubkey_update %}
|
||||
{% blocktrans %}
|
||||
Your ssh public key not set or expired. Please click <a href="{{ user_pubkey_update }}"> this link </a>to update your
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} help-message" >
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="renderer" content="webkit">
|
||||
|
||||
<title>Jumpserver</title>
|
||||
|
||||
<link rel="shortcut icon" href="{% static 'img/facio.ico' %}" type="image/x-icon">
|
||||
{% include '_head_css_js.html' %}
|
||||
<link href="{% static 'css/jumpserver.css' %}" rel="stylesheet">
|
||||
|
@ -20,27 +18,7 @@
|
|||
<div id="page-wrapper" class="gray-bg">
|
||||
{% include '_header_bar.html' %}
|
||||
{% include '_message.html' %}
|
||||
{% block first_login_message %}
|
||||
{% if user.is_authenticated and user.is_first_login %}
|
||||
<div class="alert alert-danger help-message">
|
||||
{% url 'users:user-first-login' as first_login_url %}
|
||||
{% blocktrans %}
|
||||
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block update_public_key_message %}
|
||||
{% if user.is_authenticated and not user.is_public_key_valid %}
|
||||
<div class="alert alert-danger help-message">
|
||||
{% url 'users:user-pubkey-update' as user_pubkey_update %}
|
||||
{% blocktrans %}
|
||||
Your ssh public key not set or expired. Please click <a href="{{ user_pubkey_update }}"> this link </a>to update your
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block help_message %}{% endblock %}
|
||||
{% block help_message %} {% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
{% include '_footer.html' %}
|
||||
</div>
|
||||
|
|
|
@ -124,7 +124,7 @@ class SessionDetailView(SingleObjectMixin, ListView):
|
|||
model = Session
|
||||
|
||||
def get_queryset(self):
|
||||
self.object = self.get_object(self.model.objects.all())
|
||||
self.object = self.get_object()
|
||||
return command_store.filter(session=self.object.id)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
|
Loading…
Reference in New Issue