anaconda/anaconda-40.22.3.13/pyanaconda/modules/timezone/initialization.py
2024-11-14 21:39:56 -08:00

122 lines
4.5 KiB
Python

#
# Copyright (C) 2022 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
import time
import requests
from pyanaconda.timezone import get_preferred_timezone, is_valid_timezone
from pyanaconda.core.configuration.anaconda import conf
from pyanaconda.core.constants import NETWORK_CONNECTION_TIMEOUT
from pyanaconda.modules.common.constants.services import NETWORK
from pyanaconda.modules.common.structures.timezone import GeolocationData
from pyanaconda.modules.common.task import Task
from pyanaconda.modules.common.util import is_module_available
from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)
class GeolocationTask(Task):
"""Run geolocation"""
@property
def name(self):
return "Geolocate the system"
def run(self):
url = conf.timezone.geolocation_provider
if not url:
log.info("Geoloc: skipping because no provider was set")
return GeolocationData()
log.info("Geoloc: starting lookup using provider: %s", url)
start_time = time.time()
if not self._wait_for_network():
log.error("Geoloc: no network connection")
return GeolocationData()
result = self._locate(url)
log.info(
"Geoloc: lookup finished in %1.1f seconds, result is valid: %s",
time.time() - start_time,
not result.is_empty()
)
return result
def _wait_for_network(self, timeout=NETWORK_CONNECTION_TIMEOUT):
"""Wait until network is available, or time runs out
:param float timeout: how long shall we try waiting
:return bool: is there network connectivity
"""
if not is_module_available(NETWORK):
return False
network = NETWORK.get_proxy()
if network.Connected:
return True
log.info("Geoloc: Waiting for network to become available")
interval = 0.1
start = time.perf_counter()
end = start + timeout
while time.perf_counter() < end:
time.sleep(interval)
if network.Connected:
return True
return network.Connected
def _locate(self, url):
"""Geolocate the computer using the service at given URL
:param str url: URL to query
:return GeolocationData: data structure describing geolocation results
"""
try:
log.info("Geoloc: querying the API")
reply = requests.get(
url,
timeout=NETWORK_CONNECTION_TIMEOUT,
verify=True
)
if reply.status_code == requests.codes.ok: # pylint: disable=no-member
json_reply = reply.json()
territory = json_reply.get("country_code", "")
timezone = json_reply.get("time_zone", "")
# check if the timezone returned by the API is valid
if not is_valid_timezone(timezone):
# try to get a timezone from the territory code
timezone = get_preferred_timezone(territory)
if territory or timezone:
return GeolocationData.from_values(
territory=territory,
timezone=timezone,
)
else:
log.error("Geoloc: API lookup failed with status code: %s", reply.status_code)
except requests.exceptions.RequestException as exc:
log.debug("Geoloc: RequestException for API lookup:\n%s", exc)
except ValueError as exc:
log.debug("Geoloc: Unable to decode JSON:\n%s", exc)
return GeolocationData()