diff --git a/apps/assets/api/__init__.py b/apps/assets/api/__init__.py
index 4a41c0706..a1a3beee7 100644
--- a/apps/assets/api/__init__.py
+++ b/apps/assets/api/__init__.py
@@ -3,3 +3,4 @@ from .asset import *
from .label import *
from .system_user import *
from .node import *
+from .domain import *
diff --git a/apps/assets/api/domain.py b/apps/assets/api/domain.py
new file mode 100644
index 000000000..5114b5561
--- /dev/null
+++ b/apps/assets/api/domain.py
@@ -0,0 +1,55 @@
+# ~*~ coding: utf-8 ~*~
+
+from rest_framework_bulk import BulkModelViewSet
+from rest_framework.views import APIView, Response
+from rest_framework.generics import RetrieveAPIView
+
+from django.views.generic.detail import SingleObjectMixin
+
+from common.utils import get_logger
+from ..hands import IsSuperUser, IsSuperUserOrAppUser
+from ..models import Domain, Gateway
+from ..utils import test_gateway_connectability
+from .. import serializers
+
+
+logger = get_logger(__file__)
+__all__ = ['DomainViewSet', 'GatewayViewSet', "GatewayTestConnectionApi"]
+
+
+class DomainViewSet(BulkModelViewSet):
+ queryset = Domain.objects.all()
+ permission_classes = (IsSuperUser,)
+ serializer_class = serializers.DomainSerializer
+
+ def get_serializer_class(self):
+ if self.request.query_params.get('gateway'):
+ return serializers.DomainWithGatewaySerializer
+ return super().get_serializer_class()
+
+ def get_permissions(self):
+ if self.request.query_params.get('gateway'):
+ self.permission_classes = (IsSuperUserOrAppUser,)
+ return super().get_permissions()
+
+
+class GatewayViewSet(BulkModelViewSet):
+ filter_fields = ("domain",)
+ search_fields = filter_fields
+ queryset = Gateway.objects.all()
+ permission_classes = (IsSuperUser,)
+ serializer_class = serializers.GatewaySerializer
+
+
+class GatewayTestConnectionApi(SingleObjectMixin, APIView):
+ permission_classes = (IsSuperUser,)
+ model = Gateway
+ object = None
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object(Gateway.objects.all())
+ ok, e = test_gateway_connectability(self.object)
+ if ok:
+ return Response("ok")
+ else:
+ return Response({"failed": e}, status=404)
diff --git a/apps/assets/forms/__init__.py b/apps/assets/forms/__init__.py
index 9175d7c43..4eaa40948 100644
--- a/apps/assets/forms/__init__.py
+++ b/apps/assets/forms/__init__.py
@@ -3,3 +3,4 @@
from .asset import *
from .label import *
from .user import *
+from .domain import *
diff --git a/apps/assets/forms/asset.py b/apps/assets/forms/asset.py
index 65716f533..a6f488761 100644
--- a/apps/assets/forms/asset.py
+++ b/apps/assets/forms/asset.py
@@ -16,6 +16,7 @@ class AssetCreateForm(forms.ModelForm):
fields = [
'hostname', 'ip', 'public_ip', 'port', 'comment',
'nodes', 'is_active', 'admin_user', 'labels', 'platform',
+ 'domain',
]
widgets = {
@@ -29,6 +30,9 @@ class AssetCreateForm(forms.ModelForm):
'class': 'select2', 'data-placeholder': _('Labels')
}),
'port': forms.TextInput(),
+ 'domain': forms.Select(attrs={
+ 'class': 'select2', 'data-placeholder': _('Domain')
+ }),
}
help_texts = {
'hostname': '* required',
@@ -38,7 +42,8 @@ class AssetCreateForm(forms.ModelForm):
'root or other NOPASSWD sudo privilege user existed in asset,'
'If asset is windows or other set any one, more see admin user left menu'
),
- 'platform': _("* required Must set exact system platform, Windows, Linux ...")
+ 'platform': _("* required Must set exact system platform, Windows, Linux ..."),
+ 'domain': _("If your have some network not connect with each other, you can set domain")
}
@@ -48,6 +53,7 @@ class AssetUpdateForm(forms.ModelForm):
fields = [
'hostname', 'ip', 'port', 'nodes', 'is_active', 'platform',
'public_ip', 'number', 'comment', 'admin_user', 'labels',
+ 'domain',
]
widgets = {
'nodes': forms.SelectMultiple(attrs={
@@ -60,6 +66,9 @@ class AssetUpdateForm(forms.ModelForm):
'class': 'select2', 'data-placeholder': _('Labels')
}),
'port': forms.TextInput(),
+ 'domain': forms.Select(attrs={
+ 'class': 'select2', 'data-placeholder': _('Domain')
+ }),
}
help_texts = {
'hostname': '* required',
@@ -70,7 +79,8 @@ class AssetUpdateForm(forms.ModelForm):
'root or other NOPASSWD sudo privilege user existed in asset,'
'If asset is windows or other set any one, more see admin user left menu'
),
- 'platform': _("* required Must set exact system platform, Windows, Linux ...")
+ 'platform': _("* required Must set exact system platform, Windows, Linux ..."),
+ 'domain': _("If your have some network not connect with each other, you can set domain")
}
diff --git a/apps/assets/forms/domain.py b/apps/assets/forms/domain.py
new file mode 100644
index 000000000..ec3af8f2e
--- /dev/null
+++ b/apps/assets/forms/domain.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+#
+from django import forms
+from django.utils.translation import gettext_lazy as _
+
+from ..models import Domain, Asset, Gateway
+from .user import PasswordAndKeyAuthForm
+
+__all__ = ['DomainForm', 'GatewayForm']
+
+
+class DomainForm(forms.ModelForm):
+ assets = forms.ModelMultipleChoiceField(
+ queryset=Asset.objects.all(), label=_('Asset'), required=False,
+ widget=forms.SelectMultiple(
+ attrs={'class': 'select2', 'data-placeholder': _('Select assets')}
+ )
+ )
+
+ class Meta:
+ model = Domain
+ fields = ['name', 'comment', 'assets']
+
+ def __init__(self, *args, **kwargs):
+ if kwargs.get('instance', None):
+ initial = kwargs.get('initial', {})
+ initial['assets'] = kwargs['instance'].assets.all()
+ super().__init__(*args, **kwargs)
+
+ def save(self, commit=True):
+ instance = super().save(commit=commit)
+ assets = self.cleaned_data['assets']
+ instance.assets.set(assets)
+ return instance
+
+
+class GatewayForm(PasswordAndKeyAuthForm):
+
+ def save(self, commit=True):
+ # Because we define custom field, so we need rewrite :method: `save`
+ instance = super().save()
+ password = self.cleaned_data.get('password')
+ private_key, public_key = super().gen_keys()
+ instance.set_auth(password=password, private_key=private_key)
+ return instance
+
+ class Meta:
+ model = Gateway
+ fields = [
+ 'name', 'ip', 'port', 'username', 'protocol', 'domain', 'password',
+ 'private_key_file', 'is_active', 'comment',
+ ]
+ widgets = {
+ 'name': forms.TextInput(attrs={'placeholder': _('Name')}),
+ 'username': forms.TextInput(attrs={'placeholder': _('Username')}),
+ }
+ help_texts = {
+ 'name': '* required',
+ 'username': '* required',
+ }
diff --git a/apps/assets/forms/user.py b/apps/assets/forms/user.py
index 487d2714b..2295dc005 100644
--- a/apps/assets/forms/user.py
+++ b/apps/assets/forms/user.py
@@ -8,7 +8,7 @@ from common.utils import validate_ssh_private_key, ssh_pubkey_gen, get_logger
logger = get_logger(__file__)
__all__ = [
- 'FileForm', 'SystemUserForm', 'AdminUserForm',
+ 'FileForm', 'SystemUserForm', 'AdminUserForm', 'PasswordAndKeyAuthForm',
]
diff --git a/apps/assets/models/__init__.py b/apps/assets/models/__init__.py
index dbc703706..35c275b99 100644
--- a/apps/assets/models/__init__.py
+++ b/apps/assets/models/__init__.py
@@ -5,6 +5,7 @@ from .user import AdminUser, SystemUser
from .label import Label
from .cluster import *
from .group import *
+from .domain import *
from .node import *
from .asset import *
from .utils import *
diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py
index 3f7dec4ec..b8c1f768e 100644
--- a/apps/assets/models/asset.py
+++ b/apps/assets/models/asset.py
@@ -4,14 +4,13 @@
import uuid
import logging
+import random
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache
from ..const import ASSET_ADMIN_CONN_CACHE_KEY
-from .cluster import Cluster
-from .group import AssetGroup
from .user import AdminUser, SystemUser
__all__ = ['Asset']
@@ -50,6 +49,7 @@ class Asset(models.Model):
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
port = models.IntegerField(default=22, verbose_name=_('Port'))
+ domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"))
nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes"))
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
@@ -122,12 +122,15 @@ class Asset(models.Model):
return False
def to_json(self):
- return {
+ 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):
"""
@@ -168,7 +171,6 @@ class Asset(models.Model):
try:
asset.save()
asset.system_users = [choice(SystemUser.objects.all()) for i in range(3)]
- asset.groups = [choice(AssetGroup.objects.all()) for i in range(3)]
logger.debug('Generate fake asset : %s' % asset.ip)
except IntegrityError:
print('Error continue')
diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py
new file mode 100644
index 000000000..ad2a3b904
--- /dev/null
+++ b/apps/assets/models/base.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+#
+import os
+import uuid
+from hashlib import md5
+
+import sshpubkeys
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django.conf import settings
+
+from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen
+from .utils import private_key_validator
+
+signer = get_signer()
+
+
+class AssetUser(models.Model):
+ id = models.UUIDField(default=uuid.uuid4, primary_key=True)
+ name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
+ username = models.CharField(max_length=128, verbose_name=_('Username'))
+ _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
+ _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
+ _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
+ comment = models.TextField(blank=True, verbose_name=_('Comment'))
+ date_created = models.DateTimeField(auto_now_add=True)
+ date_updated = models.DateTimeField(auto_now=True)
+ created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
+
+ @property
+ def password(self):
+ if self._password:
+ return signer.unsign(self._password)
+ else:
+ return None
+
+ @password.setter
+ def password(self, password_raw):
+ raise AttributeError("Using set_auth do that")
+ # self._password = signer.sign(password_raw)
+
+ @property
+ def private_key(self):
+ if self._private_key:
+ return signer.unsign(self._private_key)
+
+ @private_key.setter
+ def private_key(self, private_key_raw):
+ raise AttributeError("Using set_auth do that")
+ # self._private_key = signer.sign(private_key_raw)
+
+ @property
+ def private_key_obj(self):
+ if self._private_key:
+ key_str = signer.unsign(self._private_key)
+ return ssh_key_string_to_obj(key_str, password=self.password)
+ else:
+ return None
+
+ @property
+ def private_key_file(self):
+ if not self.private_key_obj:
+ return None
+ project_dir = settings.PROJECT_DIR
+ tmp_dir = os.path.join(project_dir, 'tmp')
+ key_str = signer.unsign(self._private_key)
+ key_name = '.' + md5(key_str.encode('utf-8')).hexdigest()
+ key_path = os.path.join(tmp_dir, key_name)
+ if not os.path.exists(key_path):
+ self.private_key_obj.write_private_key_file(key_path)
+ os.chmod(key_path, 0o400)
+ return key_path
+
+ @property
+ def public_key(self):
+ key = signer.unsign(self._public_key)
+ if key:
+ return key
+ else:
+ return None
+
+ @property
+ def public_key_obj(self):
+ if self.public_key:
+ try:
+ return sshpubkeys.SSHKey(self.public_key)
+ except TabError:
+ pass
+ return None
+
+ def set_auth(self, password=None, private_key=None, public_key=None):
+ update_fields = []
+ if password:
+ self._password = signer.sign(password)
+ update_fields.append('_password')
+ if private_key:
+ self._private_key = signer.sign(private_key)
+ update_fields.append('_private_key')
+ if public_key:
+ self._public_key = signer.sign(public_key)
+ update_fields.append('_public_key')
+
+ if update_fields:
+ self.save(update_fields=update_fields)
+
+ def auto_gen_auth(self):
+ password = str(uuid.uuid4())
+ private_key, public_key = ssh_key_gen(
+ username=self.name, password=password
+ )
+ self.set_auth(password=password,
+ private_key=private_key,
+ public_key=public_key)
+
+ def _to_secret_json(self):
+ """Push system user use it"""
+ return {
+ 'name': self.name,
+ 'username': self.username,
+ 'password': self.password,
+ 'public_key': self.public_key,
+ 'private_key': self.private_key_file,
+ }
+
+ class Meta:
+ abstract = True
diff --git a/apps/assets/models/domain.py b/apps/assets/models/domain.py
new file mode 100644
index 000000000..6f29a0381
--- /dev/null
+++ b/apps/assets/models/domain.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+#
+
+import uuid
+import random
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from .base import AssetUser
+
+__all__ = ['Domain', 'Gateway']
+
+
+class Domain(models.Model):
+ id = models.UUIDField(default=uuid.uuid4, primary_key=True)
+ name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
+ comment = models.TextField(blank=True, verbose_name=_('Comment'))
+ date_created = models.DateTimeField(auto_now_add=True, null=True,
+ verbose_name=_('Date created'))
+
+ def __str__(self):
+ return self.name
+
+ def has_gateway(self):
+ return self.gateway_set.filter(is_active=True).exists()
+
+ @property
+ def gateways(self):
+ return self.gateway_set.filter(is_active=True)
+
+ def random_gateway(self):
+ return random.choice(self.gateways)
+
+
+class Gateway(AssetUser):
+ SSH_PROTOCOL = 'ssh'
+ RDP_PROTOCOL = 'rdp'
+ PROTOCOL_CHOICES = (
+ (SSH_PROTOCOL, 'ssh'),
+ (RDP_PROTOCOL, 'rdp'),
+ )
+ ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
+ port = models.IntegerField(default=22, verbose_name=_('Port'))
+ protocol = models.CharField(choices=PROTOCOL_CHOICES, max_length=16, default=SSH_PROTOCOL, verbose_name=_("Protocol"))
+ domain = models.ForeignKey(Domain, verbose_name=_("Domain"))
+ comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Comment"))
+ is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
+
+ def __str__(self):
+ return self.name
+
diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py
index 7eaff63e6..541ef8b6a 100644
--- a/apps/assets/models/user.py
+++ b/apps/assets/models/user.py
@@ -2,20 +2,15 @@
# -*- coding: utf-8 -*-
#
-import os
import logging
-import uuid
-from hashlib import md5
-import sshpubkeys
from django.core.cache import cache
from django.db import models
from django.utils.translation import ugettext_lazy as _
-from django.conf import settings
-from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen
-from .utils import private_key_validator
+from common.utils import get_signer
from ..const import SYSTEM_USER_CONN_CACHE_KEY
+from .base import AssetUser
__all__ = ['AdminUser', 'SystemUser',]
@@ -23,117 +18,6 @@ logger = logging.getLogger(__name__)
signer = get_signer()
-class AssetUser(models.Model):
- id = models.UUIDField(default=uuid.uuid4, primary_key=True)
- name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
- username = models.CharField(max_length=128, verbose_name=_('Username'))
- _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
- _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
- _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
- comment = models.TextField(blank=True, verbose_name=_('Comment'))
- date_created = models.DateTimeField(auto_now_add=True)
- date_updated = models.DateTimeField(auto_now=True)
- created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
-
- @property
- def password(self):
- if self._password:
- return signer.unsign(self._password)
- else:
- return None
-
- @password.setter
- def password(self, password_raw):
- raise AttributeError("Using set_auth do that")
- # self._password = signer.sign(password_raw)
-
- @property
- def private_key(self):
- if self._private_key:
- return signer.unsign(self._private_key)
-
- @private_key.setter
- def private_key(self, private_key_raw):
- raise AttributeError("Using set_auth do that")
- # self._private_key = signer.sign(private_key_raw)
-
- @property
- def private_key_obj(self):
- if self._private_key:
- key_str = signer.unsign(self._private_key)
- return ssh_key_string_to_obj(key_str, password=self.password)
- else:
- return None
-
- @property
- def private_key_file(self):
- if not self.private_key_obj:
- return None
- project_dir = settings.PROJECT_DIR
- tmp_dir = os.path.join(project_dir, 'tmp')
- key_str = signer.unsign(self._private_key)
- key_name = '.' + md5(key_str.encode('utf-8')).hexdigest()
- key_path = os.path.join(tmp_dir, key_name)
- if not os.path.exists(key_path):
- self.private_key_obj.write_private_key_file(key_path)
- os.chmod(key_path, 0o400)
- return key_path
-
- @property
- def public_key(self):
- key = signer.unsign(self._public_key)
- if key:
- return key
- else:
- return None
-
- @property
- def public_key_obj(self):
- if self.public_key:
- try:
- return sshpubkeys.SSHKey(self.public_key)
- except TabError:
- pass
- return None
-
- def set_auth(self, password=None, private_key=None, public_key=None):
- update_fields = []
- if password:
- self._password = signer.sign(password)
- update_fields.append('_password')
- if private_key:
- self._private_key = signer.sign(private_key)
- update_fields.append('_private_key')
- if public_key:
- self._public_key = signer.sign(public_key)
- update_fields.append('_public_key')
-
- if update_fields:
- self.save(update_fields=update_fields)
-
- def auto_gen_auth(self):
- password = str(uuid.uuid4())
- private_key, public_key = ssh_key_gen(
- username=self.name, password=password
- )
- self.set_auth(password=password,
- private_key=private_key,
- public_key=public_key)
-
- def _to_secret_json(self):
- """Push system user use it"""
- return {
- 'name': self.name,
- 'username': self.username,
- 'password': self.password,
- 'public_key': self.public_key,
- 'private_key': self.private_key_file,
- }
-
- class Meta:
- abstract = True
-
-
class AdminUser(AssetUser):
"""
A privileged user that ansible can use it to push system user and so on
diff --git a/apps/assets/models/utils.py b/apps/assets/models/utils.py
index a819715ab..11d347685 100644
--- a/apps/assets/models/utils.py
+++ b/apps/assets/models/utils.py
@@ -10,15 +10,15 @@ __all__ = ['init_model', 'generate_fake']
def init_model():
- from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
- for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
+ from . import SystemUser, AdminUser, Asset
+ for cls in [SystemUser, AdminUser, Asset]:
if hasattr(cls, 'initial'):
cls.initial()
def generate_fake():
- from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
- for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
+ from . import SystemUser, AdminUser, Asset
+ for cls in [SystemUser, AdminUser, Asset]:
if hasattr(cls, 'generate_fake'):
cls.generate_fake()
diff --git a/apps/assets/serializers/__init__.py b/apps/assets/serializers/__init__.py
index c39d34767..111f070a7 100644
--- a/apps/assets/serializers/__init__.py
+++ b/apps/assets/serializers/__init__.py
@@ -6,3 +6,4 @@ from .admin_user import *
from .label import *
from .system_user import *
from .node import *
+from .domain import *
diff --git a/apps/assets/serializers/asset.py b/apps/assets/serializers/asset.py
index e479a7149..bcb3b81b1 100644
--- a/apps/assets/serializers/asset.py
+++ b/apps/assets/serializers/asset.py
@@ -38,7 +38,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
model = Asset
fields = (
"id", "hostname", "ip", "port", "system_users_granted",
- "is_active", "system_users_join", "os",
+ "is_active", "system_users_join", "os", 'domain',
"platform", "comment"
)
diff --git a/apps/assets/serializers/cluster.py b/apps/assets/serializers/cluster.py
deleted file mode 100644
index 43724a4a2..000000000
--- a/apps/assets/serializers/cluster.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-
-from rest_framework import serializers
-from common.mixins import BulkSerializerMixin
-from ..models import Asset, Cluster
-
-
-class ClusterUpdateAssetsSerializer(serializers.ModelSerializer):
- """
- 集群更新资产数据结构
- """
- assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
-
- class Meta:
- model = Cluster
- fields = ['id', 'assets']
-
-
-class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
- """
- cluster
- """
- assets_amount = serializers.SerializerMethodField()
- admin_user_name = serializers.SerializerMethodField()
- assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
- system_users = serializers.SerializerMethodField()
-
- class Meta:
- model = Cluster
- fields = '__all__'
-
- @staticmethod
- def get_assets_amount(obj):
- return obj.assets.count()
-
- @staticmethod
- def get_admin_user_name(obj):
- try:
- return obj.admin_user.name
- except AttributeError:
- return ''
-
- @staticmethod
- def get_system_users(obj):
- return ', '.join(obj.name for obj in obj.systemuser_set.all())
diff --git a/apps/assets/serializers/domain.py b/apps/assets/serializers/domain.py
new file mode 100644
index 000000000..034c29387
--- /dev/null
+++ b/apps/assets/serializers/domain.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+#
+from rest_framework import serializers
+
+from ..models import Domain, Gateway
+
+
+class DomainSerializer(serializers.ModelSerializer):
+ asset_count = serializers.SerializerMethodField()
+ gateway_count = serializers.SerializerMethodField()
+
+ class Meta:
+ model = Domain
+ fields = '__all__'
+
+ @staticmethod
+ def get_asset_count(obj):
+ return obj.assets.count()
+
+ @staticmethod
+ def get_gateway_count(obj):
+ return obj.gateway_set.all().count()
+
+
+class GatewaySerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = Gateway
+ fields = [
+ 'id', 'name', 'ip', 'port', 'protocol', 'username',
+ 'domain', 'is_active', 'date_created', 'date_updated',
+ 'created_by', 'comment',
+ ]
+
+
+class GatewayWithAuthSerializer(GatewaySerializer):
+ def get_field_names(self, declared_fields, info):
+ fields = super().get_field_names(declared_fields, info)
+ fields.extend(
+ ['password', 'private_key']
+ )
+ return fields
+
+
+class DomainWithGatewaySerializer(serializers.ModelSerializer):
+ gateways = GatewayWithAuthSerializer(many=True, read_only=True)
+
+ class Meta:
+ model = Domain
+ fields = '__all__'
diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py
index 0cf5cbfd8..50a57a806 100644
--- a/apps/assets/tasks.py
+++ b/apps/assets/tasks.py
@@ -3,6 +3,7 @@ import json
import re
import os
+import paramiko
from celery import shared_task
from django.core.cache import cache
from django.utils.translation import ugettext as _
@@ -12,7 +13,7 @@ from common.utils import get_object_or_none, capacity_convert, \
from common.celery import register_as_period_task, after_app_shutdown_clean, \
after_app_ready_start, app as celery_app
-from .models import SystemUser, AdminUser, Asset, Cluster
+from .models import SystemUser, AdminUser, Asset
from . import const
@@ -438,3 +439,7 @@ def push_node_system_users_to_asset(node, assets):
# def push_system_user_period():
# for system_user in SystemUser.objects.all():
# push_system_user_related_nodes(system_user)
+
+
+
+
diff --git a/apps/assets/templates/assets/asset_create.html b/apps/assets/templates/assets/asset_create.html
index 1eae7ebd4..7f01e0530 100644
--- a/apps/assets/templates/assets/asset_create.html
+++ b/apps/assets/templates/assets/asset_create.html
@@ -19,6 +19,7 @@
{% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %}
+ {% bootstrap_field form.domain layout="horizontal" %}
{% trans 'Auth' %}
diff --git a/apps/assets/templates/assets/asset_update.html b/apps/assets/templates/assets/asset_update.html
index 5d8006451..3e96438bc 100644
--- a/apps/assets/templates/assets/asset_update.html
+++ b/apps/assets/templates/assets/asset_update.html
@@ -24,6 +24,7 @@
{% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %}
+ {% bootstrap_field form.domain layout="horizontal" %}
{% trans 'Auth' %}
diff --git a/apps/assets/templates/assets/domain_create_update.html b/apps/assets/templates/assets/domain_create_update.html
new file mode 100644
index 000000000..36ca40fc1
--- /dev/null
+++ b/apps/assets/templates/assets/domain_create_update.html
@@ -0,0 +1,31 @@
+{% extends '_base_create_update.html' %}
+{% load static %}
+{% load bootstrap3 %}
+{% load i18n %}
+
+{% block form %}
+
+{% endblock %}
+
+{% block custom_foot_js %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/domain_detail.html b/apps/assets/templates/assets/domain_detail.html
new file mode 100644
index 000000000..e60daa334
--- /dev/null
+++ b/apps/assets/templates/assets/domain_detail.html
@@ -0,0 +1,132 @@
+{% extends 'base.html' %}
+{% load static %}
+{% load i18n %}
+
+{% block custom_head_css_js %}
+
+
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans 'Name' %}: |
+ {{ object.name }} |
+
+
+ {% trans 'Asset' %}: |
+ {{ object.assets.count }} |
+
+
+ {% trans 'Gateway' %}: |
+ {{ object.gateway_set.count }} |
+
+
+ {% trans 'Date created' %}: |
+ {{ object.date_created }} |
+
+
+ {% trans 'Created by' %}: |
+ {{ object.created_by }} |
+
+
+ {% trans 'Comment' %}: |
+ {{ object.comment }} |
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+{% block content_bottom_left %}{% endblock %}
+{% block custom_foot_js %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html
new file mode 100644
index 000000000..1f25e6ac1
--- /dev/null
+++ b/apps/assets/templates/assets/domain_gateway_list.html
@@ -0,0 +1,131 @@
+{% extends 'base.html' %}
+{% load static %}
+{% load i18n %}
+
+{% block custom_head_css_js %}
+
+
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+
+
{% trans 'Gateway list' %}
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+{% block content_bottom_left %}{% endblock %}
+{% block custom_foot_js %}
+
+{% endblock %}
diff --git a/apps/assets/templates/assets/domain_list.html b/apps/assets/templates/assets/domain_list.html
new file mode 100644
index 000000000..03b671bf3
--- /dev/null
+++ b/apps/assets/templates/assets/domain_list.html
@@ -0,0 +1,70 @@
+{% extends '_base_list.html' %}
+{% load i18n static %}
+{% block table_search %}{% endblock %}
+{% block table_container %}
+
+
+{% endblock %}
+{% block content_bottom_left %}{% endblock %}
+{% block custom_foot_js %}
+
+{% endblock %}
+
+
+
diff --git a/apps/assets/templates/assets/gateway_create_update.html b/apps/assets/templates/assets/gateway_create_update.html
new file mode 100644
index 000000000..7d6800c41
--- /dev/null
+++ b/apps/assets/templates/assets/gateway_create_update.html
@@ -0,0 +1,68 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% load static %}
+{% load bootstrap3 %}
+{% block custom_head_css_js %}
+
+
+{% endblock %}
+
+{% block content %}
+
+{% endblock %}
diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html
index 28d792bd2..b74b402cf 100644
--- a/apps/assets/templates/assets/system_user_detail.html
+++ b/apps/assets/templates/assets/system_user_detail.html
@@ -206,7 +206,7 @@
{% endblock %}
{% block custom_foot_js %}