1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
# This file is part of cloud-init. See LICENSE file for license information.
from typing import Optional, Type
from unittest import mock
from cloudinit import cloud, distros, helpers
from cloudinit.config import Config
from cloudinit.net.dhcp import IscDhclient
from cloudinit.sources import DataSource, DataSourceHostname
from cloudinit.sources.DataSourceNone import DataSourceNone
class DataSourceTesting(DataSourceNone):
def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False):
return DataSourceHostname("hostname", False)
def persist_instance_data(self):
return True
@property
def cloud_name(self):
return "testing"
def get_cloud(
distro: Optional[str] = None,
paths: Optional[helpers.Paths] = None,
sys_cfg: Optional[Config] = None,
metadata=None,
mocked_distro=False,
ds: Type[DataSource] = DataSourceTesting,
):
"""Obtain a "cloud" that can be used for testing.
Modules take a 'cloud' parameter to call into things that are
datasource/distro specific. In most cases, the specifics of this cloud
implementation aren't needed to test the module, so provide a fake
datasource/distro with stubbed calls to methods that may attempt to
read/write files or shell out. If a specific distro is needed, it can
be passed in as the distro parameter.
"""
paths = paths or helpers.Paths({})
sys_cfg = sys_cfg or {}
if distro:
distro_cls: Type[distros.Distro] = distros.fetch(distro)
else:
distro = "testingdistro"
distro_cls = MockDistro
# *BSD calls platform.system to determine osfamilies
osfamily = distro.lower() if distro else "ubuntu"
with mock.patch("platform.system", return_value=osfamily):
mydist = distro_cls(distro, sys_cfg, paths)
if mocked_distro:
mydist = mock.MagicMock(wraps=mydist)
myds = ds(sys_cfg, mydist, paths)
if metadata:
myds.metadata.update(metadata)
if paths:
paths.datasource = myds
return cloud.Cloud(
myds, paths, sys_cfg, mydist, runners=helpers.Runners(paths)
)
def abstract_to_concrete(abclass):
"""Takes an abstract class and returns a concrete version of it."""
class concreteCls(abclass):
pass
concreteCls.__abstractmethods__ = frozenset()
return type("DummyConcrete" + abclass.__name__, (concreteCls,), {})
class MockDistro(distros.Distro):
fallback_interface = "eth9"
# MockDistro is here to test base Distro class implementations
def __init__(self, name="testingdistro", cfg=None, paths=None):
self._client = None
if not cfg:
cfg = {}
if not paths:
paths = {}
super(MockDistro, self).__init__(name, cfg, paths)
@property
def dhcp_client(self):
if not self._client:
with mock.patch(
"cloudinit.net.dhcp.subp.which", return_value=True
):
self._client = IscDhclient()
return self._client
def install_packages(self, pkglist):
pass
def set_hostname(self, hostname, fqdn=None):
pass
@staticmethod
def uses_systemd():
return True
@staticmethod
def get_proc_ppid(_):
return 1
@staticmethod
def get_proc_pgid(_):
return 99999
def get_primary_arch(self):
return "i386"
def get_package_mirror_info(self, arch=None, data_source=None):
pass
def generate_fallback_config(self):
return {}
def apply_network_config(self, netconfig, bring_up=False) -> bool:
return False
def apply_locale(self, locale, out_fn=None):
pass
def set_timezone(self, tz):
pass
def _read_hostname(self, filename, default=None):
raise NotImplementedError()
def _write_hostname(self, hostname, filename):
raise NotImplementedError()
def _read_system_hostname(self):
raise NotImplementedError()
def update_hostname(self, hostname, fqdn, prev_hostname_fn):
pass
def update_etc_hosts(self, hostname, fqdn):
pass
def add_user(self, name, **kwargs):
pass
def add_snap_user(self, name, **kwargs):
return "snap_user"
def create_user(self, name, **kwargs):
return True
def lock_passwd(self, name):
pass
def expire_passwd(self, user):
pass
def set_passwd(self, user, passwd, hashed=False):
return True
def ensure_sudo_dir(self, path, sudo_base="/etc/sudoers"):
pass
def write_sudo_rules(self, user, rules, sudo_file=None):
pass
def create_group(self, name, members=None):
pass
def shutdown_command(self, *, mode, delay, message):
pass
def package_command(self, command, args=None, pkgs=None):
pass
def update_package_sources(self, *, force=False):
return (True, "yay")
def do_as(self, command, args=None, **kwargs):
return ("stdout", "stderr")
TEST_INSTANCE_ID = "i-testing"
class FakeDataSource(DataSource):
def __init__(
self,
userdata=None,
vendordata=None,
vendordata2=None,
network_config="",
paths=None,
):
DataSource.__init__(self, {}, None, paths=paths)
self.metadata = {"instance-id": TEST_INSTANCE_ID}
self.userdata_raw = userdata
self.vendordata_raw = vendordata
self.vendordata2_raw = vendordata2
self._network_config = None
if network_config: # Permit for None value to setup attribute
self._network_config = network_config
@property
def network_config(self):
return self._network_config
def _get_data(self):
return True
|