Source code for libioc.Host

# Copyright (c) 2017-2019, Stefan Grönke
# Copyright (c) 2014-2018, iocage
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted providing that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""ioc Host module."""
import typing
import os
import platform
import re
import freebsd_sysctl

import libzfs

import libioc.Datasets
import libioc.DevfsRules
import libioc.Distribution
import libioc.Resource
import libioc.helpers
import libioc.helpers_object

# MyPy
import libioc.Config.Jail.BaseConfig  # noqa: F401
import libioc.DevfsRules
_distribution_types = typing.Union[
    libioc.Distribution.DistributionGenerator,
    libioc.Distribution.Distribution,
]


[docs]class HostGenerator: """Asynchronous representation of the jail host.""" _class_distribution = libioc.Distribution.DistributionGenerator _devfs: libioc.DevfsRules.DevfsRules _defaults: libioc.Resource.DefaultResource __user_provided_defaults: typing.Optional[libioc.Resource.DefaultResource] __hostid: str releases_dataset: libzfs.ZFSDataset datasets: libioc.Datasets.Datasets distribution: _distribution_types __branch_pattern = re.compile( r"""\(hardened/ (?P<release>[A-z0-9]+(?:[A-z0-9\-]+[A-z0-9])) / (?P<branch>[A-z0-9]+) \):""", re.X ) __release_name_pattern = re.compile( r"^(?P<major>\d+)(?:\.(?P<minor>\d+))-(?P<type>[A-Z]+)-HBSD$", re.X ) def __init__( self, defaults: typing.Optional[libioc.Resource.DefaultResource]=None, datasets: typing.Optional[libioc.Datasets.Datasets]=None, zfs: typing.Optional['libioc.ZFS.ZFS']=None, logger: typing.Optional['libioc.Logger.Logger']=None ) -> None: self.logger = libioc.helpers_object.init_logger(self, logger) self.zfs = libioc.helpers_object.init_zfs(self, zfs) if datasets is not None: self.datasets = datasets else: self.datasets = libioc.Datasets.Datasets( logger=self.logger, zfs=self.zfs ) self.distribution = self._class_distribution( host=self, logger=self.logger, zfs=self.zfs ) # this variable stores user provided defaults until the property # was initialized and accessed the first time self.__user_provided_defaults = defaults def __init_defaults(self) -> None: defaults = self.__user_provided_defaults if defaults is not None: self._defaults = defaults else: self._defaults = libioc.Resource.DefaultResource( dataset=self.datasets.main.root, logger=self.logger, zfs=self.zfs ) self.__user_provided_defaults = None self._defaults.read_config() @property def id(self) -> str: """Return the hostid and memoize on first lookup.""" try: return self.__hostid except AttributeError: pass with open("/etc/hostid", "r", encoding="utf-8") as f: self.__hostid = f.read().strip() return self.__hostid @property def defaults(self) -> 'libioc.Resource.DefaultResource': """Return the lazy-loaded defaults.""" try: return self._defaults except AttributeError: pass self.__init_defaults() return self._defaults @property def default_config( self ) -> 'libioc.Config.Jail.BaseConfig.BaseConfig': """Return the lazy-loaded default configuration.""" return self.defaults.config @property def devfs(self) -> 'libioc.DevfsRules.DevfsRules': """Return the lazy-loaded DevfsRules instance.""" if "_devfs" not in dir(self): self._devfs = libioc.DevfsRules.DevfsRules( logger=self.logger ) return self._devfs @property def userland_version(self) -> float: """Return the host userland version number.""" return float(libioc.helpers.get_os_version()["userland"]) @property def release_version(self) -> str: """Return the host release version.""" if self.distribution.name == "FreeBSD": release_version_string = os.uname()[2] release_version_fragments = release_version_string.split("-") if len(release_version_fragments) > 1: return "-".join(release_version_fragments[0:2]) elif self.distribution.name == "HardenedBSD": match = re.search(self.__branch_pattern, os.uname()[3]) if match is not None: return match["release"].upper() match = re.search(self.__release_name_pattern, os.uname()[2]) if match is not None: return f"{match['major']}-{match['type']}" raise libioc.errors.HostReleaseUnknown() @property def processor(self) -> str: """Return the hosts processor architecture.""" return platform.processor() @property def ipfw_enabled(self) -> bool: """Return True if ipfw is enabled on the host system.""" try: firewall_enabled = freebsd_sysctl.Sysctl("net.inet.ip.fw.enable") return (firewall_enabled.value == 1) is True except Exception: return False
[docs]class Host(HostGenerator): """Synchronous wrapper of HostGenerator.""" _class_distribution = libioc.Distribution.Distribution