from django.db import models from django.utils.translation import gettext_lazy as _ from common.db.models import IncludesTextChoicesMeta, ChoicesMixin from common.tree import TreeNode __all__ = [ 'Category', 'HostTypes', 'NetworkingTypes', 'DatabaseTypes', 'WebTypes', 'CloudTypes', 'Protocol', 'AllTypes', ] class PlatformMixin: @classmethod def platform_constraints(cls): return { 'has_domain': False, 'has_su': False, 'has_ping': False, 'has_change_password': False, 'has_verify_account': False, 'has_create_account': False, '_protocols': [] } class Category(PlatformMixin, ChoicesMixin, models.TextChoices): HOST = 'host', _('Host') NETWORKING = 'networking', _("NetworkDevice") DATABASE = 'database', _("Database") CLOUD = 'cloud', _("Clouding") WEB = 'web', _("Web") @classmethod def platform_constraints(cls) -> dict: return { cls.HOST: { 'has_domain': True, 'has_ping': True, 'has_verify_account': True, 'has_change_password': True, 'has_create_account': True, '_protocols': ['ssh', 'telnet'] }, cls.NETWORKING: { 'has_domain': True, '_protocols': ['ssh', 'telnet'] }, cls.DATABASE: { 'has_domain': True, }, cls.WEB: { 'has_domain': False, '_protocols': [] }, cls.CLOUD: { 'has_domain': False, '_protocols': [] } } class HostTypes(PlatformMixin, ChoicesMixin, models.TextChoices): LINUX = 'linux', 'Linux' WINDOWS = 'windows', 'Windows' UNIX = 'unix', 'Unix' BSD = 'bsd', 'BSD' MACOS = 'macos', 'MacOS' MAINFRAME = 'mainframe', _("Mainframe") OTHER_HOST = 'other_host', _("Other host") @classmethod def platform_constraints(cls): return { cls.LINUX: { '_protocols': ['ssh', 'rdp', 'vnc', 'telnet'] }, cls.WINDOWS: { '_protocols': ['ssh', 'rdp', 'vnc'], 'has_su': False }, cls.MACOS: { '_protocols': ['ssh', 'vnc'] } } class NetworkingTypes(PlatformMixin, ChoicesMixin, models.TextChoices): SWITCH = 'switch', _("Switch") ROUTER = 'router', _("Router") FIREWALL = 'firewall', _("Firewall") OTHER_NETWORK = 'other_network', _("Other device") class DatabaseTypes(PlatformMixin, ChoicesMixin, models.TextChoices): MYSQL = 'mysql', 'MySQL' MARIADB = 'mariadb', 'MariaDB' POSTGRESQL = 'postgresql', 'PostgreSQL' ORACLE = 'oracle', 'Oracle' SQLSERVER = 'sqlserver', 'SQLServer' MONGODB = 'mongodb', 'MongoDB' REDIS = 'redis', 'Redis' @classmethod def platform_constraints(cls): meta = {} for name, label in cls.choices: meta[name] = { 'protocols': [name] } return meta class WebTypes(PlatformMixin, ChoicesMixin, models.TextChoices): General = 'general', 'General' class CloudTypes(PlatformMixin, ChoicesMixin, models.TextChoices): K8S = 'k8s', 'Kubernetes' class AllTypes(ChoicesMixin, metaclass=IncludesTextChoicesMeta): choices: list includes = [ HostTypes, NetworkingTypes, DatabaseTypes, WebTypes, CloudTypes ] @classmethod def get_constraints(cls, category, tp): constraints = PlatformMixin.platform_constraints() category_constraints = Category.platform_constraints().get(category) or {} constraints.update(category_constraints) types_cls = dict(cls.category_types()).get(category) if not types_cls: return constraints type_constraints = types_cls.platform_constraints().get(tp) or {} constraints.update(type_constraints) _protocols = constraints.pop('_protocols', []) default_ports = Protocol.default_ports() protocols = [] for p in _protocols: port = default_ports.get(p, 0) protocols.append({'name': p, 'port': port}) constraints['protocols'] = protocols return constraints @classmethod def category_types(cls): return ( (Category.HOST, HostTypes), (Category.NETWORKING, NetworkingTypes), (Category.DATABASE, DatabaseTypes), (Category.WEB, WebTypes), (Category.CLOUD, CloudTypes) ) @classmethod def grouped_choices(cls): grouped_types = [(str(ca), tp.choices) for ca, tp in cls.category_types()] return grouped_types @classmethod def grouped_choices_to_objs(cls): choices = cls.serialize_to_objs(Category.choices) mapper = dict(cls.grouped_choices()) for choice in choices: children = cls.serialize_to_objs(mapper[choice['value']]) choice['children'] = children return choices @staticmethod def serialize_to_objs(choices): title = ['value', 'display_name'] return [dict(zip(title, choice)) for choice in choices] @staticmethod def choice_to_node(choice, pid, opened=True, is_parent=True, meta=None): node = TreeNode(**{ 'id': choice.name, 'name': choice.label, 'title': choice.label, 'pId': pid, 'open': opened, 'isParent': is_parent, }) if meta: node.meta = meta return node @classmethod def to_tree_nodes(cls): root = TreeNode(id='ROOT', name='类型节点', title='类型节点') nodes = [root] for category, types in cls.category_types(): category_node = cls.choice_to_node(category, 'ROOT', meta={'type': 'category'}) nodes.append(category_node) for tp in types: tp_node = cls.choice_to_node(tp, category_node.id, meta={'type': 'type'}) nodes.append(tp_node) return nodes class Protocol(ChoicesMixin, models.TextChoices): ssh = 'ssh', 'SSH' rdp = 'rdp', 'RDP' telnet = 'telnet', 'Telnet' vnc = 'vnc', 'VNC' mysql = 'mysql', 'MySQL' mariadb = 'mariadb', 'MariaDB' oracle = 'oracle', 'Oracle' postgresql = 'postgresql', 'PostgreSQL' sqlserver = 'sqlserver', 'SQLServer' redis = 'redis', 'Redis' mongodb = 'mongodb', 'MongoDB' k8s = 'k8s', 'K8S' http = 'http', 'HTTP' https = 'https', 'HTTPS' @classmethod def host_protocols(cls): return [cls.ssh, cls.rdp, cls.telnet, cls.vnc] @classmethod def db_protocols(cls): return [ cls.mysql, cls.mariadb, cls.postgresql, cls.oracle, cls.sqlserver, cls.redis, cls.mongodb, ] @classmethod def default_ports(cls): return { cls.ssh: 22, cls.rdp: 3389, cls.vnc: 5900, cls.telnet: 21, cls.mysql: 3306, cls.mariadb: 3306, cls.postgresql: 5432, cls.oracle: 1521, cls.sqlserver: 1433, cls.mongodb: 27017, cls.redis: 6379, cls.k8s: 0, cls.http: 80, cls.https: 443 }