class BaseHost(models.Model): name = models.CharField(max_length=256) ip = models.GenericIPAddressField(null=True) port = models.IntegerField(default=22) username = models.CharField(max_length=256, default='root') password = common_models.EncryptCharField(max_length=4096, blank=True, null=True) private_key = common_models.EncryptCharField(max_length=8192, blank=True, null=True) vars = common_models.JsonDictTextField(default={}) meta = common_models.JsonDictTextField(default={}) comment = models.TextField(blank=True) class Meta: abstract = True @property def ansible_vars(self): host_vars = {k: v for k, v in self.vars.items()} host_vars['ansible_ssh_host'] = self.ip host_vars['ansible_ssh_port'] = self.port host_vars['ansible_ssh_user'] = self.username host_vars['ansible_ssh_pass'] = self.password host_vars['ansible_ssh_private_key_file'] = self.private_key_path return host_vars @property def private_key_obj(self): return ssh_key_string_to_obj(self.private_key, self.password) @property def private_key_path(self): if not self.private_key_obj: return None tmp_dir = os.path.join(settings.BASE_DIR, 'data', 'tmp') if not os.path.isdir(tmp_dir): os.makedirs(tmp_dir) key_name = '.' + md5(self.private_key.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 def add_to_groups(self, group_names, auto_create=True): with transaction.atomic(): for name in group_names: group = self.groups.model.get_group(name=name, auto_create=auto_create) group.hosts.add(self) def set_groups(self, group_names, auto_create=True): with transaction.atomic(): groups = [] for name in group_names: group = self.groups.model.get_group(name=name, auto_create=auto_create) groups.append(group) self.groups.set(groups)
class BaseHost(models.Model): name = models.CharField(max_length=1024, validators=[name_validator]) ip = models.GenericIPAddressField(null=True) port = models.IntegerField(default=22) username = models.CharField(max_length=1024, default='root') password = common_models.EncryptCharField(max_length=4096, blank=True, null=True) private_key = common_models.EncryptCharField(max_length=8192, blank=True, null=True) vars = common_models.JsonDictTextField(default={}) meta = common_models.JsonDictTextField(default={}) comment = models.TextField(blank=True) class Meta: abstract = True @property def ansible_vars(self): host_vars = {k: v for k, v in self.vars.items()} host_vars['ansible_ssh_host'] = self.ip host_vars['ansible_ssh_port'] = self.port host_vars['ansible_ssh_user'] = self.username host_vars['ansible_ssh_pass'] = self.password return host_vars def add_to_groups(self, group_names, auto_create=True): with transaction.atomic(): for name in group_names: group = self.groups.model.get_group(name=name, auto_create=auto_create) group.hosts.add(self) def set_groups(self, group_names, auto_create=True): with transaction.atomic(): groups = [] for name in group_names: group = self.groups.model.get_group(name=name, auto_create=auto_create) groups.append(group) self.groups.set(groups)
class Credential(models.Model): CREDENTIAL_TYPE_PASSWORD = "******" CREDENTIAL_TYPE_PRIVATE_KEY = "privateKey" CREDENTIAL_TYPE_CHOICES = ((CREDENTIAL_TYPE_PASSWORD, "password"), (CREDENTIAL_TYPE_PRIVATE_KEY, "privateKey")) id = models.UUIDField(default=uuid.uuid4, primary_key=True) name = models.SlugField(max_length=128, allow_unicode=True, unique=True, verbose_name=_('Name')) username = models.CharField(max_length=256, default='root') password = common_models.EncryptCharField(max_length=4096, blank=True, null=True) private_key = common_models.EncryptCharField(max_length=8192, blank=True, null=True) type = models.CharField(max_length=128, choices=CREDENTIAL_TYPE_CHOICES, default=CREDENTIAL_TYPE_PASSWORD) date_created = models.DateTimeField(auto_now_add=True)
class Credential(models.Model): CREDENTIAL_TYPE_PASSWORD = "******" CREDENTIAL_TYPE_PRIVATE_KEY = "privateKey" CREDENTIAL_TYPE_CHOICES = ((CREDENTIAL_TYPE_PASSWORD, "password"), (CREDENTIAL_TYPE_PRIVATE_KEY, "privateKey")) id = models.UUIDField(default=uuid.uuid4, primary_key=True) name = models.SlugField(max_length=128, allow_unicode=True, unique=True, verbose_name=_('Name')) username = models.CharField(max_length=256, default='root') password = common_models.EncryptCharField(max_length=4096, blank=True, null=True) private_key = common_models.EncryptCharField(max_length=8192, blank=True, null=True) type = models.CharField(max_length=128, choices=CREDENTIAL_TYPE_CHOICES, default=CREDENTIAL_TYPE_PASSWORD) date_created = models.DateTimeField(auto_now_add=True) @property def private_key_obj(self): return ssh_key_string_to_obj(self.private_key, self.password) @property def private_key_path(self): if not self.type == 'privateKey': return None tmp_dir = os.path.join(settings.BASE_DIR, 'data', 'tmp') if not os.path.isdir(tmp_dir): os.makedirs(tmp_dir) key_name = '.' + md5(self.private_key.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
class Host(BaseHost): HOST_STATUS_RUNNING = "RUNNING" HOST_STATUS_CREATING = "CREATING" HOST_STATUS_UNKNOWN = "UNKNOWN" DEPLOY_TEMPLATE_CHOICES = ( (HOST_STATUS_RUNNING, 'running'), (HOST_STATUS_CREATING, 'creating'), (HOST_STATUS_UNKNOWN, "unknown") ) id = models.UUIDField(primary_key=True, default=uuid.uuid4) node = models.ForeignKey('Node', default=None, null=True, related_name='node',on_delete=models.SET_NULL) name = models.CharField(max_length=128, validators=[name_validator], unique=True) credential = models.ForeignKey("kubeops_api.Credential", null=True, on_delete=models.SET_NULL) memory = models.fields.BigIntegerField(default=0) os = models.fields.CharField(max_length=128, default="") os_version = models.fields.CharField(max_length=128, default="") cpu_core = models.fields.IntegerField(default=0) volumes = models.ManyToManyField('Volume') zone = models.ForeignKey('cloud_provider.Zone', null=True, on_delete=models.CASCADE) status = models.CharField(choices=DEPLOY_TEMPLATE_CHOICES, default=HOST_STATUS_UNKNOWN, max_length=128) username = models.CharField(max_length=256, default=NODE_CREDENTIAL['username']) password = common_models.EncryptCharField(max_length=4096, blank=True, null=True, default=NODE_CREDENTIAL['password']) auto_gather_info = models.BooleanField(default=True, null=True) def full_host_credential(self): if self.credential: self.username = self.credential.username if self.credential.type == Credential.CREDENTIAL_TYPE_PASSWORD: self.password = self.credential.password else: self.private_key = self.credential.private_key self.save() @property def cluster(self): if self.node: return self.node.project.name @property def region(self): if self.zone: return self.zone.region.name def delete(self, using=None, keep_parents=False): if self.zone: self.zone.recover_ip(self.ip) super().delete(using=None, keep_parents=False) def gather_info(self, retry=1): try: facts = gather_host_info(self.ip, self.username, self.password, retry) except Exception as e: self.status = Host.HOST_STATUS_RUNNING raise e self.memory = facts["ansible_memtotal_mb"] cpu_cores = facts["ansible_processor_cores"] cpu_count = facts["ansible_processor_count"] self.cpu_core = int(cpu_cores) * int(cpu_count) self.os = facts["ansible_distribution"] self.os_version = facts["ansible_distribution_version"] self.save() devices = facts["ansible_devices"] volumes = [] for name in devices: if not name.startswith(('dm', 'loop', 'sr')): volume = Volume(name='/dev/' + name) volume.size = devices[name]['size'] volume.save() volumes.append(volume) self.volumes.set(volumes) self.status = Host.HOST_STATUS_RUNNING self.save() class Meta: ordering = ('name',)
class Host(BaseHost): HOST_STATUS_RUNNING = "RUNNING" HOST_STATUS_CREATING = "CREATING" HOST_STATUS_UNKNOWN = "UNKNOWN" DEPLOY_TEMPLATE_CHOICES = ((HOST_STATUS_RUNNING, 'running'), (HOST_STATUS_CREATING, 'creating'), (HOST_STATUS_UNKNOWN, "unknown")) id = models.UUIDField(primary_key=True, default=uuid.uuid4) node = models.ForeignKey('Node', default=None, null=True, related_name='node', on_delete=models.SET_NULL) name = models.CharField(max_length=128, validators=[name_validator], unique=True) credential = models.ForeignKey("kubeops_api.Credential", null=True, on_delete=models.SET_NULL) memory = models.fields.BigIntegerField(default=0) os = models.fields.CharField(max_length=128, default="") os_version = models.fields.CharField(max_length=128, default="") cpu_core = models.fields.IntegerField(default=0) volumes = models.ManyToManyField('Volume') gpus = models.ManyToManyField('GPU') zone = models.ForeignKey('cloud_provider.Zone', null=True, on_delete=models.CASCADE) status = models.CharField(choices=DEPLOY_TEMPLATE_CHOICES, default=HOST_STATUS_UNKNOWN, max_length=128) username = models.CharField(max_length=256, default=NODE_CREDENTIAL['username']) password = common_models.EncryptCharField( max_length=4096, blank=True, null=True, default=NODE_CREDENTIAL['password']) auto_gather_info = models.BooleanField(default=True, null=True) conditions = models.ManyToManyField("Condition") gpu = models.BooleanField(default=False) gpu_info = models.CharField(default="", max_length=128) gpu_num = models.IntegerField(default=0) def full_host_credential(self): if self.credential: self.username = self.credential.username if self.credential.type == Credential.CREDENTIAL_TYPE_PASSWORD: self.password = self.credential.password else: self.private_key = self.credential.private_key self.save() @property def cluster(self): if self.node: return self.node.project.name @property def has_gpu(self): gpus = self.gpus.all() if gpus and len(gpus) > 0: return True else: return False @property def region(self): if self.zone: return self.zone.region.name def delete(self, using=None, keep_parents=False): if self.zone: self.zone.recover_ip(self.ip) super().delete(using=None, keep_parents=False) def to_ssh_config(self): return SshConfig(self.ip, self.port, self.username, self.password, 10) def health_check(self): from kubeops_api.models.health.host_health import HostHealthCheck health_check = HostHealthCheck(host=self) health_check.run() def gather_gpu_info(self): msg = get_gpu_device(self.to_ssh_config()) gpus = [] if msg: host_gpus = str(msg).split('\n') for hg in host_gpus: g = GPU() g.name = hg[hg.index("[") + 1:hg.index("]")] g.save() gpus.append(g) self.gpus.set(gpus) self.save() def gather_info(self, retry=1): try: logger.info("host: {} gather host info ".format(self.name)) facts = gather_host_info(ip=self.ip, port=self.port, username=self.username, retry=retry, password=self.password, private_key_path=self.private_key_path) self.memory = facts["ansible_memtotal_mb"] cpu_cores = facts["ansible_processor_cores"] cpu_count = facts["ansible_processor_count"] vcpus = facts.get("ansible_processor_vcpus", None) if vcpus: self.cpu_core = int(vcpus) else: self.cpu_core = int(cpu_cores) * int(cpu_count) self.os = facts["ansible_distribution"] self.os_version = facts["ansible_distribution_version"] self.save() devices = facts["ansible_devices"] volumes = [] for name in devices: if not name.startswith(('dm', 'loop', 'sr')): volume = Volume(name='/dev/' + name) volume.size = devices[name]['size'] volume.save() volumes.append(volume) self.volumes.set(volumes) self.status = Host.HOST_STATUS_RUNNING self.gather_gpu_info() self.save() except Exception as e: self.status = Host.HOST_STATUS_UNKNOWN self.cpu_core = 0 self.memory = 0 self.os = "未知" self.volumes.set([]) self.os_version = "" self.save() logger.error("host: {} gather host info".format(self.name), exc_info=True) class Meta: ordering = ('name', )