def test_retrieving_settings(): """Test that the correct settings are retrieved.""" test_config = get_config(override_default="test") dev_config = get_config(override_default="dev") prod_config = get_config(override_default="prod") wrong_config = get_config(override_default="wrong") assert test_config == TestConfig assert dev_config == DevConfig assert prod_config == ProdConfig assert wrong_config == DevConfig
def set_wpa_mode(): """Perform the setup and intialization work for interfaces with no ap present.""" logger.debug("setting all wlan into wpa mode") session = get_session() # get the info for the wpa_supplicant file wifi_defs = session.query(Wifi).filter(Wifi.mode != "ap").all() networks = [] for wifi in wifi_defs: new_network = {} new_network["ssid"] = wifi.name new_network["password"] = wifi.password networks.append(new_network) iptables_file(None, None, flush_only=True) interface_file() wpa_supplicant_file(networks) dhcpcd_file() config = get_config() path = config.APP_DIR + "/network/wpa_script.sh" command = ["sudo", "sh", path] subprocess.check_call(command) session.close()
def check_rabbitmq_address(logger, address): """Check if the address is good, by trying to connect.""" config = get_config() user = config.RABBITMQ_USER password = config.RABBITMQ_PASSWORD port = 5672 virtual_host = config.RABBITMQ_VHOST credentials = pika.PlainCredentials(username=user, password=password) parameters = pika.ConnectionParameters(host=address, port=port, virtual_host=virtual_host, credentials=credentials) try: logger.debug(f"testing connection to: {address}") connection = pika.BlockingConnection(parameters=parameters) if connection.is_open: logger.debug(f"Connection to {address} is good.") connection.close() return True except AMQPConnectionError: logger.debug(f"Connection to {address} failed.") return False return False
def create_revision(message): """Create a database migration using alembic.""" config = get_config() alembic_cnf = AlConfig(config.PROJECT_ROOT + "/migrations/alembic.ini") alembic_cnf.set_main_option("script_location", config.PROJECT_ROOT + "/migrations") al_command.revision(alembic_cnf, message=message, autogenerate=True)
def database_upgrade(revision): """Upgrade database to given revision.""" config = get_config() alembic_cnf = AlConfig(config.PROJECT_ROOT + "/migrations/alembic.ini") alembic_cnf.set_main_option("script_location", config.PROJECT_ROOT + "/migrations") al_command.upgrade(alembic_cnf, revision)
def set_ap_mode(): """Perform the setup and intialization work for interfaces with an ap present.""" logger.debug("setting wifi into ap mode") session = get_session() # get the wlan0 and wlan1 dhcp states try: ap_interface = session.query(Interface).filter_by(state="ap").first() ap_ssid = ap_interface.credentials[0].name ap_password = ap_interface.credentials[0].password except NoResultFound: # error. abort logger.warning("No interface with state set to 'ap'. Aborting") return # get info for interface file if ap_interface.interface == "wlan0": wlan0_dhcp = False wlan1_dhcp = True else: wlan0_dhcp = True wlan1_dhcp = False # get the info for the wpa_supplicant file wifi_defs = session.query(Wifi).filter(Wifi.mode != "ap").all() networks = [] for wifi in wifi_defs: new_network = {} new_network["ssid"] = wifi.name new_network["password"] = wifi.password networks.append(new_network) # get the information for the iptables_file internal_interface = ap_interface.interface external_interface = get_external_interface() iptables_file(external_interface, internal_interface) interface_file(wlan0_dhcp=wlan0_dhcp, wlan1_dhcp=wlan1_dhcp) wpa_supplicant_file(networks) dhcpcd_file(interface=ap_interface.interface) dnsmasq_file(interface=ap_interface.interface) hostapd_file(ap_interface.interface, ap_ssid, ap_password) config = get_config() path = config.APP_DIR + "/network/ap_script.sh" command = ["sudo", "sh", path, ap_interface.interface] subprocess.check_call(command) session.close()
def search_on_socket(logger, session, connection): """Look for farm monitor presence notifier on the network.""" config = get_config() presence_port = config.PRESENCE_PORT # get the first interface that is for farm monitor interface = session.query( Interface.interface).filter_by(is_for_fm=True).scalar() if interface is None: logger.warning( "Interface from database is None. Has initial configuration been run? Setting interface to 'eth0'" ) interface = "eth0" interface_address = get_ip_of_interface(interface, broadcast=True) logger.info(f"looking for FarmMonitor address on interface {interface}") logger.debug(f"address is {interface_address}:{presence_port}") # Create UDP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # Ask operating system to let us do broadcasts from socket sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # Bind UDP socket to local port so we can receive pings sock.bind((interface_address, int(presence_port))) try: while True: timeout = 5 ready = select.select([sock], [], [], timeout) # Someone answered our ping if ready[0]: _, addrinfo = sock.recvfrom(2) if check_rabbitmq_address(logger, addrinfo[0]): sock.close() logger.debug( f"Found FarmMonitor at {addrinfo[0]}:{addrinfo[1]}") connection.address = addrinfo[0] session.commit() return True logger.debug( f"Reply from {addrinfo[0]}:{addrinfo[1]}, but no rabbitmq server present" ) else: logger.debug("No broadcast from FarmMonitor yet") except KeyboardInterrupt: sock.close() session.commit() return False
def create_tables(): """Create all database tables for first time setup.""" click.echo("creating all tables") create_all_tables() config = get_config() alembic_cnf = AlConfig(config.PROJECT_ROOT + "/migrations/alembic.ini") alembic_cnf.set_main_option("script_location", config.PROJECT_ROOT + "/migrations") click.echo("stamping alembic head") al_command.stamp(alembic_cnf, "head") click.echo("done")
def get_rabbitmq_address(logger, session): # noqa: C901 """Find and return the address of the RabbitMQ server to connect to.""" try: connection = session.query(Connection).one() except NoResultFound: connection = Connection() session.add(connection) # try environment variable address (if present) to see if it works. config = get_config() if config.RABBITMQ_HOST_ADDRESS is not None: logger.debug( f"trying environment variable for rabbitmq address of {config.RABBITMQ_HOST_ADDRESS}" ) if check_rabbitmq_address(logger, config.RABBITMQ_HOST_ADDRESS): logger.info( f"environment variable address of host {config.RABBITMQ_HOST_ADDRESS} was found and the url was valid" ) connection.address = config.RABBITMQ_HOST_ADDRESS session.commit() return True # try previously found address (if available) to see if it is still working if connection.address: logger.debug( f"trying previous rabbitmq address of {connection.address}") if check_rabbitmq_address(logger, connection.address): logger.info("previously used rabbitmq address is still valid") return True possible_addresses = ["fm_rabbitmq", "host.docker.internal", "localhost"] for address in possible_addresses: logger.debug(f"testing address: {address}") try: address = socket.gethostbyname(address) if check_rabbitmq_address(logger, address): logger.info( f"'{address}' host was found and the url was valid") connection.address = address session.commit() return True except socket.gaierror: logger.debug(f"'{address}' host was not found") # if all else fails, look for farm monitor presence notifier return search_on_socket(logger, session, connection)
def __init__(self, logger): """Create the Connection object.""" self.LOGGER = logger # store and manage internal state self._connection = None self._channel = None self._closing = False config = get_config() # connection parameters self._user = config.RABBITMQ_USER self._password = config.RABBITMQ_PASSWORD # self._host = host - this is set in the overwritten function self._port = 5672 self._virtual_host = config.RABBITMQ_VHOST
"""Main celery module.""" import logging import time import schedule from amqp import exceptions as amqp_exceptions # type: ignore from celery import Celery, exceptions from celery.result import AsyncResult from fd_device.device.update import get_device_info from fd_device.grainbin.update import get_grainbin_updates from fd_device.settings import get_config LOGGER = logging.getLogger("fd.celery_runner") CONFIG = get_config() app = Celery() app.config_from_object("fd_device.settings:CeleryConfig") def send_update_to_server(task_name: str, payload, ignore_result: bool = False): """Send a payload to a specific task on the server.""" try: LOGGER.debug(f"Sending '{task_name}' to Celery broker") result: AsyncResult = app.send_task( task_name, args=[payload], ignore_result=ignore_result ) if not ignore_result: response = result.get(timeout=CONFIG.SEND_TASK_GET_TIMEOUT) LOGGER.debug(f"'{task_name}' task returned: {response}")
# -*- coding: utf-8 -*- """Click commands.""" import os import sys from glob import glob from subprocess import PIPE, call, run from typing import List import click from pyment import PyComment from fd_device.settings import get_config config = get_config() # pylint: disable=invalid-name APP_DIR = config.APP_DIR PROJECT_ROOT = config.PROJECT_ROOT TEST_PATH = os.path.join(PROJECT_ROOT, "tests") MAX_DEPTH_RECUR = 50 """The maximum depth to reach while recursively exploring sub folders.""" def get_files_from_dir(path, recursive=True, depth=0, file_ext=".py"): """Retrieve the list of files from a folder. @param path: file or directory where to search files @param recursive: if True will search also sub-directories @param depth: if explore recursively, the depth of sub directories to follow @param file_ext: the files extension to get. Default is '.py' @return: the file list retrieved. if the input is a file then a one element list. """ file_list = []
from __future__ import with_statement from alembic import context from sqlalchemy import engine_from_config, pool from logging.config import fileConfig # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config # this will overwrite the ini-file sqlalchemy.url path # with the path given in the config of the main code from fd_device.settings import get_config device_config = get_config() config.set_main_option('sqlalchemy.url', device_config.SQLALCHEMY_DATABASE_URI) config.set_main_option('script_location', device_config.PROJECT_ROOT + '/migrations') # Interpret the config file for Python logging. # This line sets up loggers basically. fileConfig(config.config_file_name) # add your model's MetaData object here # for 'autogenerate' support from fd_device.database.base import get_base from fd_device.database.device import Device, Grainbin from fd_device.database.system import Hardware Base = get_base() target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, # can be acquired: # my_important_option = config.get_main_option("my_important_option")
def test_main_env(): """Test that the main environment variable is set for testing.""" config = get_config() assert config == TestConfig