def probe_dhcp(self): """Find all the interfaces on this rack controller and probe for DHCP servers. """ client = yield self._tryGetClient() if client is None: maaslog.error( "Can't initiate DHCP probe; no RPC connection to region.") return # Iterate over interfaces and probe each one. interfaces = yield self._get_interfaces() self.log("Probe for external DHCP servers started on interfaces: %s." % (", ".join(interfaces))) for interface in interfaces: try: servers = yield maybeDeferred(probe_interface, interface) except socket.error as e: error = ( "Failed to probe for external DHCP servers on interface " "'%s'." % interface) if is_dev_environment(): error += " (Did you configure authbind per HACKING.rst?)" self.err(e, error) continue else: if len(servers) > 0: # XXX For now, only send the region one server, since # it can only track one per VLAN (this could be considered # a bug). yield self._inform_region_of_dhcp(client, interface, servers.pop()) else: yield self._inform_region_of_dhcp(client, interface, None) self.log("External DHCP probe complete.")
def _loadSettings(self): # Load the settings from rackd.conf. with ClusterConfiguration.open() as config: settings.DEBUG = config.debug # Debug mode is always on in the development environment. if is_dev_environment(): settings.DEBUG = True
def is_dev_environment(): """Is this the development environment, or production? Lazy import to avoid circular import issues. """ from provisioningserver.config import is_dev_environment return is_dev_environment()
def sudo_write_file(filename, contents, mode=0o644): """Write (or overwrite) file as root. USE WITH EXTREME CARE. Runs an atomic update using non-interactive `sudo`. This will fail if it needs to prompt for a password. When running in a snap or devel mode, this function calls `atomic_write` directly. :type contents: `bytes`. """ from provisioningserver.config import is_dev_environment if not isinstance(contents, bytes): raise TypeError("Content must be bytes, got: %r" % (contents, )) if snappy.running_in_snap(): atomic_write(contents, filename, mode=mode) else: maas_write_file = get_library_script_path("maas-write-file") command = _with_dev_python(maas_write_file, filename, "%.4o" % mode) if not is_dev_environment(): command = sudo(command) proc = Popen(command, stdin=PIPE) stdout, stderr = proc.communicate(contents) if proc.returncode != 0: raise ExternalProcessError(proc.returncode, command, stderr)
def _with_dev_python(*command): # Avoid circular imports. from provisioningserver.config import is_dev_environment if is_dev_environment(): from maastesting import root interpreter = os.path.join(root, "bin", "py") command = interpreter, *command return command
def get_resources_bin_path(): """Return the path of the resources binary.""" if is_dev_environment(): path = "src/machine-resources/bin" else: prefix = SnapPaths.from_environ().snap or "" path = f"{prefix}/usr/share/maas/machine-resources" return os.path.join(path, get_architecture())
def run(): is_snap = "SNAP" in os.environ is_devenv = is_dev_environment() if not is_devenv: check_user() if not is_snap: set_group() set_umask() run_django(is_snap, is_devenv)
def monitorServices(self): """Monitors all of the external services and makes sure they stay running. """ if is_dev_environment(): log.msg("Skipping check of services; they're not running under " "the supervision of systemd.") else: d = service_monitor.ensureServices() d.addCallback(self._updateDatabase) d.addErrback(log.err, "Failed to monitor services and update database.") return d
def get_maas_common_command(): """Return path to the maas-rack command. In production mode this will just return 'maas-rack', but in development mode it will return the path for the current development environment. """ # Avoid circular imports. from provisioningserver.config import is_dev_environment if is_dev_environment(): from maastesting import root return os.path.join(root, "bin", "maas-common") else: return os.path.join(get_path("/usr/lib/maas"), "maas-common")
def _reconfigureLogging(self): # Reconfigure the logging based on the debug mode of Django. from django.conf import settings if settings.DEBUG: # In debug mode, force logging to debug mode. logger.set_verbosity(3) # When not in the developer environment, patch Django to not # use the debug cursor. This is needed or Django will store in # memory every SQL query made. from provisioningserver.config import is_dev_environment if not is_dev_environment(): from django.db.backends.base import base from django.db.backends.utils import CursorWrapper base.BaseDatabaseWrapper.make_debug_cursor = ( lambda self, cursor: CursorWrapper(cursor, self))
def get_maas_common_command(): """Return path to the maas-rack command. In production mode this will just return 'maas-rack', but in development mode it will return the path for the current development environment. """ # Avoid circular imports. from provisioningserver.config import is_dev_environment if is_dev_environment(): from maastesting import root return os.path.join(root, 'bin/maas-common') elif snappy.running_in_snap(): # there's no maas-common in the snap as maas-rack is always present return os.path.join(snappy.get_snap_path(), 'bin/maas-rack') else: return get_path('usr/lib/maas/maas-common')
def _getInterfacesForNeighbourDiscovery(self, interfaces: dict, monitoring_state: dict): """Return the interfaces which will be used for neighbour discovery. :return: The set of interface names to run neighbour discovery on. """ # Don't observe interfaces when running the test suite/dev env. # In addition, if we don't own the lock, we should not be monitoring # any interfaces. if is_dev_environment() or not self._locked or interfaces is None: return set() monitored_interfaces = { ifname for ifname in interfaces if (ifname in monitoring_state and monitoring_state[ifname].get('neighbour', False) is True) } return monitored_interfaces
def run(): is_snap = "SNAP" in os.environ is_devenv = is_dev_environment() if not is_devenv: if is_snap: os.environ.update({ "MAAS_PATH": os.environ["SNAP"], "MAAS_ROOT": os.environ["SNAP_DATA"], "MAAS_DATA": os.path.join(os.environ["SNAP_COMMON"], "maas"), "MAAS_CLUSTER_CONFIG": os.path.join(os.environ["SNAP_DATA"], "rackd.conf"), }) users = ["root"] # Allow dhcpd user to call dhcp-notify, and maas user to call # observe-arp. if not is_snap and len(sys.argv) > 1: if sys.argv[1] == "dhcp-notify": users.append("dhcpd") if sys.argv[1] == "observe-arp": users.append("maas") if sys.argv[1] == "observe-beacons": users.append("maas") if sys.argv[1] == "observe-mdns": # Any user can call this. (It might be necessary for a normal # user to call this for support/debugging purposes.) users.append(None) # Only set the group and umask when running as root. if check_users(users) == "root": if not is_snap: set_group() set_umask() # Run the script. # Run the main provisioning script. from provisioningserver.__main__ import main main()
def get_library_script_path(name): """Return path to a "library script". By convention (here) scripts are always installed to ``/usr/lib/maas`` on the target machine. The FHS (Filesystem Hierarchy Standard) defines ``/usr/lib/`` as the location for libraries used by binaries in ``/usr/bin`` and ``/usr/sbin``, hence the term "library script". In production mode this will return ``/usr/lib/maas/$name``, but in development mode it will return ``$root/scripts/$name``. """ # Avoid circular imports. from provisioningserver.config import is_dev_environment if is_dev_environment(): from maastesting import root return os.path.join(root, "scripts", name) else: return os.path.join(get_path("/usr/lib/maas"), name)
def sudo_delete_file(filename): """Delete file as root. USE WITH EXTREME CARE. Runs an atomic update using non-interactive `sudo`. This will fail if it needs to prompt for a password. When running in a snap this function calls `atomic_write` directly. """ from provisioningserver.config import is_dev_environment if snappy.running_in_snap(): atomic_delete(filename) else: maas_delete_file = get_library_script_path("maas-delete-file") command = _with_dev_python(maas_delete_file, filename) if not is_dev_environment(): command = sudo(command) proc = Popen(command) stdout, stderr = proc.communicate() if proc.returncode != 0: raise ExternalProcessError(proc.returncode, command, stderr)
def call_uec2roottar(root_image_path, root_tgz_path): """Invoke `uec2roottar` with the given arguments. Here only so tests can stub it out. :param root_image_path: Input file. :param root_tgz_path: Output file. """ if is_dev_environment(): # In debug mode this is skipped as it requires the uec2roottar # script to have sudo abilities. The root-tgz is created as an # empty file so the correct links can be made. log.msg( "Conversion of root-image to root-tgz is skipped in DEVELOP mode.") open(root_tgz_path, "wb").close() else: call_and_check([ 'sudo', '/usr/bin/uec2roottar', '--user=maas', root_image_path, root_tgz_path, ])
def test_is_dev_environment_returns_true(self): self.assertTrue(is_dev_environment())
def test_is_dev_environment_returns_false(self): self.useFixture(ImportErrorFixture('maastesting', 'root')) self.assertFalse(is_dev_environment())