Esempio n. 1
0
def test_no_collisions():
    machines = [test_machine()]
    c = Configuration(machines=machines)
    assert c.machines == machines

    machines = [test_machine("a"), test_machine("b")]
    c = Configuration(machines=machines)
    assert c.machines == machines
Esempio n. 2
0
def test_spinnaker_ip_collision():
    with pytest.raises(ValueError):
        machines = [
            test_machine("a", spinnaker_prefix="bmp"),
            test_machine("b", spinnaker_prefix="bmp")
        ]
        Configuration(machines=machines)
Esempio n. 3
0
def test_sensible_defaults():
    c = Configuration()

    assert c.machines == []
    assert c.ip == ""
    assert c.timeout_check_interval == 5.0
    assert c.max_retired_jobs == 1200
Esempio n. 4
0
def test_read_config_file(simple_config, s):
    # Should fail if config file is missing
    os.remove(simple_config)
    assert s.read_config_file() is False

    # Should fail if config file is syntactically invalid
    with open(simple_config, "w") as f:
        f.write("1_2_3")
    assert s.read_config_file() is False

    # Should fail if no configuration variable is set
    with open(simple_config, "w") as f:
        f.write("config = 123")
    assert s.read_config_file() is False

    # Should succeed otherwise!
    with open(simple_config, "w") as f:
        # Make a simple config file
        f.write("configuration = {}".format(repr(Configuration())))
    assert s.read_config_file() is True

    # Should pass on parameters to controller
    with open(simple_config, "w") as f:
        f.write("configuration = {}".format(repr(
            Configuration(max_retired_jobs=123))))
    assert s.read_config_file() is True
    assert s._controller.max_retired_jobs == 123

    # Should pass on machines to controller in right order
    with open(simple_config, "w") as f:
        f.write("configuration = {}".format(repr(
            Configuration(machines=[simple_machine("m0", ip_prefix="0"),
                                    simple_machine("m1", ip_prefix="1"),
                                    simple_machine("m2", ip_prefix="2"),
                                    simple_machine("m3", ip_prefix="3"),
                                    simple_machine("m4", ip_prefix="4")]))))
    assert s.read_config_file() is True
    assert list(s._controller.machines) == "m0 m1 m2 m3 m4".split()
Esempio n. 5
0
def test_reread_config_file(simple_config, s):
    if not hasattr(signal, "SIGHUP"):  # pragma: no cover
        return

    # Make sure config re-reading works
    assert list(s._controller.machines) == ["m"]

    # Modify config file
    with open(simple_config, "w") as f:
        f.write("configuration = {}".format(repr(Configuration())))
    os.kill(os.getpid(), signal.SIGHUP)
    time.sleep(0.2)

    # Configuration should have changed accordingly
    assert list(s._controller.machines) == []
Esempio n. 6
0
def test_machine_notifications(double_config, s):
    with SimpleClient() as c0:
        with SimpleClient() as c1:

            c0.call("notify_machine", "m0")
            c1.call("notify_machine")

            job_id0 = c0.call("create_job", 1, 2, owner="me")
            time.sleep(0.05)

            # Should be notified new jobs being scheduled
            assert c0.get_notification() == {"machines_changed": ["m0"]}
            assert c1.get_notification() == {"machines_changed": ["m0"]}

            job_id1 = c0.call("create_job", owner="me")
            time.sleep(0.05)

            # Make sure filtering works
            assert c1.get_notification() == {"machines_changed": ["m1"]}

            # Should be notified on job completion
            c0.call("destroy_job", job_id0)
            assert c0.get_notification() == {"machines_changed": ["m0"]}
            assert c1.get_notification() == {"machines_changed": ["m0"]}

            # Should be notified on job completion
            c1.call("destroy_job", job_id1)
            assert c1.get_notification() == {"machines_changed": ["m1"]}

            # Make sure machine changes get announced
            if not hasattr(signal, "SIGHUP"):  # pragma: no cover
                return
            with open(double_config, "w") as f:
                f.write("configuration = {}".format(repr(Configuration())))
            os.kill(os.getpid(), signal.SIGHUP)

            assert c0.get_notification() == {"machines_changed": ["m0"]}
            assert c1.get_notification() in (
                {"machines_changed": ["m0", "m1"]},
                {"machines_changed": ["m1", "m0"]})
Esempio n. 7
0
    def __init__(self, config_filename, cold_start=False, port=22244):
        """
        :param config_filename: \
            The filename of the config file for the server which describes the\
            machines to be controlled.
        :type config_filename: str
        :param cold_start: \
            If False (the default), the server will attempt to restore its\
            previous state, if True, the server will start from scratch.
        :type cold_start: bool
        :param port: Which port to listen on. Defaults to 22244.
        :type port: int
        """
        # ============ STATE THAT NEEDS TO BE ALWAYS DEFINED ============

        self._cold_start = cold_start
        self._port = port

        # Should the background thread terminate?
        self._stop = False

        # Flag for checking if the server is still alive
        self._running = False

        # Currently open sockets to clients. Once server started, should only
        # be accessed from the server thread.
        self._server_socket = None

        # The server core object that the object that is persisted
        self._controller = None

        # Buffered data received from each socket
        # {fd: buf, ...}
        self._client_buffers = {}

        # ============ SUPERCLASS INITIALISATION ============

        PollingServerCore.__init__(self)
        ConfigurationReloader.__init__(self, config_filename, self.wake)

        # ============ ACTIVE OBJECTS ============

        # The background thread in which the server will run
        self._server_thread = Thread(target=self._run, name="Server Thread")

        # The current server configuration options. Once server started, should
        # only be accessed from the server thread.
        self._configuration = Configuration()

        # Infer the saved-state location
        self._state_filename = self._get_state_filename(
            self.configuration_file)

        # Attempt to restore saved state if required
        if not self._cold_start and path.isfile(self._state_filename):
            try:
                with open(self._state_filename, "rb") as f:
                    self._controller = unpickle(f)
                log.info("Server warm-starting from %s.", self._state_filename)
            except Exception:
                # Some other error occurred during unpickling.
                log.exception("Server state could not be unpacked from %s.",
                              self._state_filename)
                self._controller = None

        # Perform cold-start if no saved state was loaded
        if self._controller is None:
            log.info("Server cold-starting.")
            self._controller = Controller()

        # Notify the background thread when something changes in the background
        # of the controller (e.g. power state changes).
        self._controller.on_background_state_change = self.wake

        # Read configuration file. This must succeed when the server is first
        # being started.
        if not self.read_config_file():
            self._controller.stop()
            raise Exception("Config file could not be loaded.")

        # Start the server
        self._server_thread.start()
        self._running = True
Esempio n. 8
0
def test_name_collision():
    with pytest.raises(ValueError):
        machines = [test_machine("a"), test_machine("b"), test_machine("a")]
        Configuration(machines=machines)
Esempio n. 9
0
def test_machine_type():
    with pytest.raises(TypeError):
        Configuration(machines=["m"])