diff --git a/.gitignore b/.gitignore index ccd5937f2..abf165e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ celerybeat.pid django.db celerybeat-schedule.db data/static +_build/ diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 5ce195783..7facaed22 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -12,7 +12,7 @@ __all__ = ['Node'] class Node(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True) key = models.CharField(unique=True, max_length=64, verbose_name=_("Key")) # '1:1:1:1' - value = models.CharField(max_length=128, unique=True, verbose_name=_("Value")) + value = models.CharField(max_length=128, verbose_name=_("Value")) child_mark = models.IntegerField(default=0) date_create = models.DateTimeField(auto_now_add=True) diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index a429d9895..7eaff63e6 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -26,14 +26,14 @@ signer = get_signer() class AssetUser(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) - username = models.CharField(max_length=16, verbose_name=_('Username')) + username = models.CharField(max_length=128, verbose_name=_('Username')) _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password')) _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ]) _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key')) comment = models.TextField(blank=True, verbose_name=_('Comment')) date_created = models.DateTimeField(auto_now_add=True) date_updated = models.DateTimeField(auto_now=True) - created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by')) + created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by')) @property def password(self): diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index 30f463597..a20ab3a74 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -91,7 +91,7 @@ def update_assets_hardware_info_util(assets, task_name=None): if task_name is None: task_name = _("Update some assets hardware info") tasks = const.UPDATE_ASSETS_HARDWARE_TASKS - hostname_list = [asset.hostname for asset in assets] + hostname_list = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] task, created = update_or_create_ansible_task( task_name, hosts=hostname_list, tasks=tasks, pattern='all', options=const.TASK_OPTIONS, run_as_admin=True, created_by='System', @@ -120,7 +120,10 @@ def update_assets_hardware_info_period(): """ from ops.utils import update_or_create_ansible_task task_name = _("Update assets hardware info period") - hostname_list = [asset.hostname for asset in Asset.objects.all()] + hostname_list = [ + asset.hostname for asset in Asset.objects.all() + if asset.is_active and asset.is_unixlike() + ] tasks = const.UPDATE_ASSETS_HARDWARE_TASKS # Only create, schedule by celery beat @@ -165,7 +168,8 @@ def test_admin_user_connectability_util(admin_user, task_name): from ops.utils import update_or_create_ansible_task assets = admin_user.get_related_assets() - hosts = [asset.hostname for asset in assets] + hosts = [asset.hostname for asset in assets + if asset.is_active and asset.is_unixlike()] if not hosts: return tasks = const.TEST_ADMIN_USER_CONN_TASKS @@ -257,7 +261,7 @@ def test_system_user_connectability_util(system_user, task_name): """ from ops.utils import update_or_create_ansible_task assets = system_user.assets - hosts = [asset.hostname for asset in assets] + hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] tasks = const.TEST_SYSTEM_USER_CONN_TASKS if not hosts: logger.info("No hosts, passed") @@ -346,7 +350,7 @@ def push_system_user_util(system_users, assets, task_name): logger.info("Not tasks, passed") return {} - hosts = [asset.hostname for asset in assets] + hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] if not hosts: logger.info("Not hosts, passed") return {} diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html index fe06a6fc7..528e271e6 100644 --- a/apps/assets/templates/assets/_system_user.html +++ b/apps/assets/templates/assets/_system_user.html @@ -13,7 +13,7 @@
-
{% trans 'Create system user' %}
+
{{ action }}
@@ -81,6 +81,14 @@ {% block custom_foot_js %} @@ -224,7 +230,9 @@ function editTreeNode() { if (!current_node){ return } - current_node.name = current_node.value; + if (current_node.value) { + current_node.name = current_node.value; + } zTree.editName(current_node); } @@ -313,38 +321,36 @@ function beforeDrag() { return true } -function beforeDrop() { - return true +function beforeDrop(treeId, treeNodes, targetNode, moveType) { + var treeNodesNames = []; + $.each(treeNodes, function (index, value) { + treeNodesNames.push(value.value); + }); + + var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.value + "` 下吗?"; + if (confirm(msg)){ + return true + } else { + return false + } } function onDrag(event, treeId, treeNodes) { } function onDrop(event, treeId, treeNodes, targetNode, moveType) { - console.log("DROP"); - console.log(event); - console.log(treeNodes); - console.log(targetNode); - console.log(moveType); - - var treeNodesNames = []; var treeNodesIds = []; $.each(treeNodes, function (index, value) { - treeNodesNames.push(value.value); treeNodesIds.push(value.id); }); - var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.value + "` 下吗?"; var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.id); var body = {nodes: treeNodesIds}; - if (confirm(msg)){ - APIUpdateAttr({ - url: the_url, - method: "PUT", - body: JSON.stringify(body) - }) - } - + APIUpdateAttr({ + url: the_url, + method: "PUT", + body: JSON.stringify(body) + }) } function initTree() { diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index d1f30c161..ad1afa7a4 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -178,7 +178,7 @@ - + @@ -187,7 +187,7 @@ {{ node.name }} - + {% endfor %} @@ -204,27 +204,27 @@ {% endblock %} {% block custom_foot_js %} {% endblock %} diff --git a/apps/terminal/urls/api_urls.py b/apps/terminal/urls/api_urls.py index 9138012b4..0d9da427d 100644 --- a/apps/terminal/urls/api_urls.py +++ b/apps/terminal/urls/api_urls.py @@ -22,6 +22,7 @@ urlpatterns = [ url(r'^v1/sessions/(?P[0-9a-zA-Z\-]{36})/replay/$', api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), name='session-replay'), + url(r'^v1/tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'), url(r'^v1/terminal/(?P[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key'), url(r'^v1/terminal/config', api.TerminalConfig.as_view(), name='terminal-config'), ] diff --git a/apps/terminal/views/command.py b/apps/terminal/views/command.py index 6fdf905bd..0af0b5bfd 100644 --- a/apps/terminal/views/command.py +++ b/apps/terminal/views/command.py @@ -6,7 +6,7 @@ from django.conf import settings from django.utils import timezone from django.utils.translation import ugettext as _ -from common.mixins import DatetimeSearchMixin +from common.mixins import DatetimeSearchMixin, AdminUserRequiredMixin from ..models import Command from .. import utils from ..backends import get_multi_command_store @@ -15,7 +15,7 @@ __all__ = ['CommandListView'] common_storage = get_multi_command_store() -class CommandListView(DatetimeSearchMixin, ListView): +class CommandListView(DatetimeSearchMixin, AdminUserRequiredMixin, ListView): model = Command template_name = "terminal/command_list.html" context_object_name = 'command_list' diff --git a/apps/terminal/views/session.py b/apps/terminal/views/session.py index 0970cade2..3b66baff7 100644 --- a/apps/terminal/views/session.py +++ b/apps/terminal/views/session.py @@ -74,6 +74,7 @@ class SessionOnlineListView(SessionListView): context = { 'app': _('Terminal'), 'action': _('Session online list'), + 'type': 'online', 'now': timezone.now(), } kwargs.update(context) @@ -97,7 +98,7 @@ class SessionOfflineListView(SessionListView): return super().get_context_data(**kwargs) -class SessionDetailView(SingleObjectMixin, ListView): +class SessionDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView): template_name = 'terminal/session_detail.html' model = Session object = None diff --git a/apps/users/api.py b/apps/users/api.py index 0d99e0a4c..b485a593e 100644 --- a/apps/users/api.py +++ b/apps/users/api.py @@ -145,7 +145,8 @@ class UserAuthApi(APIView): if not login_ip: x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',') - if x_forwarded_for: + + if x_forwarded_for and x_forwarded_for[0]: login_ip = x_forwarded_for[0] else: login_ip = request.META.get("REMOTE_ADDR") diff --git a/apps/users/models/authentication.py b/apps/users/models/authentication.py index f023d3d59..5169a79d2 100644 --- a/apps/users/models/authentication.py +++ b/apps/users/models/authentication.py @@ -16,7 +16,8 @@ class AccessKey(models.Model): default=uuid.uuid4, editable=False) secret = models.UUIDField(verbose_name='AccessKeySecret', default=uuid.uuid4, editable=False) - user = models.ForeignKey(User, verbose_name='User', on_delete=models.CASCADE, related_name='access_key') + user = models.ForeignKey(User, verbose_name='User', + on_delete=models.CASCADE, related_name='access_key') def get_id(self): return str(self.id) diff --git a/apps/users/models/group.py b/apps/users/models/group.py index 07238c1a5..128fbdbcb 100644 --- a/apps/users/models/group.py +++ b/apps/users/models/group.py @@ -22,6 +22,7 @@ class UserGroup(NoDeleteModelMixin): class Meta: ordering = ['name'] + verbose_name = _("User group") @classmethod def initial(cls): diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 25d7d0303..4c051db22 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -251,6 +251,7 @@ class User(AbstractUser): class Meta: ordering = ['username'] + verbose_name = _("User") #: Use this method initial user @classmethod diff --git a/apps/users/templates/users/login.html b/apps/users/templates/users/login.html index 1f6498370..13276f6fe 100644 --- a/apps/users/templates/users/login.html +++ b/apps/users/templates/users/login.html @@ -22,24 +22,27 @@
-

欢迎使用Jumpserver开源跳板机

+

欢迎使用Jumpserver开源堡垒机

- 符合4A规范的专业运维审计系统:拥有跳板机的所有功能,认证,授权,审计,文件上传; + 全球首款完全开源的堡垒机,使用GNU GPL v2.0开源协议,是符合 4A 的专业运维审计系统。

- 极致的用户使用体验:拥有时尚外观是区别与以往版本和其他软件的铭牌,高雅的气质让你爱不释手; + 使用Python / Django 进行开发,遵循 Web 2.0 规范,配备了业界领先的 Web Terminal 解决方案,交互界面美观、用户体验好。

- 混合云环境下的堡垒机:怎么能容忍传统堡垒机的繁琐步骤,Jumpserver让你极致省力; + 采纳分布式架构,支持多机房跨区域部署,中心节点提供 API,各机房部署登录节点,可横向扩展、无并发访问限制。

- 改变世界,从一点点开始。 + 改变世界,从一点点开始。

-
{% trans 'Login' %}
+
+ + {% trans 'Login' %} +
{% csrf_token %} {% if form.errors %} @@ -60,12 +63,16 @@
+ {% if demo_mode %} +

+ Demo账号: admin 密码: admin +

+ {% endif %} +
{% trans 'Forgot password' %}? -

-

diff --git a/apps/users/views/group.py b/apps/users/views/group.py index fb279b582..958c00ccc 100644 --- a/apps/users/views/group.py +++ b/apps/users/views/group.py @@ -92,8 +92,8 @@ class UserGroupGrantedAssetView(AdminUserRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = { - 'app': 'User', - 'action': 'User group granted asset', + 'app': _('Users'), + 'action': _('User group granted asset'), } kwargs.update(context) return super().get_context_data(**kwargs) diff --git a/apps/users/views/login.py b/apps/users/views/login.py index 10ad697ba..0b70238c0 100644 --- a/apps/users/views/login.py +++ b/apps/users/views/login.py @@ -1,6 +1,7 @@ # ~*~ coding: utf-8 ~*~ from __future__ import unicode_literals +import os from django import forms from django.shortcuts import render from django.contrib.auth import login as auth_login, logout as auth_logout @@ -56,6 +57,7 @@ class UserLoginView(FormView): return HttpResponse(_("Please enable cookies and try again.")) auth_login(self.request, form.get_user()) x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR', '').split(',') + if x_forwarded_for and x_forwarded_for[0]: login_ip = x_forwarded_for[0] else: @@ -75,6 +77,13 @@ class UserLoginView(FormView): self.redirect_field_name, self.request.GET.get(self.redirect_field_name, reverse('index'))) + def get_context_data(self, **kwargs): + context = { + 'demo_mode': os.environ.get("DEMO_MODE"), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + @method_decorator(never_cache, name='dispatch') class UserLogoutView(TemplateView): @@ -237,7 +246,7 @@ class LoginLogListView(DatetimeSearchMixin, ListView): if self.user: queryset = queryset.filter(username=self.user) if self.keyword: - queryset = self.queryset.filter( + queryset = queryset.filter( Q(ip__contains=self.keyword) | Q(city__contains=self.keyword) | Q(username__contains=self.keyword) diff --git a/apps/users/views/user.py b/apps/users/views/user.py index e85f04877..bf2ecca57 100644 --- a/apps/users/views/user.py +++ b/apps/users/views/user.py @@ -313,7 +313,6 @@ class UserProfileView(LoginRequiredMixin, TemplateView): def get_context_data(self, **kwargs): context = { - 'app': _('Users'), 'action': _('Profile'), } kwargs.update(context) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..526c8f5df --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# 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) \ No newline at end of file diff --git a/docs/_static/img/logo-text.png b/docs/_static/img/logo-text.png new file mode 100644 index 000000000..cb76b555a Binary files /dev/null and b/docs/_static/img/logo-text.png differ diff --git a/docs/_static/img/structure.png b/docs/_static/img/structure.png new file mode 100644 index 000000000..90476014c Binary files /dev/null and b/docs/_static/img/structure.png differ diff --git a/docs/admin_asset.rst b/docs/admin_asset.rst new file mode 100644 index 000000000..758db8912 --- /dev/null +++ b/docs/admin_asset.rst @@ -0,0 +1,2 @@ +资产管理模块 +============= \ No newline at end of file diff --git a/docs/admin_guide.rst b/docs/admin_guide.rst new file mode 100644 index 000000000..df59969cc --- /dev/null +++ b/docs/admin_guide.rst @@ -0,0 +1,10 @@ +管理文档 +========= + +这里介绍管理员功能。 + +.. toctree:: + :maxdepth: 1 + + admin_user + admin_asset diff --git a/docs/admin_user.rst b/docs/admin_user.rst new file mode 100644 index 000000000..cdce938e1 --- /dev/null +++ b/docs/admin_user.rst @@ -0,0 +1,51 @@ +用户管理 +======== + +这里介绍用户管理模块的功能。 + +点击页面左侧“用户列表”菜单下的“用户列表,进入用户列表页面。 + +.. contents:: Topics + +.. _create_user: + +创建用户 +```````` + +点击页面左上角“创建用户”按钮,进入创建用户页面,填写账户,角色安全,个人等信息,点击“提交”按钮,用户创建完成。 + + +.. _update_user: + +更新用户 +```````` + +点击页面右边的“更新”按钮,进入编辑用户页面,编辑用户信息,点击“提交”按钮,更新用户完成。 + +.. _delete_user: + +删除用户 +```````` + +点击页面右边的“删除”按钮,弹出是否删除确认框,点击“确定”按钮,删除用户完成。 + +.. _export_user: + +导出用户 +```````` + +选中用户,点击右上角的“导出”按钮,导出用户完成。 + +.. _inport_user: + +导入用户 +```````` + +点击右上角的“导入”按钮,弹出导入对话框,选择要导入的CSV格式文件,点击“确认”按钮,导入用户完成。 + +.. _batch_operation: + +批量操作 +```````` + +选中用户,选择页面左下角的批量操作选项,点击”提交“按钮,批量操作完成。 \ No newline at end of file diff --git a/docs/api_style_guide.rst b/docs/api_style_guide.rst new file mode 100644 index 000000000..438a6d94a --- /dev/null +++ b/docs/api_style_guide.rst @@ -0,0 +1,166 @@ +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 \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000..068048c0f --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,168 @@ +# -*- 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': False +} + +# 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 Documentation', + author, 'jumpserver', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- +html_logo = '_static/img/logo-text.png' diff --git a/docs/contact.rst b/docs/contact.rst new file mode 100644 index 000000000..767554517 --- /dev/null +++ b/docs/contact.rst @@ -0,0 +1,33 @@ +联系方式 ++++++++++++++++++++++++++ + +QQ群 +~~~~~~~~ + +群1: 390139816 +群2: 399218702 +群3: 552054376 + + +Github +~~~~~~~~ + +https://github.com/jumpserver/jumpserver.git + + +官网 +~~~~~~~~ + +http://www.jumpserver.org + + +Demo +~~~~~~~~ + +http://demo.jumpserver.org:8080 + + +邮件 +~~~~~~~~ + +ibuler#fit2cloud.com (#替换为@) \ No newline at end of file diff --git a/docs/contributor.rst b/docs/contributor.rst new file mode 100644 index 000000000..05c2604f1 --- /dev/null +++ b/docs/contributor.rst @@ -0,0 +1,13 @@ +贡献者 +++++++++++++++++++++++++ + +感谢一下朋友为Jumpserver做出的贡献,世界因你们而不同,排名不分先后 + + +- **小彧 <李磊>** Django资深开发者,为用户模块贡献了很多代码 +- **sofia <周小侠>** 资深前端工程师, 前端代码贡献者 +- **liuz <刘正> 全栈工程师** 编写了Web terminal大部分代码 +- **jiaxiangkong <陈尚委>** Jumpserver测试运营 +- **halcyon <王墉>** DevOps 资深开发者, 0.3.2 核心开发者之一 +- **yumaojun03 <喻茂峻>** DevOps 资深开发者,擅长Python, Go以及PAAS平台开发 +- **kelianchun <柯连春>** DevOps 资产开发者,fix了很多bug \ No newline at end of file diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 000000000..9e2411ea9 --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,12 @@ +开发文档 +====================================== + +.. toctree:: + :maxdepth: 1 + :caption: 开发文档 + + api_style_guide + python_style_guide + project_structure + + diff --git a/docs/faq.rst b/docs/faq.rst new file mode 100644 index 000000000..d02cca126 --- /dev/null +++ b/docs/faq.rst @@ -0,0 +1,2 @@ +FAQ ++++++++++++++++++++++ \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 000000000..787f05564 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,29 @@ +.. 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 + :caption: 文档: + + intro + installation + admin_guide + user_guide + development + contributor + contact + faq + + + +索引 +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 000000000..e9dde1f48 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,9 @@ +安装文档 +++++++++++++++++++++++++ + +.. toctree:: + :maxdepth: 1 + + quickstart + step_by_step + upgrade diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 000000000..a8810e14f --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,51 @@ +简介 +============ + +Jumpserver是混合云下更好用的堡垒机, 分布式架构设计无限扩展,轻松对接混合云资产,支持使用云存储(AWS S3, ES等)存储录像、命令 + +Jumpserver颠覆传统堡垒机, 无主机和并发数量限制,支持水平扩容,FIT2CLOUD提供完备的商业服务支持,用户无后顾之忧 + +Jumpserver拥有极致的用户体验, 极致UI体验,容器化的部署方式,部署过程方便快捷,可持续升级 + + +组件说明 +++++++++++++++++++++++++ + +Jumpserver +``````````` +现指Jumpserver管理后台,是核心组件(Core), 使用 Django Class Based View 风格开发,支持Restful API。 + +`Github `_ + + +Coco +```````` +实现了SSH Server 和 Web Terminal Server的组件,提供ssh和websocket接口, 使用 Paramiko 和 Flask 开发。 + + +`Github `__ + + +Luna +```````` +现在是Web Terminal前端,计划前端页面都由该项目提供,Jumpserver只提供API,不再负责后台渲染html等。 + +`Github `__ + + +Guacamole +``````````` +Apache 跳板机项目,Jumpserver使用其组件实现RDP功能,Jumpserver并没有修改其代码而是添加了额外的插件,支持Jumpserver调用 + + +Jumpserver-python-sdk +``````````````````````` +Jumpserver API Python SDK,Coco目前使用该SDK与Jumpserver API交互 + +`Github `__ + + +组件架构图 +++++++++++++++++++++++++ +.. image:: _static/img/structure.png + :alt: 组件架构图 diff --git a/docs/README.md b/docs/old/README.md similarity index 100% rename from docs/README.md rename to docs/old/README.md diff --git a/docs/api_style_guide.md b/docs/old/api_style_guide.md similarity index 100% rename from docs/api_style_guide.md rename to docs/old/api_style_guide.md diff --git a/docs/django_class_base_view_inheritance.py b/docs/old/django_class_base_view_inheritance.py similarity index 100% rename from docs/django_class_base_view_inheritance.py rename to docs/old/django_class_base_view_inheritance.py diff --git a/docs/install.md b/docs/old/install.md similarity index 100% rename from docs/install.md rename to docs/old/install.md diff --git a/docs/project_structure.md b/docs/old/project_structure.md similarity index 100% rename from docs/project_structure.md rename to docs/old/project_structure.md diff --git a/docs/python_style_guide.md b/docs/old/python_style_guide.md similarity index 100% rename from docs/python_style_guide.md rename to docs/old/python_style_guide.md diff --git a/docs/table_design.xml b/docs/old/table_design.xml similarity index 100% rename from docs/table_design.xml rename to docs/old/table_design.xml diff --git a/docs/project_structure.rst b/docs/project_structure.rst new file mode 100644 index 000000000..151cda143 --- /dev/null +++ b/docs/project_structure.rst @@ -0,0 +1,51 @@ +项目骨架 +-------- + +说明如下: + +:: + + . + ├── 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 // 项目模板目录 \ No newline at end of file diff --git a/docs/python_style_guide.rst b/docs/python_style_guide.rst new file mode 100644 index 000000000..de7bae56f --- /dev/null +++ b/docs/python_style_guide.rst @@ -0,0 +1,216 @@ +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 (:raw-latex:`\t`)。 + 之所以与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) \ No newline at end of file diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 000000000..7892999fe --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,48 @@ +快速安装 +========================== + +Jumpserver 封装了一个All in one Docker,可以快速启动。该镜像集成了所有需要的组件,可以使用外置db和redis + +Tips: 不建议在生产中使用 + + +Docker 安装见: `Docker官方安装文档 `_ + + +快速启动 +``````````````` +使用root命令行输入:: + + $ docker run -p 8080:80 -p 2222:2222 jumpserver/jumpserver:0.5.0-beta2 + +访问 +``````````````` + +浏览器访问: http://localhost:8080 + +ssh访问: ssh -p 2222 localhost + + +额外环境变量 +``````````````` + +- DB_ENGINE = mysql +- DB_HOST = mysql_host +- DB_PORT = 3306 +- DB_USER = xxx +- DB_PASSWORD = xxxx +- DB_NAME = jumpserver + +- REDIS_HOST = '' +- REDIS_PORT = '' +- REDIS_PASSWORD = '' + + :: + + docker run -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 jumpserver/jumpserver:0.5.0-beta2 + + +仓库地址 +``````````````` + +https://github.com/jumpserver/Dockerfile diff --git a/docs/step_by_step.rst b/docs/step_by_step.rst new file mode 100644 index 000000000..db4b08608 --- /dev/null +++ b/docs/step_by_step.rst @@ -0,0 +1,294 @@ +一步一步安装 +-------------------------- + +环境 +~~~~ + +- 系统: 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 + +**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 0.5.0 +~~~~~~~~~~~~~~~~~~~~~~~~ + +**2.1 下载或clone项目** + +项目提交较多git clone时较大,你可以选择去github项目页面直接下载 +zip包,我的网速好,我直接clone了 + +:: + + $ cd /opt/ + $ git clone --depth=1 https://github.com/jumpserver/jumpserver.git && cd jumpserver && git checkout dev + +**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 broker** + +:: + + $ 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,而要用空格** **注意: +配置文件是python格式,不要用tab,而要用空格** **注意: +配置文件是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和Web Socket Server: Coco +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**3.1 下载clone项目** + +新开一个终端,连接测试机,别忘了 source /opt/py3/bin/activate + +:: + + $ cd /opt + $ git clone https://github.com/jumpserver/coco.git && cd coco && git checkout dev + +**3.2 安装依赖** + +:: + + $ cd /opt/coco/requirements $ yum -y install $(cat rpm_requirements.txt) $ pip install requirements.txt + + +**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来运行访问 + +下载 release包,直接解压,不需要编译 + +访问 https://github.com/jumpserver/luna/releases,下载对应release包 + +4.1 解压luna + +:: + + $ pwd + /opt/ + + $ tar xvf luna.tar.gz + $ ls /opt/luna + ... + +五. 安装Windows支持组件 +~~~~~~~~~~~~~~~~~~~~~~~ + +使用docker启动 guacamole + +.. code:: shell + + docker run \ + -p 8080:8080 \ + -e JUMPSERVER_SERVER=http://:8080 \ + jumpserver/guacamole + +这里所需要注意的是guacamole暴露出来的端口是8080,若与jumpserver部署在同一主机上自定义一下。 + +修改JUMPSERVER_SERVER的配置,填上jumpserver的内网地址 + +六. 配置 nginx 整合各组件 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +6.1 安装nginx 根据喜好选择安装方式和版本 + +6.2 配置文件 + +:: + + 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_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location /guacamole/ { + proxy_pass http://:8080/; + } + + location / { + proxy_pass http://localhost:8080; + } + } + +6.3 运行 nginx + +6.4 访问 http://192.168.244.144 \ No newline at end of file diff --git a/docs/upgrade.rst b/docs/upgrade.rst new file mode 100644 index 000000000..422aba51b --- /dev/null +++ b/docs/upgrade.rst @@ -0,0 +1,18 @@ +升级 +---- + +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包 \ No newline at end of file diff --git a/docs/user_asset.rst b/docs/user_asset.rst new file mode 100644 index 000000000..71855f76e --- /dev/null +++ b/docs/user_asset.rst @@ -0,0 +1,27 @@ +个人资产 +========= + +这里介绍用户个人资产相关的功能。 + +.. contents:: Topics + +.. _view_personal_assets: + +查看个人资产 +```````````` + +登录个人用户,默认展示个人资产列表。点击主机名,查看资产的详细信息。 + +.. _host_login: + +主机登录 +````````` + +点解页面左侧的"Web终端",进入主机登录页,然后点击页面右侧的主机IP地址,连接主机,页面右侧会展示当前连接的终端信息。 + +.. _host_logout: + +主机登出 +````````` + +在主机登录页面,选择左上角的“服务器”按钮,出现两个选项,一个“断开链接“按钮,断开当前连接的主机;另一个”断开所有链接“,断开当前所有连接的主机。 \ No newline at end of file diff --git a/docs/user_guide.rst b/docs/user_guide.rst new file mode 100644 index 000000000..97d9810b3 --- /dev/null +++ b/docs/user_guide.rst @@ -0,0 +1,10 @@ +用户使用文档 +============= + +这部分给您介绍Jumpserver的用户管理模块的使用方法。 + +.. toctree:: + :maxdepth: 1 + + user_asset + user_info \ No newline at end of file diff --git a/docs/user_info.rst b/docs/user_info.rst new file mode 100644 index 000000000..23feb4754 --- /dev/null +++ b/docs/user_info.rst @@ -0,0 +1,34 @@ +个人信息 +========= + +这里介绍个人信息相关的功能。 + +.. contents:: Topics + +.. _view_personal_info: + +查看个人信息 +```````````` + +点击页面左侧的“个人信息”,查看用户的个人信息、SSH密钥。 + +.. _modify_personal_info: + +修改个人信息 +```````````` + +在个人信息页,点击页面右上角的“设置”按钮,进入个人信息修改页面,填写个人信息,点击“提交”按钮,完成个人信息修改。 + +.. _update_password: + +更新密码 +````````` + +在个人信息页,点击页面右上角的“重置密码“按钮,进入密码更新页面,填写原来密码、新密码等信息,点击“提交”按钮,完成密码更新。 + +.. _update_ssh_key: + +密钥更新 +````````` + +在个人信息页,点击页面左上角的“重置SSH密钥“按钮,进入密钥更新页面,填写SSH公钥,点击“提交”按钮,完成密钥更新。 \ No newline at end of file diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 47989e7e8..42f3bc36a 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -56,8 +56,8 @@ uritemplate==3.0.0 urllib3==1.22 vine==1.1.4 gunicorn==19.7.1 -https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat -#django_celery_beat==1.1.0 +#https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat +django_celery_beat==1.1.1 ephem==3.7.6.0 python-gssapi==0.6.4 jms-es-sdk