Api (#2439)
* [Update] 迁移settings到独立app * [Update] 修改settings migrations * [Update] 修改docs说明
@ -1,197 +1,17 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
import jms_storage
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from rest_framework.views import Response, APIView
|
from rest_framework.views import Response
|
||||||
from rest_framework import generics
|
from rest_framework import generics, serializers
|
||||||
from ldap3 import Server, Connection
|
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from .permissions import IsOrgAdmin, IsSuperUser
|
|
||||||
from .serializers import (
|
|
||||||
MailTestSerializer, LDAPTestSerializer, OutputSerializer
|
|
||||||
)
|
|
||||||
from .models import Setting
|
|
||||||
|
|
||||||
|
|
||||||
class MailTestingAPI(APIView):
|
class OutputSerializer(serializers.Serializer):
|
||||||
permission_classes = (IsOrgAdmin,)
|
output = serializers.CharField()
|
||||||
serializer_class = MailTestSerializer
|
is_end = serializers.BooleanField()
|
||||||
success_message = _("Test mail sent to {}, please check")
|
mark = serializers.CharField()
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = self.serializer_class(data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
email_host_user = serializer.validated_data["EMAIL_HOST_USER"]
|
|
||||||
for k, v in serializer.validated_data.items():
|
|
||||||
if k.startswith('EMAIL'):
|
|
||||||
setattr(settings, k, v)
|
|
||||||
try:
|
|
||||||
subject = "Test"
|
|
||||||
message = "Test smtp setting"
|
|
||||||
send_mail(subject, message, email_host_user, [email_host_user])
|
|
||||||
except Exception as e:
|
|
||||||
return Response({"error": str(e)}, status=401)
|
|
||||||
|
|
||||||
return Response({"msg": self.success_message.format(email_host_user)})
|
|
||||||
else:
|
|
||||||
return Response({"error": str(serializer.errors)}, status=401)
|
|
||||||
|
|
||||||
|
|
||||||
class LDAPTestingAPI(APIView):
|
|
||||||
permission_classes = (IsOrgAdmin,)
|
|
||||||
serializer_class = LDAPTestSerializer
|
|
||||||
success_message = _("Test ldap success")
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = self.serializer_class(data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
host = serializer.validated_data["AUTH_LDAP_SERVER_URI"]
|
|
||||||
bind_dn = serializer.validated_data["AUTH_LDAP_BIND_DN"]
|
|
||||||
password = serializer.validated_data["AUTH_LDAP_BIND_PASSWORD"]
|
|
||||||
use_ssl = serializer.validated_data.get("AUTH_LDAP_START_TLS", False)
|
|
||||||
search_ougroup = serializer.validated_data["AUTH_LDAP_SEARCH_OU"]
|
|
||||||
search_filter = serializer.validated_data["AUTH_LDAP_SEARCH_FILTER"]
|
|
||||||
attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
|
|
||||||
|
|
||||||
try:
|
|
||||||
attr_map = json.loads(attr_map)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
return Response({"error": "AUTH_LDAP_USER_ATTR_MAP not valid"}, status=401)
|
|
||||||
|
|
||||||
server = Server(host, use_ssl=use_ssl)
|
|
||||||
conn = Connection(server, bind_dn, password)
|
|
||||||
try:
|
|
||||||
conn.bind()
|
|
||||||
except Exception as e:
|
|
||||||
return Response({"error": str(e)}, status=401)
|
|
||||||
|
|
||||||
users = []
|
|
||||||
for search_ou in str(search_ougroup).split("|"):
|
|
||||||
ok = conn.search(search_ou, search_filter % ({"user": "*"}),
|
|
||||||
attributes=list(attr_map.values()))
|
|
||||||
if not ok:
|
|
||||||
return Response({"error": _("Search no entry matched in ou {}").format(search_ou)}, status=401)
|
|
||||||
|
|
||||||
for entry in conn.entries:
|
|
||||||
user = {}
|
|
||||||
for attr, mapping in attr_map.items():
|
|
||||||
if hasattr(entry, mapping):
|
|
||||||
user[attr] = getattr(entry, mapping)
|
|
||||||
users.append(user)
|
|
||||||
if len(users) > 0:
|
|
||||||
return Response({"msg": _("Match {} s users").format(len(users))})
|
|
||||||
else:
|
|
||||||
return Response({"error": "Have user but attr mapping error"}, status=401)
|
|
||||||
else:
|
|
||||||
return Response({"error": str(serializer.errors)}, status=401)
|
|
||||||
|
|
||||||
|
|
||||||
class ReplayStorageCreateAPI(APIView):
|
|
||||||
permission_classes = (IsSuperUser,)
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
storage_data = request.data
|
|
||||||
|
|
||||||
if storage_data.get('TYPE') == 'ceph':
|
|
||||||
port = storage_data.get('PORT')
|
|
||||||
if port.isdigit():
|
|
||||||
storage_data['PORT'] = int(storage_data.get('PORT'))
|
|
||||||
|
|
||||||
storage_name = storage_data.pop('NAME')
|
|
||||||
data = {storage_name: storage_data}
|
|
||||||
|
|
||||||
if not self.is_valid(storage_data):
|
|
||||||
return Response({
|
|
||||||
"error": _("Error: Account invalid (Please make sure the "
|
|
||||||
"information such as Access key or Secret key is correct)")},
|
|
||||||
status=401
|
|
||||||
)
|
|
||||||
|
|
||||||
Setting.save_storage('TERMINAL_REPLAY_STORAGE', data)
|
|
||||||
return Response({"msg": _('Create succeed')}, status=200)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_valid(storage_data):
|
|
||||||
if storage_data.get('TYPE') == 'server':
|
|
||||||
return True
|
|
||||||
storage = jms_storage.get_object_storage(storage_data)
|
|
||||||
target = 'tests.py'
|
|
||||||
src = os.path.join(settings.BASE_DIR, 'common', target)
|
|
||||||
return storage.is_valid(src, target)
|
|
||||||
|
|
||||||
|
|
||||||
class ReplayStorageDeleteAPI(APIView):
|
|
||||||
permission_classes = (IsSuperUser,)
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
storage_name = str(request.data.get('name'))
|
|
||||||
Setting.delete_storage('TERMINAL_REPLAY_STORAGE', storage_name)
|
|
||||||
return Response({"msg": _('Delete succeed')}, status=200)
|
|
||||||
|
|
||||||
|
|
||||||
class CommandStorageCreateAPI(APIView):
|
|
||||||
permission_classes = (IsSuperUser,)
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
storage_data = request.data
|
|
||||||
storage_name = storage_data.pop('NAME')
|
|
||||||
data = {storage_name: storage_data}
|
|
||||||
if not self.is_valid(storage_data):
|
|
||||||
return Response(
|
|
||||||
{"error": _("Error: Account invalid (Please make sure the "
|
|
||||||
"information such as Access key or Secret key is correct)")},
|
|
||||||
status=401
|
|
||||||
)
|
|
||||||
|
|
||||||
Setting.save_storage('TERMINAL_COMMAND_STORAGE', data)
|
|
||||||
return Response({"msg": _('Create succeed')}, status=200)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_valid(storage_data):
|
|
||||||
if storage_data.get('TYPE') == 'server':
|
|
||||||
return True
|
|
||||||
try:
|
|
||||||
storage = jms_storage.get_log_storage(storage_data)
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return storage.ping()
|
|
||||||
|
|
||||||
|
|
||||||
class CommandStorageDeleteAPI(APIView):
|
|
||||||
permission_classes = (IsSuperUser,)
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
storage_name = str(request.data.get('name'))
|
|
||||||
Setting.delete_storage('TERMINAL_COMMAND_STORAGE', storage_name)
|
|
||||||
return Response({"msg": _('Delete succeed')}, status=200)
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoSettingsAPI(APIView):
|
|
||||||
def get(self, request):
|
|
||||||
if not settings.DEBUG:
|
|
||||||
return Response("Not in debug mode")
|
|
||||||
|
|
||||||
data = {}
|
|
||||||
for i in [settings, getattr(settings, '_wrapped')]:
|
|
||||||
if not i:
|
|
||||||
continue
|
|
||||||
for k, v in i.__dict__.items():
|
|
||||||
if k and k.isupper():
|
|
||||||
try:
|
|
||||||
json.dumps(v)
|
|
||||||
data[k] = v
|
|
||||||
except (json.JSONDecodeError, TypeError):
|
|
||||||
data[k] = str(v)
|
|
||||||
return Response(data)
|
|
||||||
|
|
||||||
|
|
||||||
class LogTailApi(generics.RetrieveAPIView):
|
class LogTailApi(generics.RetrieveAPIView):
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import sys
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.db.backends.signals import connection_created
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(connection_created, dispatch_uid="my_unique_identifier")
|
||||||
|
def on_db_connection_ready(sender, **kwargs):
|
||||||
|
from .signals import django_ready
|
||||||
|
if 'migrate' not in sys.argv:
|
||||||
|
django_ready.send(CommonConfig)
|
||||||
|
|
||||||
|
|
||||||
class CommonConfig(AppConfig):
|
class CommonConfig(AppConfig):
|
||||||
name = 'common'
|
name = 'common'
|
||||||
|
|
||||||
def ready(self):
|
|
||||||
from . import signals_handler
|
|
||||||
from .signals import django_ready
|
|
||||||
django_ready.send(self.__class__)
|
|
||||||
return super().ready()
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11 on 2018-01-11 06:07
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('common', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameModel(
|
|
||||||
old_name='Settings',
|
|
||||||
new_name='Setting',
|
|
||||||
),
|
|
||||||
migrations.AlterModelManagers(
|
|
||||||
name='setting',
|
|
||||||
managers=[
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.AlterModelTable(
|
|
||||||
name='setting',
|
|
||||||
table='settings',
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,20 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11 on 2018-01-22 03:54
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('common', '0002_auto_20180111_1407'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='setting',
|
|
||||||
name='category',
|
|
||||||
field=models.CharField(default='default', max_length=128),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 2.1 on 2018-09-03 03:32
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('common', '0003_setting_category'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='setting',
|
|
||||||
name='encrypted',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,17 +0,0 @@
|
|||||||
# Generated by Django 2.1.7 on 2019-02-21 11:02
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('common', '0004_setting_encrypted'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='setting',
|
|
||||||
options={'verbose_name': 'Setting'},
|
|
||||||
),
|
|
||||||
]
|
|
@ -2,7 +2,6 @@ from django.core.mail import send_mail
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from .utils import get_logger
|
from .utils import get_logger
|
||||||
from .models import Setting
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
@ -59,6 +59,7 @@ INSTALLED_APPS = [
|
|||||||
'assets.apps.AssetsConfig',
|
'assets.apps.AssetsConfig',
|
||||||
'perms.apps.PermsConfig',
|
'perms.apps.PermsConfig',
|
||||||
'ops.apps.OpsConfig',
|
'ops.apps.OpsConfig',
|
||||||
|
'settings.apps.SettingsConfig',
|
||||||
'common.apps.CommonConfig',
|
'common.apps.CommonConfig',
|
||||||
'terminal.apps.TerminalConfig',
|
'terminal.apps.TerminalConfig',
|
||||||
'audits.apps.AuditsConfig',
|
'audits.apps.AuditsConfig',
|
||||||
|
@ -20,7 +20,7 @@ api_v1_patterns = [
|
|||||||
path('ops/v1/', include('ops.urls.api_urls', namespace='api-ops')),
|
path('ops/v1/', include('ops.urls.api_urls', namespace='api-ops')),
|
||||||
path('audits/v1/', include('audits.urls.api_urls', namespace='api-audits')),
|
path('audits/v1/', include('audits.urls.api_urls', namespace='api-audits')),
|
||||||
path('orgs/v1/', include('orgs.urls.api_urls', namespace='api-orgs')),
|
path('orgs/v1/', include('orgs.urls.api_urls', namespace='api-orgs')),
|
||||||
path('common/v1/', include('common.urls.api_urls', namespace='api-common')),
|
path('settings/v1/', include('settings.urls.api_urls', namespace='api-settings')),
|
||||||
]))
|
]))
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -56,8 +56,7 @@ urlpatterns = [
|
|||||||
path('', include(api_v1_patterns)),
|
path('', include(api_v1_patterns)),
|
||||||
path('luna/', LunaView.as_view(), name='luna-error'),
|
path('luna/', LunaView.as_view(), name='luna-error'),
|
||||||
path('i18n/<str:lang>/', I18NView.as_view(), name='i18n-switch'),
|
path('i18n/<str:lang>/', I18NView.as_view(), name='i18n-switch'),
|
||||||
path('settings/', include('common.urls.view_urls', namespace='settings')),
|
path('settings/', include('settings.urls.view_urls', namespace='settings')),
|
||||||
path('common/', include('common.urls.view_urls', namespace='common')),
|
|
||||||
# path('api/v2/', include(api_v2_patterns)),
|
# path('api/v2/', include(api_v2_patterns)),
|
||||||
|
|
||||||
# External apps url
|
# External apps url
|
||||||
|
0
apps/settings/__init__.py
Normal file
3
apps/settings/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
194
apps/settings/api.py
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import jms_storage
|
||||||
|
|
||||||
|
from rest_framework.views import Response, APIView
|
||||||
|
from ldap3 import Server, Connection
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from common.permissions import IsOrgAdmin, IsSuperUser
|
||||||
|
from .serializers import (
|
||||||
|
MailTestSerializer, LDAPTestSerializer
|
||||||
|
)
|
||||||
|
from .models import Setting
|
||||||
|
|
||||||
|
|
||||||
|
class MailTestingAPI(APIView):
|
||||||
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
serializer_class = MailTestSerializer
|
||||||
|
success_message = _("Test mail sent to {}, please check")
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
serializer = self.serializer_class(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
email_host_user = serializer.validated_data["EMAIL_HOST_USER"]
|
||||||
|
for k, v in serializer.validated_data.items():
|
||||||
|
if k.startswith('EMAIL'):
|
||||||
|
setattr(settings, k, v)
|
||||||
|
try:
|
||||||
|
subject = "Test"
|
||||||
|
message = "Test smtp setting"
|
||||||
|
send_mail(subject, message, email_host_user, [email_host_user])
|
||||||
|
except Exception as e:
|
||||||
|
return Response({"error": str(e)}, status=401)
|
||||||
|
|
||||||
|
return Response({"msg": self.success_message.format(email_host_user)})
|
||||||
|
else:
|
||||||
|
return Response({"error": str(serializer.errors)}, status=401)
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPTestingAPI(APIView):
|
||||||
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
serializer_class = LDAPTestSerializer
|
||||||
|
success_message = _("Test ldap success")
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
serializer = self.serializer_class(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
host = serializer.validated_data["AUTH_LDAP_SERVER_URI"]
|
||||||
|
bind_dn = serializer.validated_data["AUTH_LDAP_BIND_DN"]
|
||||||
|
password = serializer.validated_data["AUTH_LDAP_BIND_PASSWORD"]
|
||||||
|
use_ssl = serializer.validated_data.get("AUTH_LDAP_START_TLS", False)
|
||||||
|
search_ougroup = serializer.validated_data["AUTH_LDAP_SEARCH_OU"]
|
||||||
|
search_filter = serializer.validated_data["AUTH_LDAP_SEARCH_FILTER"]
|
||||||
|
attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
attr_map = json.loads(attr_map)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return Response({"error": "AUTH_LDAP_USER_ATTR_MAP not valid"}, status=401)
|
||||||
|
|
||||||
|
server = Server(host, use_ssl=use_ssl)
|
||||||
|
conn = Connection(server, bind_dn, password)
|
||||||
|
try:
|
||||||
|
conn.bind()
|
||||||
|
except Exception as e:
|
||||||
|
return Response({"error": str(e)}, status=401)
|
||||||
|
|
||||||
|
users = []
|
||||||
|
for search_ou in str(search_ougroup).split("|"):
|
||||||
|
ok = conn.search(search_ou, search_filter % ({"user": "*"}),
|
||||||
|
attributes=list(attr_map.values()))
|
||||||
|
if not ok:
|
||||||
|
return Response({"error": _("Search no entry matched in ou {}").format(search_ou)}, status=401)
|
||||||
|
|
||||||
|
for entry in conn.entries:
|
||||||
|
user = {}
|
||||||
|
for attr, mapping in attr_map.items():
|
||||||
|
if hasattr(entry, mapping):
|
||||||
|
user[attr] = getattr(entry, mapping)
|
||||||
|
users.append(user)
|
||||||
|
if len(users) > 0:
|
||||||
|
return Response({"msg": _("Match {} s users").format(len(users))})
|
||||||
|
else:
|
||||||
|
return Response({"error": "Have user but attr mapping error"}, status=401)
|
||||||
|
else:
|
||||||
|
return Response({"error": str(serializer.errors)}, status=401)
|
||||||
|
|
||||||
|
|
||||||
|
class ReplayStorageCreateAPI(APIView):
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
storage_data = request.data
|
||||||
|
|
||||||
|
if storage_data.get('TYPE') == 'ceph':
|
||||||
|
port = storage_data.get('PORT')
|
||||||
|
if port.isdigit():
|
||||||
|
storage_data['PORT'] = int(storage_data.get('PORT'))
|
||||||
|
|
||||||
|
storage_name = storage_data.pop('NAME')
|
||||||
|
data = {storage_name: storage_data}
|
||||||
|
|
||||||
|
if not self.is_valid(storage_data):
|
||||||
|
return Response({
|
||||||
|
"error": _("Error: Account invalid (Please make sure the "
|
||||||
|
"information such as Access key or Secret key is correct)")},
|
||||||
|
status=401
|
||||||
|
)
|
||||||
|
|
||||||
|
Setting.save_storage('TERMINAL_REPLAY_STORAGE', data)
|
||||||
|
return Response({"msg": _('Create succeed')}, status=200)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_valid(storage_data):
|
||||||
|
if storage_data.get('TYPE') == 'server':
|
||||||
|
return True
|
||||||
|
storage = jms_storage.get_object_storage(storage_data)
|
||||||
|
target = 'tests.py'
|
||||||
|
src = os.path.join(settings.BASE_DIR, 'common', target)
|
||||||
|
return storage.is_valid(src, target)
|
||||||
|
|
||||||
|
|
||||||
|
class ReplayStorageDeleteAPI(APIView):
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
storage_name = str(request.data.get('name'))
|
||||||
|
Setting.delete_storage('TERMINAL_REPLAY_STORAGE', storage_name)
|
||||||
|
return Response({"msg": _('Delete succeed')}, status=200)
|
||||||
|
|
||||||
|
|
||||||
|
class CommandStorageCreateAPI(APIView):
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
storage_data = request.data
|
||||||
|
storage_name = storage_data.pop('NAME')
|
||||||
|
data = {storage_name: storage_data}
|
||||||
|
if not self.is_valid(storage_data):
|
||||||
|
return Response(
|
||||||
|
{"error": _("Error: Account invalid (Please make sure the "
|
||||||
|
"information such as Access key or Secret key is correct)")},
|
||||||
|
status=401
|
||||||
|
)
|
||||||
|
|
||||||
|
Setting.save_storage('TERMINAL_COMMAND_STORAGE', data)
|
||||||
|
return Response({"msg": _('Create succeed')}, status=200)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_valid(storage_data):
|
||||||
|
if storage_data.get('TYPE') == 'server':
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
storage = jms_storage.get_log_storage(storage_data)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return storage.ping()
|
||||||
|
|
||||||
|
|
||||||
|
class CommandStorageDeleteAPI(APIView):
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
storage_name = str(request.data.get('name'))
|
||||||
|
Setting.delete_storage('TERMINAL_COMMAND_STORAGE', storage_name)
|
||||||
|
return Response({"msg": _('Delete succeed')}, status=200)
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoSettingsAPI(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
if not settings.DEBUG:
|
||||||
|
return Response("Not in debug mode")
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
for i in [settings, getattr(settings, '_wrapped')]:
|
||||||
|
if not i:
|
||||||
|
continue
|
||||||
|
for k, v in i.__dict__.items():
|
||||||
|
if k and k.isupper():
|
||||||
|
try:
|
||||||
|
json.dumps(v)
|
||||||
|
data[k] = v
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
data[k] = str(v)
|
||||||
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
8
apps/settings/apps.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsConfig(AppConfig):
|
||||||
|
name = 'settings'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
from . import signals_handler
|
@ -6,8 +6,9 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from .models import Setting, settings
|
from .models import Setting, settings
|
||||||
from .fields import FormDictField, FormEncryptCharField, \
|
from common.fields import (
|
||||||
FormEncryptMixin
|
FormDictField, FormEncryptCharField, FormEncryptMixin
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseForm(forms.Form):
|
class BaseForm(forms.Form):
|
@ -1,9 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# Generated by Django 2.1.7 on 2019-02-26 03:11
|
||||||
# Generated by Django 1.11 on 2018-01-11 05:35
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.manager
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@ -15,16 +12,19 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Settings',
|
name='Setting',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('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(default='default', max_length=128)),
|
||||||
|
('encrypted', models.BooleanField(default=False)),
|
||||||
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
||||||
('comment', models.TextField(verbose_name='Comment')),
|
('comment', models.TextField(verbose_name='Comment')),
|
||||||
],
|
],
|
||||||
managers=[
|
options={
|
||||||
('configs', django.db.models.manager.Manager()),
|
'verbose_name': 'Setting',
|
||||||
],
|
'db_table': 'setting',
|
||||||
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
17
apps/settings/migrations/0002_migrate_data.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from django.db import migrations, connection
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("settings", "0001_initial"),
|
||||||
|
]
|
||||||
|
sql = "INSERT INTO setting(name, value, category, encrypted, enabled, comment) " \
|
||||||
|
"SELECT name, value, category, encrypted, enabled, comment from settings"
|
||||||
|
settings_table_exist = 'settings' in connection.introspection.table_names()
|
||||||
|
|
||||||
|
operations = []
|
||||||
|
if settings_table_exist:
|
||||||
|
operations.append(migrations.RunSQL(sql))
|
0
apps/settings/migrations/__init__.py
Normal file
@ -6,7 +6,7 @@ from django.db.utils import ProgrammingError, OperationalError
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .utils import get_signer
|
from common.utils import get_signer
|
||||||
|
|
||||||
signer = get_signer()
|
signer = get_signer()
|
||||||
|
|
||||||
@ -122,5 +122,5 @@ class Setting(models.Model):
|
|||||||
settings.AUTHENTICATION_BACKENDS = old_setting
|
settings.AUTHENTICATION_BACKENDS = old_setting
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "settings"
|
db_table = "setting"
|
||||||
verbose_name = _("Setting")
|
verbose_name = _("Setting")
|
@ -20,7 +20,4 @@ class LDAPTestSerializer(serializers.Serializer):
|
|||||||
AUTH_LDAP_START_TLS = serializers.BooleanField(required=False)
|
AUTH_LDAP_START_TLS = serializers.BooleanField(required=False)
|
||||||
|
|
||||||
|
|
||||||
class OutputSerializer(serializers.Serializer):
|
|
||||||
output = serializers.CharField()
|
|
||||||
is_end = serializers.BooleanField()
|
|
||||||
mark = serializers.CharField()
|
|
@ -3,15 +3,15 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db.models.signals import post_save, pre_save
|
from django.db.models.signals import post_save, pre_save, pre_migrate
|
||||||
from django.conf import LazySettings, empty
|
from django.conf import LazySettings, empty
|
||||||
from django.db.utils import ProgrammingError, OperationalError
|
from django.db.utils import ProgrammingError, OperationalError
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
from jumpserver.utils import current_request
|
from jumpserver.utils import current_request
|
||||||
|
from common.utils import get_logger, ssh_key_gen
|
||||||
|
from common.signals import django_ready
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
from .utils import get_logger, ssh_key_gen
|
|
||||||
from .signals import django_ready
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
@ -159,10 +159,10 @@ $(document).ready(function() {
|
|||||||
data[name] = value
|
data[name] = value
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var url = "{% url 'api-common:command-storage-create' %}";
|
var url = "{% url 'api-settings:command-storage-create' %}";
|
||||||
var success = function(data, textStatus) {
|
var success = function(data, textStatus) {
|
||||||
console.log(data, textStatus);
|
console.log(data, textStatus);
|
||||||
location = "{% url 'common:terminal-setting' %}";
|
location = "{% url 'settings:terminal-setting' %}";
|
||||||
};
|
};
|
||||||
var error = function(data, textStatus) {
|
var error = function(data, textStatus) {
|
||||||
var error_msg = data.responseJSON.error;
|
var error_msg = data.responseJSON.error;
|
@ -84,7 +84,7 @@ $(document).ready(function () {
|
|||||||
data[field.name] = field.value;
|
data[field.name] = field.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
var the_url = "{% url 'api-common:mail-testing' %}";
|
var the_url = "{% url 'api-settings:mail-testing' %}";
|
||||||
|
|
||||||
function error(message) {
|
function error(message) {
|
||||||
toastr.error(message)
|
toastr.error(message)
|
@ -84,7 +84,7 @@ $(document).ready(function () {
|
|||||||
data[field.name] = field.value;
|
data[field.name] = field.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
var the_url = "{% url 'api-common:ldap-testing' %}";
|
var the_url = "{% url 'api-settings:ldap-testing' %}";
|
||||||
|
|
||||||
function error(message) {
|
function error(message) {
|
||||||
toastr.error(message)
|
toastr.error(message)
|
@ -251,9 +251,9 @@ $(document).ready(function() {
|
|||||||
var name = $(id_field).attr('name');
|
var name = $(id_field).attr('name');
|
||||||
data[name] = $(id_field).val();
|
data[name] = $(id_field).val();
|
||||||
});
|
});
|
||||||
var url = "{% url 'api-common:replay-storage-create' %}";
|
var url = "{% url 'api-settings:replay-storage-create' %}";
|
||||||
var success = function(data, textStatus) {
|
var success = function(data, textStatus) {
|
||||||
location = "{% url 'common:terminal-setting' %}";
|
location = "{% url 'settings:terminal-setting' %}";
|
||||||
submitBtn.removeClass('disabled');
|
submitBtn.removeClass('disabled');
|
||||||
submitBtn.html(origin_text);
|
submitBtn.html(origin_text);
|
||||||
};
|
};
|
@ -92,7 +92,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<a href="{% url 'common:command-storage-create' %}" class="btn btn-primary btn-xs">{% trans 'Add' %}</a>
|
<a href="{% url 'settings:command-storage-create' %}" class="btn btn-primary btn-xs">{% trans 'Add' %}</a>
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans "Replay storage" %}</h3>
|
<h3>{% trans "Replay storage" %}</h3>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<a href="{% url 'common:replay-storage-create' %}" class="btn btn-primary btn-xs">{% trans 'Add' %}</a>
|
<a href="{% url 'settings:replay-storage-create' %}" class="btn btn-primary btn-xs">{% trans 'Add' %}</a>
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
</form>
|
</form>
|
||||||
@ -174,12 +174,12 @@ $(document).ready(function () {
|
|||||||
})
|
})
|
||||||
.on('click', '.btn-del-replay', function(){
|
.on('click', '.btn-del-replay', function(){
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var the_url = "{% url 'api-common:replay-storage-delete' %}";
|
var the_url = "{% url 'api-settings:replay-storage-delete' %}";
|
||||||
deleteStorage($this, the_url);
|
deleteStorage($this, the_url);
|
||||||
})
|
})
|
||||||
.on('click', '.btn-del-command', function() {
|
.on('click', '.btn-del-command', function() {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var the_url = "{% url 'api-common:command-storage-delete' %}";
|
var the_url = "{% url 'api-settings:command-storage-delete' %}";
|
||||||
deleteStorage($this, the_url)
|
deleteStorage($this, the_url)
|
||||||
});
|
});
|
||||||
|
|
3
apps/settings/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
@ -3,15 +3,15 @@ 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 common.permissions import SuperUserRequiredMixin
|
||||||
|
from common import utils
|
||||||
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
||||||
TerminalSettingForm, SecuritySettingForm
|
TerminalSettingForm, SecuritySettingForm
|
||||||
from common.permissions import SuperUserRequiredMixin
|
|
||||||
from . import utils
|
|
||||||
|
|
||||||
|
|
||||||
class BasicSettingView(SuperUserRequiredMixin, TemplateView):
|
class BasicSettingView(SuperUserRequiredMixin, TemplateView):
|
||||||
form_class = BasicSettingForm
|
form_class = BasicSettingForm
|
||||||
template_name = "common/basic_setting.html"
|
template_name = "settings/basic_setting.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
@ -37,7 +37,7 @@ class BasicSettingView(SuperUserRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
class EmailSettingView(SuperUserRequiredMixin, TemplateView):
|
class EmailSettingView(SuperUserRequiredMixin, TemplateView):
|
||||||
form_class = EmailSettingForm
|
form_class = EmailSettingForm
|
||||||
template_name = "common/email_setting.html"
|
template_name = "settings/email_setting.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
@ -63,7 +63,7 @@ class EmailSettingView(SuperUserRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
class LDAPSettingView(SuperUserRequiredMixin, TemplateView):
|
class LDAPSettingView(SuperUserRequiredMixin, TemplateView):
|
||||||
form_class = LDAPSettingForm
|
form_class = LDAPSettingForm
|
||||||
template_name = "common/ldap_setting.html"
|
template_name = "settings/ldap_setting.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
@ -89,7 +89,7 @@ class LDAPSettingView(SuperUserRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
class TerminalSettingView(SuperUserRequiredMixin, TemplateView):
|
class TerminalSettingView(SuperUserRequiredMixin, TemplateView):
|
||||||
form_class = TerminalSettingForm
|
form_class = TerminalSettingForm
|
||||||
template_name = "common/terminal_setting.html"
|
template_name = "settings/terminal_setting.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
command_storage = utils.get_command_storage_setting()
|
command_storage = utils.get_command_storage_setting()
|
||||||
@ -119,7 +119,7 @@ class TerminalSettingView(SuperUserRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
|
|
||||||
class ReplayStorageCreateView(SuperUserRequiredMixin, TemplateView):
|
class ReplayStorageCreateView(SuperUserRequiredMixin, TemplateView):
|
||||||
template_name = 'common/replay_storage_create.html'
|
template_name = 'settings/replay_storage_create.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
@ -131,7 +131,7 @@ class ReplayStorageCreateView(SuperUserRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
|
|
||||||
class CommandStorageCreateView(SuperUserRequiredMixin, TemplateView):
|
class CommandStorageCreateView(SuperUserRequiredMixin, TemplateView):
|
||||||
template_name = 'common/command_storage_create.html'
|
template_name = 'settings/command_storage_create.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
@ -144,7 +144,7 @@ class CommandStorageCreateView(SuperUserRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
class SecuritySettingView(SuperUserRequiredMixin, TemplateView):
|
class SecuritySettingView(SuperUserRequiredMixin, TemplateView):
|
||||||
form_class = SecuritySettingForm
|
form_class = SecuritySettingForm
|
||||||
template_name = "common/security_setting.html"
|
template_name = "settings/security_setting.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
@ -6,7 +6,6 @@ import re
|
|||||||
import pyotp
|
import pyotp
|
||||||
import base64
|
import base64
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import ipaddress
|
import ipaddress
|
||||||
@ -20,8 +19,6 @@ from datetime import datetime
|
|||||||
|
|
||||||
from common.tasks import send_mail_async
|
from common.tasks import send_mail_async
|
||||||
from common.utils import reverse, get_object_or_none
|
from common.utils import reverse, get_object_or_none
|
||||||
from common.forms import SecuritySettingForm
|
|
||||||
from common.models import Setting
|
|
||||||
from .models import User, LoginLog
|
from .models import User, LoginLog
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
# Minimal makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
|
||||||
SPHINXOPTS =
|
|
||||||
SPHINXBUILD = sphinx-build
|
|
||||||
SPHINXPROJ = Jumpserver
|
|
||||||
SOURCEDIR = .
|
|
||||||
BUILDDIR = _build
|
|
||||||
|
|
||||||
# Put it first so that "make" without argument is like "make help".
|
|
||||||
help:
|
|
||||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
|
|
||||||
.PHONY: help Makefile
|
|
||||||
|
|
||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
||||||
%: Makefile
|
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
BIN
docs/_static/img/admin_asset.png
vendored
Before Width: | Height: | Size: 335 KiB |
BIN
docs/_static/img/admin_user.png
vendored
Before Width: | Height: | Size: 416 KiB |
BIN
docs/_static/img/dash_board.png
vendored
Before Width: | Height: | Size: 410 KiB |
BIN
docs/_static/img/linux_terminal.png
vendored
Before Width: | Height: | Size: 513 KiB |
BIN
docs/_static/img/logo-text.png
vendored
Before Width: | Height: | Size: 39 KiB |
BIN
docs/_static/img/structure.png
vendored
Before Width: | Height: | Size: 29 KiB |
BIN
docs/_static/img/windows_terminal.png
vendored
Before Width: | Height: | Size: 215 KiB |
@ -1,12 +0,0 @@
|
|||||||
资产管理模块
|
|
||||||
=============
|
|
||||||
|
|
||||||
这里介绍资产管理模块功能。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
asset_list
|
|
||||||
asset_admin_user
|
|
||||||
asset_system_user
|
|
||||||
asset_label
|
|
@ -1,15 +0,0 @@
|
|||||||
管理文档
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍管理员功能。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
admin_instruction
|
|
||||||
admin_user
|
|
||||||
admin_asset
|
|
||||||
admin_permission
|
|
||||||
admin_work_center
|
|
||||||
admin_session
|
|
||||||
admin_system_settings
|
|
@ -1,44 +0,0 @@
|
|||||||
架构说明
|
|
||||||
=================
|
|
||||||
|
|
||||||
.. image:: _static/img/structure.png
|
|
||||||
:alt: 组件架构图
|
|
||||||
|
|
||||||
|
|
||||||
组件说明
|
|
||||||
=================
|
|
||||||
|
|
||||||
Jumpserver
|
|
||||||
`````````````
|
|
||||||
现指 Jumpserver 管理后台,是核心组件(Core), 使用 Django Class Based View 风格开发,支持 Restful API。
|
|
||||||
|
|
||||||
`Github <https://github.com/jumpserver/jumpserver.git>`_
|
|
||||||
|
|
||||||
|
|
||||||
Coco
|
|
||||||
````````
|
|
||||||
实现了 SSH Server 和 Web Terminal Server 的组件,提供 SSH 和 WebSocket 接口, 使用 Paramiko 和 Flask 开发。
|
|
||||||
|
|
||||||
|
|
||||||
`Github <https://github.com/jumpserver/coco.git>`__
|
|
||||||
|
|
||||||
|
|
||||||
Luna
|
|
||||||
````````
|
|
||||||
现在是 Web Terminal 前端,计划前端页面都由该项目提供,Jumpserver 只提供 API,不再负责后台渲染html等。
|
|
||||||
|
|
||||||
`Github <https://github.com/jumpserver/luna.git>`__
|
|
||||||
|
|
||||||
|
|
||||||
Guacamole
|
|
||||||
```````````
|
|
||||||
Apache 跳板机项目,Jumpserver 使用其组件实现 RDP 功能,Jumpserver 并没有修改其代码而是添加了额外的插件,支持 Jumpserver 调用。
|
|
||||||
|
|
||||||
|
|
||||||
Jumpserver-Python-SDK
|
|
||||||
```````````````````````
|
|
||||||
Jumpserver API Python SDK,Coco 目前使用该 SDK 与 Jumpserver API 交互。
|
|
||||||
|
|
||||||
`Github <https://github.com/jumpserver/jumpserver-python-sdk.git>`__
|
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
权限管理模块
|
|
||||||
=============
|
|
||||||
|
|
||||||
这里介绍权限管理功能。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
permission_asset_authorized
|
|
@ -1,13 +0,0 @@
|
|||||||
会话管理模块
|
|
||||||
==============
|
|
||||||
|
|
||||||
这里介绍会话管理功能。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
session_history
|
|
||||||
session_online
|
|
||||||
session_command
|
|
||||||
session_web_terminal
|
|
||||||
session_terminal
|
|
@ -1,41 +0,0 @@
|
|||||||
系统设置
|
|
||||||
=============
|
|
||||||
|
|
||||||
这里介绍系统设置的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_system_settings:
|
|
||||||
|
|
||||||
查看系统设置
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
点击页面左侧“系统设置”按钮,进入系统设置页面,产看基本设置、邮件设置、LDAP 设置和终端设置等内容。
|
|
||||||
|
|
||||||
.. _basic_settings:
|
|
||||||
|
|
||||||
基本设置
|
|
||||||
`````````
|
|
||||||
|
|
||||||
点击页面上边的"基本设置" TAB ,进入基本设置页面,编辑当前站点 URL、用户想到 URL、Email 主题前缀等信息,点击“提交”按钮,基本设置完成。
|
|
||||||
|
|
||||||
.. _email_settings:
|
|
||||||
|
|
||||||
邮件设置
|
|
||||||
`````````
|
|
||||||
|
|
||||||
点击页面上边的"邮件设置" TAB ,进入邮件设置页面,编辑 SMTP 主机、SMTP 端口、SMTP 账号、SMTP 密码和使用 SSL 或者 TSL 等信息,点击“测试连接”按钮,测试是否正确设置,点击“提交”按钮,邮件设置完成。
|
|
||||||
|
|
||||||
.. _ladp_settings:
|
|
||||||
|
|
||||||
LDAP 设置
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面上边的" LDAP 设置" TAB ,进入 LDAP 设置页面,编辑 LDAP 地址、DN、用户 OU、用户过滤器、LDAP 属性映射和是否使用 SSL、是否启用 LDAP 认证等信息,点击“测试连接”按钮,测试是否正确设置,点击“提交”按钮,完成 LDAP 设置。
|
|
||||||
|
|
||||||
.. _terminal_settings:
|
|
||||||
|
|
||||||
终端设置
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面上边的“终端设置” TAB ,进入终端设置页面,编辑终端信息,点击“提交”按钮,终端设置完成。
|
|
@ -1,11 +0,0 @@
|
|||||||
用户管理模块
|
|
||||||
=============
|
|
||||||
|
|
||||||
这里介绍用户管理功能。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
user
|
|
||||||
user_group
|
|
||||||
login_log
|
|
@ -1,9 +0,0 @@
|
|||||||
作业中心模块
|
|
||||||
==============
|
|
||||||
|
|
||||||
这里介绍作业中心功能。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
work_center_list
|
|
@ -1,163 +0,0 @@
|
|||||||
REST API规范约定
|
|
||||||
----------------
|
|
||||||
|
|
||||||
这里仅考虑 REST API 的基本情况。参考
|
|
||||||
|
|
||||||
`RESTful API 设计指南`_
|
|
||||||
|
|
||||||
`Github API 文档`_
|
|
||||||
|
|
||||||
协议
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
API 与用户的通信协议,总是使用 HTTPS 协议。
|
|
||||||
|
|
||||||
域名
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
这版 API 相对简单, 没有前后端分离, 没有独立 APP, 所以放在主域名下
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
https://example.org/api/
|
|
||||||
|
|
||||||
版本
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
将 API 的版本号放入 URL 中,由于一个项目多个 APP 所以 Jumpserver 使用以下风格,将版本号放到 APP 后面
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
https://example.com/api/:app:/:version:/:resource:
|
|
||||||
https://example.com/api/assets/v1.0/assets [GET, POST]
|
|
||||||
https://example.com/api/assets/v1.0/assets/1 [GET, PUT, DELETE]
|
|
||||||
|
|
||||||
路径
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
路径又称“终点”(endpoint),表示 API 的具体网址。
|
|
||||||
在 RESTful 架构中,每个网址代表一种资源(Resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的“集合”(Collection),所以 API 中的名词也应该使用复数。
|
|
||||||
举例来说 Cmdb 中的 Assets 列表, IDC 列表。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
https://example.com/api/:app:/:version:/:resource:
|
|
||||||
|
|
||||||
https://example.com/api/assets/v1.0/assets [GET, POST]
|
|
||||||
https://example.com/api/assets/v1.0/assets/1 [GET, PUT, DELETE]
|
|
||||||
https://example.com/api/assets/v1.0/idcs [GET, POST]
|
|
||||||
|
|
||||||
一般性的增删查改(CRUD)API,完全使用 HTTP Method 加上 URL 提供的语义,URL 中的可变部分(比如上面提到的),一般用来传递该API操作的核心实体对象的唯一 ID,如果有更多的参数需要提供,GET 方法请使用 URL Parameter(例如:“?client_id=xxxxx&app_id=xxxxxx”),PUT/POST/DELETE 方法请使用请求体传递参数。
|
|
||||||
|
|
||||||
HTTP Method
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
对于资源的具体操作类型,由 HTTP 动词表示。
|
|
||||||
|
|
||||||
常用的HTTP动词有下面五个(括号里是对应的 SQL 命令)。
|
|
||||||
|
|
||||||
- GET(SELECT):从服务器取出资源(一项或多项)。
|
|
||||||
- POST(CREATE):在服务器新建一个资源。
|
|
||||||
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源, 幂等
|
|
||||||
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
|
|
||||||
- DELETE(DELETE):从服务器删除资源。
|
|
||||||
|
|
||||||
.. _RESTful API 设计指南: http://www.ruanyifeng.com/blog/2014/05/restful_api.html
|
|
||||||
.. _Github API 文档: https://developer.github.com/v3/
|
|
||||||
|
|
||||||
|
|
||||||
过滤信息
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
常见参数约定
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
?keyword=localhost 模糊搜索
|
|
||||||
?limit=10:指定返回记录的数量
|
|
||||||
?offset=10:指定返回记录的开始位置。
|
|
||||||
?page=2&per_page=100:指定第几页,以及每页的记录数。
|
|
||||||
?sort=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
|
|
||||||
?asset_id=1:指定筛选条件
|
|
||||||
|
|
||||||
状态码
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。
|
|
||||||
|
|
||||||
- 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
|
|
||||||
- 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
|
|
||||||
- 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
|
|
||||||
- 204 NO CONTENT - [DELETE]:用户删除数据成功。
|
|
||||||
- 400 INVALID REQUEST -
|
|
||||||
[POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
|
|
||||||
- 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
|
|
||||||
- 403 Forbidden - [*]
|
|
||||||
表示用户得到授权(与401错误相对),但是访问是被禁止的。
|
|
||||||
- 404 NOT FOUND -
|
|
||||||
[*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
|
|
||||||
- 406 Not Acceptable -
|
|
||||||
[GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
|
|
||||||
- 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
|
|
||||||
- 422 Unprocesable entity - [POST/PUT/PATCH]
|
|
||||||
当创建一个对象时,发生一个验证错误。
|
|
||||||
- 500 INTERNAL SERVER ERROR -
|
|
||||||
[*]:服务器发生错误,用户将无法判断发出的请求是否成功。
|
|
||||||
|
|
||||||
错误处理
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将 error 作为键名,出错信息作为键值即可。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
{
|
|
||||||
error: "Invalid API key"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
返回结果
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
针对不同操作,服务器向用户返回的结果应该符合以下规范。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
GET /collection:返回资源对象的列表(数组)
|
|
||||||
GET /collection/resource:返回单个资源对象
|
|
||||||
POST /collection:返回新生成的资源对象
|
|
||||||
PUT /collection/resource:返回完整的资源对象
|
|
||||||
PATCH /collection/resource:返回完整的资源对象
|
|
||||||
DELETE /collection/resource:返回一个空文档
|
|
||||||
|
|
||||||
Hypermedia API
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
RESTful
|
|
||||||
API 最好做到 Hypermedia,即返回结果中提供链接,连向其他 API 方法,使得用户不查文档,也知道下一步应该做什么。
|
|
||||||
比如,当用户向 api.example.com 的根目录发出请求,会得到这样一个文档。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
{"link": {
|
|
||||||
"rel": "collection https://www.example.com/zoos",
|
|
||||||
"href": "https://api.example.com/zoos",
|
|
||||||
"title": "List of zoos",
|
|
||||||
"type": "application/vnd.yourformat+json"
|
|
||||||
}}
|
|
||||||
|
|
||||||
上面代码表示,文档中有一个 Link 属性,用户读取这个属性就知道下一步该调用什么 API 了。
|
|
||||||
|
|
||||||
- rel 表示这个 API 与当前网址的关系(Collection 关系,并给出该 Collection 的网址)
|
|
||||||
- href 表示 API 的路径
|
|
||||||
- title 表示 API 的标题
|
|
||||||
- type 表示返回类型
|
|
||||||
|
|
||||||
Hypermedia API 的设计被称为 HATEOAS。 Github API 就是这种设计.
|
|
||||||
|
|
||||||
其它
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
(1)API 的身份认证应该使用 OAuth 2.0 框架。
|
|
||||||
|
|
||||||
(2)服务器返回的数据格式,应该尽量使用 JSON。
|
|
@ -1,35 +0,0 @@
|
|||||||
管理用户
|
|
||||||
==========
|
|
||||||
|
|
||||||
这里介绍管理用户的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_admin_user_list:
|
|
||||||
|
|
||||||
查看管理用户列表
|
|
||||||
````````````````
|
|
||||||
|
|
||||||
点击页面左侧“资产管理“菜单下的“管理用户”按钮,进入管理用户列表页面,查看管理用户的名称、资产数等信息。
|
|
||||||
|
|
||||||
|
|
||||||
.. _create_admin_user:
|
|
||||||
|
|
||||||
创建管理用户
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面左上角的“创建管理用户“按钮,进入创建管理用户界面,填写名称、用户名、密码、ssh私钥等信息,点击“提交”按钮,完成管理用户创建。
|
|
||||||
|
|
||||||
.. _update_admin_user:
|
|
||||||
|
|
||||||
更新管理用户
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面右边动作栏的“更新”按钮,进入更新管理用户页面,编辑管理用户的信息,点击“提交”按钮,完成管理用户更新。
|
|
||||||
|
|
||||||
.. _delete_admin_user:
|
|
||||||
|
|
||||||
删除管理用户
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面右边动作栏的“删除”按钮,弹出删除确认框,点击"确认"按钮,管理用户删除完成。
|
|
@ -1,34 +0,0 @@
|
|||||||
标签管理
|
|
||||||
============
|
|
||||||
|
|
||||||
这里介绍标签管理的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_label_list:
|
|
||||||
|
|
||||||
查看标签列表
|
|
||||||
````````````````
|
|
||||||
|
|
||||||
点击页面左边“资产管理”菜单下的“标签管理”按钮,进入标签列表页面,产看标签的名称、值、资产数等信息。
|
|
||||||
|
|
||||||
.. _create_label:
|
|
||||||
|
|
||||||
创建标签
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面左上角“创建标签”按钮,进入创建标签页面,填写标签的名称、值等信息,选择资产,点击“提交”按钮,标签创建完成。
|
|
||||||
|
|
||||||
.. _update_label:
|
|
||||||
|
|
||||||
更新标签
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面右边动作栏的“更新”按钮,进入更新标签页面,编辑标签信息,点击“提交”按钮,标签更新完成。
|
|
||||||
|
|
||||||
.. _delete_label:
|
|
||||||
|
|
||||||
删除标签
|
|
||||||
`````````
|
|
||||||
|
|
||||||
点击页面右边动作栏的“删除”按钮,弹出删除确认框,点击“确认”按钮,完成标签删除。
|
|
@ -1,41 +0,0 @@
|
|||||||
资产列表
|
|
||||||
===========
|
|
||||||
|
|
||||||
这里介绍资产列表的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_asset_list:
|
|
||||||
|
|
||||||
查看资产列表
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
点击页面左侧的“资产管理”菜单下的“资产列表”按钮,查看当前所有的资产列表。
|
|
||||||
|
|
||||||
.. _create_asset:
|
|
||||||
|
|
||||||
创建资产
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面左上角的“创建资产”按钮,进入资产创建页面,填写资产信息,点击“提交”按钮,完成资产创建。
|
|
||||||
|
|
||||||
.. _update_asset:
|
|
||||||
|
|
||||||
更新资产
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面右边的“更新”按钮,进入编辑资产页面,更新资产信息,点击“提交”按钮,完成资产更新。
|
|
||||||
|
|
||||||
.. _delete_asset:
|
|
||||||
|
|
||||||
删除资产
|
|
||||||
`````````
|
|
||||||
|
|
||||||
点击页面右边的“删除”按钮,弹出删除确认框,点击“确认”按钮,完成资产删除。
|
|
||||||
|
|
||||||
.. _batch_operation:
|
|
||||||
|
|
||||||
批量操作
|
|
||||||
````````````
|
|
||||||
|
|
||||||
选中资产,选择页面左下角批量操作选项,点击“提交”按钮,完成批量操作。
|
|
@ -1,34 +0,0 @@
|
|||||||
系统用户
|
|
||||||
===========
|
|
||||||
|
|
||||||
这里介绍系统用户功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_admin_system_user:
|
|
||||||
|
|
||||||
查看系统用户
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面左侧“资产管理“菜单下的”系统用户“按钮,进入系统用户列表页面,查看系统用户的名称,资产数和连接数等信息。
|
|
||||||
|
|
||||||
.. _create_admin_system_user:
|
|
||||||
|
|
||||||
创建系统用户
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面左上角的“创建系统用户“按钮,进入创建系统用户页面,填写系统用户的基本信息、认证信息和其它信息,点击“提交“按钮,完成系统用户创建。
|
|
||||||
|
|
||||||
.. _update_admin_system_user:
|
|
||||||
|
|
||||||
更新系统用户
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
点击页面动作栏的“更新”按钮,进入更新系统用户页面,编辑系统用户信息,点击“提交”按钮,系统用户更新完成。
|
|
||||||
|
|
||||||
.. _delete_admin_system_user:
|
|
||||||
|
|
||||||
删除系统用户
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
点击页面动作栏的“删除”按钮,弹出删除确认框,点击“删除”按钮,完成删除系统用户。
|
|
168
docs/conf.py
@ -1,168 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Configuration file for the Sphinx documentation builder.
|
|
||||||
#
|
|
||||||
# This file does only contain a selection of the most common options. For a
|
|
||||||
# full list see the documentation:
|
|
||||||
# http://www.sphinx-doc.org/en/stable/config
|
|
||||||
|
|
||||||
# -- Path setup --------------------------------------------------------------
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
#
|
|
||||||
# import os
|
|
||||||
# import sys
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
import sphinx_rtd_theme
|
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
|
||||||
|
|
||||||
project = 'Jumpserver'
|
|
||||||
copyright = '北京堆栈科技有限公司 © 2014-2018'
|
|
||||||
author = 'Jumpserver team'
|
|
||||||
|
|
||||||
# The short X.Y version
|
|
||||||
version = ''
|
|
||||||
# The full version, including alpha/beta/rc tags
|
|
||||||
release = '0.5.0'
|
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
|
||||||
#
|
|
||||||
# needs_sphinx = '1.0'
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
||||||
# ones.
|
|
||||||
extensions = [
|
|
||||||
'sphinx.ext.viewcode',
|
|
||||||
'sphinx.ext.githubpages',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
|
||||||
templates_path = ['_templates']
|
|
||||||
|
|
||||||
# The suffix(es) of source filenames.
|
|
||||||
# You can specify multiple suffix as a list of string:
|
|
||||||
#
|
|
||||||
# source_suffix = ['.rst', '.md']
|
|
||||||
source_suffix = '.rst'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
||||||
# for a list of supported languages.
|
|
||||||
#
|
|
||||||
# This is also used if you do content translation via gettext catalogs.
|
|
||||||
# Usually you set "language" from the command line for these cases.
|
|
||||||
language = 'zh_CN'
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
|
||||||
# directories to ignore when looking for source files.
|
|
||||||
# This pattern also affects html_static_path and html_extra_path .
|
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = 'sphinx'
|
|
||||||
html_show_sourcelink = False
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
||||||
# a list of builtin themes.
|
|
||||||
#
|
|
||||||
# html_theme = 'alabaster'
|
|
||||||
html_theme = "sphinx_rtd_theme"
|
|
||||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
|
||||||
# further. For a list of options available for each theme, see the
|
|
||||||
# documentation.
|
|
||||||
#
|
|
||||||
html_theme_options = {
|
|
||||||
'logo_only': True,
|
|
||||||
'display_version': True
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
||||||
html_static_path = ['_static']
|
|
||||||
|
|
||||||
# Custom sidebar templates, must be a dictionary that maps document names
|
|
||||||
# to template names.
|
|
||||||
#
|
|
||||||
# The default sidebars (for documents that don't match any pattern) are
|
|
||||||
# defined by theme itself. Builtin themes are using these templates by
|
|
||||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
|
||||||
# 'searchbox.html']``.
|
|
||||||
#
|
|
||||||
# html_sidebars = {}
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTMLHelp output ---------------------------------------------
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
htmlhelp_basename = 'Jumpserver 文档'
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ------------------------------------------------
|
|
||||||
|
|
||||||
latex_elements = {
|
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
|
||||||
#
|
|
||||||
# 'papersize': 'letterpaper',
|
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
|
||||||
#
|
|
||||||
# 'pointsize': '10pt',
|
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
#
|
|
||||||
# 'preamble': '',
|
|
||||||
|
|
||||||
# Latex figure (float) alignment
|
|
||||||
#
|
|
||||||
# 'figure_align': 'htbp',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
|
||||||
# (source start file, target name, title,
|
|
||||||
# author, documentclass [howto, manual, or own class]).
|
|
||||||
latex_documents = [
|
|
||||||
(master_doc, 'Jumpserver.tex', 'Jumpserver Documentation',
|
|
||||||
'Jumpserver team', 'manual'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ------------------------------------------
|
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
|
||||||
# (source start file, name, description, authors, manual section).
|
|
||||||
man_pages = [
|
|
||||||
(master_doc, 'Jumpserver', 'Jumpserver Documentation',
|
|
||||||
[author], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ----------------------------------------------
|
|
||||||
|
|
||||||
# Grouping the document tree into Texinfo files. List of tuples
|
|
||||||
# (source start file, target name, title, author,
|
|
||||||
# dir menu entry, description, category)
|
|
||||||
texinfo_documents = [
|
|
||||||
(master_doc, 'Jumpserver', 'Jumpserver 文档',
|
|
||||||
author, 'Jumpserver', ' Jumpserver是全球首款完全开源的堡垒机,是符合 4A 的专业运维审计系统',
|
|
||||||
'Miscellaneous'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Extension configuration -------------------------------------------------
|
|
||||||
html_logo = '_static/img/logo-text.png'
|
|
@ -1,41 +0,0 @@
|
|||||||
联系方式
|
|
||||||
+++++++++++++++++++++++++
|
|
||||||
|
|
||||||
商业支持
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
`阿里云市场购买: <https://market.aliyun.com/products/53690006/cmgj026011.html>`_
|
|
||||||
|
|
||||||
|
|
||||||
QQ 群
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
群1: 390139816 (推荐)
|
|
||||||
|
|
||||||
群2: 399218702 (满)
|
|
||||||
|
|
||||||
群3: 552054376 (满)
|
|
||||||
|
|
||||||
|
|
||||||
Github
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
https://github.com/jumpserver/jumpserver.git
|
|
||||||
|
|
||||||
|
|
||||||
官网
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
http://www.jumpserver.org
|
|
||||||
|
|
||||||
|
|
||||||
Demo
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
http://demo.jumpserver.org
|
|
||||||
|
|
||||||
|
|
||||||
邮件
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
support@fit2cloud.com (#替换为@)
|
|
@ -1,17 +0,0 @@
|
|||||||
贡献者
|
|
||||||
=============
|
|
||||||
|
|
||||||
感谢以下朋友为 Jumpserver 做出的贡献,世界因你们而不同,排名不分先后
|
|
||||||
|
|
||||||
|
|
||||||
- **小彧 <李磊>** Django 资深开发者,为用户模块贡献了很多代码
|
|
||||||
- **sofia <周小侠>** 资深前端工程师, 前端代码贡献者
|
|
||||||
- **liuz <刘正> 全栈工程师** 编写了 Web Terminal 大部分代码
|
|
||||||
- **jiaxiangkong <陈尚委>** Jumpserver 测试运营
|
|
||||||
- **halcyon <王墉>** DevOps 资深开发者, 0.3.2 核心开发者之一
|
|
||||||
- **yumaojun03 <喻茂峻>** DevOps 资深开发者,擅长 Python、Go 以及 PaaS 平台开发
|
|
||||||
- **kelianchun <柯连春>** DevOps 资产开发者,修复了很多 Bugs
|
|
||||||
- **q4speed <莫鹍>** 架构师,贡献了 0.5.0 Windows 远程桌面登录大部分代码
|
|
||||||
- **ZhangFengyi <张峰毅>** 贡献了 0.5.0 新版文档
|
|
||||||
- **Aaron3S <沈晨阳>** 贡献了 0.5.0 新版文档
|
|
||||||
- **liqiang-fit2cloud <张立强>** 0.5.0 版本测试,给资产树设计贡献了很多建议
|
|
@ -1,12 +0,0 @@
|
|||||||
开发文档
|
|
||||||
======================================
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
:caption: 开发文档
|
|
||||||
|
|
||||||
api_style_guide
|
|
||||||
python_style_guide
|
|
||||||
project_structure
|
|
||||||
|
|
||||||
|
|
19
docs/faq.rst
@ -1,19 +0,0 @@
|
|||||||
FAQ
|
|
||||||
==========
|
|
||||||
|
|
||||||
1. Windows 无法连接
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
(1). 如果白屏 可能是nginx设置的不对,也可能运行guacamole的docker容器有问题,总之请求到不了guacamole
|
|
||||||
(2). 如果显示没有权限 可能是你在 终端管理里没有接受 guacamole的注册,请接受一下,如果还是不行,就删除刚才的注册,重启guacamole的docker重新注册
|
|
||||||
(3). 如果显示未知问题 可能是你的资产填写的端口不对,或者授权的系统用户的协议不是rdp
|
|
||||||
|
|
||||||
|
|
||||||
2. 用户、系统用户、管理用户的关系
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
用户:每个公司的同事创建一个用户账号,用来登录Jumpserver
|
|
||||||
系统用户:使用来登录到服务器的用户,如 web, dba, root等
|
|
||||||
管理用户:是服务器上已存在的特权用户,Ansible用来获取硬件信息, 如 root, 或者其它拥有 sudo NOPASSWD: ALL权限的用户
|
|
@ -1,22 +0,0 @@
|
|||||||
.. jumpserver documentation master file, created by
|
|
||||||
sphinx-quickstart on Mon Feb 26 23:28:27 2018.
|
|
||||||
You can adapt this file completely to your liking, but it should at least
|
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
Jumpserver 文档
|
|
||||||
======================================
|
|
||||||
|
|
||||||
目录:
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
introduce
|
|
||||||
installation
|
|
||||||
admin_guide
|
|
||||||
user_guide
|
|
||||||
development
|
|
||||||
contributor
|
|
||||||
contact
|
|
||||||
snapshot
|
|
||||||
faq
|
|
@ -1,9 +0,0 @@
|
|||||||
安装文档
|
|
||||||
++++++++++++++++++++++++
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
quickstart
|
|
||||||
step_by_step
|
|
||||||
upgrade
|
|
@ -1,12 +0,0 @@
|
|||||||
总体介绍
|
|
||||||
==================
|
|
||||||
|
|
||||||
欢迎来到 Jumpserver 文档。
|
|
||||||
|
|
||||||
Jumpserver 是全球首款完全开源的堡垒机,使用 GNU GPL v2.0 开源协议,是符合 4A 的专业运维审计系统。
|
|
||||||
|
|
||||||
Jumpserver 使用 Python / Django 进行开发,遵循 Web 2.0 规范,配备了业界领先的 Web Terminal 解决方案,交互界面美观、用户体验好。
|
|
||||||
|
|
||||||
Jumpserver 采纳分布式架构,支持多机房跨区域部署,中心节点提供 API,各机房部署登录节点,可横向扩展、无并发访问限制。
|
|
||||||
|
|
||||||
改变世界,从一点点开始。
|
|
@ -1,6 +0,0 @@
|
|||||||
登录日志
|
|
||||||
==========
|
|
||||||
|
|
||||||
这里介绍登录日志的功能。
|
|
||||||
|
|
||||||
点击页面左侧“用户管理”菜单下的“登录日志”按钮,进入登录日志页面。
|
|
@ -1,34 +0,0 @@
|
|||||||
资产授权
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍资产授权的相关的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_asset_authorized:
|
|
||||||
|
|
||||||
查看资产授权规则列表
|
|
||||||
````````````````````
|
|
||||||
|
|
||||||
资产授权页面默认展示资产授权列表。点击左侧资产节点树下的节点,右侧展示此节点下的资产授权规则。
|
|
||||||
|
|
||||||
.. _create_asset_authorized:
|
|
||||||
|
|
||||||
创建授权规则
|
|
||||||
````````````
|
|
||||||
在左侧资产节点树下选择要创建授权规则的节点,点击页面右侧创建授权规则进入创建授权规则页面,填写授权规则信息,点击提交,完成创建授权规则。
|
|
||||||
|
|
||||||
.. _update_asset_authorized:
|
|
||||||
|
|
||||||
更新授权规则
|
|
||||||
````````````
|
|
||||||
|
|
||||||
在左侧资产节点树下选择要更新授权规则的节点,在右侧授权规则列表中找到要更新的授权规则,点击“动作”标题下的“更新”按钮进入授权规则更新页面,填写授权规则信息,点击提交,完成创建授权规则。
|
|
||||||
|
|
||||||
.. _delete_asset_authorized:
|
|
||||||
|
|
||||||
删除授权规则
|
|
||||||
````````````
|
|
||||||
|
|
||||||
在左侧资产节点树下选择要删除授权规则的节点,在右侧授权规则列表中找到要删除的授权规则,点击“动作”标题下的“删除”按钮,弹出确认删除页面,点击确认,完成删除授权规则。
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
项目骨架
|
|
||||||
--------
|
|
||||||
|
|
||||||
说明如下:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
.
|
|
||||||
├── config-example.py // 配置文件样例
|
|
||||||
├── docs // 所有 DOC 文件放到该目录
|
|
||||||
│ └── README.md
|
|
||||||
├── LICENSE
|
|
||||||
├── README.md
|
|
||||||
├── install // 安装说明
|
|
||||||
├── logs // 日志目录
|
|
||||||
├── apps // 管理后台目录,也是各 APP 所在目录
|
|
||||||
│ └── assets // APP 目录
|
|
||||||
│ │ ├── admin.py
|
|
||||||
│ │ ├── apps.py // 新版本 Django APP 设置文件
|
|
||||||
│ │ ├── api.py // API 文件
|
|
||||||
│ │ ├── __init__.py // 对外暴露的接口,放到该文件中,方便别的 APP 引用
|
|
||||||
│ │ ├── migrations // Models Migrations 版本控制目录
|
|
||||||
│ │ │ └── __init__.py
|
|
||||||
│ │ ├── models.py // 数据模型目录
|
|
||||||
│ │ ├── static // APP 下静态资源目录,如果需要
|
|
||||||
│ │ │ └── assets // 多一层目录,防止资源重名
|
|
||||||
│ │ │ └── some_image.png
|
|
||||||
│ │ ├── templates // APP 下模板目录
|
|
||||||
│ │ │ └── assets // 多一层目录,防止资源重名
|
|
||||||
│ │ │ └── asset_list.html
|
|
||||||
│ │ ├── templatetags // 模板标签目录
|
|
||||||
│ │ ├── tests.py // 测试用例文件
|
|
||||||
│ │ ├── urls.py // Urlconf 文件
|
|
||||||
│ │ ├── utils.py // 将 Views 和 API 可复用的代码放在这里, API 和 Views 只是请求和返回不同
|
|
||||||
│ │ └── views.py // Views 文件
|
|
||||||
│ ├── common
|
|
||||||
│ │ ├── templatetags // 通用 Template Tag
|
|
||||||
│ │ ├── utils.py // 通用的函数方法
|
|
||||||
│ │ └── views.py
|
|
||||||
│ ├── fixtures // 初始化数据目录
|
|
||||||
│ │ ├── init.json // 初始化项目数据库
|
|
||||||
│ │ └── fake.json // 生成大量测试数据
|
|
||||||
│ ├── jumpserver // 项目设置目录
|
|
||||||
│ │ ├── __init__.py
|
|
||||||
│ │ ├── settings.py // 项目设置文件
|
|
||||||
│ │ ├── urls.py // 项目入口 Urlconf
|
|
||||||
│ │ └── wsgi.py
|
|
||||||
│ ├── manage.py
|
|
||||||
│ ├── static // 项目静态资源目录
|
|
||||||
│ ├── i18n // 项目多语言目录
|
|
||||||
│ └── templates // 项目模板目录
|
|
@ -1,211 +0,0 @@
|
|||||||
Jumpserver 项目规范(Draft)
|
|
||||||
============================
|
|
||||||
|
|
||||||
语言框架
|
|
||||||
----------
|
|
||||||
|
|
||||||
1. Python 3.6.1 (当前最新)
|
|
||||||
2. Django 1.11 (当前最新)
|
|
||||||
3. Flask 0.12 Luna (当前最新)
|
|
||||||
4. Paramiko 2.12 Coco (当前最新)
|
|
||||||
|
|
||||||
Django 规范
|
|
||||||
--------------
|
|
||||||
|
|
||||||
1. 尽量使用 Class Base View 编程,更少代码
|
|
||||||
2. 使用 Django Form
|
|
||||||
3. 每个 URL 独立命名,不要硬编码,同理 Static 也是
|
|
||||||
4. 数据库表名手动指定,不要使用默认
|
|
||||||
5. 代码优雅简洁
|
|
||||||
6. 注释明确优美
|
|
||||||
7. 测试案例尽可能完整
|
|
||||||
8. 尽可能利用 Django 造好的轮子
|
|
||||||
|
|
||||||
代码风格
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Python 方面大致的风格,我们采用 pocoo 的\ `Style
|
|
||||||
Guidance`_\ ,但是有些细节部分会尽量放开 参考国内翻译
|
|
||||||
|
|
||||||
基本的代码布局
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
缩进
|
|
||||||
^^^^^^^^
|
|
||||||
|
|
||||||
1. Python 严格采用4个空格的缩进,任何 Python 代码都都必须遵守此规定。
|
|
||||||
2. Web 部分代码(HTML、CSS、JavaScript),Node.js 采用2空格缩进,同样不使用 TAB。
|
|
||||||
之所以与 Python 不同,是因为 JS 中有大量回调式的写法,2空格可以显著降低视觉上的负担。
|
|
||||||
|
|
||||||
最大行长度
|
|
||||||
^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
按 PEP8 规范,Python 一般限制最大79个字符,
|
|
||||||
但是 Django 的命名,URL 等通常比较长,
|
|
||||||
而且21世纪都是宽屏了,所以我们限制最大120字符
|
|
||||||
|
|
||||||
**补充说明:HTML 代码不受此规范约束。**
|
|
||||||
|
|
||||||
长语句缩进
|
|
||||||
^^^^^^^^^^^^
|
|
||||||
|
|
||||||
编写长语句时,可以使用换行符"\"换行。在这种情况下,下一行应该与上一行的最后一个“.”句点或“=”对齐,或者是缩进4个空格符。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
this_is_a_very_long(function_call, 'with many parameters') \
|
|
||||||
.that_returns_an_object_with_an_attribute
|
|
||||||
|
|
||||||
MyModel.query.filter(MyModel.scalar > 120) \
|
|
||||||
.order_by(MyModel.name.desc()) \
|
|
||||||
.limit(10)
|
|
||||||
|
|
||||||
如果你使用括号“()”或花括号“{}”为长语句换行,那么下一行应与括号或花括号对齐:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
this_is_a_very_long(function_call, 'with many parameters',
|
|
||||||
23, 42, 'and even more')
|
|
||||||
|
|
||||||
对于元素众多的列表或元组,在第一个“[”或“(”之后马上换行:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
items = [
|
|
||||||
'this is the first', 'set of items', 'with more items',
|
|
||||||
'to come in this line', 'like this'
|
|
||||||
]
|
|
||||||
|
|
||||||
.. _Style Guidance: http://www.pocoo.org/internal/styleguide/
|
|
||||||
|
|
||||||
|
|
||||||
空行
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
顶层函数与类之间空两行,此外都只空一行。不要在代码中使用太多的空行来区分不同的逻辑模块。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
def hello(name):
|
|
||||||
print 'Hello %s!' % name
|
|
||||||
|
|
||||||
|
|
||||||
def goodbye(name):
|
|
||||||
print 'See you %s.' % name
|
|
||||||
|
|
||||||
|
|
||||||
class MyClass(object):
|
|
||||||
"""This is a simple docstring."""
|
|
||||||
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def get_annoying_name(self):
|
|
||||||
return self.name.upper() + '!!!!111'
|
|
||||||
|
|
||||||
语句和表达式
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
一般空格规则
|
|
||||||
^^^^^^^^^^^^
|
|
||||||
|
|
||||||
1. 单目运算符与运算对象之间不空格(例如,-,~等),即使单目运算符位于括号内部也一样。
|
|
||||||
2. 双目运算符与运算对象之间要空格。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
exp = -1.05
|
|
||||||
value = (item_value / item_count) * offset / exp
|
|
||||||
value = my_list[index]
|
|
||||||
value = my_dict['key']
|
|
||||||
|
|
||||||
比较
|
|
||||||
^^^^
|
|
||||||
|
|
||||||
1. 任意类型之间的比较,使用“==”和“!=”。
|
|
||||||
2. 与单例(singletons)进行比较时,使用 is 和 is not。
|
|
||||||
3. 永远不要与True或False进行比较(例如,不要这样写:foo ==
|
|
||||||
False,而应该这样写:not foo)。
|
|
||||||
|
|
||||||
否定成员关系检查
|
|
||||||
^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
使用 foo not in bar,而不是 not foo in bar。
|
|
||||||
|
|
||||||
命名约定
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
1. 类名称:采用骆驼拼写法(CamelCase),首字母缩略词保持大写不变(HTTPWriter,而不是 HttpWriter)。
|
|
||||||
2. 变量名:小写_以及_下划线(lowercase_with_underscores)。
|
|
||||||
3. 方法与函数名:小写_以及_下划线(lowercase_with_underscores)。
|
|
||||||
4. 常量:大写_以及_下划线(UPPERCASE_WITH_UNDERSCORES)。
|
|
||||||
5. 预编译的正则表达式:name_re。
|
|
||||||
6. 受保护的元素以一个下划线为前缀。双下划线前缀只有定义混入类(mixin classes)时才使用。
|
|
||||||
7. 如果使用关键词(keywords)作为类名称,应在名称后添加后置下划线(trailing underscore)。
|
|
||||||
允许与内建变量重名,不要在变量名后添加下划线进行区分。如果函数需要访问重名的内建变量,请将内建变量重新绑定为其他名称。
|
|
||||||
8. 命名要有寓意, 不使用拼音,不使用无意义简单字母命名 (循环中计数例外 for i in)
|
|
||||||
9. 命名缩写要谨慎, 尽量是大家认可的缩写
|
|
||||||
|
|
||||||
函数和方法的参数:
|
|
||||||
^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
1. 类方法:cls 为第一个参数。
|
|
||||||
2. 实例方法:self 为第一个参数。
|
|
||||||
3. property函数中使用匿名函数(lambdas)时,匿名函数的第一个参数可以用 x 替代,
|
|
||||||
例如:display_name = property(lambda x: x.real_name or x.username)。
|
|
||||||
|
|
||||||
|
|
||||||
文档注释(Docstring,即各方法,类的说明文档注释)
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
所有文档字符串均以 reStructuredText 格式编写,方便 Sphinx 处理。文档字符串的行数不同,布局也不一样。
|
|
||||||
如果只有一行,代表字符串结束的三个引号与代表字符串开始的三个引号在同一行。
|
|
||||||
如果为多行,文档字符串中的文本紧接着代表字符串开始的三个引号编写,代表字符串结束的三个引号则自己独立成一行。
|
|
||||||
(有能力尽可能用英文, 否则请中文优雅注释)
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
def foo():
|
|
||||||
"""This is a simple docstring."""
|
|
||||||
|
|
||||||
|
|
||||||
def bar():
|
|
||||||
"""This is a longer docstring with so much information in there
|
|
||||||
that it spans three lines. In this case, the closing triple quote
|
|
||||||
is on its own line.
|
|
||||||
"""
|
|
||||||
|
|
||||||
文档字符串应分成简短摘要(尽量一行)和详细介绍。如果必要的话,摘要与详细介绍之间空一行。
|
|
||||||
|
|
||||||
模块头部
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
模块文件的头部包含有 utf-8 编码声明(如果模块中使用了非 ASCII 编码的字符,建议进行声明),以及标准的文档字符串。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
package.module
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
A brief description goes here.
|
|
||||||
|
|
||||||
:copyright: (c) YEAR by AUTHOR.
|
|
||||||
:license: LICENSE_NAME, see LICENSE_FILE for more details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
注释(Comment)
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
注释的规范与文档字符串编写规范类似。二者均以 reStructuredText 格式编写。
|
|
||||||
如果使用注释来编写类属性的文档,请在#符号后添加一个冒号“:”。
|
|
||||||
(有能力尽可能用英文, 否则请中文优雅注释)
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
class User(object):
|
|
||||||
#: the name of the user as unicode string
|
|
||||||
name = Column(String)
|
|
||||||
#: the sha1 hash of the password + inline salt
|
|
||||||
pw_hash = Column(String)
|
|
@ -1,54 +0,0 @@
|
|||||||
快速安装
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Jumpserver 封装了一个 All in one Docker,可以快速启动。该镜像集成了所需要的组件(Windows组件未暂未集成),也支持使用外置 Database 和 Redis
|
|
||||||
|
|
||||||
Tips: 不建议在生产中使用, 生产中请使用 详细安装 `CentOS <step_by_step.html>`_ `Ubuntu <setup_by_ubuntu.html>`_
|
|
||||||
|
|
||||||
|
|
||||||
Docker 安装见: `Docker官方安装文档 <https://docs.docker.com/install/>`_
|
|
||||||
|
|
||||||
|
|
||||||
快速启动
|
|
||||||
```````````````
|
|
||||||
使用 root 命令行输入::
|
|
||||||
|
|
||||||
$ docker run -d -p 8080:80 -p 2222:2222 registry.jumpserver.org/public/jumpserver:1.0.0
|
|
||||||
|
|
||||||
访问
|
|
||||||
```````````````
|
|
||||||
|
|
||||||
浏览器访问: http://<容器所在服务器IP>:8080
|
|
||||||
|
|
||||||
SSH访问: ssh -p 2222 <容器所在服务器IP>
|
|
||||||
|
|
||||||
XShell等工具请添加connection连接
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
额外环境变量
|
|
||||||
```````````````
|
|
||||||
|
|
||||||
- DB_ENGINE = mysql
|
|
||||||
- DB_HOST = mysql_host
|
|
||||||
- DB_PORT = 3306
|
|
||||||
- DB_USER = xxx
|
|
||||||
- DB_PASSWORD = xxxx
|
|
||||||
- DB_NAME = jumpserver
|
|
||||||
|
|
||||||
- REDIS_HOST = <redis-host>
|
|
||||||
- REDIS_PORT = <redis-port>
|
|
||||||
- REDIS_PASSWORD = <
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
docker run -d -p 8080:80 -p 2222:2222 -e DB_ENGINE=mysql -e DB_HOST=192.168.1.1 -e DB_PORT=3306 -e DB_USER=root -e DB_PASSWORD=xxx -e DB_NAME=jumpserver registry.jumpserver.org/public/jumpserver:1.0.0
|
|
||||||
|
|
||||||
|
|
||||||
仓库地址
|
|
||||||
```````````````
|
|
||||||
|
|
||||||
https://github.com/jumpserver/Dockerfile
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
命令记录
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍命令记录功能。
|
|
||||||
|
|
||||||
点击页面左侧“会话管理”菜单下的“命令记录”,进入命令记录列表页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_command_session:
|
|
||||||
|
|
||||||
查看命令记录
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
命令记录页面默认展示一周内命令记录,页面左上角提供起止时间、用户、资产、系统用户等搜索过滤条件。
|
|
||||||
|
|
||||||
.. _detial_command_invoke:
|
|
||||||
|
|
||||||
查看命令执行详情
|
|
||||||
````````````````
|
|
||||||
|
|
||||||
点击命令记录列表中需要查看命令执行详情的行,即可显示命令执行详情。
|
|
||||||
|
|
||||||
.. _detial_command_session:
|
|
||||||
|
|
||||||
转到会话详情
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在命令记录列表中找到需要转到会话详情的记录,点击“会话”标题下的“转到”按钮,完成转到会话详情。
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
历史会话
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍历史会话功能。
|
|
||||||
|
|
||||||
点击页面左侧“会话管理”菜单下的“历史会话”,进入历史会话列表页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_history_session:
|
|
||||||
|
|
||||||
查看历史会话
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
历史会话页面默认展示一周内历史会话,页面左上角提供起止时间、用户、资产、系统用户等搜索过滤条件。
|
|
||||||
|
|
||||||
.. _playback_history_session:
|
|
||||||
|
|
||||||
历史会话回放
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在在线会话列表中找到要回放的历史会话,点击动作标签下的“回放”按钮,弹出回放页面,完成回放历史会话。
|
|
@ -1,25 +0,0 @@
|
|||||||
在线会话
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍在线会话功能。
|
|
||||||
|
|
||||||
点击页面左侧“会话管理”菜单下的“在线会话”,进入在线会话列表页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_online_session:
|
|
||||||
|
|
||||||
查看在线会话
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在线会话页面默认展示一周内在线会话,页面左上角提供起止时间、用户、资产、系统用户等搜索过滤条件。
|
|
||||||
|
|
||||||
.. _stop_online_session:
|
|
||||||
|
|
||||||
终断在线会话
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在在线会话列表中找到要终止的在线会话,点击动作标签下的“终断”按钮,完成终断在线会话。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
|||||||
终端管理
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍终端管理功能。
|
|
||||||
|
|
||||||
点击页面左侧“会话管理”菜单下的“终端管理”,进入终端列表页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_terminal_session:
|
|
||||||
|
|
||||||
查看终端列表
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
终端列表页面默认展示全部终端列表。
|
|
||||||
|
|
||||||
.. _upate_terminal_session:
|
|
||||||
|
|
||||||
更新终端
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在在线会话列表中找到要更新的终端,点击动作标签下的“更新”按钮,在更新终端页面填写相关信息,点击提交,完成更新终端。
|
|
||||||
|
|
||||||
.. _delete_terminal_session:
|
|
||||||
|
|
||||||
删除终端
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在在线会话列表中找到要删除的终端,点击动作标签下的“删除”按钮,在弹出确认删除页面点击确认,完成删除终端。
|
|
@ -1,23 +0,0 @@
|
|||||||
Web终端
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍Web终端功能。
|
|
||||||
|
|
||||||
点击页面左侧“会话管理”菜单下的“Web终端”,进入Web终端页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _login:
|
|
||||||
|
|
||||||
主机登录
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
点解页面左侧的”Web终端”,进入主机登录页,然后点击页面右侧的主机IP地址,连接主机,页面右侧会展示当前连接的终端信息。
|
|
||||||
|
|
||||||
.. _logout:
|
|
||||||
|
|
||||||
主机登出
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在主机登录页面,选择左上角的“服务器”按钮,出现两个选项,一个“断开链接“按钮,断开当前连接的主机;另一个”断开所有链接“,断开当前所有连接的主机。
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
Snapshot 截图
|
|
||||||
+++++++++++++++++
|
|
||||||
|
|
||||||
仪表盘
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
.. image:: _static/img/dash_board.png
|
|
||||||
|
|
||||||
用户管理
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
.. image:: _static/img/admin_user.png
|
|
||||||
|
|
||||||
资产管理
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
.. image:: _static/img/admin_asset.png
|
|
||||||
|
|
||||||
Linux 终端
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. image:: _static/img/linux_terminal.png
|
|
||||||
|
|
||||||
Windows 终端
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. image:: _static/img/windows_terminal.png
|
|
@ -1,307 +0,0 @@
|
|||||||
一步一步安装
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
环境
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
- 系统: CentOS 7
|
|
||||||
- IP: 192.168.244.144
|
|
||||||
- 关闭 selinux 和防火墙
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
# CentOS 7
|
|
||||||
$ setenforce 0 # 可以设置配置文件永久关闭
|
|
||||||
$ systemctl stop iptables.service
|
|
||||||
$ systemctl stop firewalld.service
|
|
||||||
|
|
||||||
# CentOS6
|
|
||||||
$ setenforce 0
|
|
||||||
$ service iptables stop
|
|
||||||
|
|
||||||
一. 准备 Python3 和 Python 虚拟环境
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**1.1 安装依赖包**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ yum -y install wget sqlite-devel xz gcc automake zlib-devel openssl-devel epel-release git
|
|
||||||
|
|
||||||
**1.2 编译安装**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tar.xz
|
|
||||||
$ tar xvf Python-3.6.1.tar.xz && cd Python-3.6.1
|
|
||||||
$ ./configure && make && make install
|
|
||||||
|
|
||||||
**1.3 建立 Python 虚拟环境**
|
|
||||||
|
|
||||||
因为 CentOS 6/7 自带的是 Python2,而 Yum 等工具依赖原来的 Python,为了不扰乱原来的环境我们来使用 Python 虚拟环境
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt
|
|
||||||
$ python3 -m venv py3
|
|
||||||
$ source /opt/py3/bin/activate
|
|
||||||
|
|
||||||
# 看到下面的提示符代表成功,以后运行 Jumpserver 都要先运行以上 source 命令,以下所有命令均在该虚拟环境中运行
|
|
||||||
(py3) [root@localhost py3]
|
|
||||||
|
|
||||||
二. 安装 Jumpserver 1.0.0
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**2.1 下载或 Clone 项目**
|
|
||||||
|
|
||||||
项目提交较多 git clone 时较大,你可以选择去 Github 项目页面直接下载zip包。
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/
|
|
||||||
$ git clone --depth=1 https://github.com/jumpserver/jumpserver.git && cd jumpserver && git checkout master
|
|
||||||
|
|
||||||
**2.2 安装依赖 RPM 包**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/jumpserver/requirements
|
|
||||||
$ yum -y install $(cat rpm_requirements.txt) # 如果没有任何报错请继续
|
|
||||||
|
|
||||||
**2.3 安装 Python 库依赖**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ pip install -r requirements.txt # 不要指定-i参数,因为镜像上可能没有最新的包,如果没有任何报错请继续
|
|
||||||
|
|
||||||
**2.4 安装 Redis, Jumpserver 使用 Redis 做 cache 和 celery broke**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ yum -y install redis
|
|
||||||
$ service redis start
|
|
||||||
|
|
||||||
**2.5 安装 MySQL**
|
|
||||||
|
|
||||||
本教程使用 Mysql 作为数据库,如果不使用 Mysql 可以跳过相关 Mysql 安装和配置
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
# centos7
|
|
||||||
$ yum -y install mariadb mariadb-devel mariadb-server # centos7下安装的是mariadb
|
|
||||||
$ service mariadb start
|
|
||||||
|
|
||||||
# centos6
|
|
||||||
$ yum -y install mysql mysql-devel mysql-server
|
|
||||||
$ service mysqld start
|
|
||||||
|
|
||||||
**2.6 创建数据库 Jumpserver 并授权**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ mysql
|
|
||||||
> create database jumpserver default charset 'utf8';
|
|
||||||
> grant all on jumpserver.* to 'jumpserver'@'127.0.0.1' identified by 'somepassword';
|
|
||||||
|
|
||||||
**2.7 修改 Jumpserver 配置文件**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/jumpserver
|
|
||||||
$ cp config_example.py config.py
|
|
||||||
$ vi config.py # 我们计划修改 DevelopmentConfig中的配置,因为默认jumpserver是使用该配置,它继承自Config
|
|
||||||
|
|
||||||
**注意: 配置文件是 Python 格式,不要用 TAB,而要用空格**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
class DevelopmentConfig(Config):
|
|
||||||
DEBUG = True
|
|
||||||
DB_ENGINE = 'mysql'
|
|
||||||
DB_HOST = '127.0.0.1'
|
|
||||||
DB_PORT = 3306
|
|
||||||
DB_USER = 'jumpserver'
|
|
||||||
DB_PASSWORD = 'somepassword'
|
|
||||||
DB_NAME = 'jumpserver'
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
config = DevelopmentConfig() # 确保使用的是刚才设置的配置文件
|
|
||||||
|
|
||||||
**2.8 生成数据库表结构和初始化数据**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/jumpserver/utils
|
|
||||||
$ bash make_migrations.sh
|
|
||||||
|
|
||||||
**2.9 运行 Jumpserver**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/jumpserver
|
|
||||||
$ python run_server.py all
|
|
||||||
|
|
||||||
运行不报错,请浏览器访问 http://192.168.244.144:8080/
|
|
||||||
(这里只是 Jumpserver, 没有 Web Terminal,所以访问 Web Terminal 会报错)
|
|
||||||
|
|
||||||
账号: admin 密码: admin
|
|
||||||
|
|
||||||
三. 安装 SSH Server 和 WebSocket Server: Coco
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**3.1 下载或 Clone 项目**
|
|
||||||
|
|
||||||
新开一个终端,连接测试机,别忘了 source /opt/py3/bin/activate
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt
|
|
||||||
$ git clone https://github.com/jumpserver/coco.git && cd coco && git checkout master
|
|
||||||
|
|
||||||
|
|
||||||
**3.2 安装依赖**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/coco/requirements
|
|
||||||
$ yum -y install $(cat rpm_requirements.txt)
|
|
||||||
$ pip install -r requirements.txt
|
|
||||||
|
|
||||||
**3.3 查看配置文件并运行**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cd /opt/coco
|
|
||||||
$ cp conf_example.py conf.py
|
|
||||||
$ python run_server.py
|
|
||||||
|
|
||||||
这时需要去 Jumpserver 管理后台-会话管理-终端管理(http://192.168.244.144:8080/terminal/terminal/)接受 Coco 的注册
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
Coco version 0.4.0, more see https://www.jumpserver.org
|
|
||||||
Starting ssh server at 0.0.0.0:2222
|
|
||||||
Quit the server with CONTROL-C.
|
|
||||||
|
|
||||||
**3.4 测试连接**
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ ssh -p2222 admin@192.168.244.144
|
|
||||||
密码: admin
|
|
||||||
|
|
||||||
如果是用在 Windows 下,Xshell Terminal 登录语法如下
|
|
||||||
$ssh admin@192.168.244.144 2222
|
|
||||||
密码: admin
|
|
||||||
如果能登陆代表部署成功
|
|
||||||
|
|
||||||
四. 安装 Web Terminal 前端: Luna
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Luna 已改为纯前端,需要 Nginx 来运行访问
|
|
||||||
|
|
||||||
访问(https://github.com/jumpserver/luna/releases)下载对应版本的 release 包,直接解压,不需要编译
|
|
||||||
|
|
||||||
4.1 解压 Luna
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ pwd
|
|
||||||
/opt/
|
|
||||||
|
|
||||||
$ tar xvf luna.tar.gz
|
|
||||||
$ ls /opt/luna
|
|
||||||
...
|
|
||||||
|
|
||||||
五. 安装 Windows 支持组件
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
因为手动安装 guacamole 组件比较复杂,这里提供打包好的 docker 使用, 启动 guacamole
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
|
|
||||||
# 注意:这里一定要改写一下本机的IP地址, 否则会出错
|
|
||||||
|
|
||||||
docker run --name jms_guacamole -d \
|
|
||||||
-p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \
|
|
||||||
-e JUMPSERVER_KEY_DIR=/config/guacamole/key \
|
|
||||||
-e JUMPSERVER_SERVER=http://<填写本机的IP地址>:8080 \
|
|
||||||
registry.jumpserver.org/public/guacamole:latest
|
|
||||||
|
|
||||||
这里所需要注意的是 guacamole 暴露出来的端口是 8081,若与主机上其他端口冲突请自定义一下。
|
|
||||||
|
|
||||||
再次强调:修改 JUMPSERVER_SERVER 环境变量的配置,填上 Jumpserver 的内网地址, 这时
|
|
||||||
去 Jumpserver-会话管理-终端管理 接受[Gua]开头的一个注册
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
六. 配置 Nginx 整合各组件
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
6.1 安装 Nginx 根据喜好选择安装方式和版本
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
yum -y install nginx
|
|
||||||
|
|
||||||
|
|
||||||
6.2 准备配置文件 修改 /etc/nginx/nginx.conf
|
|
||||||
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
|
|
||||||
location /luna/ {
|
|
||||||
try_files $uri / /index.html;
|
|
||||||
alias /opt/luna/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /media/ {
|
|
||||||
add_header Content-Encoding gzip;
|
|
||||||
root /opt/jumpserver/data/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /static/ {
|
|
||||||
root /opt/jumpserver/data/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /socket.io/ {
|
|
||||||
proxy_pass http://localhost:5000/socket.io/;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
}
|
|
||||||
|
|
||||||
location /guacamole/ {
|
|
||||||
proxy_pass http://localhost:8081/;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $http_connection;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:8080;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
6.3 运行 Nginx
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
nginx -t
|
|
||||||
service nginx start
|
|
||||||
|
|
||||||
|
|
||||||
6.4 访问 http://192.168.244.144
|
|
142
docs/upgrade.rst
@ -1,142 +0,0 @@
|
|||||||
更新升级
|
|
||||||
-------------
|
|
||||||
|
|
||||||
1. 升级 Jumpserver
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ git pull && pip install -r requirements/requirements.txt && cd utils && sh make_migrations.sh
|
|
||||||
|
|
||||||
2. 升级 Coco
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ git pull && cd requirements && pip install -r requirements.txt # 不要指定 -i参数
|
|
||||||
|
|
||||||
3. 升级 Luna
|
|
||||||
|
|
||||||
重新下载 release 包(https://github.com/jumpserver/luna/releases)
|
|
||||||
|
|
||||||
4. 升级 guacamole
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ docker pull registry.jumpserver.org/public/guacamole:latest
|
|
||||||
$ docker stop jms_guacamole # 或者写guacamole的容器ID
|
|
||||||
$ docker run --name jms_guacamole -d \
|
|
||||||
-p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \
|
|
||||||
-e JUMPSERVER_KEY_DIR=/config/guacamole/key \
|
|
||||||
-e JUMPSERVER_SERVER=http://<填写本机的IP地址>:8080 \
|
|
||||||
registry.jumpserver.org/public/guacamole:latest
|
|
||||||
|
|
||||||
|
|
||||||
切换分支或离线升级
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
**Jumpserver**
|
|
||||||
|
|
||||||
说明: 以下操作,都在jumpserver所在目录运行
|
|
||||||
|
|
||||||
1. 备份配置文件
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ jumpserver_backup=/tmp/jumpserver_backup
|
|
||||||
$ mkdir -p $jumpserver_backup
|
|
||||||
$ cp config.py $jumpserver_backup
|
|
||||||
|
|
||||||
2. 备份migrations migrations中存的是数据库表结构的变更,切换分支会丢失
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ for app in common users assets ops perms terminal;do
|
|
||||||
mkdir -p $jumpserver_backup/${app}_migrations
|
|
||||||
cp apps/${app}/migrations/*.py $jumpserver_backup/${app}_migrations
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
3. 备份数据库,已被不时之需
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ mysqldump -u你的数据库账号 -h数据库地址 -p 数据库名称 > $jumpserver_backup/db_backup.sql
|
|
||||||
|
|
||||||
4. 备份录像文件
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cp -r data/media $jumpserver_backup/
|
|
||||||
|
|
||||||
5. 切换分支或下载离线包, 更新代码
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ git checkout master # or other branch
|
|
||||||
|
|
||||||
|
|
||||||
6. 还原配置文件
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cp $jumpserver_backup/config.py .
|
|
||||||
|
|
||||||
7. 还原数据库表结构记录
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ for app in common users assets ops perms terminal;do
|
|
||||||
cp $jumpserver_backup/${app}_migrations/*.py ${app}/migrations/
|
|
||||||
done
|
|
||||||
|
|
||||||
8. 还原录像文件
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cp -r $jumpserver_backup/media/* data/media/
|
|
||||||
|
|
||||||
9. 更新依赖或表结构
|
|
||||||
|
|
||||||
::
|
|
||||||
$ pip install -r requirements/requirements.txt && cd utils && sh make_migrations.sh
|
|
||||||
|
|
||||||
|
|
||||||
**Coco**
|
|
||||||
|
|
||||||
说明: 以下操作都在 coco 项目所在目录
|
|
||||||
|
|
||||||
coco是无状态的,备份 keys 目录即可
|
|
||||||
|
|
||||||
1. 备份keys
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ cp -r keys $jumpserver_backup/
|
|
||||||
|
|
||||||
|
|
||||||
2. 离线更新升级coco
|
|
||||||
|
|
||||||
3. 还原 keys目录
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ mv keys keys_backup
|
|
||||||
$ cp -r $jumpserver_backup/keys .
|
|
||||||
|
|
||||||
4. 升级依赖
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ git pull && cd requirements && pip install -r requirements.txt
|
|
||||||
|
|
||||||
|
|
||||||
**Luna**
|
|
||||||
|
|
||||||
直接下载最新Release包替换即可
|
|
||||||
|
|
||||||
|
|
||||||
**Guacamole**
|
|
||||||
|
|
||||||
直接参考上面的升级即可, 需要注意的是如果更换机器,请备份
|
|
||||||
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
用户列表
|
|
||||||
========
|
|
||||||
|
|
||||||
这里介绍用户列表的功能。
|
|
||||||
|
|
||||||
点击页面左侧“用户列表”菜单下的“用户列表“,进入用户列表页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _create_user:
|
|
||||||
|
|
||||||
创建用户
|
|
||||||
````````
|
|
||||||
|
|
||||||
点击页面左上角“创建用户”按钮,进入创建用户页面,填写账户,角色安全,个人等信息,点击“提交”按钮,用户创建完成。
|
|
||||||
|
|
||||||
|
|
||||||
.. _update_user:
|
|
||||||
|
|
||||||
更新用户
|
|
||||||
````````
|
|
||||||
|
|
||||||
点击页面右边的“更新”按钮,进入编辑用户页面,编辑用户信息,点击“提交”按钮,更新用户完成。
|
|
||||||
|
|
||||||
.. _delete_user:
|
|
||||||
|
|
||||||
删除用户
|
|
||||||
````````
|
|
||||||
|
|
||||||
点击页面右边的“删除”按钮,弹出是否删除确认框,点击“确定”按钮,删除用户完成。
|
|
||||||
|
|
||||||
.. _export_user:
|
|
||||||
|
|
||||||
导出用户
|
|
||||||
````````
|
|
||||||
|
|
||||||
选中用户,点击右上角的“导出”按钮,导出用户完成。
|
|
||||||
|
|
||||||
.. _import_user:
|
|
||||||
|
|
||||||
导入用户
|
|
||||||
````````
|
|
||||||
|
|
||||||
点击右上角的“导入”按钮,弹出导入对话框,选择要导入的CSV格式文件,点击“确认”按钮,导入用户完成。
|
|
||||||
|
|
||||||
.. _batch_user_operation:
|
|
||||||
|
|
||||||
批量操作
|
|
||||||
````````
|
|
||||||
|
|
||||||
选中用户,选择页面左下角的批量操作选项,点击”提交“按钮,批量操作完成。
|
|
@ -1,27 +0,0 @@
|
|||||||
个人资产
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍用户个人资产相关的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_personal_assets:
|
|
||||||
|
|
||||||
查看个人资产
|
|
||||||
````````````
|
|
||||||
|
|
||||||
登录个人用户,默认展示个人资产列表。点击主机名,查看资产的详细信息。
|
|
||||||
|
|
||||||
.. _host_login:
|
|
||||||
|
|
||||||
主机登录
|
|
||||||
`````````
|
|
||||||
|
|
||||||
点解页面左侧的"Web终端",进入主机登录页,然后点击页面右侧的主机IP地址,连接主机,页面右侧会展示当前连接的终端信息。
|
|
||||||
|
|
||||||
.. _host_logout:
|
|
||||||
|
|
||||||
主机登出
|
|
||||||
`````````
|
|
||||||
|
|
||||||
在主机登录页面,选择左上角的“服务器”按钮,出现两个选项,一个“断开链接“按钮,断开当前连接的主机;另一个”断开所有链接“,断开当前所有连接的主机。
|
|
@ -1,29 +0,0 @@
|
|||||||
用户组列表
|
|
||||||
============
|
|
||||||
|
|
||||||
这里介绍用户组列表的功能。
|
|
||||||
|
|
||||||
点击页面左侧“用户管理”菜单下的”用户组“,进入用户组列表页面。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _create_user_group:
|
|
||||||
|
|
||||||
创建用户组
|
|
||||||
``````````
|
|
||||||
|
|
||||||
点击页面左上角“创建用户组”按钮,进入创建用户组页面,填写用户组信息,点击“提交”按钮,创建用户完成。
|
|
||||||
|
|
||||||
.. _update_user_group:
|
|
||||||
|
|
||||||
更新用户组
|
|
||||||
``````````
|
|
||||||
|
|
||||||
点击页面右边的“更新”按钮,进入编辑用户组页面,编辑用户组信息,点击“确认”按钮,更新用户组完成。
|
|
||||||
|
|
||||||
.. _delete_user_group:
|
|
||||||
|
|
||||||
删除用户组
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面右边的“删除”按钮,弹出删除确认框,点击“确认”按钮,删除用户组完成。
|
|
@ -1,10 +0,0 @@
|
|||||||
用户使用文档
|
|
||||||
=============
|
|
||||||
|
|
||||||
这部分给您介绍Jumpserver的用户管理模块的使用方法。
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
user_asset
|
|
||||||
user_info
|
|
@ -1,34 +0,0 @@
|
|||||||
个人信息
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍个人信息相关的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_personal_info:
|
|
||||||
|
|
||||||
查看个人信息
|
|
||||||
````````````
|
|
||||||
|
|
||||||
点击页面左侧的“个人信息”,查看用户的个人信息、SSH密钥。
|
|
||||||
|
|
||||||
.. _modify_personal_info:
|
|
||||||
|
|
||||||
修改个人信息
|
|
||||||
````````````
|
|
||||||
|
|
||||||
在个人信息页,点击页面右上角的“设置”按钮,进入个人信息修改页面,填写个人信息,点击“提交”按钮,完成个人信息修改。
|
|
||||||
|
|
||||||
.. _update_password:
|
|
||||||
|
|
||||||
更新密码
|
|
||||||
`````````
|
|
||||||
|
|
||||||
在个人信息页,点击页面右上角的“重置密码“按钮,进入密码更新页面,填写原来密码、新密码等信息,点击“提交”按钮,完成密码更新。
|
|
||||||
|
|
||||||
.. _update_ssh_key:
|
|
||||||
|
|
||||||
密钥更新
|
|
||||||
`````````
|
|
||||||
|
|
||||||
在个人信息页,点击页面左上角的“重置SSH密钥“按钮,进入密钥更新页面,填写SSH公钥,点击“提交”按钮,完成密钥更新。
|
|
@ -1,35 +0,0 @@
|
|||||||
任务列表
|
|
||||||
=========
|
|
||||||
|
|
||||||
这里介绍任务列表的相关的功能。
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
.. _view_asset_works:
|
|
||||||
|
|
||||||
查看任务列表
|
|
||||||
````````````
|
|
||||||
|
|
||||||
任务列表页面默认展示一周内所有任务。点击标题可根据当前字段进行排序。
|
|
||||||
|
|
||||||
.. _invoke_asset_work:
|
|
||||||
|
|
||||||
手动执行任务
|
|
||||||
````````````
|
|
||||||
|
|
||||||
在任务列表中找到要手动执行的任务,点击“动作”标题下的“执行”按钮,完成手动执行当前任务。
|
|
||||||
|
|
||||||
.. _delete_asset_work:
|
|
||||||
|
|
||||||
删除任务
|
|
||||||
`````````
|
|
||||||
|
|
||||||
在任务列表中找到要删除的任务,点击“动作”标题下的“删除”按钮,完成删除当前任务。
|
|
||||||
|
|
||||||
.. _detial_asset_work:
|
|
||||||
|
|
||||||
查看任务详情
|
|
||||||
`````````````
|
|
||||||
|
|
||||||
在任务列表中找到要查看的任务,点击要查看的任务名称,即可进入任务详情页面。
|
|
||||||
|
|