Unverified Commit a609f170 authored by 老广's avatar 老广 Committed by GitHub

[Update] Stash it (#2197)

* [Update] Stash it

* [Bugfix] 修复错误

* [Update] 修改jms
parent 1293d721
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
from django.db import transaction from django.db import transaction
from django.shortcuts import get_object_or_404
from rest_framework import generics from rest_framework import generics
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
...@@ -24,13 +25,14 @@ from common.utils import get_logger ...@@ -24,13 +25,14 @@ from common.utils import get_logger
from ..hands import IsOrgAdmin from ..hands import IsOrgAdmin
from ..models import AdminUser, Asset from ..models import AdminUser, Asset
from .. import serializers from .. import serializers
from ..tasks import test_admin_user_connectability_manual from ..tasks import test_admin_user_connectivity_manual
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'AdminUserViewSet', 'ReplaceNodesAdminUserApi', 'AdminUserViewSet', 'ReplaceNodesAdminUserApi',
'AdminUserTestConnectiveApi', 'AdminUserAuthApi', 'AdminUserTestConnectiveApi', 'AdminUserAuthApi',
'AdminUserAssetsListView',
] ]
...@@ -81,12 +83,29 @@ class ReplaceNodesAdminUserApi(generics.UpdateAPIView): ...@@ -81,12 +83,29 @@ class ReplaceNodesAdminUserApi(generics.UpdateAPIView):
class AdminUserTestConnectiveApi(generics.RetrieveAPIView): class AdminUserTestConnectiveApi(generics.RetrieveAPIView):
""" """
Test asset admin user connectivity Test asset admin user assets_connectivity
""" """
queryset = AdminUser.objects.all() queryset = AdminUser.objects.all()
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
admin_user = self.get_object() admin_user = self.get_object()
task = test_admin_user_connectability_manual.delay(admin_user) task = test_admin_user_connectivity_manual.delay(admin_user)
return Response({"task": task.id}) return Response({"task": task.id})
class AdminUserAssetsListView(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.AssetSimpleSerializer
pagination_class = LimitOffsetPagination
filter_fields = ("hostname", "ip")
http_method_names = ['get']
search_fields = filter_fields
def get_object(self):
pk = self.kwargs.get('pk')
return get_object_or_404(AdminUser, pk=pk)
def get_queryset(self):
admin_user = self.get_object()
return admin_user.get_related_assets()
...@@ -17,7 +17,7 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser ...@@ -17,7 +17,7 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from ..models import Asset, AdminUser, Node from ..models import Asset, AdminUser, Node
from .. import serializers from .. import serializers
from ..tasks import update_asset_hardware_info_manual, \ from ..tasks import update_asset_hardware_info_manual, \
test_asset_connectability_manual test_asset_connectivity_manual
from ..utils import LabelFilter from ..utils import LabelFilter
...@@ -109,7 +109,7 @@ class AssetRefreshHardwareApi(generics.RetrieveAPIView): ...@@ -109,7 +109,7 @@ class AssetRefreshHardwareApi(generics.RetrieveAPIView):
class AssetAdminUserTestApi(generics.RetrieveAPIView): class AssetAdminUserTestApi(generics.RetrieveAPIView):
""" """
Test asset admin user connectivity Test asset admin user assets_connectivity
""" """
queryset = Asset.objects.all() queryset = Asset.objects.all()
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
...@@ -117,7 +117,7 @@ class AssetAdminUserTestApi(generics.RetrieveAPIView): ...@@ -117,7 +117,7 @@ class AssetAdminUserTestApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
asset_id = kwargs.get('pk') asset_id = kwargs.get('pk')
asset = get_object_or_404(Asset, pk=asset_id) asset = get_object_or_404(Asset, pk=asset_id)
task = test_asset_connectability_manual.delay(asset) task = test_asset_connectivity_manual.delay(asset)
return Response({"task": task.id}) return Response({"task": task.id})
......
...@@ -24,7 +24,7 @@ from common.utils import get_logger, get_object_or_none ...@@ -24,7 +24,7 @@ from common.utils import get_logger, get_object_or_none
from common.tree import TreeNodeSerializer from common.tree import TreeNodeSerializer
from ..hands import IsOrgAdmin from ..hands import IsOrgAdmin
from ..models import Node from ..models import Node
from ..tasks import update_assets_hardware_info_util, test_asset_connectability_util from ..tasks import update_assets_hardware_info_util, test_asset_connectivity_util
from .. import serializers from .. import serializers
...@@ -273,5 +273,5 @@ class TestNodeConnectiveApi(APIView): ...@@ -273,5 +273,5 @@ class TestNodeConnectiveApi(APIView):
assets = node.assets.all() assets = node.assets.all()
# task_name = _("测试节点下资产是否可连接: {}".format(node.name)) # task_name = _("测试节点下资产是否可连接: {}".format(node.name))
task_name = _("Test if the assets under the node are connectable: {}".format(node.name)) task_name = _("Test if the assets under the node are connectable: {}".format(node.name))
task = test_asset_connectability_util.delay(assets, task_name=task_name) task = test_asset_connectivity_util.delay(assets, task_name=task_name)
return Response({"task": task.id}) return Response({"task": task.id})
...@@ -24,8 +24,8 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser ...@@ -24,8 +24,8 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from ..models import SystemUser, Asset from ..models import SystemUser, Asset
from .. import serializers from .. import serializers
from ..tasks import push_system_user_to_assets_manual, \ from ..tasks import push_system_user_to_assets_manual, \
test_system_user_connectability_manual, push_system_user_a_asset_manual, \ test_system_user_connectivity_manual, push_system_user_a_asset_manual, \
test_system_user_connectability_a_asset test_system_user_connectivity_a_asset
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -33,7 +33,7 @@ __all__ = [ ...@@ -33,7 +33,7 @@ __all__ = [
'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserViewSet', 'SystemUserAuthInfoApi',
'SystemUserPushApi', 'SystemUserTestConnectiveApi', 'SystemUserPushApi', 'SystemUserTestConnectiveApi',
'SystemUserAssetsListView', 'SystemUserPushToAssetApi', 'SystemUserAssetsListView', 'SystemUserPushToAssetApi',
'SystemUserTestAssetConnectabilityApi', 'SystemUserCommandFilterRuleListApi', 'SystemUserTestAssetConnectivityApi', 'SystemUserCommandFilterRuleListApi',
] ]
...@@ -93,15 +93,16 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView): ...@@ -93,15 +93,16 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
system_user = self.get_object() system_user = self.get_object()
task = test_system_user_connectability_manual.delay(system_user) task = test_system_user_connectivity_manual.delay(system_user)
return Response({"task": task.id}) return Response({"task": task.id})
class SystemUserAssetsListView(generics.ListAPIView): class SystemUserAssetsListView(generics.ListAPIView):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
serializer_class = serializers.AssetSerializer serializer_class = serializers.AssetSimpleSerializer
pagination_class = LimitOffsetPagination pagination_class = LimitOffsetPagination
filter_fields = ("hostname", "ip") filter_fields = ("hostname", "ip")
http_method_names = ['get']
search_fields = filter_fields search_fields = filter_fields
def get_object(self): def get_object(self):
...@@ -125,7 +126,7 @@ class SystemUserPushToAssetApi(generics.RetrieveAPIView): ...@@ -125,7 +126,7 @@ class SystemUserPushToAssetApi(generics.RetrieveAPIView):
return Response({"task": task.id}) return Response({"task": task.id})
class SystemUserTestAssetConnectabilityApi(generics.RetrieveAPIView): class SystemUserTestAssetConnectivityApi(generics.RetrieveAPIView):
queryset = SystemUser.objects.all() queryset = SystemUser.objects.all()
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
...@@ -133,7 +134,7 @@ class SystemUserTestAssetConnectabilityApi(generics.RetrieveAPIView): ...@@ -133,7 +134,7 @@ class SystemUserTestAssetConnectabilityApi(generics.RetrieveAPIView):
system_user = self.get_object() system_user = self.get_object()
asset_id = self.kwargs.get('aid') asset_id = self.kwargs.get('aid')
asset = get_object_or_404(Asset, id=asset_id) asset = get_object_or_404(Asset, id=asset_id)
task = test_system_user_connectability_a_asset.delay(system_user, asset) task = test_system_user_connectivity_a_asset.delay(system_user, asset)
return Response({"task": task.id}) return Response({"task": task.id})
......
...@@ -99,8 +99,8 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): ...@@ -99,8 +99,8 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
auto_generate_key = self.cleaned_data.get('auto_generate_key', False) auto_generate_key = self.cleaned_data.get('auto_generate_key', False)
private_key, public_key = super().gen_keys() private_key, public_key = super().gen_keys()
if login_mode == SystemUser.MANUAL_LOGIN or \ if login_mode == SystemUser.LOGIN_MANUAL or \
protocol in [SystemUser.RDP_PROTOCOL, SystemUser.TELNET_PROTOCOL]: protocol in [SystemUser.PROTOCOL_RDP, SystemUser.PROTOCOL_TELNET]:
system_user.auto_push = 0 system_user.auto_push = 0
auto_generate_key = False auto_generate_key = False
system_user.save() system_user.save()
...@@ -124,7 +124,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): ...@@ -124,7 +124,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
validated = super().is_valid() validated = super().is_valid()
username = self.cleaned_data.get('username') username = self.cleaned_data.get('username')
login_mode = self.cleaned_data.get('login_mode') login_mode = self.cleaned_data.get('login_mode')
if login_mode == SystemUser.AUTO_LOGIN and not username: if login_mode == SystemUser.LOGIN_AUTO and not username:
self.add_error( self.add_error(
"username", _('* Automatic login mode,' "username", _('* Automatic login mode,'
' must fill in the username.') ' must fill in the username.')
......
...@@ -13,7 +13,6 @@ from django.db.models import Q ...@@ -13,7 +13,6 @@ from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache from django.core.cache import cache
from ..const import ASSET_ADMIN_CONN_CACHE_KEY
from .user import AdminUser, SystemUser from .user import AdminUser, SystemUser
from orgs.mixins import OrgModelMixin, OrgManager from orgs.mixins import OrgModelMixin, OrgManager
...@@ -75,63 +74,48 @@ class Asset(OrgModelMixin): ...@@ -75,63 +74,48 @@ class Asset(OrgModelMixin):
protocol = models.CharField(max_length=128, default=SSH_PROTOCOL, choices=PROTOCOL_CHOICES, verbose_name=_('Protocol')) protocol = models.CharField(max_length=128, default=SSH_PROTOCOL, choices=PROTOCOL_CHOICES, verbose_name=_('Protocol'))
port = models.IntegerField(default=22, verbose_name=_('Port')) port = models.IntegerField(default=22, verbose_name=_('Port'))
platform = models.CharField(max_length=128, choices=PLATFORM_CHOICES, default='Linux', verbose_name=_('Platform')) platform = models.CharField(max_length=128, choices=PLATFORM_CHOICES, default='Linux', verbose_name=_('Platform'))
domain = models.ForeignKey("assets.Domain", null=True, blank=True, domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"), on_delete=models.SET_NULL)
related_name='assets', verbose_name=_("Domain"), nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes"))
on_delete=models.SET_NULL)
nodes = models.ManyToManyField('assets.Node', default=default_node,
related_name='assets',
verbose_name=_("Nodes"))
is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
# Auth # Auth
admin_user = models.ForeignKey('assets.AdminUser', on_delete=models.PROTECT, admin_user = models.ForeignKey('assets.AdminUser', on_delete=models.PROTECT, null=True, verbose_name=_("Admin user"))
null=True, verbose_name=_("Admin user"))
# Some information # Some information
public_ip = models.GenericIPAddressField(max_length=32, blank=True, null=True, verbose_name=_('Public IP')) public_ip = models.GenericIPAddressField(max_length=32, blank=True, null=True, verbose_name=_('Public IP'))
number = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Asset number')) number = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Asset number'))
# Collect # Collect
vendor = models.CharField(max_length=64, null=True, blank=True, vendor = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Vendor'))
verbose_name=_('Vendor')) model = models.CharField(max_length=54, null=True, blank=True, verbose_name=_('Model'))
model = models.CharField(max_length=54, null=True, blank=True, sn = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Serial number'))
verbose_name=_('Model'))
sn = models.CharField(max_length=128, null=True, blank=True, cpu_model = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU model'))
verbose_name=_('Serial number'))
cpu_model = models.CharField(max_length=64, null=True, blank=True,
verbose_name=_('CPU model'))
cpu_count = models.IntegerField(null=True, verbose_name=_('CPU count')) cpu_count = models.IntegerField(null=True, verbose_name=_('CPU count'))
cpu_cores = models.IntegerField(null=True, verbose_name=_('CPU cores')) cpu_cores = models.IntegerField(null=True, verbose_name=_('CPU cores'))
cpu_vcpus = models.IntegerField(null=True, verbose_name=_('CPU vcpus')) cpu_vcpus = models.IntegerField(null=True, verbose_name=_('CPU vcpus'))
memory = models.CharField(max_length=64, null=True, blank=True, memory = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Memory'))
verbose_name=_('Memory')) disk_total = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk total'))
disk_total = models.CharField(max_length=1024, null=True, blank=True, disk_info = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk info'))
verbose_name=_('Disk total'))
disk_info = models.CharField(max_length=1024, null=True, blank=True, os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS'))
verbose_name=_('Disk info')) os_version = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('OS version'))
os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch'))
os = models.CharField(max_length=128, null=True, blank=True, hostname_raw = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Hostname raw'))
verbose_name=_('OS'))
os_version = models.CharField(max_length=16, null=True, blank=True, labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels"))
verbose_name=_('OS version')) created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
os_arch = models.CharField(max_length=16, blank=True, null=True, date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
verbose_name=_('OS arch')) comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
hostname_raw = models.CharField(max_length=128, blank=True, null=True,
verbose_name=_('Hostname raw'))
labels = models.ManyToManyField('assets.Label', blank=True,
related_name='assets',
verbose_name=_("Labels"))
created_by = models.CharField(max_length=32, null=True, blank=True,
verbose_name=_('Created by'))
date_created = models.DateTimeField(auto_now_add=True, null=True,
blank=True,
verbose_name=_('Date created'))
comment = models.TextField(max_length=128, default='', blank=True,
verbose_name=_('Comment'))
objects = OrgManager.from_queryset(AssetQuerySet)() objects = OrgManager.from_queryset(AssetQuerySet)()
CONNECTIVITY_CACHE_KEY = '_JMS_ASSET_CONNECTIVITY_{}'
UNREACHABLE, REACHABLE, UNKNOWN = range(0, 3)
CONNECTIVITY_CHOICES = (
(UNREACHABLE, _("Unreachable")),
(REACHABLE, _('Reachable')),
(UNKNOWN, _("Unknown")),
)
def __str__(self): def __str__(self):
return '{0.hostname}({0.ip})'.format(self) return '{0.hostname}({0.ip})'.format(self)
...@@ -197,25 +181,17 @@ class Asset(OrgModelMixin): ...@@ -197,25 +181,17 @@ class Asset(OrgModelMixin):
return '' return ''
@property @property
def is_connective(self): def connectivity(self):
if not self.is_unixlike(): if not self.is_unixlike():
return True return self.UNKNOWN
val = cache.get(ASSET_ADMIN_CONN_CACHE_KEY.format(self.hostname)) key = self.CONNECTIVITY_CACHE_KEY.format(str(self.id))
if val == 1: cached = cache.get(key, None)
return True return cached if cached is not None else self.UNKNOWN
else:
return False
def to_json(self): @connectivity.setter
info = { def connectivity(self, value):
'id': self.id, key = self.CONNECTIVITY_CACHE_KEY.format(str(self.id))
'hostname': self.hostname, cache.set(key, value, 3600*2)
'ip': self.ip,
'port': self.port,
}
if self.domain and self.domain.gateway_set.all():
info["gateways"] = [d.id for d in self.domain.gateway_set.all()]
return info
def get_auth_info(self): def get_auth_info(self):
if self.admin_user: if self.admin_user:
...@@ -236,11 +212,20 @@ class Asset(OrgModelMixin): ...@@ -236,11 +212,20 @@ class Asset(OrgModelMixin):
fake_node.is_node = False fake_node.is_node = False
return fake_node return fake_node
def to_json(self):
info = {
'id': self.id,
'hostname': self.hostname,
'ip': self.ip,
'port': self.port,
}
if self.domain and self.domain.gateway_set.all():
info["gateways"] = [d.id for d in self.domain.gateway_set.all()]
return info
def _to_secret_json(self): def _to_secret_json(self):
""" """
Ansible use it create inventory, First using asset user, Ansible use it create inventory
otherwise using cluster admin user
Todo: May be move to ops implements it Todo: May be move to ops implements it
""" """
data = self.to_json() data = self.to_json()
......
...@@ -29,6 +29,13 @@ class AssetUser(OrgModelMixin): ...@@ -29,6 +29,13 @@ class AssetUser(OrgModelMixin):
date_updated = models.DateTimeField(auto_now=True) date_updated = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
UNREACHABLE, REACHABLE, UNKNOWN = range(0, 3)
CONNECTIVITY_CHOICES = (
(UNREACHABLE, _("Unreachable")),
(REACHABLE, _('Reachable')),
(UNKNOWN, _("Unknown")),
)
@property @property
def password(self): def password(self):
if self._password: if self._password:
......
...@@ -14,7 +14,7 @@ from ..const import SYSTEM_USER_CONN_CACHE_KEY ...@@ -14,7 +14,7 @@ from ..const import SYSTEM_USER_CONN_CACHE_KEY
from .base import AssetUser from .base import AssetUser
__all__ = ['AdminUser', 'SystemUser',] __all__ = ['AdminUser', 'SystemUser']
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
signer = get_signer() signer = get_signer()
...@@ -31,6 +31,7 @@ class AdminUser(AssetUser): ...@@ -31,6 +31,7 @@ class AdminUser(AssetUser):
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4) become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
become_user = models.CharField(default='root', max_length=64) become_user = models.CharField(default='root', max_length=64)
_become_pass = models.CharField(default='', max_length=128) _become_pass = models.CharField(default='', max_length=128)
CONNECTIVE_CACHE_KEY = '_JMS_ADMIN_USER_CONNECTIVE_{}'
def __str__(self): def __str__(self):
return self.name return self.name
...@@ -67,6 +68,23 @@ class AdminUser(AssetUser): ...@@ -67,6 +68,23 @@ class AdminUser(AssetUser):
def assets_amount(self): def assets_amount(self):
return self.get_related_assets().count() return self.get_related_assets().count()
@property
def connectivity(self):
from .asset import Asset
assets = self.get_related_assets().values_list('id', 'hostname', flat=True)
data = {
'unreachable': [],
'reachable': [],
}
for asset_id, hostname in assets:
key = Asset.CONNECTIVITY_CACHE_KEY.format(str(self.id))
value = cache.get(key, Asset.UNKNOWN)
if value == Asset.REACHABLE:
data['reachable'].append(hostname)
elif value == Asset.UNREACHABLE:
data['unreachable'].append(hostname)
return data
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
unique_together = [('name', 'org_id')] unique_together = [('name', 'org_id')]
...@@ -94,34 +112,34 @@ class AdminUser(AssetUser): ...@@ -94,34 +112,34 @@ class AdminUser(AssetUser):
class SystemUser(AssetUser): class SystemUser(AssetUser):
SSH_PROTOCOL = 'ssh' PROTOCOL_SSH = 'ssh'
RDP_PROTOCOL = 'rdp' PROTOCOL_RDP = 'rdp'
TELNET_PROTOCOL = 'telnet' PROTOCOL_TELNET = 'telnet'
PROTOCOL_CHOICES = ( PROTOCOL_CHOICES = (
(SSH_PROTOCOL, 'ssh'), (PROTOCOL_SSH, 'ssh'),
(RDP_PROTOCOL, 'rdp'), (PROTOCOL_RDP, 'rdp'),
(TELNET_PROTOCOL, 'telnet (beta)'), (PROTOCOL_TELNET, 'telnet (beta)'),
) )
AUTO_LOGIN = 'auto' LOGIN_AUTO = 'auto'
MANUAL_LOGIN = 'manual' LOGIN_MANUAL = 'manual'
LOGIN_MODE_CHOICES = ( LOGIN_MODE_CHOICES = (
(AUTO_LOGIN, _('Automatic login')), (LOGIN_AUTO, _('Automatic login')),
(MANUAL_LOGIN, _('Manually login')) (LOGIN_MANUAL, _('Manually login'))
) )
nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes")) nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes"))
assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets")) assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets"))
priority = models.IntegerField(default=20, verbose_name=_("Priority"), priority = models.IntegerField(default=20, verbose_name=_("Priority"), validators=[MinValueValidator(1), MaxValueValidator(100)])
validators=[MinValueValidator(1), MaxValueValidator(100)])
protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol')) protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push')) auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo')) sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell')) shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
login_mode = models.CharField(choices=LOGIN_MODE_CHOICES, default=AUTO_LOGIN, max_length=10, verbose_name=_('Login mode')) login_mode = models.CharField(choices=LOGIN_MODE_CHOICES, default=LOGIN_AUTO, max_length=10, verbose_name=_('Login mode'))
cmd_filters = models.ManyToManyField('CommandFilter', related_name='system_users', verbose_name=_("Command filter"), blank=True) cmd_filters = models.ManyToManyField('CommandFilter', related_name='system_users', verbose_name=_("Command filter"), blank=True)
cache_key = "__SYSTEM_USER_CACHED_{}" SYSTEM_USER_CACHE_KEY = "__SYSTEM_USER_CACHED_{}"
CONNECTIVE_CACHE_KEY = '_JMS_SYSTEM_USER_CONNECTIVE_{}'
def __str__(self): def __str__(self):
return '{0.name}({0.username})'.format(self) return '{0.name}({0.username})'.format(self)
...@@ -136,34 +154,61 @@ class SystemUser(AssetUser): ...@@ -136,34 +154,61 @@ class SystemUser(AssetUser):
'auto_push': self.auto_push, 'auto_push': self.auto_push,
} }
def get_assets(self): def get_related_assets(self):
assets = set(self.assets.all()) assets = set(self.assets.all())
return assets return assets
@property @property
def assets_connective(self): def connectivity(self):
_result = cache.get(SYSTEM_USER_CONN_CACHE_KEY.format(self.name), {}) cache_key = self.CONNECTIVE_CACHE_KEY.format(str(self.id))
return _result value = cache.get(cache_key, None)
if not value or 'unreachable' not in value:
return {'unreachable': [], 'reachable': []}
else:
return value
@connectivity.setter
def connectivity(self, value):
data = self.connectivity
unreachable = data['unreachable']
reachable = data['reachable']
for host in value.get('dark', {}).keys():
if host not in unreachable:
unreachable.append(host)
if host in reachable:
reachable.remove(host)
for host in value.get('contacted'):
if host not in reachable:
reachable.append(host)
if host in unreachable:
unreachable.remove(host)
cache_key = self.CONNECTIVE_CACHE_KEY.format(str(self.id))
cache.set(cache_key, data, 3600)
@property
def assets_unreachable(self):
return self.connectivity.get('unreachable')
@property @property
def unreachable_assets(self): def assets_reachable(self):
return list(self.assets_connective.get('dark', {}).keys()) return self.connectivity.get('reachable')
@property @property
def reachable_assets(self): def login_mode_display(self):
return self.assets_connective.get('contacted', []) return self.get_login_mode_display()
def is_need_push(self): def is_need_push(self):
if self.auto_push and self.protocol == self.__class__.SSH_PROTOCOL: if self.auto_push and self.protocol == self.PROTOCOL_SSH:
return True return True
else: else:
return False return False
def set_cache(self): def set_cache(self):
cache.set(self.cache_key.format(self.id), self, 3600) cache.set(self.SYSTEM_USER_CACHE_KEY.format(self.id), self, 3600)
def expire_cache(self): def expire_cache(self):
cache.delete(self.cache_key.format(self.id)) cache.delete(self.SYSTEM_USER_CACHE_KEY.format(self.id))
@property @property
def cmd_filter_rules(self): def cmd_filter_rules(self):
...@@ -184,7 +229,7 @@ class SystemUser(AssetUser): ...@@ -184,7 +229,7 @@ class SystemUser(AssetUser):
@classmethod @classmethod
def get_system_user_by_id_or_cached(cls, sid): def get_system_user_by_id_or_cached(cls, sid):
cached = cache.get(cls.cache_key.format(sid)) cached = cache.get(cls.SYSTEM_USER_CACHE_KEY.format(sid))
if cached: if cached:
return cached return cached
try: try:
......
...@@ -9,7 +9,7 @@ from .system_user import AssetSystemUserSerializer ...@@ -9,7 +9,7 @@ from .system_user import AssetSystemUserSerializer
__all__ = [ __all__ = [
'AssetSerializer', 'AssetGrantedSerializer', 'MyAssetGrantedSerializer', 'AssetSerializer', 'AssetGrantedSerializer', 'MyAssetGrantedSerializer',
'AssetAsNodeSerializer', 'AssetAsNodeSerializer', 'AssetSimpleSerializer',
] ]
...@@ -33,7 +33,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -33,7 +33,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
def get_field_names(self, declared_fields, info): def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info) fields = super().get_field_names(declared_fields, info)
fields.extend([ fields.extend([
'hardware_info', 'is_connective', 'org_name' 'hardware_info', 'connectivity', 'org_name'
]) ])
return fields return fields
...@@ -78,3 +78,9 @@ class MyAssetGrantedSerializer(AssetGrantedSerializer): ...@@ -78,3 +78,9 @@ class MyAssetGrantedSerializer(AssetGrantedSerializer):
"is_active", "system_users_join", "org_name", "is_active", "system_users_join", "org_name",
"os", "platform", "comment", "org_id", "protocol" "os", "platform", "comment", "org_id", "protocol"
) )
class AssetSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = ['id', 'hostname', 'port', 'ip', 'connectivity']
from rest_framework import serializers from rest_framework import serializers
from ..models import SystemUser from ..models import SystemUser, Asset
from .base import AuthSerializer from .base import AuthSerializer
...@@ -21,17 +21,17 @@ class SystemUserSerializer(serializers.ModelSerializer): ...@@ -21,17 +21,17 @@ class SystemUserSerializer(serializers.ModelSerializer):
def get_field_names(self, declared_fields, info): def get_field_names(self, declared_fields, info):
fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info) fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info)
fields.extend([ fields.extend([
'get_login_mode_display', 'login_mode_display',
]) ])
return fields return fields
@staticmethod @staticmethod
def get_unreachable_assets(obj): def get_unreachable_assets(obj):
return obj.unreachable_assets return obj.assets_unreachable
@staticmethod @staticmethod
def get_reachable_assets(obj): def get_reachable_assets(obj):
return obj.reachable_assets return obj.assets_reachable
def get_unreachable_amount(self, obj): def get_unreachable_amount(self, obj):
return len(self.get_unreachable_assets(obj)) return len(self.get_unreachable_assets(obj))
...@@ -41,7 +41,7 @@ class SystemUserSerializer(serializers.ModelSerializer): ...@@ -41,7 +41,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_assets_amount(obj): def get_assets_amount(obj):
return len(obj.get_assets()) return len(obj.get_related_assets())
class SystemUserAuthSerializer(AuthSerializer): class SystemUserAuthSerializer(AuthSerializer):
...@@ -75,4 +75,7 @@ class SystemUserSimpleSerializer(serializers.ModelSerializer): ...@@ -75,4 +75,7 @@ class SystemUserSimpleSerializer(serializers.ModelSerializer):
""" """
class Meta: class Meta:
model = SystemUser model = SystemUser
fields = ('id', 'name', 'username') fields = ('id', 'name', 'username')
\ No newline at end of file
...@@ -7,7 +7,7 @@ from django.dispatch import receiver ...@@ -7,7 +7,7 @@ from django.dispatch import receiver
from common.utils import get_logger from common.utils import get_logger
from .models import Asset, SystemUser, Node from .models import Asset, SystemUser, Node
from .tasks import update_assets_hardware_info_util, \ from .tasks import update_assets_hardware_info_util, \
test_asset_connectability_util, push_system_user_to_assets test_asset_connectivity_util, push_system_user_to_assets
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -19,8 +19,8 @@ def update_asset_hardware_info_on_created(asset): ...@@ -19,8 +19,8 @@ def update_asset_hardware_info_on_created(asset):
def test_asset_conn_on_created(asset): def test_asset_conn_on_created(asset):
logger.debug("Test asset `{}` connectability".format(asset)) logger.debug("Test asset `{}` connectivity".format(asset))
test_asset_connectability_util.delay([asset]) test_asset_connectivity_util.delay([asset])
def set_asset_root_node(asset): def set_asset_root_node(asset):
......
...@@ -26,6 +26,23 @@ disk_pattern = re.compile(r'^hd|sd|xvd|vd') ...@@ -26,6 +26,23 @@ disk_pattern = re.compile(r'^hd|sd|xvd|vd')
PERIOD_TASK = os.environ.get("PERIOD_TASK", "off") PERIOD_TASK = os.environ.get("PERIOD_TASK", "off")
def clean_hosts(assets):
clean_assets = []
for asset in assets:
if not asset.is_active:
msg = _("Asset has been disabled, skipped: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skipped: {}").format(asset)
logger.info(msg)
continue
clean_assets.append(asset)
if not clean_assets:
logger.info(_("No assets matched, stop task"))
return clean_assets
@shared_task @shared_task
def set_assets_hardware_info(assets, result, **kwargs): def set_assets_hardware_info(assets, result, **kwargs):
""" """
...@@ -60,9 +77,12 @@ def set_assets_hardware_info(assets, result, **kwargs): ...@@ -60,9 +77,12 @@ def set_assets_hardware_info(assets, result, **kwargs):
___cpu_model = 'Unknown' ___cpu_model = 'Unknown'
___cpu_model = ___cpu_model[:64] ___cpu_model = ___cpu_model[:64]
___cpu_count = info.get('ansible_processor_count', 0) ___cpu_count = info.get('ansible_processor_count', 0)
___cpu_cores = info.get('ansible_processor_cores', None) or len(info.get('ansible_processor', [])) ___cpu_cores = info.get('ansible_processor_cores', None) or \
len(info.get('ansible_processor', []))
___cpu_vcpus = info.get('ansible_processor_vcpus', 0) ___cpu_vcpus = info.get('ansible_processor_vcpus', 0)
___memory = '%s %s' % capacity_convert('{} MB'.format(info.get('ansible_memtotal_mb'))) ___memory = '%s %s' % capacity_convert(
'{} MB'.format(info.get('ansible_memtotal_mb'))
)
disk_info = {} disk_info = {}
for dev, dev_info in info.get('ansible_devices', {}).items(): for dev, dev_info in info.get('ansible_devices', {}).items():
if disk_pattern.match(dev) and dev_info['removable'] == '0': if disk_pattern.match(dev) and dev_info['removable'] == '0':
...@@ -96,19 +116,8 @@ def update_assets_hardware_info_util(assets, task_name=None): ...@@ -96,19 +116,8 @@ def update_assets_hardware_info_util(assets, task_name=None):
if task_name is None: if task_name is None:
task_name = _("Update some assets hardware info") task_name = _("Update some assets hardware info")
tasks = const.UPDATE_ASSETS_HARDWARE_TASKS tasks = const.UPDATE_ASSETS_HARDWARE_TASKS
hosts = [] hosts = clean_hosts(assets)
for asset in assets:
if not asset.is_active:
msg = _("Asset has been disabled, skipped: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skipped: {}").format(asset)
logger.info(msg)
continue
hosts.append(asset)
if not hosts: if not hosts:
logger.info(_("No assets matched, stop task"))
return {} return {}
created_by = str(assets[0].org_id) created_by = str(assets[0].org_id)
task, created = update_or_create_ansible_task( task, created = update_or_create_ansible_task(
...@@ -125,7 +134,6 @@ def update_assets_hardware_info_util(assets, task_name=None): ...@@ -125,7 +134,6 @@ def update_assets_hardware_info_util(assets, task_name=None):
@shared_task @shared_task
def update_asset_hardware_info_manual(asset): def update_asset_hardware_info_manual(asset):
task_name = _("Update asset hardware info: {}").format(asset.hostname) task_name = _("Update asset hardware info: {}").format(asset.hostname)
# task_name = _("更新资产硬件信息")
return update_assets_hardware_info_util( return update_assets_hardware_info_util(
[asset], task_name=task_name [asset], task_name=task_name
) )
...@@ -141,166 +149,92 @@ def update_assets_hardware_info_period(): ...@@ -141,166 +149,92 @@ def update_assets_hardware_info_period():
logger.debug("Period task disabled, update assets hardware info pass") logger.debug("Period task disabled, update assets hardware info pass")
return return
# from ops.utils import update_or_create_ansible_task
# from orgs.models import Organization
# orgs = Organization.objects.all().values_list('id', flat=True)
# orgs.append('')
# task_name = _("Update assets hardware info period")
# for org_id in orgs:
# org_id = str(org_id)
# hostname_list = [
# asset 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
# 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',
# interval=60*60*24, is_periodic=True, callback=set_assets_hardware_info.name,
# )
## ADMIN USER CONNECTIVE ## ## ADMIN USER CONNECTIVE ##
def set_admin_user_connectability_info(result, **kwargs):
admin_user = kwargs.get("admin_user")
task_name = kwargs.get("task_name")
if admin_user is None and task_name is not None:
admin_user = task_name.split(":")[-1]
raw, summary = result @shared_task
cache_key = const.ADMIN_USER_CONN_CACHE_KEY.format(admin_user) def test_asset_connectivity_util(assets, task_name=None):
cache.set(cache_key, summary, CACHE_MAX_TIME) from ops.utils import update_or_create_ansible_task
if task_name is None:
task_name = _("Test assets connectivity")
hosts = clean_hosts(assets)
if not hosts:
return {}
tasks = const.TEST_ADMIN_USER_CONN_TASKS
created_by = assets[0].org_id
task, created = update_or_create_ansible_task(
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
options=const.TASK_OPTIONS, run_as_admin=True, created_by=created_by,
)
result = task.run()
summary = result[1]
for asset in assets:
if asset.hostname in summary.get('dark', {}):
asset.connectivity = asset.UNREACHABLE
elif asset.hostname in summary.get('contacted', []):
asset.connectivity = asset.REACHABLE
else:
asset.connectivity = asset.UNKNOWN
return summary
for i in summary.get('contacted', []): @shared_task
asset_conn_cache_key = const.ASSET_ADMIN_CONN_CACHE_KEY.format(i) def test_asset_connectivity_manual(asset):
cache.set(asset_conn_cache_key, 1, CACHE_MAX_TIME) task_name = _("Test assets connectivity: {}").format(asset)
summary = test_asset_connectivity_util([asset], task_name=task_name)
for i, msg in summary.get('dark', {}).items(): if summary.get('dark'):
asset_conn_cache_key = const.ASSET_ADMIN_CONN_CACHE_KEY.format(i) return False, summary['dark']
cache.set(asset_conn_cache_key, 0, CACHE_MAX_TIME) else:
logger.error(msg) return True, ""
@shared_task @shared_task
def test_admin_user_connectability_util(admin_user, task_name): def test_admin_user_connectivity_util(admin_user, task_name):
""" """
Test asset admin user can connect or not. Using ansible api do that Test asset admin user can connect or not. Using ansible api do that
:param admin_user: :param admin_user:
:param task_name: :param task_name:
:return: :return:
""" """
from ops.utils import update_or_create_ansible_task
assets = admin_user.get_related_assets() assets = admin_user.get_related_assets()
hosts = [] hosts = clean_hosts(assets)
for asset in assets:
if not asset.is_active:
msg = _("Asset has been disabled, skipped: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skipped: {}").format(asset)
logger.info(msg)
continue
hosts.append(asset)
if not hosts: if not hosts:
logger.info(_("No assets matched, stop task"))
return {} return {}
tasks = const.TEST_ADMIN_USER_CONN_TASKS summary = test_asset_connectivity_util(hosts, task_name)
task, created = update_or_create_ansible_task( return summary
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
options=const.TASK_OPTIONS, run_as_admin=True, created_by=admin_user.org_id,
)
result = task.run()
set_admin_user_connectability_info(result, admin_user=admin_user.name)
return result
@shared_task @shared_task
@register_as_period_task(interval=3600) @register_as_period_task(interval=3600)
def test_admin_user_connectability_period(): def test_admin_user_connectivity_period():
""" """
A period task that update the ansible task period A period task that update the ansible task period
""" """
admin_users = AdminUser.objects.all() admin_users = AdminUser.objects.all()
for admin_user in admin_users: for admin_user in admin_users:
task_name = _("Test admin user connectability period: {}").format(admin_user.name) task_name = _("Test admin user connectivity period: {}").format(admin_user.name)
test_admin_user_connectability_util(admin_user, task_name) test_admin_user_connectivity_util(admin_user, task_name)
@shared_task @shared_task
def test_admin_user_connectability_manual(admin_user): def test_admin_user_connectivity_manual(admin_user):
task_name = _("Test admin user connectability: {}").format(admin_user.name) task_name = _("Test admin user connectivity: {}").format(admin_user.name)
# task_name = _("测试管理行号可连接性: {}").format(admin_user.name) return test_admin_user_connectivity_util(admin_user, task_name)
return test_admin_user_connectability_util(admin_user, task_name)
@shared_task
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 assets connectability")
# task_name = _("测试资产可连接性")
hosts = []
for asset in assets:
if not asset.is_active:
msg = _("Asset has been disabled, skip: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skip: {}").format(asset)
logger.info(msg)
continue
hosts.append(asset)
if not hosts:
logger.info(_("No assets, task stop"))
return {}
tasks = const.TEST_ADMIN_USER_CONN_TASKS
created_by = assets[0].org_id
task, created = update_or_create_ansible_task(
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
options=const.TASK_OPTIONS, run_as_admin=True, created_by=created_by,
)
result = task.run()
summary = result[1]
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):
task_name = _("Test assets connectability: {}").format(asset)
summary = test_asset_connectability_util([asset], task_name=task_name)
if summary.get('dark'):
return False, summary['dark']
else:
return True, ""
## System user connective ## ## System user connective ##
@shared_task @shared_task
def set_system_user_connectablity_info(result, **kwargs): def set_system_user_connectivity_info(system_user, result):
summary = result[1] summary = result[1]
task_name = kwargs.get("task_name") system_user.connectivity = summary
system_user = kwargs.get("system_user")
if system_user is None:
system_user = task_name.split(":")[-1]
cache_key = const.SYSTEM_USER_CONN_CACHE_KEY.format(str(system_user.id))
cache.set(cache_key, summary, CACHE_MAX_TIME)
@shared_task @shared_task
def test_system_user_connectability_util(system_user, assets, task_name): def test_system_user_connectivity_util(system_user, assets, task_name):
""" """
Test system cant connect his assets or not. Test system cant connect his assets or not.
:param system_user: :param system_user:
...@@ -309,20 +243,9 @@ def test_system_user_connectability_util(system_user, assets, task_name): ...@@ -309,20 +243,9 @@ def test_system_user_connectability_util(system_user, assets, task_name):
:return: :return:
""" """
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
hosts = []
tasks = const.TEST_SYSTEM_USER_CONN_TASKS tasks = const.TEST_SYSTEM_USER_CONN_TASKS
for asset in assets: hosts = clean_hosts(assets)
if not asset.is_active:
msg = _("Asset has been disabled, skip: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skip: {}").format(asset)
logger.info(msg)
continue
hosts.append(asset)
if not hosts: if not hosts:
logger.info(_("No assets matched, stop task"))
return {} return {}
task, created = update_or_create_ansible_task( task, created = update_or_create_ansible_task(
task_name, hosts=hosts, tasks=tasks, pattern='all', task_name, hosts=hosts, tasks=tasks, pattern='all',
...@@ -330,36 +253,35 @@ def test_system_user_connectability_util(system_user, assets, task_name): ...@@ -330,36 +253,35 @@ def test_system_user_connectability_util(system_user, assets, task_name):
run_as=system_user, created_by=system_user.org_id, run_as=system_user, created_by=system_user.org_id,
) )
result = task.run() result = task.run()
set_system_user_connectablity_info(result, system_user=system_user) set_system_user_connectivity_info(system_user, result)
return result return result
@shared_task @shared_task
def test_system_user_connectability_manual(system_user): def test_system_user_connectivity_manual(system_user):
task_name = _("Test system user connectability: {}").format(system_user) task_name = _("Test system user connectivity: {}").format(system_user)
assets = system_user.get_assets() assets = system_user.get_related_assets()
return test_system_user_connectability_util(system_user, assets, task_name) return test_system_user_connectivity_util(system_user, assets, task_name)
@shared_task @shared_task
def test_system_user_connectability_a_asset(system_user, asset): def test_system_user_connectivity_a_asset(system_user, asset):
task_name = _("Test system user connectability: {} => {}").format( task_name = _("Test system user connectivity: {} => {}").format(
system_user, asset system_user, asset
) )
return test_system_user_connectability_util(system_user, [asset], task_name) return test_system_user_connectivity_util(system_user, [asset], task_name)
@shared_task @shared_task
def test_system_user_connectability_period(): def test_system_user_connectivity_period():
if PERIOD_TASK != "on": if PERIOD_TASK != "on":
logger.debug("Period task disabled, test system user connectability pass") logger.debug("Period task disabled, test system user connectivity pass")
return return
# Todo: 暂时禁用定期测试 system_users = SystemUser.objects.all()
# system_users = SystemUser.objects.all() for system_user in system_users:
# for system_user in system_users: task_name = _("Test system user connectivity period: {}").format(system_user)
# task_name = _("Test system user connectability period: {}").format(system_user) assets = system_user.get_related_assets()
# # task_name = _("定期测试系统用户可连接性: {}".format(system_user)) test_system_user_connectivity_util(system_user, assets, task_name)
# test_system_user_connectability_util(system_user, task_name)
#### Push system user tasks #### #### Push system user tasks ####
...@@ -381,6 +303,24 @@ def get_push_system_user_tasks(system_user): ...@@ -381,6 +303,24 @@ def get_push_system_user_tasks(system_user):
), ),
} }
}) })
tasks.extend([
{
'name': 'Check home dir exists',
'action': {
'module': 'stat',
'args': 'path=/home/{}'.format(system_user.username)
},
'register': 'home_existed'
},
{
'name': "Set home dir permission",
'action': {
'module': 'file',
'args': "path=/home/{0} owner={0} group={0} mode=700".format(system_user.username)
},
'when': 'home_existed.stat.exists == true'
}
])
if system_user.public_key: if system_user.public_key:
tasks.append({ tasks.append({
'name': 'Set {} authorized key'.format(system_user.username), 'name': 'Set {} authorized key'.format(system_user.username),
...@@ -417,19 +357,8 @@ def push_system_user_util(system_user, assets, task_name): ...@@ -417,19 +357,8 @@ def push_system_user_util(system_user, assets, task_name):
return return
tasks = get_push_system_user_tasks(system_user) tasks = get_push_system_user_tasks(system_user)
hosts = [] hosts = clean_hosts(assets)
for asset in assets:
if not asset.is_active:
msg = _("Asset has been disabled, skip: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skip: {}").format(asset)
logger.info(msg)
continue
hosts.append(asset)
if not hosts: if not hosts:
logger.info(_("No assets matched, stop task"))
return {} return {}
task, created = update_or_create_ansible_task( task, created = update_or_create_ansible_task(
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all', task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
...@@ -441,7 +370,7 @@ def push_system_user_util(system_user, assets, task_name): ...@@ -441,7 +370,7 @@ def push_system_user_util(system_user, assets, task_name):
@shared_task @shared_task
def push_system_user_to_assets_manual(system_user): def push_system_user_to_assets_manual(system_user):
assets = system_user.get_assets() assets = system_user.get_related_assets()
task_name = _("Push system users to assets: {}").format(system_user.name) task_name = _("Push system users to assets: {}").format(system_user.name)
return push_system_user_util(system_user, assets, task_name=task_name) return push_system_user_util(system_user, assets, task_name=task_name)
......
...@@ -45,13 +45,11 @@ ...@@ -45,13 +45,11 @@
<table class="table table-striped table-bordered table-hover" id="asset_list_table"> <table class="table table-striped table-bordered table-hover" id="asset_list_table">
<thead> <thead>
<tr> <tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th>{% trans 'Hostname' %}</th> <th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th> <th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th> <th>{% trans 'Port' %}</th>
<th>{% trans 'Reachable' %}</th> <th>{% trans 'Reachable' %}</th>
<th>{% trans 'Action' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -91,26 +89,36 @@ ...@@ -91,26 +89,36 @@
<script> <script>
function initTable() { function initTable() {
var reachable = {{ admin_user.REACHABLE }};
var unreachable = {{ admin_user.UNREACHABLE }};
var options = { var options = {
ele: $('#asset_list_table'), ele: $('#asset_list_table'),
buttons: [], buttons: [],
order: [], order: [],
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 0, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'+rowData.id+'">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 3, createdCell: function (td, cellData) {
if (!cellData) { if (cellData === unreachable) {
$(td).html('<i class="fa fa-times text-danger"></i>') $(td).html('<i class="fa fa-times text-danger"></i>')
} else { } else if (cellData === reachable) {
$(td).html('<i class="fa fa-check text-navy"></i>') $(td).html('<i class="fa fa-check text-navy"></i>')
} } else {
}}], $(td).html('')
ajax_url: '{% url "api-assets:asset-list" %}?admin_user_id={{ admin_user.id }}', }
}},
{targets: 4, createdCell: function (td, cellData) {
var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
$(td).html(test_btn);
}}
],
ajax_url: '{% url "api-assets:admin-user-assets" pk=admin_user.id %}',
columns: [ columns: [
{data: function(){return ""}}, {data: "hostname" }, {data: "ip" }, {data: "hostname" }, {data: "ip" },
{data: "port" }, {data: "is_connective" }], {data: "port" }, {data: "connectivity" }, {data: "id"}],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
jumpserver.initServerSideDataTable(options); jumpserver.initServerSideDataTable(options);
...@@ -119,6 +127,21 @@ function initTable() { ...@@ -119,6 +127,21 @@ function initTable() {
$(document).ready(function () { $(document).ready(function () {
initTable(); initTable();
}) })
.on('click', '.btn-test-asset', function () {
var asset_id = $(this).data('uid');
var the_url = "{% url 'api-assets:asset-alive-test' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', asset_id);
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
flash_message: false
});
})
.on('click', '.btn-test-connective', function () { .on('click', '.btn-test-connective', function () {
var the_url = "{% url 'api-assets:admin-user-connective' pk=admin_user.id %}"; var the_url = "{% url 'api-assets:admin-user-connective' pk=admin_user.id %}";
var success = function (data) { var success = function (data) {
......
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function initAssetsTable() { function initAssetsTable() {
var unreachable = {{ system_user.unreachable_assets|safe }}; var connectivity = {{ system_user.connectivity | safe }};
var options = { var options = {
ele: $('#system_user_list'), ele: $('#system_user_list'),
buttons: [], buttons: [],
...@@ -147,11 +147,13 @@ function initAssetsTable() { ...@@ -147,11 +147,13 @@ function initAssetsTable() {
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
{targets: 3, createdCell: function (td, cellData) { {targets: 3, createdCell: function (td, cellData) {
if (unreachable.indexOf(cellData) >= 0) { if (connectivity.unreachable.indexOf(cellData) >= 0) {
$(td).html('<i class="fa fa-times text-danger"></i>') $(td).html('<i class="fa fa-times text-danger"></i>')
} else { } else if (connectivity.reachable.indexOf(cellData) >= 0 ) {
$(td).html('<i class="fa fa-check text-navy"></i>') $(td).html('<i class="fa fa-check text-navy"></i>')
} } else {
$(td).html('')
}
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData) {
var push_btn = ''; var push_btn = '';
......
...@@ -95,7 +95,7 @@ function initTable() { ...@@ -95,7 +95,7 @@ function initTable() {
}}], }}],
ajax_url: '{% url "api-assets:system-user-list" %}', ajax_url: '{% url "api-assets:system-user-list" %}',
columns: [ columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "get_login_mode_display"}, {data: "assets_amount" }, {data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "login_mode_display"}, {data: "assets_amount" },
{data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" } {data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
......
...@@ -24,32 +24,34 @@ cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-r ...@@ -24,32 +24,34 @@ cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-r
urlpatterns = [ urlpatterns = [
path('assets-bulk/', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), path('assets-bulk/', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
path('system-user/<uuid:pk>/auth-info/',
api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'),
path('system-user/<uuid:pk>/assets/',
api.SystemUserAssetsListView.as_view(), name='system-user-assets'),
path('assets/<uuid:pk>/refresh/', path('assets/<uuid:pk>/refresh/',
api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'), api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'),
path('assets/<uuid:pk>/alive/', path('assets/<uuid:pk>/alive/',
api.AssetAdminUserTestApi.as_view(), name='asset-alive-test'), api.AssetAdminUserTestApi.as_view(), name='asset-alive-test'),
path('assets/<uuid:pk>/gateway/', path('assets/<uuid:pk>/gateway/',
api.AssetGatewayApi.as_view(), name='asset-gateway'), api.AssetGatewayApi.as_view(), name='asset-gateway'),
path('admin-user/<uuid:pk>/nodes/', path('admin-user/<uuid:pk>/nodes/',
api.ReplaceNodesAdminUserApi.as_view(), name='replace-nodes-admin-user'), api.ReplaceNodesAdminUserApi.as_view(), name='replace-nodes-admin-user'),
path('admin-user/<uuid:pk>/auth/', path('admin-user/<uuid:pk>/auth/',
api.AdminUserAuthApi.as_view(), name='admin-user-auth'), api.AdminUserAuthApi.as_view(), name='admin-user-auth'),
path('admin-user/<uuid:pk>/connective/', path('admin-user/<uuid:pk>/connective/',
api.AdminUserTestConnectiveApi.as_view(), name='admin-user-connective'), api.AdminUserTestConnectiveApi.as_view(), name='admin-user-connective'),
path('admin-user/<uuid:pk>/assets/',
api.AdminUserAssetsListView.as_view(), name='admin-user-assets'),
path('system-user/<uuid:pk>/auth-info/',
api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'),
path('system-user/<uuid:pk>/assets/',
api.SystemUserAssetsListView.as_view(), name='system-user-assets'),
path('system-user/<uuid:pk>/push/', path('system-user/<uuid:pk>/push/',
api.SystemUserPushApi.as_view(), name='system-user-push'), api.SystemUserPushApi.as_view(), name='system-user-push'),
path('system-user/<uuid:pk>/asset/<uuid:aid>/push/', path('system-user/<uuid:pk>/asset/<uuid:aid>/push/',
api.SystemUserPushToAssetApi.as_view(), name='system-user-push-to-asset'), api.SystemUserPushToAssetApi.as_view(), name='system-user-push-to-asset'),
path('system-user/<uuid:pk>/asset/<uuid:aid>/test/', path('system-user/<uuid:pk>/asset/<uuid:aid>/test/',
api.SystemUserTestAssetConnectabilityApi.as_view(), name='system-user-test-to-asset'), api.SystemUserTestAssetConnectivityApi.as_view(), name='system-user-test-to-asset'),
path('system-user/<uuid:pk>/connective/', path('system-user/<uuid:pk>/connective/',
api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'), api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'),
path('system-user/<uuid:pk>/cmd-filter-rules/', path('system-user/<uuid:pk>/cmd-filter-rules/',
api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'), api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'),
......
...@@ -102,7 +102,7 @@ class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView): ...@@ -102,7 +102,7 @@ class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
'app': _('Assets'), 'app': _('Assets'),
'action': _('Admin user detail'), 'action': _('Admin user detail'),
"total_amount": len(self.queryset), "total_amount": len(self.queryset),
'unreachable_amount': len([asset for asset in self.queryset if asset.is_connective is False]) 'unreachable_amount': len([asset for asset in self.queryset if asset.connectivity is False])
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
......
...@@ -304,7 +304,7 @@ defaults = { ...@@ -304,7 +304,7 @@ defaults = {
'REDIS_DB_CELERY': 3, 'REDIS_DB_CELERY': 3,
'REDIS_DB_CACHE': 4, 'REDIS_DB_CACHE': 4,
'CAPTCHA_TEST_MODE': None, 'CAPTCHA_TEST_MODE': None,
'TOKEN_EXPIRATION': 3600, 'TOKEN_EXPIRATION': 3600 * 24,
'DISPLAY_PER_PAGE': 25, 'DISPLAY_PER_PAGE': 25,
'DEFAULT_EXPIRED_YEARS': 70, 'DEFAULT_EXPIRED_YEARS': 70,
'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_DOMAIN': None,
...@@ -312,6 +312,7 @@ defaults = { ...@@ -312,6 +312,7 @@ defaults = {
'SESSION_COOKIE_AGE': 3600 * 24, 'SESSION_COOKIE_AGE': 3600 * 24,
'SESSION_EXPIRE_AT_BROWSER_CLOSE': False, 'SESSION_EXPIRE_AT_BROWSER_CLOSE': False,
'AUTH_OPENID': False, 'AUTH_OPENID': False,
'OTP_ISSUER_NAME': 'Jumpserver',
'EMAIL_SUFFIX': 'jumpserver.org', 'EMAIL_SUFFIX': 'jumpserver.org',
'TERMINAL_PASSWORD_AUTH': True, 'TERMINAL_PASSWORD_AUTH': True,
'TERMINAL_PUBLIC_KEY_AUTH': True, 'TERMINAL_PUBLIC_KEY_AUTH': True,
......
...@@ -637,7 +637,7 @@ msgstr "分类" ...@@ -637,7 +637,7 @@ msgstr "分类"
#: assets/models/node.py:20 #: assets/models/node.py:20
msgid "Key" msgid "Key"
msgstr "" msgstr ""
#: assets/models/node.py:127 #: assets/models/node.py:127
msgid "New node" msgid "New node"
...@@ -739,15 +739,15 @@ msgid "Update asset hardware info: {}" ...@@ -739,15 +739,15 @@ msgid "Update asset hardware info: {}"
msgstr "更新资产硬件信息: {}" msgstr "更新资产硬件信息: {}"
#: assets/tasks.py:230 #: assets/tasks.py:230
msgid "Test admin user connectability period: {}" msgid "Test admin user connectivity period: {}"
msgstr "定期测试管理账号可连接性: {}" msgstr "定期测试管理账号可连接性: {}"
#: assets/tasks.py:236 #: assets/tasks.py:236
msgid "Test admin user connectability: {}" msgid "Test admin user connectivity: {}"
msgstr "测试管理行号可连接性: {}" msgstr "测试管理行号可连接性: {}"
#: assets/tasks.py:246 #: assets/tasks.py:246
msgid "Test assets connectability" msgid "Test assets connectivity"
msgstr "测试资产可连接性" msgstr "测试资产可连接性"
#: assets/tasks.py:251 assets/tasks.py:316 assets/tasks.py:423 #: assets/tasks.py:251 assets/tasks.py:316 assets/tasks.py:423
...@@ -763,15 +763,15 @@ msgid "No assets, task stop" ...@@ -763,15 +763,15 @@ msgid "No assets, task stop"
msgstr "没有匹配到资产,结束任务" msgstr "没有匹配到资产,结束任务"
#: assets/tasks.py:280 #: assets/tasks.py:280
msgid "Test assets connectability: {}" msgid "Test assets connectivity: {}"
msgstr "测试资产可连接性: {}" msgstr "测试资产可连接性: {}"
#: assets/tasks.py:339 #: assets/tasks.py:339
msgid "Test system user connectability: {}" msgid "Test system user connectivity: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:346 #: assets/tasks.py:346
msgid "Test system user connectability: {} => {}" msgid "Test system user connectivity: {} => {}"
msgstr "测试系统用户可连接性: {} => {}" msgstr "测试系统用户可连接性: {} => {}"
#: assets/tasks.py:414 #: assets/tasks.py:414
...@@ -4508,7 +4508,7 @@ msgstr "创建账户" ...@@ -4508,7 +4508,7 @@ msgstr "创建账户"
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:91 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:91
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr "加载中..."
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:106 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:106
msgid "Load failed" msgid "Load failed"
...@@ -4634,7 +4634,7 @@ msgstr "更新组织" ...@@ -4634,7 +4634,7 @@ msgstr "更新组织"
#~ msgid "Update assets hardware info period" #~ msgid "Update assets hardware info period"
#~ msgstr "定期更新资产硬件信息" #~ msgstr "定期更新资产硬件信息"
#~ msgid "Test system user connectability period: {}" #~ msgid "Test system user connectivity period: {}"
#~ msgstr "定期测试系统用户可连接性: {}" #~ msgstr "定期测试系统用户可连接性: {}"
#~ msgid "Date finished" #~ msgid "Date finished"
......
...@@ -24,8 +24,10 @@ class TaskViewSet(viewsets.ModelViewSet): ...@@ -24,8 +24,10 @@ class TaskViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = super().get_queryset() queryset = super().get_queryset()
if current_org: if current_org.is_real():
queryset = queryset.filter(created_by=current_org.id) queryset = queryset.filter(created_by=current_org.id)
else:
queryset = queryset.filter(created_by='')
return queryset return queryset
......
...@@ -27,7 +27,7 @@ class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView): ...@@ -27,7 +27,7 @@ class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
def get_queryset(self): def get_queryset(self):
queryset = super().get_queryset() queryset = super().get_queryset()
if current_org: if current_org.is_real():
queryset = queryset.filter(created_by=current_org.id) queryset = queryset.filter(created_by=current_org.id)
else: else:
queryset = queryset.filter(created_by='') queryset = queryset.filter(created_by='')
......
...@@ -46,6 +46,9 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet): ...@@ -46,6 +46,9 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet):
self.permission_classes = (IsOrgAdminOrAppUser,) self.permission_classes = (IsOrgAdminOrAppUser,)
return super().get_permissions() return super().get_permissions()
def allow_bulk_destroy(self, qs, filtered):
return qs.count() == filtered.count()
class UserChangePasswordApi(generics.RetrieveUpdateAPIView): class UserChangePasswordApi(generics.RetrieveUpdateAPIView):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment