mirror of https://github.com/jumpserver/jumpserver
[Feature] 添加es支持
parent
ba5ab21b37
commit
b936d54a48
|
@ -60,11 +60,6 @@ class ClusterUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView)
|
||||||
success_url = reverse_lazy('assets:cluster-list')
|
success_url = reverse_lazy('assets:cluster-list')
|
||||||
success_message = update_success_msg
|
success_message = update_success_msg
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
cluster = form.save(commit=False)
|
|
||||||
cluster.save()
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('assets'),
|
'app': _('assets'),
|
||||||
|
|
|
@ -4,7 +4,9 @@ import json
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.html import escape
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
from .fields import DictField
|
from .fields import DictField
|
||||||
|
@ -30,28 +32,32 @@ def to_form_value(value):
|
||||||
class BaseForm(forms.Form):
|
class BaseForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
settings = Setting.objects.all()
|
db_settings = Setting.objects.all()
|
||||||
for name, field in self.fields.items():
|
for name, field in self.fields.items():
|
||||||
db_value = getattr(settings, name).value
|
db_value = getattr(db_settings, name).value
|
||||||
if db_value:
|
django_value = getattr(settings, name) if hasattr(settings, name) else None
|
||||||
|
if db_value is not None:
|
||||||
field.initial = to_form_value(db_value)
|
field.initial = to_form_value(db_value)
|
||||||
|
elif django_value is not None:
|
||||||
|
field.initial = django_value
|
||||||
|
|
||||||
def save(self):
|
def save(self, category="default"):
|
||||||
if not self.is_bound:
|
if not self.is_bound:
|
||||||
raise ValueError("Form is not bound")
|
raise ValueError("Form is not bound")
|
||||||
|
|
||||||
settings = Setting.objects.all()
|
db_settings = Setting.objects.all()
|
||||||
if self.is_valid():
|
if self.is_valid():
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
for name, value in self.cleaned_data.items():
|
for name, value in self.cleaned_data.items():
|
||||||
field = self.fields[name]
|
field = self.fields[name]
|
||||||
if isinstance(field.widget, forms.PasswordInput) and not value:
|
if isinstance(field.widget, forms.PasswordInput) and not value:
|
||||||
continue
|
continue
|
||||||
if value == to_form_value(getattr(settings, name).value):
|
if value == to_form_value(getattr(db_settings, name).value):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
'name': name,
|
'name': name,
|
||||||
|
'category': category,
|
||||||
'value': to_model_value(value)
|
'value': to_model_value(value)
|
||||||
}
|
}
|
||||||
Setting.objects.update_or_create(defaults=defaults, name=name)
|
Setting.objects.update_or_create(defaults=defaults, name=name)
|
||||||
|
@ -129,3 +135,28 @@ class LDAPSettingForm(BaseForm):
|
||||||
AUTH_LDAP_START_TLS = forms.BooleanField(
|
AUTH_LDAP_START_TLS = forms.BooleanField(
|
||||||
label=_("Use SSL"), initial=False, required=False
|
label=_("Use SSL"), initial=False, required=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TerminalSettingForm(BaseForm):
|
||||||
|
SORT_BY_CHOICES = (
|
||||||
|
('hostname', _('Hostname')),
|
||||||
|
('ip', _('IP')),
|
||||||
|
)
|
||||||
|
TERMINAL_ASSET_LIST_SORT_BY = forms.ChoiceField(
|
||||||
|
choices=SORT_BY_CHOICES, initial='hostname', label=_("List sort by")
|
||||||
|
)
|
||||||
|
TERMINAL_HEARTBEAT_INTERVAL = forms.IntegerField(
|
||||||
|
initial=5, label=_("Heartbeat interval"), help_text=_("Units: seconds")
|
||||||
|
)
|
||||||
|
TERMINAL_PASSWORD_AUTH = forms.BooleanField(
|
||||||
|
initial=True, required=False, label=_("Password auth")
|
||||||
|
)
|
||||||
|
TERMINAL_PUBLIC_KEY_AUTH = forms.BooleanField(
|
||||||
|
initial=True, required=False, label=_("Public key auth")
|
||||||
|
)
|
||||||
|
TERMINAL_COMMAND_STORAGE = DictField(
|
||||||
|
label=_("Command storage"), help_text=_(
|
||||||
|
"Set terminal storage setting, `default` is the using as default,"
|
||||||
|
"You can set other storage and some terminal using"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -24,6 +24,7 @@ class SettingManager(models.Manager):
|
||||||
class Setting(models.Model):
|
class Setting(models.Model):
|
||||||
name = models.CharField(max_length=128, unique=True, verbose_name=_("Name"))
|
name = models.CharField(max_length=128, unique=True, verbose_name=_("Name"))
|
||||||
value = models.TextField(verbose_name=_("Value"))
|
value = models.TextField(verbose_name=_("Value"))
|
||||||
|
category = models.CharField(max_length=128, default="default")
|
||||||
enabled = models.BooleanField(verbose_name=_("Enabled"), default=True)
|
enabled = models.BooleanField(verbose_name=_("Enabled"), default=True)
|
||||||
comment = models.TextField(verbose_name=_("Comment"))
|
comment = models.TextField(verbose_name=_("Comment"))
|
||||||
|
|
||||||
|
@ -33,12 +34,20 @@ class Setting(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value_(self):
|
def cleaned_value(self):
|
||||||
try:
|
try:
|
||||||
return json.loads(self.value)
|
return json.loads(self.value)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@cleaned_value.setter
|
||||||
|
def cleaned_value(self, item):
|
||||||
|
try:
|
||||||
|
v = json.dumps(item)
|
||||||
|
self.value = v
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
raise ValueError("Json dump error: {}".format(str(e)))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def refresh_all_settings(cls):
|
def refresh_all_settings(cls):
|
||||||
settings_list = cls.objects.all()
|
settings_list = cls.objects.all()
|
||||||
|
@ -53,9 +62,9 @@ class Setting(models.Model):
|
||||||
setattr(settings, self.name, value)
|
setattr(settings, self.name, value)
|
||||||
|
|
||||||
if self.name == "AUTH_LDAP":
|
if self.name == "AUTH_LDAP":
|
||||||
if self.value_ and settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
|
if self.cleaned_value and settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
|
||||||
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
|
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
|
||||||
elif not self.value_ and settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
elif not self.cleaned_value and settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
||||||
settings.AUTHENTICATION_BACKENDS.remove(settings.AUTH_LDAP_BACKEND)
|
settings.AUTHENTICATION_BACKENDS.remove(settings.AUTH_LDAP_BACKEND)
|
||||||
|
|
||||||
if self.name == "AUTH_LDAP_SEARCH_FILTER":
|
if self.name == "AUTH_LDAP_SEARCH_FILTER":
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
{% extends '_modal.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block modal_id %}add_command_storage_model{% endblock %}
|
||||||
|
{% block modal_title%}{% trans "Add command storage" %}{% endblock %}
|
||||||
|
{% block modal_body %}
|
||||||
|
<form method="post" action="" id="add_command_storage_form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="id_assets">{% trans "Template" %}</label>
|
||||||
|
<a href="{% url 'assets:asset-export' %}" style="display: block">{% trans 'Download' %}</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="id_users">{% trans "Asset csv file" %}</label>
|
||||||
|
<input id="id_assets" type="file" name="file" />
|
||||||
|
<span class="help-block red-fonts">
|
||||||
|
{% trans 'If set id, will use this id update asset existed' %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
{% block modal_confirm_id %}btn_asset_import{% endblock %}
|
|
@ -21,7 +21,7 @@
|
||||||
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'settings:storage-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Storage setting' %} </a>
|
<a href="{% url 'settings:terminal-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Terminal setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'settings:storage-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Storage setting' %} </a>
|
<a href="{% url 'settings:terminal-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Terminal setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'settings:storage-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Storage setting' %} </a>
|
<a href="{% url 'settings:terminal-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Terminal setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a href="{% url 'settings:storage-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Storage setting' %} </a>
|
<a href="{% url 'settings:terminal-setting' %}" class="text-center"><i class="fa fa-hdd-o"></i> {% trans 'Terminal setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,26 +35,50 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<h3>{% trans "Basic setting" %}</h3>
|
||||||
|
{% for field in form %}
|
||||||
|
{% if not field.field|is_bool_field %}
|
||||||
|
{% bootstrap_field field layout="horizontal" %}
|
||||||
|
{% else %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="col-sm-1">
|
||||||
|
{{ field }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<span class="help-block" >{{ field.help_text }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans "Command storage" %}</h3>
|
<h3>{% trans "Command storage" %}</h3>
|
||||||
<table class="table table-hover " id="task-history-list-table" >
|
<table class="table table-hover " id="task-history-list-table" >
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'Name' %}</th>
|
<th>{% trans 'Name' %}</th>
|
||||||
<th>{% trans 'Engine' %}</th>
|
<th>{% trans 'Type' %}</th>
|
||||||
<th>{% trans 'Action' %}</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% for name, setting in command_storage.items %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ name }}</td>
|
||||||
|
<td>{{ setting.TYPE }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{# <button class="btn btn-default btn-circle btn-add-command-storage" data-toggle="modal" data-target="#add_command_storage_model" tabindex="0" type="button"><i class="fa fa-plus"></i></button>#}
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans "Replay storage" %}</h3>
|
<h3>{% trans "Replay storage" %}</h3>
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-4 col-sm-offset-2">
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
<button class="btn btn-default btn-test" type="button"> {% trans 'Test connection' %}</button>
|
|
||||||
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
||||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,6 +92,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% include 'common/_add_terminal_command_storage_modal.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
@ -97,6 +122,9 @@ $(document).ready(function () {
|
||||||
success: success,
|
success: success,
|
||||||
error: error
|
error: error
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.on('click', '', function () {
|
||||||
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -10,5 +10,5 @@ urlpatterns = [
|
||||||
url(r'^$', views.BasicSettingView.as_view(), name='basic-setting'),
|
url(r'^$', views.BasicSettingView.as_view(), name='basic-setting'),
|
||||||
url(r'^email/$', views.EmailSettingView.as_view(), name='email-setting'),
|
url(r'^email/$', views.EmailSettingView.as_view(), name='email-setting'),
|
||||||
url(r'^ldap/$', views.LDAPSettingView.as_view(), name='ldap-setting'),
|
url(r'^ldap/$', views.LDAPSettingView.as_view(), name='ldap-setting'),
|
||||||
url(r'^storage/$', views.StorageSettingView.as_view(), name='storage-setting'),
|
url(r'^terminal/$', views.TerminalSettingView.as_view(), name='terminal-setting'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from django.views.generic import View, TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm
|
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
||||||
|
TerminalSettingForm
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
from .mixins import AdminUserRequiredMixin
|
from .mixins import AdminUserRequiredMixin
|
||||||
from .signals import ldap_auth_enable
|
from .signals import ldap_auth_enable
|
||||||
|
@ -89,27 +91,29 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
class StorageSettingView(AdminUserRequiredMixin, TemplateView):
|
class TerminalSettingView(AdminUserRequiredMixin, TemplateView):
|
||||||
form_class = LDAPSettingForm
|
form_class = TerminalSettingForm
|
||||||
template_name = "common/storage_setting.html"
|
template_name = "common/terminal_setting.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
command_storage = settings.TERMINAL_COMMAND_STORAGE
|
||||||
context = {
|
context = {
|
||||||
'app': _('Settings'),
|
'app': _('Settings'),
|
||||||
'action': _('Storage setting'),
|
'action': _('Terminal setting'),
|
||||||
'form': self.form_class(),
|
'form': self.form_class(),
|
||||||
'command_storage': Setting.objects.filter(name__endswith="_COMMAND_STORAGE")
|
'command_storage': command_storage,
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
print(request.POST)
|
||||||
form = self.form_class(request.POST)
|
form = self.form_class(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
msg = _("Update setting successfully, please restart program")
|
msg = _("Update setting successfully, please restart program")
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
return redirect('settings:storage-setting')
|
return redirect('settings:terminal-setting')
|
||||||
else:
|
else:
|
||||||
context = self.get_context_data()
|
context = self.get_context_data()
|
||||||
context.update({"form": form})
|
context.update({"form": form})
|
||||||
|
|
|
@ -373,7 +373,23 @@ CAPTCHA_FOREGROUND_COLOR = '#001100'
|
||||||
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
|
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
|
||||||
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
|
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
|
||||||
|
|
||||||
COMMAND_STORAGE_BACKEND = 'terminal.backends.command.db'
|
COMMAND_STORAGE = {
|
||||||
|
'ENGINE': 'terminal.backends.command.db',
|
||||||
|
}
|
||||||
|
|
||||||
|
TERMINAL_COMMAND_STORAGE = {
|
||||||
|
'default': {
|
||||||
|
'TYPE': 'server',
|
||||||
|
},
|
||||||
|
# 'ali-es': {
|
||||||
|
# 'TYPE': 'elasticsearch',
|
||||||
|
# 'HOSTS': ['http://elastic:changeme@localhost:9200'],
|
||||||
|
# },
|
||||||
|
# 'ali-hz-es': {
|
||||||
|
# 'TYPE': 'elasticsearch',
|
||||||
|
# 'HOSTS': ['http://elastic:changeme@localhost:9200'],
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
|
||||||
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
|
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
|
||||||
BOOTSTRAP3 = {
|
BOOTSTRAP3 = {
|
||||||
|
|
|
@ -21,7 +21,7 @@ from .serializers import TerminalSerializer, StatusSerializer, \
|
||||||
SessionSerializer, TaskSerializer, ReplaySerializer
|
SessionSerializer, TaskSerializer, ReplaySerializer
|
||||||
from .hands import IsSuperUserOrAppUser, IsAppUser, \
|
from .hands import IsSuperUserOrAppUser, IsAppUser, \
|
||||||
IsSuperUserOrAppUserOrUserReadonly
|
IsSuperUserOrAppUserOrUserReadonly
|
||||||
from .backends import get_command_store, SessionCommandSerializer
|
from .backends import get_terminal_command_store, SessionCommandSerializer
|
||||||
|
|
||||||
logger = logging.getLogger(__file__)
|
logger = logging.getLogger(__file__)
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ class CommandViewSet(viewsets.ViewSet):
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
command_store = get_command_store()
|
command_store = get_terminal_command_store()
|
||||||
serializer_class = SessionCommandSerializer
|
serializer_class = SessionCommandSerializer
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
|
@ -260,3 +260,10 @@ class SessionReplayViewSet(viewsets.ViewSet):
|
||||||
return redirect(url)
|
return redirect(url)
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotFound()
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
|
|
||||||
|
class LoadConfig(APIView):
|
||||||
|
permission_classes = (IsAppUser,)
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
pass
|
||||||
|
|
|
@ -2,9 +2,33 @@ from importlib import import_module
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from .command.serializers import SessionCommandSerializer
|
from .command.serializers import SessionCommandSerializer
|
||||||
|
|
||||||
|
TYPE_ENGINE_MAPPING = {
|
||||||
|
'elasticsearch': 'terminal.backends.command.db',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_command_store():
|
def get_command_store():
|
||||||
command_engine = import_module(settings.COMMAND_STORAGE_BACKEND)
|
params = settings.COMMAND_STORAGE
|
||||||
command_store = command_engine.CommandStore()
|
engine_class = import_module(params['ENGINE'])
|
||||||
return command_store
|
storage = engine_class.CommandStore(params)
|
||||||
|
return storage
|
||||||
|
|
||||||
|
|
||||||
|
def get_terminal_command_store():
|
||||||
|
storage_list = {}
|
||||||
|
for name, params in settings.TERMINAL_COMMAND_STORAGE.items():
|
||||||
|
tp = params['TYPE']
|
||||||
|
if tp == 'server':
|
||||||
|
storage = get_command_store()
|
||||||
|
else:
|
||||||
|
if not TYPE_ENGINE_MAPPING.get(tp):
|
||||||
|
raise AssertionError("Command storage type should in {}".format(
|
||||||
|
', '.join(TYPE_ENGINE_MAPPING.keys()))
|
||||||
|
)
|
||||||
|
engine_class = import_module(TYPE_ENGINE_MAPPING[tp])
|
||||||
|
storage = engine_class.CommandStore(params)
|
||||||
|
storage_list[name] = storage
|
||||||
|
return storage_list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,9 @@ class CommandBase(object):
|
||||||
input=None, session=None):
|
input=None, session=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def count(self, date_from=None, date_to=None,
|
||||||
|
user=None, asset=None, system_user=None,
|
||||||
|
input=None, session=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from .base import CommandBase
|
||||||
|
|
||||||
class CommandStore(CommandBase):
|
class CommandStore(CommandBase):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, params):
|
||||||
from terminal.models import Command
|
from terminal.models import Command
|
||||||
self.model = Command
|
self.model = Command
|
||||||
|
|
||||||
|
@ -37,9 +37,11 @@ class CommandStore(CommandBase):
|
||||||
))
|
))
|
||||||
return self.model.objects.bulk_create(_commands)
|
return self.model.objects.bulk_create(_commands)
|
||||||
|
|
||||||
def filter(self, date_from=None, date_to=None,
|
@staticmethod
|
||||||
user=None, asset=None, system_user=None,
|
def make_filter_kwargs(
|
||||||
input=None, session=None):
|
date_from=None, date_to=None,
|
||||||
|
user=None, asset=None, system_user=None,
|
||||||
|
input=None, session=None):
|
||||||
filter_kwargs = {}
|
filter_kwargs = {}
|
||||||
date_from_default = timezone.now() - datetime.timedelta(days=7)
|
date_from_default = timezone.now() - datetime.timedelta(days=7)
|
||||||
date_to_default = timezone.now()
|
date_to_default = timezone.now()
|
||||||
|
@ -60,10 +62,28 @@ class CommandStore(CommandBase):
|
||||||
if session:
|
if session:
|
||||||
filter_kwargs['session'] = session
|
filter_kwargs['session'] = session
|
||||||
|
|
||||||
|
return filter_kwargs
|
||||||
|
|
||||||
|
def filter(self, date_from=None, date_to=None,
|
||||||
|
user=None, asset=None, system_user=None,
|
||||||
|
input=None, session=None):
|
||||||
|
filter_kwargs = self.make_filter_kwargs(
|
||||||
|
date_from=date_from, date_to=date_to, user=user,
|
||||||
|
asset=asset, system_user=system_user, input=input,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
queryset = self.model.objects.filter(**filter_kwargs)
|
queryset = self.model.objects.filter(**filter_kwargs)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def all(self):
|
def count(self, date_from=None, date_to=None,
|
||||||
"""返回所有数据"""
|
user=None, asset=None, system_user=None,
|
||||||
return self.model.objects.iterator()
|
input=None, session=None):
|
||||||
|
filter_kwargs = self.make_filter_kwargs(
|
||||||
|
date_from=date_from, date_to=date_to, user=user,
|
||||||
|
asset=asset, system_user=system_user, input=input,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
count = self.model.objects.filter(**filter_kwargs).count()
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,5 +18,20 @@ class AbstractSessionCommand(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, d):
|
||||||
|
self = cls()
|
||||||
|
for k, v in d.items():
|
||||||
|
setattr(self, k, v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_multi_dict(cls, l):
|
||||||
|
commands = []
|
||||||
|
for d in l:
|
||||||
|
command = cls.from_dict(d)
|
||||||
|
commands.append(command)
|
||||||
|
return commands
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.input
|
return self.input
|
||||||
|
|
|
@ -10,7 +10,7 @@ from .models import Terminal
|
||||||
class TerminalForm(forms.ModelForm):
|
class TerminalForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Terminal
|
model = Terminal
|
||||||
fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment']
|
fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment', 'command_storage']
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'ssh_port': _("Coco ssh listen port"),
|
'ssh_port': _("Coco ssh listen port"),
|
||||||
'http_port': _("Coco http/ws listen port"),
|
'http_port': _("Coco http/ws listen port"),
|
||||||
|
|
|
@ -4,17 +4,27 @@ import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from .backends.command.models import AbstractSessionCommand
|
from .backends.command.models import AbstractSessionCommand
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_command_storage():
|
||||||
|
storage_choices = []
|
||||||
|
for k, v in settings.TERMINAL_COMMAND_STORAGE.items():
|
||||||
|
storage_choices.append((k, k))
|
||||||
|
return storage_choices
|
||||||
|
|
||||||
|
|
||||||
class Terminal(models.Model):
|
class Terminal(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||||
remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address'))
|
remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address'))
|
||||||
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
|
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
|
||||||
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
|
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
|
||||||
|
command_storage = models.CharField(max_length=128, verbose_name=_("Command storage"), default='default', choices=get_all_command_storage())
|
||||||
|
replay_storage = models.CharField(max_length=128, verbose_name=_("Replay storage"), default='default')
|
||||||
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE)
|
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE)
|
||||||
is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted')
|
is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted')
|
||||||
is_deleted = models.BooleanField(default=False)
|
is_deleted = models.BooleanField(default=False)
|
||||||
|
@ -33,6 +43,16 @@ class Terminal(models.Model):
|
||||||
self.user.is_active = active
|
self.user.is_active = active
|
||||||
self.user.save()
|
self.user.save()
|
||||||
|
|
||||||
|
def get_common_storage(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_replay_storage(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config(self):
|
||||||
|
return
|
||||||
|
|
||||||
def create_app_user(self):
|
def create_app_user(self):
|
||||||
random = uuid.uuid4().hex[:6]
|
random = uuid.uuid4().hex[:6]
|
||||||
user, access_key = User.create_app_user(name="{}-{}".format(self.name, random), comment=self.comment)
|
user, access_key = User.create_app_user(name="{}-{}".format(self.name, random), comment=self.comment)
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.utils import timezone
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import Terminal, Status, Session, Task
|
from .models import Terminal, Status, Session, Task
|
||||||
from .backends import get_command_store
|
from .backends import get_terminal_command_store
|
||||||
|
|
||||||
|
|
||||||
class TerminalSerializer(serializers.ModelSerializer):
|
class TerminalSerializer(serializers.ModelSerializer):
|
||||||
|
@ -43,7 +43,7 @@ class TerminalSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class SessionSerializer(serializers.ModelSerializer):
|
class SessionSerializer(serializers.ModelSerializer):
|
||||||
command_amount = serializers.SerializerMethodField()
|
command_amount = serializers.SerializerMethodField()
|
||||||
command_store = get_command_store()
|
command_store = get_terminal_command_store()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Session
|
model = Session
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
{% bootstrap_field form.remote_addr layout="horizontal" %}
|
{% bootstrap_field form.remote_addr layout="horizontal" %}
|
||||||
{% bootstrap_field form.ssh_port layout="horizontal" %}
|
{% bootstrap_field form.ssh_port layout="horizontal" %}
|
||||||
{% bootstrap_field form.http_port layout="horizontal" %}
|
{% bootstrap_field form.http_port layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.command_storage layout="horizontal" %}
|
||||||
{% bootstrap_field form.comment layout="horizontal" %}
|
{% bootstrap_field form.comment layout="horizontal" %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
{% bootstrap_field form.remote_addr layout="horizontal" %}
|
{% bootstrap_field form.remote_addr layout="horizontal" %}
|
||||||
{% bootstrap_field form.ssh_port layout="horizontal" %}
|
{% bootstrap_field form.ssh_port layout="horizontal" %}
|
||||||
{% bootstrap_field form.http_port layout="horizontal" %}
|
{% bootstrap_field form.http_port layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.command_storage layout="horizontal" %}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans 'Other' %}</h3>
|
<h3>{% trans 'Other' %}</h3>
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
from ..backends import get_command_store
|
from ..backends import get_terminal_command_store
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
command_store = get_command_store()
|
command_store_dict = get_terminal_command_store()
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def get_session_command_amount(session_id):
|
def get_session_command_amount(session_id):
|
||||||
return len(command_store.filter(session=str(session_id)))
|
amount = 0
|
||||||
|
for name, store in command_store_dict.items():
|
||||||
|
amount += store.count(session=str(session_id))
|
||||||
|
return amount
|
||||||
|
|
|
@ -9,10 +9,10 @@ from django.utils.translation import ugettext as _
|
||||||
from common.mixins import DatetimeSearchMixin
|
from common.mixins import DatetimeSearchMixin
|
||||||
from ..models import Command
|
from ..models import Command
|
||||||
from .. import utils
|
from .. import utils
|
||||||
from ..backends import get_command_store
|
from ..backends import get_terminal_command_store
|
||||||
|
|
||||||
__all__ = ['CommandListView']
|
__all__ = ['CommandListView']
|
||||||
command_store = get_command_store()
|
command_store_list = get_terminal_command_store()
|
||||||
|
|
||||||
|
|
||||||
class CommandListView(DatetimeSearchMixin, ListView):
|
class CommandListView(DatetimeSearchMixin, ListView):
|
||||||
|
@ -39,7 +39,10 @@ class CommandListView(DatetimeSearchMixin, ListView):
|
||||||
filter_kwargs['system_user'] = self.system_user
|
filter_kwargs['system_user'] = self.system_user
|
||||||
if self.command:
|
if self.command:
|
||||||
filter_kwargs['input'] = self.command
|
filter_kwargs['input'] = self.command
|
||||||
queryset = command_store.filter(**filter_kwargs)
|
queryset = []
|
||||||
|
for store in command_store_list:
|
||||||
|
queryset.extend(store.filter(**filter_kwargs))
|
||||||
|
queryset = sorted(queryset, key=lambda c: c.timestamp, reverse=True)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.conf import settings
|
||||||
from users.utils import AdminUserRequiredMixin
|
from users.utils import AdminUserRequiredMixin
|
||||||
from common.mixins import DatetimeSearchMixin
|
from common.mixins import DatetimeSearchMixin
|
||||||
from ..models import Session, Command, Terminal
|
from ..models import Session, Command, Terminal
|
||||||
from ..backends import get_command_store
|
from ..backends import get_terminal_command_store
|
||||||
from .. import utils
|
from .. import utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ __all__ = [
|
||||||
'SessionDetailView',
|
'SessionDetailView',
|
||||||
]
|
]
|
||||||
|
|
||||||
command_store = get_command_store()
|
command_store = get_terminal_command_store()
|
||||||
|
|
||||||
|
|
||||||
class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
||||||
|
|
Loading…
Reference in New Issue