Пример #1
0
    def test_fgip_raise(self, mock_get):
        """Test FedoraGeoIPProvider handling of exceptions"""
        task = GeolocationTask()

        mock_get.side_effect = RequestException
        with self.assertLogs(level="DEBUG") as logs:
            result = task._locate(GEOLOC_URL_FEDORA_GEOIP)
        assert isinstance(result, GeolocationData)

        assert result.is_empty()
        mock_get.assert_called_once()
        assert "RequestException" in "\n".join(logs.output)

        mock_get.reset_mock()

        # This is technically cheating, ValueError is expected to be raised elsewhere than the
        # request itself. But it's all wrapped in a single try....except block so it is a good
        # enough approximation.
        mock_get.side_effect = ValueError
        with self.assertLogs(level="DEBUG") as logs:
            result = task._locate(GEOLOC_URL_FEDORA_GEOIP)

        assert isinstance(result, GeolocationData)
        assert result.is_empty()
        mock_get.assert_called_once()
        assert "Unable to decode" in "\n".join(logs.output)
Пример #2
0
    def test_fgip_emptydata(self, mock_get):
        """Test FedoraGeoIPProvider with empty data"""
        task = GeolocationTask()
        result = task._locate(GEOLOC_URL_FEDORA_GEOIP)

        assert isinstance(result, GeolocationData)
        assert result.is_empty()
        mock_get.assert_called_once()
Пример #3
0
    def test_fgip_failure(self, mock_get):
        """Test FedoraGeoIPProvider with HTTP failure"""
        task = GeolocationTask()
        with self.assertLogs(level="DEBUG") as logs:
            result = task._locate(GEOLOC_URL_FEDORA_GEOIP)

        assert isinstance(result, GeolocationData)
        assert result.is_empty()
        mock_get.assert_called_once()
        assert "failed with status code: 503" in "\n".join(logs.output)
Пример #4
0
    def test_hip_success(self, mock_get):
        """Test HostipGeoIPProvider success"""
        task = GeolocationTask()
        result = task._locate(GEOLOC_URL_HOSTIP)

        assert isinstance(result, GeolocationData)
        assert result.territory == "GB"
        assert result.timezone == "Europe/London"
        assert not result.is_empty()
        mock_get.assert_called_once()
Пример #5
0
    def test_fgip_bad_timezone(self, mock_get):
        """Test FedoraGeoIPProvider with bad time zone data"""
        task = GeolocationTask()
        result = task._locate(GEOLOC_URL_FEDORA_GEOIP)

        assert isinstance(result, GeolocationData)
        assert result.territory == "GB"
        assert result.timezone == "Europe/London"
        assert not result.is_empty()
        mock_get.assert_called_once()
Пример #6
0
    def start_geolocation(self):
        """Start geolocation, if not already started."""
        if self._geoloc_task is not None:
            log.info("Geoloc: already started")
            return

        self._geoloc_task = GeolocationTask()
        self._geoloc_task.succeeded_signal.connect(
            self._set_geolocation_result)
        log.info("Geoloc: starting lookup")
        self._geoloc_task.start()
Пример #7
0
    def test_no_network(self, time_mock, avail_mock, net_mock):
        """Test waiting for network when no network available"""
        time_mock.sleep = Mock()
        time_mock.perf_counter = Mock(side_effect=[0, 1, 2, 3, 4,
                                                   65536])  # fake time out
        net_mock.get_proxy = Mock(return_value=MockNetworkProxy(
            connect_results=[False]))

        task = GeolocationTask()
        result = task._wait_for_network()

        assert result is False
        time_mock.sleep.assert_not_called()
        avail_mock.assert_called_once_with(net_mock)
        assert net_mock.get_proxy.return_value.call_count == 0
Пример #8
0
    def test_immediate_success(self, time_mock, avail_mock, net_mock):
        """Test waiting for network when already connected"""
        time_mock.sleep = Mock()
        time_mock.perf_counter = Mock()
        net_mock.get_proxy = Mock(return_value=MockNetworkProxy(
            connect_results=[True]))

        task = GeolocationTask()
        result = task._wait_for_network()

        assert result is True
        time_mock.sleep.assert_not_called()
        time_mock.perf_counter.assert_not_called()
        avail_mock.assert_called_once_with(net_mock)
        assert net_mock.get_proxy.return_value.call_count == 1
Пример #9
0
    def test_success_after_waiting(self, time_mock, avail_mock, net_mock):
        """Test waiting for network when network becomes available at the very last moment"""
        time_mock.sleep = Mock()
        time_mock.perf_counter = Mock(side_effect=[0, 0, 1, 2, 3, 4,
                                                   65536])  # fake time out
        net_mock.get_proxy = Mock(return_value=MockNetworkProxy(
            connect_results=[False] + [False] * 5 + [True]
            # 1 before, 5 iterations, 1 timeout interation, last exit
        ))

        task = GeolocationTask()
        result = task._wait_for_network()

        assert result is True
        assert time_mock.sleep.call_count == 5
        avail_mock.assert_called_once_with(net_mock)
        assert net_mock.get_proxy.return_value.call_count == 7  # same as number of results
Пример #10
0
    def test_no_result(self, conf_mock):
        """Test GeolocationTask with no viable result"""
        conf_mock.timezone.geolocation_provider = GEOLOC_URL_FEDORA_GEOIP
        retval = GeolocationData()  # empty by default

        with patch.object(GeolocationTask,
                          "_wait_for_network",
                          return_value=True) as wfn_mock:
            with patch.object(GeolocationTask, "_locate",
                              return_value=retval) as loc_mock:
                task = GeolocationTask()
                result = task.run()

        assert isinstance(result, GeolocationData)
        assert result.is_empty()
        wfn_mock.assert_called_once_with()
        loc_mock.assert_called_once()
Пример #11
0
    def test_success(self, conf_mock):
        """Test success case for GeolocationTask"""
        conf_mock.timezone.geolocation_provider = GEOLOC_URL_FEDORA_GEOIP
        retval = GeolocationData.from_values(territory="territory",
                                             timezone="timezone")

        with patch.object(GeolocationTask,
                          "_wait_for_network",
                          return_value=True) as wfn_mock:
            with patch.object(GeolocationTask, "_locate",
                              return_value=retval) as loc_mock:
                task = GeolocationTask()
                result = task.run()

        assert isinstance(result, GeolocationData)
        assert result.timezone == retval.timezone
        assert result.territory == retval.territory
        wfn_mock.assert_called_once_with()
        loc_mock.assert_called_once()
Пример #12
0
    def test_success_while_waiting(self, time_mock, avail_mock, net_mock):
        """Test waiting for network when network becomes available"""
        time_mock.sleep = Mock()
        time_mock.perf_counter = Mock(
            side_effect=[0, 0, 1, 2])  # init + 3 iterations only
        net_mock.get_proxy = Mock(return_value=MockNetworkProxy(
            connect_results=[
                False,
                False,
                False,
                True  # 1 before, 2 iterations keep going, 3rd succeeds
            ]))

        task = GeolocationTask()
        result = task._wait_for_network()

        assert result is True
        assert time_mock.sleep.call_count == 3
        avail_mock.assert_called_once_with(net_mock)
        assert net_mock.get_proxy.return_value.call_count == 4  # same as number of results
Пример #13
0
    def test_no_network(self, conf_mock):
        """Test GeolocationTask with no network access"""
        conf_mock.timezone.geolocation_provider = GEOLOC_URL_FEDORA_GEOIP
        retval = GeolocationData.from_values(territory="territory",
                                             timezone="timezone")

        with self.assertLogs(level="DEBUG") as logs:
            with patch.object(GeolocationTask,
                              "_wait_for_network",
                              return_value=False) as wfn_mock:
                with patch.object(GeolocationTask,
                                  "_locate",
                                  return_value=retval) as loc_mock:
                    task = GeolocationTask()
                    result = task.run()

        assert isinstance(result, GeolocationData)
        assert result.is_empty()
        wfn_mock.assert_called_once_with()
        loc_mock.assert_not_called()
        assert "no network connection" in "\n".join(logs.output)
Пример #14
0
class TimezoneService(KickstartService):
    """The Timezone service."""
    def __init__(self):
        super().__init__()
        self.timezone_changed = Signal()
        self._timezone = "America/New_York"

        self._geoloc_task = None
        self.geolocation_result_changed = Signal()
        self._geoloc_result = GeolocationData()

        self.is_utc_changed = Signal()
        self._is_utc = False

        self.ntp_enabled_changed = Signal()
        self._ntp_enabled = True

        self.time_sources_changed = Signal()
        self._time_sources = []

    def publish(self):
        """Publish the module."""
        TaskContainer.set_namespace(TIMEZONE.namespace)
        DBus.publish_object(TIMEZONE.object_path, TimezoneInterface(self))
        DBus.register_service(TIMEZONE.service_name)

    @property
    def kickstart_specification(self):
        """Return the kickstart specification."""
        return TimezoneKickstartSpecification

    def process_kickstart(self, data):
        """Process the kickstart data."""
        self.set_timezone(data.timezone.timezone)
        self.set_is_utc(data.timezone.isUtc)
        self.set_ntp_enabled(not data.timezone.nontp)

        sources = []

        for hostname in data.timezone.ntpservers:
            source = TimeSourceData()
            source.type = TIME_SOURCE_SERVER
            source.hostname = hostname
            source.options = ["iburst"]
            sources.append(source)

        for source_data in data.timesource.dataList():
            if source_data.ntp_disable:
                self.set_ntp_enabled(False)
                continue

            source = TimeSourceData()
            source.options = ["iburst"]

            if source_data.ntp_server:
                source.type = TIME_SOURCE_SERVER
                source.hostname = source_data.ntp_server
            elif source_data.ntp_pool:
                source.type = TIME_SOURCE_POOL
                source.hostname = source_data.ntp_pool
            else:
                KickstartParseError(_("Invalid time source."),
                                    lineno=source_data.lineno)

            if source_data.nts:
                source.options.append("nts")

            sources.append(source)

        self.set_time_sources(sources)

    def setup_kickstart(self, data):
        """Set up the kickstart data."""
        data.timezone.timezone = self.timezone
        data.timezone.isUtc = self.is_utc
        source_data_list = data.timesource.dataList()

        if not self.ntp_enabled:
            source_data = data.TimesourceData()
            source_data.ntp_disable = True
            source_data_list.append(source_data)
            return

        for source in self.time_sources:
            source_data = data.TimesourceData()

            if source.type == TIME_SOURCE_SERVER:
                source_data.ntp_server = source.hostname
            elif source.type == TIME_SOURCE_POOL:
                source_data.ntp_pool = source.hostname
            else:
                log.warning("Skipping %s.", source)
                continue

            if "nts" in source.options:
                source_data.nts = True

            source_data_list.append(source_data)

    @property
    def timezone(self):
        """Return the timezone."""
        return self._timezone

    def set_timezone(self, timezone):
        """Set the timezone."""
        self._timezone = timezone
        self.timezone_changed.emit()
        log.debug("Timezone is set to %s.", timezone)

    @property
    def is_utc(self):
        """Is the hardware clock set to UTC?"""
        return self._is_utc

    def set_is_utc(self, is_utc):
        """Set if the hardware clock is set to UTC."""
        self._is_utc = is_utc
        self.is_utc_changed.emit()
        log.debug("UTC is set to %s.", is_utc)

    @property
    def ntp_enabled(self):
        """Enable automatic starting of NTP service."""
        return self._ntp_enabled

    def set_ntp_enabled(self, ntp_enabled):
        """Enable or disable automatic starting of NTP service."""
        self._ntp_enabled = ntp_enabled
        self.ntp_enabled_changed.emit()
        log.debug("NTP is set to %s.", ntp_enabled)

    @property
    def time_sources(self):
        """Return a list of time sources."""
        return self._time_sources

    def set_time_sources(self, servers):
        """Set time sources."""
        self._time_sources = list(servers)
        self.time_sources_changed.emit()
        log.debug("Time sources are set to: %s", servers)

    def collect_requirements(self):
        """Return installation requirements for this module.

        :return: a list of requirements
        """
        requirements = []

        # Add ntp service requirements.
        if self._ntp_enabled:
            requirements.append(
                Requirement.for_package(NTP_PACKAGE,
                                        reason="Needed to run NTP service."))

        return requirements

    def install_with_tasks(self):
        """Return the installation tasks of this module.

        :return: list of installation tasks
        """
        return [
            ConfigureHardwareClockTask(is_utc=self.is_utc),
            ConfigureTimezoneTask(sysroot=conf.target.system_root,
                                  timezone=self.timezone,
                                  is_utc=self.is_utc),
            ConfigureNTPTask(sysroot=conf.target.system_root,
                             ntp_enabled=self.ntp_enabled,
                             ntp_servers=self.time_sources)
        ]

    def _set_geolocation_result(self):
        """Set geolocation result when the task finished."""
        self._geoloc_result = self._geoloc_task.get_result()
        self.geolocation_result_changed.emit()
        self._geoloc_task = None
        log.debug("Geolocation result is set, valid=%s",
                  not self._geoloc_result.is_empty())

    def start_geolocation(self):
        """Start geolocation, if not already started."""
        if self._geoloc_task is not None:
            log.info("Geoloc: already started")
            return

        self._geoloc_task = GeolocationTask()
        self._geoloc_task.succeeded_signal.connect(
            self._set_geolocation_result)
        log.info("Geoloc: starting lookup")
        self._geoloc_task.start()

    @property
    def geolocation_result(self):
        """Get geolocation result.

        :return GeolocationData: result of the lookup, empty if not ready yet
        """
        return self._geoloc_result