From fcbe94de374837ba16e468c198f9bf3c5e138c5c Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 8 Mar 2018 12:28:45 +0800 Subject: [PATCH 01/25] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=96=B0=E6=8C=81?= =?UTF-8?q?=E4=B9=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/step_by_step.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/step_by_step.rst b/docs/step_by_step.rst index 3112de67a..1221c2b85 100644 --- a/docs/step_by_step.rst +++ b/docs/step_by_step.rst @@ -232,7 +232,8 @@ Luna 已改为纯前端,需要 Nginx 来运行访问 docker run -d \ - -p 8081:8080 \ + -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 From 422990a992acee09ff10e4ca47c5ef7be89f4a68 Mon Sep 17 00:00:00 2001 From: fit2cloud-fengyi Date: Fri, 9 Mar 2018 10:33:57 +0800 Subject: [PATCH 02/25] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20venv=20=E5=88=B0=20i?= =?UTF-8?q?gnore=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dc51315af..488f8a776 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .env env env* +venv dist build *.egg From 050b6e6d88c1456c1dd9edfbc6da8b0217d66d8d Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 9 Mar 2018 12:12:10 +0800 Subject: [PATCH 03/25] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9=E4=B8=80?= =?UTF-8?q?=E4=BA=9Bdocs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contact.rst | 15 +++++++++------ docs/quickstart.rst | 17 ++++++++++------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/contact.rst b/docs/contact.rst index 789207779..d858258cf 100644 --- a/docs/contact.rst +++ b/docs/contact.rst @@ -4,14 +4,17 @@ 商业支持 ~~~~~~~~~~~ -https://market.aliyun.com/products/53690006/cmgj026011.html +`阿里云市场购买: `_ + QQ群 ~~~~~~~~ -群1: 390139816 -群2: 399218702 -群3: 552054376 +群1: 390139816 (推荐) + +群2: 399218702 (满) + +群3: 552054376 (满) Github @@ -29,10 +32,10 @@ http://www.jumpserver.org Demo ~~~~~~~~ -http://demo.jumpserver.org:8080 +http://demo.jumpserver.org 邮件 ~~~~~~~~ -ibuler#fit2cloud.com (#替换为@) \ No newline at end of file +support@fit2cloud.com (#替换为@) \ No newline at end of file diff --git a/docs/quickstart.rst b/docs/quickstart.rst index c99675d5a..3a5315416 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -1,9 +1,9 @@ 快速安装 ========================== -Jumpserver 封装了一个 All in one Docker,可以快速启动。该镜像集成了所有需要的组件,可以使用外置 Database 和 Redis +Jumpserver 封装了一个 All in one Docker,可以快速启动。该镜像集成了所需要的组件(Windows组件未暂未集成),也支持使用外置 Database 和 Redis -Tips: 不建议在生产中使用 +Tips: 不建议在生产中使用, 生产中请使用 详细安装 `详细安装 `_ Docker 安装见: `Docker官方安装文档 `_ @@ -18,9 +18,12 @@ Docker 安装见: `Docker官方安装文档 `_ 访问 ``````````````` -浏览器访问: http://localhost:8080 +浏览器访问: http://<容器所在服务器IP>:8080 + +SSH访问: ssh -p 2222 <容器所在服务器IP> + +XShell等工具请添加connection连接 -SSH访问: ssh -p 2222 localhost 额外环境变量 @@ -33,9 +36,9 @@ SSH访问: ssh -p 2222 localhost - DB_PASSWORD = xxxx - DB_NAME = jumpserver -- REDIS_HOST = '' -- REDIS_PORT = '' -- REDIS_PASSWORD = '' +- REDIS_HOST = +- REDIS_PORT = +- REDIS_PASSWORD = < :: From 9ffb079c8f7368e29a43682b2e8afe5aa077c365 Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 9 Mar 2018 12:53:08 +0800 Subject: [PATCH 04/25] =?UTF-8?q?[Update]=20=E5=A2=9E=E5=8A=A0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9system=20user=20auth=20=E7=9A=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/system_user.py | 21 ++++++++++----------- apps/assets/serializers/system_user.py | 15 +++++++++++++++ apps/jumpserver/settings.py | 11 +++++++++-- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index c34690076..dd92afad4 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -40,23 +40,22 @@ class SystemUserViewSet(BulkModelViewSet): permission_classes = (IsSuperUserOrAppUser,) -class SystemUserAuthInfoApi(generics.RetrieveAPIView): +class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView): """ Get system user auth info """ queryset = SystemUser.objects.all() permission_classes = (IsSuperUserOrAppUser,) + serializer_class = serializers.SystemUserAuthSerializer - def retrieve(self, request, *args, **kwargs): - system_user = self.get_object() - data = { - 'id': system_user.id, - 'name': system_user.name, - 'username': system_user.username, - 'password': system_user.password, - 'private_key': system_user.private_key, - } - return Response(data) + def update(self, request, *args, **kwargs): + password = request.data.pop("password", None) + private_key = request.data.pop("private_key", None) + instance = self.get_object() + + if password or private_key: + instance.set_auth(password=password, private_key=private_key) + return super().update(request, *args, **kwargs) class SystemUserPushApi(generics.RetrieveAPIView): diff --git a/apps/assets/serializers/system_user.py b/apps/assets/serializers/system_user.py index 794c841f2..38aad66ce 100644 --- a/apps/assets/serializers/system_user.py +++ b/apps/assets/serializers/system_user.py @@ -36,6 +36,21 @@ class SystemUserSerializer(serializers.ModelSerializer): return len(obj.assets) +class SystemUserAuthSerializer(serializers.ModelSerializer): + """ + 系统用户认证信息 + """ + password = serializers.CharField(max_length=1024) + private_key = serializers.CharField(max_length=4096) + + class Meta: + model = SystemUser + fields = [ + "id", "name", "username", "protocol", + "password", "private_key", + ] + + class AssetSystemUserSerializer(serializers.ModelSerializer): """ 查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少 diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 04fe210b2..6fa15e1df 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -27,7 +27,14 @@ sys.path.append(PROJECT_DIR) try: from config import config as CONFIG except ImportError: - CONFIG = type('_', (), {'__getattr__': lambda arg1, arg2: None})() + msg = """ + + Error: No config file found. + + You can run `cp config_example.py config.py`, and edit it. + """ + raise ImportError(msg) + # CONFIG = type('_', (), {'__getattr__': lambda arg1, arg2: None})() # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ @@ -177,7 +184,7 @@ LOGGING = { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'formatter': 'main', - 'filename': os.path.join(CONFIG.LOG_DIR, 'jumpserver.log') + 'filename': os.path.join(PROJECT_DIR, 'logs', 'jumpserver.log') }, 'ansible_logs': { 'level': 'DEBUG', From fe0301117764fb189dd17b0d1d0c9eafb907d89b Mon Sep 17 00:00:00 2001 From: ibuler Date: Sun, 11 Mar 2018 19:46:40 +0800 Subject: [PATCH 05/25] =?UTF-8?q?[Update]=20=E4=B8=8D=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BA=94=E7=94=A8=E7=A8=8B=E5=BA=8F=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/users/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/users/forms.py b/apps/users/forms.py index b239f58ee..58b78de71 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -20,10 +20,12 @@ class UserLoginForm(AuthenticationForm): class UserCreateUpdateForm(forms.ModelForm): + role_choices = ((i, n) for i, n in User.ROLE_CHOICES if i != User.ROLE_APP) password = forms.CharField( label=_('Password'), widget=forms.PasswordInput, max_length=128, strip=False, required=False, ) + role = forms.ChoiceField(choices=role_choices, required=True, initial=User.ROLE_USER, label=_("Role")) class Meta: model = User From e085fee101b412c8915578829f42b8f1af4af44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=B9=BF?= Date: Mon, 12 Mar 2018 09:16:54 +0800 Subject: [PATCH 06/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba6766a1f..1a395ac27 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Jumpserver是全球首款完全开源的堡垒机,使用GNU GPL v2.0开源协 Jumpserver使用Python / Django 进行开发,遵循 Web 2.0 规范,配备了业界领先的 Web Terminal 解决方案,交互界面美观、用户体验好。 -Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点提供 API,各机房部署登录节点,可横向扩展、无并发访问限制。 +Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点提供 API,各机房部署登录节点,可横向扩展、无并发限制。 改变世界,从一点点开始。 From 0f2b0b146dea72ac7c42bef3f3ec25b8e0025a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=B9=BF?= Date: Mon, 12 Mar 2018 09:17:34 +0800 Subject: [PATCH 07/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a395ac27..e44a23f9c 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点 ### License & Copyright -Copyright (c) 2014-2017 Beijing Duizhan Tech, Inc., All rights reserved. +Copyright (c) 2014-2018 Beijing Duizhan Tech, Inc., All rights reserved. Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at From f59f03adfd00897d1cfba172385177c9b52cc749 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Mar 2018 10:20:23 +0800 Subject: [PATCH 08/25] =?UTF-8?q?[Update]=20=E6=94=AF=E6=8C=81=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/tasks.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index 3f792a080..be9f75152 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -1,6 +1,7 @@ # ~*~ coding: utf-8 ~*~ import json import re +import os from celery import shared_task from django.core.cache import cache @@ -20,6 +21,7 @@ TIMEOUT = 60 logger = get_logger(__file__) CACHE_MAX_TIME = 60*60*60 disk_pattern = re.compile(r'^hd|sd|xvd|vd') +PERIOD_TASK = os.environ.get("PERIOD_TASK", "on") @shared_task @@ -118,6 +120,10 @@ def update_assets_hardware_info_period(): Update asset hardware period task :return: """ + if PERIOD_TASK != "on": + logger.debug("Period task disabled, update assets hardware info pass") + return + from ops.utils import update_or_create_ansible_task task_name = _("Update assets hardware info period") hostname_list = [ @@ -190,6 +196,10 @@ def test_admin_user_connectability_period(): """ A period task that update the ansible task period """ + if PERIOD_TASK != "on": + logger.debug("Period task disabled, test admin user connectability pass") + return + admin_users = AdminUser.objects.all() for admin_user in admin_users: task_name = _("Test admin user connectability period: {}".format(admin_user.name)) @@ -287,6 +297,10 @@ def test_system_user_connectability_manual(system_user): @after_app_ready_start @after_app_shutdown_clean def test_system_user_connectability_period(): + if PERIOD_TASK != "on": + logger.debug("Period task disabled, test system user connectability pass") + return + system_users = SystemUser.objects.all() for system_user in system_users: task_name = _("test system user connectability period: {}".format(system_user)) From b92ccdd05eb9e7e753c1548c8dfbb88d7eef4f0a Mon Sep 17 00:00:00 2001 From: liuzheng Date: Mon, 12 Mar 2018 10:30:40 +0800 Subject: [PATCH 09/25] fix: update the jms-storage==0.0.11 --- apps/terminal/api.py | 44 +++++++++++------------------------ requirements/requirements.txt | 1 + 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 370835ca2..1f113ca85 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -4,7 +4,6 @@ from collections import OrderedDict import logging import os import uuid -import boto3 # AWS S3 sdk from django.core.cache import cache from django.shortcuts import get_object_or_404, redirect @@ -13,6 +12,8 @@ from django.core.files.storage import default_storage from django.http import HttpResponseNotFound from django.conf import settings +import jms_storage + from rest_framework import viewsets, serializers from rest_framework.views import APIView, Response from rest_framework.permissions import AllowAny @@ -282,36 +283,17 @@ class SessionReplayViewSet(viewsets.ViewSet): url = default_storage.url(path) return redirect(url) else: - config = settings.TERMINAL_REPLAY_STORAGE.items() - if config: - for name, value in config: - if value.get("TYPE", '') == "s3": - client, bucket = self.s3Client(value) - try: - date = self.session.date_start.strftime('%Y-%m-%d') - - client.head_object(Bucket=bucket, - Key=os.path.join(date, str(self.session.id) + '.replay.gz')) - client.download_file(bucket, os.path.join(date, str(self.session.id) + '.replay.gz'), - default_storage.base_location + '/' + path) - return redirect(default_storage.url(path)) - except: - pass - return HttpResponseNotFound() - - def s3Client(self, config): - bucket = config.get("BUCKET", "jumpserver") - REGION = config.get("REGION", None) - ACCESS_KEY = config.get("ACCESS_KEY", None) - SECRET_KEY = config.get("SECRET_KEY", None) - if ACCESS_KEY and REGION and SECRET_KEY: - s3 = boto3.client('s3', - region_name=REGION, - aws_access_key_id=ACCESS_KEY, - aws_secret_access_key=SECRET_KEY) - else: - s3 = boto3.client('s3') - return s3, bucket + configs = settings.TERMINAL_REPLAY_STORAGE.items() + if configs: + for name, config in configs: + client = jms_storage.init(config) + date = self.session.date_start.strftime('%Y-%m-%d') + if client.has_file(os.path.join(date, str(self.session.id) + '.replay.gz')) \ + and \ + client.download_file(os.path.join(date, str(self.session.id) + '.replay.gz'), + default_storage.base_location + '/' + path): + return redirect(default_storage.url(path)) + return HttpResponseNotFound() class TerminalConfig(APIView): diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 200d23480..536d00bc6 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -61,6 +61,7 @@ pytz==2017.3 PyYAML==3.12 redis==2.10.6 requests==2.18.4 +jms-storage==0.0.11 s3transfer==0.1.13 simplejson==3.13.2 six==1.11.0 From b19a0e1cdf07bef36de4af1aea6cea3245ebd0d1 Mon Sep 17 00:00:00 2001 From: fit2cloud-fengyi Date: Mon, 12 Mar 2018 10:33:55 +0800 Subject: [PATCH 10/25] =?UTF-8?q?=E5=88=A0=E9=99=A4faq=E5=92=8C=E4=B9=85?= =?UTF-8?q?=E7=9A=84intro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contact.rst | 2 +- docs/faq.rst | 2 -- docs/intro.rst | 51 ------------------------------------------------ 3 files changed, 1 insertion(+), 54 deletions(-) delete mode 100644 docs/faq.rst delete mode 100644 docs/intro.rst diff --git a/docs/contact.rst b/docs/contact.rst index 789207779..b537185a7 100644 --- a/docs/contact.rst +++ b/docs/contact.rst @@ -6,7 +6,7 @@ https://market.aliyun.com/products/53690006/cmgj026011.html -QQ群 +QQ 群 ~~~~~~~~ 群1: 390139816 diff --git a/docs/faq.rst b/docs/faq.rst deleted file mode 100644 index d02cca126..000000000 --- a/docs/faq.rst +++ /dev/null @@ -1,2 +0,0 @@ -FAQ -+++++++++++++++++++++ \ No newline at end of file diff --git a/docs/intro.rst b/docs/intro.rst deleted file mode 100644 index a8810e14f..000000000 --- a/docs/intro.rst +++ /dev/null @@ -1,51 +0,0 @@ -简介 -============ - -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: 组件架构图 From 43b4b7c55eedf22daae39d12f7f69b0a75b6935e Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Mar 2018 11:41:12 +0800 Subject: [PATCH 11/25] =?UTF-8?q?[Feature]=20=E8=B5=84=E4=BA=A7=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=A2=9E=E5=8A=A0=E6=89=B9=E9=87=8F=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=8F=AF=E8=BF=9E=E6=8E=A5=E6=80=A7=E5=92=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=A1=AC=E4=BB=B6=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/node.py | 32 ++++- apps/assets/signals_handler.py | 2 +- apps/assets/tasks.py | 19 ++- apps/assets/templates/assets/asset_list.html | 45 +++++++ apps/assets/urls/api_urls.py | 2 + apps/i18n/zh/LC_MESSAGES/django.mo | Bin 29902 -> 30169 bytes apps/i18n/zh/LC_MESSAGES/django.po | 119 +++++++++++-------- 7 files changed, 157 insertions(+), 62 deletions(-) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 78cd7a27a..3c6ff292d 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -18,10 +18,12 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework_bulk import BulkModelViewSet from django.utils.translation import ugettext_lazy as _ +from django.shortcuts import get_object_or_404 from common.utils import get_logger, get_object_or_none from ..hands import IsSuperUser from ..models import Node +from ..tasks import update_assets_hardware_info_util, test_asset_connectability_util from .. import serializers @@ -29,7 +31,8 @@ logger = get_logger(__file__) __all__ = [ 'NodeViewSet', 'NodeChildrenApi', 'NodeAddAssetsApi', 'NodeRemoveAssetsApi', - 'NodeAddChildrenApi', + 'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi', + 'TestNodeConnectiveApi' ] @@ -117,3 +120,30 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView): instance = self.get_object() if instance != Node.root(): instance.assets.remove(*tuple(assets)) + + +class RefreshNodeHardwareInfoApi(APIView): + permission_classes = (IsSuperUser,) + model = Node + + def get(self, request, *args, **kwargs): + node_id = kwargs.get('pk') + node = get_object_or_404(self.model, id=node_id) + assets = node.assets.all() + task_name = _("Refresh node assets hardware info: {}".format(node.name)) + update_assets_hardware_info_util.delay(assets, task_name=task_name) + return Response({"msg": "Task created"}) + + +class TestNodeConnectiveApi(APIView): + permission_classes = (IsSuperUser,) + model = Node + + def get(self, request, *args, **kwargs): + node_id = kwargs.get('pk') + node = get_object_or_404(self.model, id=node_id) + assets = node.assets.all() + task_name = _("Test node assets connective: {}".format(node.name)) + test_asset_connectability_util.delay(assets, task_name=task_name) + return Response({"msg": "Task created"}) + diff --git a/apps/assets/signals_handler.py b/apps/assets/signals_handler.py index 2577c7a6c..fe5508720 100644 --- a/apps/assets/signals_handler.py +++ b/apps/assets/signals_handler.py @@ -21,7 +21,7 @@ def update_asset_hardware_info_on_created(asset): def test_asset_conn_on_created(asset): logger.debug("Test asset `{}` connectability".format(asset)) - test_asset_connectability_util.delay(asset) + test_asset_connectability_util.delay([asset]) def set_asset_root_node(asset): diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index be9f75152..a6ffd2270 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -213,12 +213,12 @@ def test_admin_user_connectability_manual(admin_user): @shared_task -def test_asset_connectability_util(asset, task_name=None): +def test_asset_connectability_util(assets, task_name=None): from ops.utils import update_or_create_ansible_task if task_name is None: - task_name = _("Test asset connectability") - hosts = [asset.hostname] + task_name = _("Test assets connectability") + hosts = [asset.hostname for asset in assets] if not hosts: logger.info("No hosts, passed") return {} @@ -229,18 +229,17 @@ def test_asset_connectability_util(asset, task_name=None): ) result = task.run() summary = result[1] - if summary.get('dark'): - cache.set(const.ASSET_ADMIN_CONN_CACHE_KEY.format(asset.hostname), 0, - CACHE_MAX_TIME) - else: - cache.set(const.ASSET_ADMIN_CONN_CACHE_KEY.format(asset.hostname), 1, - CACHE_MAX_TIME) + for k in summary.get('dark'): + cache.set(const.ASSET_ADMIN_CONN_CACHE_KEY.format(k), 0, CACHE_MAX_TIME) + + for k in summary.get('contacted'): + cache.set(const.ASSET_ADMIN_CONN_CACHE_KEY.format(k), 1, CACHE_MAX_TIME) return summary @shared_task def test_asset_connectability_manual(asset): - summary = test_asset_connectability_util(asset) + summary = test_asset_connectability_util([asset]) if summary.get('dark'): return False, summary['dark'] diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index 628d0f905..da1b0be58 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -119,6 +119,8 @@