def test_spicerack_dhcp(): """Test spicerack.dhcp. It should succeed if a host list with more than one member is passed.""" mock_hosts = mock.MagicMock() mock_hosts.__len__.return_value = 1 spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) assert isinstance(spicerack.dhcp(mock_hosts), DHCP)
def test_run_cookbook_no_callback(): """It should raise a SpicerackError if there is no get_cookbook_callback defined.""" spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) with pytest.raises( SpicerackError, match= "Unable to run other cookbooks, get_cookbook_callback is not set." ): spicerack.run_cookbook("class_api.example", [])
def test_reposync(mocked_repo, mocked_is_dir): """Test spicerack.reposync.""" spicerack = Spicerack(**SPICERACK_TEST_PARAMS) repo = mock.MagicMock(spec_set=Repo) repo.bare = False with pytest.raises(SpicerackError, match="Unknown repo missing_repo"): spicerack.reposync("missing_repo") mocked_is_dir.return_value = False with pytest.raises( SpicerackError, match=r"The repo directory \(/testrepo\) does not exist"): spicerack.reposync("testrepo") mocked_is_dir.return_value = True mocked_repo.return_value = repo with pytest.raises( SpicerackError, match= r"The repo directory \(/testrepo\) is not a bare git repository"): spicerack.reposync("testrepo") repo.bare = True assert isinstance(spicerack.reposync("testrepo"), RepoSync)
def test_spicerack_management_password_instances(monkeypatch): """Should instantiate the instances that require the management password.""" monkeypatch.setenv("MGMT_PASSWORD", "env_password") spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) assert spicerack.management_password == "env_password" assert isinstance(spicerack.ipmi("test-mgmt.example.com"), Ipmi) assert isinstance(spicerack.redfish("test-mgmt.example.com", "root"), RedfishDell) assert isinstance( spicerack.redfish("test-mgmt.example.com", "root", "other_password"), RedfishDell)
def test_spicerack_puppet_master(mocked_remote_query, mocked_get_puppet_ca_hostname): """An instance of Spicerack should allow to get a PuppetMaster instance.""" host = mock.MagicMock(spec_set=RemoteHosts) host.__len__.return_value = 1 mocked_remote_query.return_value = host spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) assert isinstance(spicerack.puppet_master(), PuppetMaster) mocked_get_puppet_ca_hostname.assert_called_once_with() assert mocked_remote_query.called
def test_spicerack_management_password_cached(monkeypatch): """Should ask for the management_password only once and cache its result.""" monkeypatch.setenv("MGMT_PASSWORD", "first_password") spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) assert spicerack.management_password == "first_password" monkeypatch.setenv("MGMT_PASSWORD", "second_password") assert spicerack.management_password == "first_password"
def test_spicerack_icinga(mocked_command_file, mocked_remote_query, mocked_dns, mocked_hostname, monkeypatch): """An instance of Spicerack should allow to get an Icinga and IcingaHosts instances.""" monkeypatch.setenv("SUDO_USER", "user1") icinga_server = mock.MagicMock(spec_set=RemoteHosts) icinga_server.hosts = "icinga-server.example.com" icinga_server.__len__.return_value = 1 mocked_remote_query.return_value = icinga_server mocked_dns.return_value.resolve_cname.return_value = "icinga-server.example.com" mocked_command_file.return_value = "/var/lib/icinga/rw/icinga.cmd" spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) assert spicerack.icinga_master_host.hosts == "icinga-server.example.com" assert isinstance(spicerack.icinga_hosts(["host1", "host2"]), IcingaHosts) mocked_hostname.assert_called_once_with()
def __init__(self, args: Namespace, spicerack: Spicerack) -> None: """Initialize the runner.""" if args.batchsize > self.depool_threshold: raise ValueError( f"batchsize (args.batchsize) can't be greater then the depool_threshold {self.depool_threshold}" ) # TODO: check currently depooled hosts + batchsize is less then depool_threshold self._confctl = spicerack.confctl('node') super().__init__(args, spicerack)
def test_spicerack_netbox(mocked_pynetbox, mocked_remote_query, mocked_dns, read_write, token): """Test instantiating Netbox abstraction.""" netbox_server = mock.MagicMock(spec_set=RemoteHosts) netbox_server.hosts = "netbox-server.example.com" mocked_remote_query.return_value = netbox_server mocked_dns.return_value.resolve_cname.return_value = "netbox-server.example.com" mocked_pynetbox.reset_mock() spicerack = Spicerack(verbose=True, dry_run=False, **SPICERACK_TEST_PARAMS) assert isinstance(spicerack.netbox(read_write=read_write), Netbox) # Values from fixtures/netbox/config.yaml mocked_pynetbox.assert_called_once_with("https://netbox.example.com", token=token) assert spicerack.netbox_master_host.hosts == "netbox-server.example.com" mocked_pynetbox.reset_mock() mocked_pynetbox.return_value.dcim.devices.get.return_value.device_role.slug = "server" assert isinstance(spicerack.netbox_server("host1"), NetboxServer)
def __init__(self, args: Namespace, spicerack: Spicerack) -> None: """Initialize the runner.""" ensure_shell_is_durable() if args.alias and args.alias not in self.allowed_aliases: raise ValueError( f"Alias ({args.alias}) does not match allowed aliases: " + ', '.join(self.allowed_aliases)) self._args = args self.query = self._query() self.hosts = spicerack.remote().query(self.query) if not self.hosts: raise ValueError(f'Cumin query ({self.query}) matched zero hosts') self.number_of_batches = ceil(len(self.hosts.hosts) / args.batchsize) self.results = Results(action=args.action, hosts=self.hosts.hosts) reason = f'{args.action} {self.hosts.hosts}: {args.reason}' self.reason = spicerack.admin_reason(reason, args.task_id) self._spicerack = spicerack self.logger = getLogger('.'.join( (self.__module__, self.__class__.__name__)))
def main(argv: Optional[Sequence[str]] = None) -> Optional[int]: """Entry point, run the tool. Arguments: argv (list, optional): the list of command line arguments to parse. Returns: int: the return code, zero on success, non-zero on failure. """ args = argument_parser().parse_args(argv) if not args.cookbook: args.cookbook = "" config = load_yaml_config(args.config_file) cookbooks_base_dir = Path(config["cookbooks_base_dir"]).expanduser() sys.path.append(str(cookbooks_base_dir)) def get_cookbook( spicerack: Spicerack, cookbook_path: str, cookbook_args: Sequence[str] = () ) -> Optional[BaseItem]: """Run a single cookbook. Arguments: argv (sequence, optional): a sequence of strings of command line arguments to parse. Returns: None: on success. int: the return code, zero on success, non-zero on failure. """ cookbooks = CookbookCollection(cookbooks_base_dir, cookbook_args, spicerack, path_filter=cookbook_path) return cookbooks.get_item(cookbook_path) params = config.get("instance_params", {}) params.update({ "verbose": args.verbose, "dry_run": args.dry_run, "get_cookbook_callback": get_cookbook }) try: spicerack = Spicerack(**params) except TypeError as e: print( "Unable to instantiate Spicerack, check your configuration:", e, file=sys.stderr, ) return 1 cookbooks = CookbookCollection(cookbooks_base_dir, args.cookbook_args, spicerack, path_filter=args.cookbook) if args.list: print(cookbooks.menu.get_tree(), end="") return 0 cookbook_item = cookbooks.get_item(args.cookbook) if cookbook_item is None: logger.error("Unable to find cookbook %s", args.cookbook) return cookbook.NOT_FOUND_RETCODE base_path = Path(config["logs_base_dir"]) / cookbook_item.path.replace( ".", os.sep) _log.setup_logging( base_path, cookbook_item.name, spicerack.username, dry_run=args.dry_run, host=config.get("tcpircbot_host", None), port=int(config.get("tcpircbot_port", 0)), ) logger.debug("Executing cookbook %s with args: %s", args.cookbook, args.cookbook_args) return cookbook_item.run()
def test_spicerack_http_proxy(): """An instance of Spicerack by default should not set any HTTP proxy.""" spicerack = Spicerack(**SPICERACK_TEST_PARAMS) assert spicerack.http_proxy == "" assert spicerack.requests_proxies is None
def test_spicerack(mocked_dns_resolver, mocked_remote_query, monkeypatch): """An instance of Spicerack should allow to access all the library features.""" monkeypatch.setenv("SUDO_USER", "user1") verbose = True dry_run = False proxy = "http://proxy.example.com:8080" spicerack = Spicerack(verbose=verbose, dry_run=dry_run, http_proxy=proxy, **SPICERACK_TEST_PARAMS) assert spicerack.verbose is verbose assert spicerack.dry_run is dry_run assert spicerack.username == "user1" assert spicerack.config_dir == get_fixture_path() assert spicerack.http_proxy == proxy assert spicerack.requests_proxies == {"http": proxy, "https": proxy} assert isinstance(spicerack.irc_logger, logging.Logger) assert isinstance(spicerack.actions, ActionsDict) assert isinstance(spicerack.remote(), Remote) assert isinstance(spicerack.remote(installer=True), Remote) assert isinstance(spicerack.confctl("discovery"), ConftoolEntity) assert isinstance(spicerack.confctl("mwconfig"), ConftoolEntity) assert isinstance(spicerack.dns(), Dns) assert isinstance(spicerack.discovery("discovery-record"), Discovery) assert isinstance(spicerack.mediawiki(), MediaWiki) assert isinstance(spicerack.mysql(), Mysql) assert isinstance(spicerack.mysql_legacy(), MysqlLegacy) assert isinstance(spicerack.redis_cluster("cluster"), RedisCluster) assert isinstance( spicerack.elasticsearch_clusters("search_eqiad", ("some_core_dc", )), ElasticsearchClusters, ) assert isinstance( spicerack.admin_reason("Reason message", task_id="T12345"), Reason) assert isinstance(spicerack.puppet(mock.MagicMock(spec_set=RemoteHosts)), PuppetHosts) assert isinstance( spicerack.phabricator(get_fixture_path("phabricator", "valid.conf")), Phabricator, ) assert isinstance(spicerack.prometheus(), Prometheus) assert isinstance(spicerack.debmonitor(), Debmonitor) assert isinstance(spicerack.ganeti(), Ganeti) assert isinstance(spicerack.requests_session("name"), Session) assert isinstance( spicerack.etcdctl(remote_host=mock.MagicMock(spec_set=RemoteHosts)), EtcdctlController, ) assert isinstance(spicerack.kafka(), Kafka) assert mocked_remote_query.called assert mocked_dns_resolver.Resolver.called