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()
Ejemplo n.º 8
0
 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)
Ejemplo n.º 10
0
    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__)))
Ejemplo n.º 11
0
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