Unverified Commit 311538dc authored by 老广's avatar 老广 Committed by GitHub

Bugfix (#2513)

* [Update] 用户页面添加跳转

* [Update] 网关测试支持nat, 修复创建node等id不能指定的问题, 修复settings频繁redis, 没有has_replay录像不可以播放
parent 324cf246
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
__version__ = "1.4.8"
......@@ -51,9 +51,10 @@ class GatewayTestConnectionApi(SingleObjectMixin, APIView):
model = Gateway
object = None
def get(self, request, *args, **kwargs):
def post(self, request, *args, **kwargs):
self.object = self.get_object(Gateway.objects.all())
ok, e = self.object.test_connective()
local_port = self.request.data.get('port') or self.object.port
ok, e = self.object.test_connective(local_port=local_port)
if ok:
return Response("ok")
else:
......
......@@ -97,24 +97,12 @@ class AssetBulkUpdateForm(OrgModelForm):
}
)
)
port = forms.IntegerField(
label=_('Port'), required=False, min_value=1, max_value=65535,
)
admin_user = forms.ModelChoiceField(
required=False, queryset=AdminUser.objects,
label=_("Admin user"),
widget=forms.Select(
attrs={
'class': 'select2',
'data-placeholder': _('Admin user')
}
)
)
class Meta:
model = Asset
fields = [
'assets', 'port', 'admin_user', 'labels', 'nodes', 'platform'
'assets', 'port', 'admin_user', 'labels', 'platform',
'protocol', 'domain',
]
widgets = {
'labels': forms.SelectMultiple(
......@@ -125,6 +113,13 @@ class AssetBulkUpdateForm(OrgModelForm):
),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 重写其他字段为不再required
for name, field in self.fields.items():
if name != 'assets':
field.required = False
def save(self, commit=True):
changed_fields = []
for field in self._meta.fields:
......
......@@ -66,6 +66,9 @@ class GatewayForm(PasswordAndKeyAuthForm, OrgModelForm):
'name', 'ip', 'port', 'username', 'protocol', 'domain', 'password',
'private_key_file', 'is_active', 'comment',
]
help_texts = {
'protocol': _("SSH gateway support proxy SSH,RDP,VNC")
}
widgets = {
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
......
......@@ -60,7 +60,9 @@ class Gateway(AssetUser):
unique_together = [('name', 'org_id')]
verbose_name = _("Gateway")
def test_connective(self):
def test_connective(self, local_port=None):
if local_port is None:
local_port = self.port
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
proxy = paramiko.SSHClient()
......@@ -76,12 +78,11 @@ class Gateway(AssetUser):
paramiko.SSHException) as e:
return False, str(e)
try:
sock = proxy.get_transport().open_channel(
'direct-tcpip', ('127.0.0.1', self.port), ('127.0.0.1', 0)
'direct-tcpip', ('127.0.0.1', local_port), ('127.0.0.1', 0)
)
try:
client.connect("127.0.0.1", port=self.port,
client.connect("127.0.0.1", port=local_port,
username=self.username,
password=self.password,
key_filename=self.private_key_file,
......
# -*- coding: utf-8 -*-
from rest_framework import serializers
from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin
from ..models import Asset, Node
from .asset import AssetGrantedSerializer
__all__ = [
......@@ -22,7 +19,7 @@ class NodeSerializer(serializers.ModelSerializer):
'id', 'key', 'value', 'assets_amount', 'org_id',
]
read_only_fields = [
'id', 'key', 'assets_amount', 'org_id',
'key', 'assets_amount', 'org_id',
]
def validate_value(self, data):
......
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}gateway_test{% endblock %}
{% block modal_title%}{% trans "Test gateway test connection" %}{% endblock %}
{% block modal_body %}
{% load bootstrap3 %}
<form method="post" class="form-horizontal" action="" id="test_gateway_form" style="padding-top: 10px">
<div class="form-group">
<input id="gateway_id" name="gateway_id" hidden>
<label for="port" class="col-sm-2 control-label">{% trans 'SSH Port' %}</label>
<div class="col-sm-9" id="select2-container">
<input id="ssh_test_port" name="port" class="form-control">
<span class="help-block">{% trans 'If use nat, set the ssh real port' %}</span>
</div>
</div>
</form>
{% endblock %}
{% block modal_confirm_id %}btn_gateway_test{% endblock %}
\ No newline at end of file
......@@ -15,10 +15,16 @@
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'assets:domain-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
<a href="{% url 'assets:domain-detail' pk=object.id %}"
class="text-center"><i
class="fa fa-laptop"></i> {% trans 'Detail' %}
</a>
</li>
<li class="active">
<a href="{% url 'assets:domain-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Gateway' %} </a>
<a href="{% url 'assets:domain-detail' pk=object.id %}"
class="text-center"><i
class="fa fa-laptop"></i> {% trans 'Gateway' %}
</a>
</li>
</ul>
</div>
......@@ -33,7 +39,8 @@
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<a class="dropdown-toggle"
data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
......@@ -45,13 +52,17 @@
</div>
<div class="ibox-content">
<div class="uc pull-left m-r-5">
<a href="{% url 'assets:domain-gateway-create' pk=object.id %}" class="btn btn-sm btn-primary"> {% trans "Create gateway" %} </a>
<a href="{% url 'assets:domain-gateway-create' pk=object.id %}"
class="btn btn-sm btn-primary"> {% trans "Create gateway" %} </a>
</div>
<table class="table table-striped table-bordered table-hover " id="domain_list_table" >
<table class="table table-striped table-bordered table-hover "
id="domain_list_table">
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
<input type="checkbox"
id="check_all"
class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
......@@ -73,6 +84,7 @@
</div>
</div>
</div>
{% include 'assets/_gateway_test_modal.html' %}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
......@@ -84,7 +96,7 @@ function initTable() {
{targets: 7, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" data-uid="{{ DEFAULT_PK }}">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" data-uid="{{ DEFAULT_PK }}" data-port="PORT">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData).replace("PORT", rowData.port);
if(rowData.protocol === 'rdp'){
test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" disabled data-uid="{{ DEFAULT_PK }}">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
}
......@@ -114,12 +126,18 @@ $(document).ready(function(){
$data_table.ajax.reload();
}, 3000);
}).on('click', '.btn-test', function () {
var $this = $(this);
var uid = $this.data('uid');
$("#ssh_test_port").val($(this).data('port'));
$("#gateway_id").val($(this).data('uid'));
$("#gateway_test").modal('show');
}).on('click', '#btn_gateway_test', function () {
var data = $("#test_gateway_form").serializeObject();
var uid = data.gateway_id;
var the_url = '{% url "api-assets:test-gateway-connective" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
APIUpdateAttr({
url: the_url,
method: "GET",
method: "POST",
body: JSON.stringify({'port': parseInt(data.port)}),
success_message: "{% trans 'Can be connected' %}",
fail_message: "{% trans 'The connection fails' %}"
})
......
......@@ -45,6 +45,7 @@
<th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'Active' %}</th>
<th class="text-center">{% trans 'System users' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
......@@ -94,13 +95,18 @@ function initTable() {
users.push(data.name);
});
$(td).html(users.join(', '))
}},
{targets: 5, createdCell: function (td, cellData) {
var conn_btn = '<a href="{% url "luna-view" %}?login_to=' + cellData +'" class="btn btn-xs btn-primary">{% trans "Connect" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
$(td).html(conn_btn)
}}
],
ajax_url: url,
columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" },
{data: "is_active", orderable: false },
{data: "system_users_granted", orderable: false}
{data: "system_users_granted", orderable: false},
{data: "id", orderable: false}
]
};
asset_table = jumpserver.initServerSideDataTable(options);
......
......@@ -22,6 +22,10 @@ from .conf import load_user_config
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.dirname(BASE_DIR)
sys.path.append(PROJECT_DIR)
from apps import __version__
VERSION = __version__
CONFIG = load_user_config()
LOG_DIR = os.path.join(PROJECT_DIR, 'logs')
JUMPSERVER_LOG_FILE = os.path.join(LOG_DIR, 'jumpserver.log')
......@@ -456,8 +460,8 @@ CELERY_ACCEPT_CONTENT = ['json', 'pickle']
CELERY_RESULT_EXPIRES = 3600
# CELERY_WORKER_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s'
# CELERY_WORKER_LOG_FORMAT = '%(message)s'
CELERY_WORKER_TASK_LOG_FORMAT = '%(task_id)s %(task_name)s %(message)s'
# CELERY_WORKER_TASK_LOG_FORMAT = '%(message)s'
# CELERY_WORKER_TASK_LOG_FORMAT = '%(task_id)s %(task_name)s %(message)s'
CELERY_WORKER_TASK_LOG_FORMAT = '%(message)s'
# CELERY_WORKER_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s'
CELERY_WORKER_LOG_FORMAT = '%(message)s'
CELERY_TASK_EAGER_PROPAGATES = True
......
......@@ -60,7 +60,7 @@ urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('', include(api_v2_patterns)),
path('', include(api_v1_patterns)),
path('luna/', LunaView.as_view(), name='luna-error'),
path('luna/', LunaView.as_view(), name='luna-view'),
path('i18n/<str:lang>/', I18NView.as_view(), name='i18n-switch'),
path('settings/', include('settings.urls.view_urls', namespace='settings')),
# path('api/v2/', include(api_v2_patterns)),
......
This diff is collapsed.
......@@ -31,7 +31,7 @@ class CommandExecution(models.Model):
@property
def inventory(self):
return JMSInventory(self.hosts.all(), run_as=self.run_as)
return JMSInventory(self.hosts.all(), run_as=self.run_as.username)
@property
def result(self):
......
......@@ -75,7 +75,7 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
'is_finished', 'date_created', 'date_finished'
]
read_only_fields = [
'id', 'result', 'is_finished', 'log_url', 'date_created',
'result', 'is_finished', 'log_url', 'date_created',
'date_finished'
]
......
......@@ -16,7 +16,7 @@ class OrgSerializer(ModelSerializer):
model = Organization
list_serializer_class = BulkListSerializer
fields = '__all__'
read_only_fields = ['id', 'created_by', 'date_created']
read_only_fields = ['created_by', 'date_created']
class OrgReadSerializer(ModelSerializer):
......
......@@ -4,7 +4,7 @@ import json
from django.dispatch import receiver
from django.db.models.signals import post_save, pre_save
from django.conf import LazySettings, empty
from django.conf import LazySettings, empty, global_settings
from django.db.utils import ProgrammingError, OperationalError
from django.core.cache import cache
......@@ -25,11 +25,18 @@ def refresh_settings_on_changed(sender, instance=None, **kwargs):
@receiver(django_ready, dispatch_uid="my_unique_identifier")
def monkey_patch_settings(sender, **kwargs):
cache_key_prefix = '_SETTING_'
uncached_settings = [
'CACHES', 'DEBUG', 'SECRET_KEY', 'INSTALLED_APPS',
'ROOT_URLCONF', 'TEMPLATES', 'DATABASES', '_wrapped',
'CELERY_LOG_DIR'
custom_need_cache_settings = [
'AUTHENTICATION_BACKENDS'
]
custom_no_cache_settings = [
'BASE_DIR', 'VERSION', 'AUTH_OPENID'
]
django_settings = dir(global_settings)
uncached_settings = [i for i in django_settings if i.isupper()]
uncached_settings = [i for i in uncached_settings if not i.startswith('EMAIL')]
uncached_settings = [i for i in uncached_settings if not i.startswith('SESSION_REDIS')]
uncached_settings = [i for i in uncached_settings if i not in custom_need_cache_settings]
uncached_settings.extend(custom_no_cache_settings)
def monkey_patch_getattr(self, name):
if name not in uncached_settings:
......
......@@ -188,6 +188,14 @@ class Session(OrgModelMixin):
local_path = rel_path
return local_path
def can_replay(self):
if self.has_replay:
return True
version = settings.VERSION.split('.')
if [int(i) for i in version] > [1, 4, 8]:
return False
return True
def save_to_storage(self, f):
local_path = self.get_local_path()
try:
......
......@@ -21,7 +21,7 @@ class TerminalSerializer(serializers.ModelSerializer):
'replay_storage', 'user', 'is_accepted', 'is_deleted',
'date_created', 'comment'
]
read_only_fields = ['id', 'remote_addr', 'user', 'date_created']
read_only_fields = ['remote_addr', 'user', 'date_created']
def is_valid(self, raise_exception=False):
valid = super().is_valid(raise_exception=raise_exception)
......
......@@ -101,9 +101,8 @@
<td class="text-center">{{ session.date_start|time_util_with_seconds:session.date_end }}</td>
<td>
{% if session.is_finished %}
<a onclick="window.open('/luna/replay/{{ session.id }}','luna', 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-replay" >{% trans "Replay" %}</a>
<a {% if not session.can_replay %} disabled="" {% endif %} onclick="window.open('/luna/replay/{{ session.id }}','luna', 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-replay" >{% trans "Replay" %}</a>
{% else %}
<!--<a onclick="window.open('/luna/monitor/{{ session.id }}','luna', 'height=600, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-monitor" >{% trans "Monitor" %}</a>-->
{% if session.protocol == 'ssh' %}
<a class="btn btn-xs btn-danger btn-term" value="{{ session.id }}" terminal="{{ session.terminal.id }}" >{% trans "Terminate" %}</a>
{% else %}
......
......@@ -54,7 +54,7 @@ class UserGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
model = UserGroup
list_serializer_class = BulkListSerializer
fields = '__all__'
read_only_fields = ['id', 'created_by']
read_only_fields = ['created_by']
@staticmethod
def get_users(obj):
......
......@@ -15,7 +15,7 @@ class ServiceAccountSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'access_key']
read_only_fields = ['id', 'access_key']
read_only_fields = ['access_key']
def get_username(self):
return self.initial_data.get('name')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment