From 2ac5786ba10535a3cacd444b592491b8221b6992 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 16 Aug 2018 12:44:39 +0800 Subject: [PATCH] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8DHostname=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E4=B8=8D=E5=94=AF=E4=B8=80=E5=BC=95=E8=B5=B7=E7=9A=84?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=89=A7=E8=A1=8C=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/asset.py | 2 +- apps/assets/models/asset.py | 20 +++++++++---- apps/assets/models/label.py | 2 +- apps/assets/tasks.py | 14 ++++----- apps/assets/utils.py | 4 +-- apps/ops/inventory.py | 4 +-- apps/orgs/mixins.py | 60 ++++++++++++++++++++++++++++++++++++- apps/orgs/models.py | 41 +++++++++++++++---------- 8 files changed, 113 insertions(+), 34 deletions(-) diff --git a/apps/assets/api/asset.py b/apps/assets/api/asset.py index e2ce1b62a..a4701add9 100644 --- a/apps/assets/api/asset.py +++ b/apps/assets/api/asset.py @@ -48,7 +48,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet): return node = get_object_or_404(Node, id=node_id) - show_current_asset = self.request.query_params.get("show_current_asset") + show_current_asset = self.request.query_params.get("show_current_asset") in ('1', 'true') if node.is_root(): if show_current_asset: diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index b1d728e37..b554c5c3a 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -6,8 +6,10 @@ import uuid import logging import random from functools import reduce +from collections import defaultdict from django.db import models +from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from django.core.cache import cache @@ -162,11 +164,19 @@ class Asset(OrgModelMixin): nodes = list(reduce(lambda x, y: set(x) | set(y), nodes)) return nodes - @property - def org_name(self): - from orgs.models import Organization - org = Organization.get_instance(self.org_id) - return org.name + @classmethod + def get_queryset_by_fullname_list(cls, fullname_list): + org_fullname_map = defaultdict(list) + for fullname in fullname_list: + hostname, org = cls.split_fullname(fullname) + org_fullname_map[org].append(hostname) + filter_arg = Q() + for org, hosts in org_fullname_map.items(): + if org.is_real(): + filter_arg |= Q(hostname__in=hosts, org_id=org.id) + else: + filter_arg |= Q(Q(org_id__isnull=True) | Q(org_id=''), hostname__in=hosts) + return Asset.objects.filter(filter_arg) @property def hardware_info(self): diff --git a/apps/assets/models/label.py b/apps/assets/models/label.py index 7f1d08fa1..abc71e694 100644 --- a/apps/assets/models/label.py +++ b/apps/assets/models/label.py @@ -35,4 +35,4 @@ class Label(OrgModelMixin): class Meta: db_table = "assets_label" - unique_together = [('name', 'value')] + unique_together = [('name', 'value', 'org_id')] diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index 54d6f7f8e..463c3006a 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -44,7 +44,7 @@ def set_assets_hardware_info(result, **kwargs): logger.error("Get asset info failed: {}".format(hostname)) continue - asset = get_object_or_none(Asset, hostname=hostname) + asset = Asset.objects.get_object_by_fullname(hostname) if not asset: continue @@ -96,7 +96,7 @@ def update_assets_hardware_info_util(assets, task_name=None): # task_name = _("Update some assets hardware info") task_name = _("更新资产硬件信息") tasks = const.UPDATE_ASSETS_HARDWARE_TASKS - hostname_list = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] + hostname_list = [asset.fullname for asset in assets if asset.is_active and asset.is_unixlike()] if not hostname_list: logger.info("Not hosts get, may be asset is not active or not unixlike platform") return {} @@ -135,7 +135,7 @@ def update_assets_hardware_info_period(): # task_name = _("Update assets hardware info period") task_name = _("定期更新资产硬件信息") hostname_list = [ - asset.hostname for asset in Asset.objects.all() + asset.fullname for asset in Asset.objects.all() if asset.is_active and asset.is_unixlike() ] tasks = const.UPDATE_ASSETS_HARDWARE_TASKS @@ -182,7 +182,7 @@ 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.fullname for asset in assets if asset.is_active and asset.is_unixlike()] if not hosts: return @@ -229,7 +229,7 @@ def test_asset_connectability_util(assets, task_name=None): if task_name is None: # task_name = _("Test assets connectability") task_name = _("测试资产可连接性") - hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] + hosts = [asset.fullname for asset in assets if asset.is_active and asset.is_unixlike()] if not hosts: logger.info("No hosts, passed") return {} @@ -281,7 +281,7 @@ def test_system_user_connectability_util(system_user, task_name): """ from ops.utils import update_or_create_ansible_task assets = system_user.get_assets() - hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] + hosts = [asset.fullname 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") @@ -379,7 +379,7 @@ def push_system_user_util(system_users, assets, task_name): logger.info("Not tasks, passed") return {} - hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] + hosts = [asset.fullname 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/utils.py b/apps/assets/utils.py index f841e4a79..9cee82a46 100644 --- a/apps/assets/utils.py +++ b/apps/assets/utils.py @@ -12,8 +12,8 @@ def get_assets_by_id_list(id_list): return Asset.objects.filter(id__in=id_list) -def get_assets_by_hostname_list(hostname_list): - return Asset.objects.filter(hostname__in=hostname_list) +def get_assets_by_fullname_list(hostname_list): + return Asset.objects.get_queryset_by_fullname_list(hostname_list) def get_system_user_by_name(name): diff --git a/apps/ops/inventory.py b/apps/ops/inventory.py index 7ed89e75c..117d961a9 100644 --- a/apps/ops/inventory.py +++ b/apps/ops/inventory.py @@ -2,7 +2,7 @@ # from .ansible.inventory import BaseInventory -from assets.utils import get_assets_by_hostname_list, get_system_user_by_name +from assets.utils import get_assets_by_fullname_list, get_system_user_by_name __all__ = [ 'JMSInventory' @@ -44,7 +44,7 @@ class JMSInventory(BaseInventory): super().__init__(host_list=host_list) def get_jms_assets(self): - assets = get_assets_by_hostname_list(self.hostname_list) + assets = get_assets_by_fullname_list(self.hostname_list) return assets def convert_to_ansible(self, asset, run_as_admin=False): diff --git a/apps/orgs/mixins.py b/apps/orgs/mixins.py index 0355b02f8..648611d50 100644 --- a/apps/orgs/mixins.py +++ b/apps/orgs/mixins.py @@ -8,7 +8,7 @@ from django.shortcuts import redirect from django.forms import ModelForm from django.http.response import HttpResponseForbidden -from common.utils import get_logger +from common.utils import get_logger, is_uuid from .utils import current_org, set_current_org, set_to_root_org from .models import Organization @@ -39,6 +39,25 @@ class OrgManager(models.Manager): tl.times += 1 return queryset + def filter_by_fullname(self, fullname, field=None): + ori_org = current_org + value, org = self.model.split_fullname(fullname) + set_current_org(org) + if not field: + if hasattr(self.model, 'name'): + field = 'name' + elif hasattr(self.model, 'hostname'): + field = 'hostname' + queryset = self.get_queryset().filter(**{field: value}) + set_current_org(ori_org) + return queryset + + def get_object_by_fullname(self, fullname, field=None): + queryset = self.filter_by_fullname(fullname, field=field) + if len(queryset) == 1: + return queryset[0] + return None + def all(self): if not current_org: msg = 'You can `objects.set_current_org(org).all()` then run it' @@ -57,11 +76,50 @@ class OrgModelMixin(models.Model): org_id = models.CharField(max_length=36, null=True, blank=True, default=None) objects = OrgManager() + sep = '@' + def save(self, *args, **kwargs): if current_org and current_org.is_real(): self.org_id = current_org.id return super().save(*args, **kwargs) + @classmethod + def split_fullname(cls, fullname, sep=None): + if not sep: + sep = cls.sep + index = fullname.rfind(sep) + if index == -1: + value = fullname + org = Organization.default() + else: + value = fullname[:index] + org = Organization.get_instance(fullname[index + 1:]) + return value, org + + @property + def org(self): + from orgs.models import Organization + org = Organization.get_instance(self.org_id) + return org + + @property + def org_name(self): + return self.org.name + + @property + def fullname(self, attr=None): + name = '' + if attr and hasattr(self, attr): + name = getattr(self, attr) + elif hasattr(self, 'name'): + name = self.name + elif hasattr(self, 'hostname'): + name = self.hostname + if self.org.is_real(): + return name + self.sep + self.org_name + else: + return name + class Meta: abstract = True diff --git a/apps/orgs/models.py b/apps/orgs/models.py index ed44b8b7e..3ddd91f71 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -4,6 +4,8 @@ from django.db import models from django.core.cache import cache from django.utils.translation import ugettext_lazy as _ +from common.utils import is_uuid + class Organization(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True) @@ -15,19 +17,23 @@ class Organization(models.Model): comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) CACHE_PREFIX = 'JMS_ORG_{}' - ROOT_ID = 'ROOT' - DEFAULT_ID = 'DEFAULT' + ROOT_ID_NAME = 'ROOT' + DEFAULT_ID_NAME = 'DEFAULT' def __str__(self): return self.name def set_to_cache(self): - key = self.CACHE_PREFIX.format(self.id) - cache.set(key, self, 3600) + key_id = self.CACHE_PREFIX.format(self.id) + key_name = self.CACHE_PREFIX.format(self.name) + cache.set(key_id, self, 3600) + cache.set(key_name, self, 3600) def expire_cache(self): - key = self.CACHE_PREFIX.format(self.id) - cache.set(key, self, 1) + key_id = self.CACHE_PREFIX.format(self.id) + key_name = self.CACHE_PREFIX.format(self.name) + cache.delete(key_id) + cache.delete(key_name) @classmethod def get_instance_from_cache(cls, oid): @@ -35,18 +41,23 @@ class Organization(models.Model): return cache.get(key, None) @classmethod - def get_instance(cls, oid, default=True): - cached = cls.get_instance_from_cache(oid) + def get_instance(cls, id_or_name, default=True): + cached = cls.get_instance_from_cache(id_or_name) if cached: return cached - if oid == cls.DEFAULT_ID: + if not id_or_name: + return cls.default() if default else None + elif id_or_name == cls.DEFAULT_ID_NAME: return cls.default() - elif oid == cls.ROOT_ID: + elif id_or_name == cls.ROOT_ID_NAME: return cls.root() try: - org = cls.objects.get(id=oid) + if is_uuid(id_or_name): + org = cls.objects.get(id=id_or_name) + else: + org = cls.objects.get(name=id_or_name) org.set_to_cache() except cls.DoesNotExist: org = cls.default() if default else None @@ -92,20 +103,20 @@ class Organization(models.Model): @classmethod def default(cls): - return cls(id=cls.DEFAULT_ID, name="Default") + return cls(id=cls.DEFAULT_ID_NAME, name=cls.DEFAULT_ID_NAME) @classmethod def root(cls): - return cls(id=cls.ROOT_ID, name='Root') + return cls(id=cls.ROOT_ID_NAME, name=cls.ROOT_ID_NAME) def is_root(self): - if self.id is self.ROOT_ID: + if self.id is self.ROOT_ID_NAME: return True else: return False def is_default(self): - if self.id is self.DEFAULT_ID: + if self.id is self.DEFAULT_ID_NAME: return True else: return False