Commit 2ac5786b authored by ibuler's avatar ibuler

[Bugfix] 修复Hostname可能不唯一引起的任务执行失败

parent 5b93a1a0
......@@ -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:
......
......@@ -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):
......
......@@ -35,4 +35,4 @@ class Label(OrgModelMixin):
class Meta:
db_table = "assets_label"
unique_together = [('name', 'value')]
unique_together = [('name', 'value', 'org_id')]
......@@ -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 {}
......
......@@ -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):
......
......@@ -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):
......
......@@ -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
......
......@@ -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
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