Esempio n. 1
0
class DHCPv6Server(DHCPServer):
    """Represents the settings for a DHCPv6 server.

    See `DHCPServer`.
    """

    descriptive_name = "DHCPv6"
    template_basename = "dhcpd6.conf.template"
    interfaces_filename = get_maas_data_path(DHCPv6_INTERFACES_FILE)
    config_filename = get_maas_data_path(DHCPv6_CONFIG_FILE)
    dhcp_service = "dhcpd6"
    ipv6 = True
Esempio n. 2
0
 def test_can_write_file_in_development(self):
     filename = get_maas_data_path("dhcpd.conf")
     contents = factory.make_bytes()  # Binary safe.
     mode = random.randint(0o000, 0o777) | 0o400  # Always u+r.
     sudo_write_file(filename, contents, mode)
     self.assertThat(filename, FileContains(contents))
     self.assertThat(os.stat(filename).st_mode & 0o777, Equals(mode))
Esempio n. 3
0
    def _makeTFTPService(self, tftp_root, tftp_port, rpc_service):
        """Create the dynamic TFTP service."""
        from provisioningserver.rackdservices.tftp import TFTPService

        tftp_service = TFTPService(resource_root=tftp_root,
                                   port=tftp_port,
                                   client_service=rpc_service)
        tftp_service.setName("tftp")

        # *** EXPERIMENTAL ***
        # https://code.launchpad.net/~allenap/maas/tftp-offload/+merge/312146
        # If the TFTP port has been set to zero, use the experimental offload
        # service. Otherwise stick to the normal in-process TFTP service.
        if tftp_port == 0:
            from provisioningserver.path import get_maas_data_path
            from provisioningserver.rackdservices import tftp_offload
            from twisted.internet.endpoints import UNIXServerEndpoint

            tftp_offload_socket = get_maas_data_path("tftp-offload.sock")
            tftp_offload_endpoint = UNIXServerEndpoint(reactor,
                                                       tftp_offload_socket,
                                                       wantPID=False)
            tftp_offload_service = tftp_offload.TFTPOffloadService(
                reactor, tftp_offload_endpoint, tftp_service.backend)
            tftp_offload_service.setName("tftp-offload")
            return tftp_offload_service
        # *** /EXPERIMENTAL ***

        return tftp_service
Esempio n. 4
0
def get_config_v4(
    template_name: str,
    global_dhcp_snippets: Sequence[dict],
    failover_peers: Sequence[dict],
    shared_networks: Sequence[dict],
    hosts: Sequence[dict],
    omapi_key: str,
) -> str:
    """Return a DHCP config file based on the supplied parameters.

    :param template_name: Template file name: `dhcpd.conf.template` for the
        IPv4 template.
    :return: A full configuration, as a string.
    """
    platform_codename = lsb_release()["codename"]
    template = load_template("dhcp", template_name)
    dhcp_socket = get_maas_data_path("dhcpd.sock")

    # Helper functions to stuff into the template namespace.
    helpers = {
        "oneline": normalise_whitespace,
        "commalist": normalise_any_iterable_to_comma_list,
        "quoted_commalist": normalise_any_iterable_to_quoted_comma_list,
        "running_in_snap": snappy.running_in_snap(),
    }

    for shared_network in shared_networks:
        interface = shared_network.get("interface", None)
        for subnet in shared_network["subnets"]:
            rack_ip = get_rack_ip_for_subnet(
                4, subnet["subnet_cidr"], interface
            )
            if rack_ip is not None:
                subnet["next_server"] = rack_ip
                subnet["bootloader"] = compose_conditional_bootloader(
                    False, rack_ip
                )
            ntp_servers = subnet["ntp_servers"]  # Is a list.
            ntp_servers_ipv4, ntp_servers_ipv6 = _get_addresses(*ntp_servers)
            subnet["ntp_servers_ipv4"] = ", ".join(ntp_servers_ipv4)
            subnet["ntp_servers_ipv6"] = ", ".join(ntp_servers_ipv6)

    try:
        return template.substitute(
            global_dhcp_snippets=global_dhcp_snippets,
            hosts=hosts,
            failover_peers=failover_peers,
            shared_networks=shared_networks,
            platform_codename=platform_codename,
            omapi_key=omapi_key,
            dhcp_helper=(get_path("/usr/sbin/maas-dhcp-helper")),
            dhcp_socket=dhcp_socket,
            **helpers
        )
    except (KeyError, NameError) as error:
        raise DHCPConfigError(
            "Failed to render DHCP configuration."
        ) from error
Esempio n. 5
0
class ClusterConfiguration(Configuration, metaclass=ClusterConfigurationMeta):
    """Local configuration for the MAAS cluster."""

    maas_url = ConfigurationOption(
        "maas_url",
        "The HTTP URL(s) for the MAAS region.",
        ForEach(
            ExtendedURL(require_tld=False),
            convert_to_list=True,
            if_missing=["http://localhost:5240/MAAS"],
        ),
    )

    # TFTP options.
    tftp_port = ConfigurationOption(
        "tftp_port",
        "The UDP port on which to listen for TFTP requests.",
        Number(min=0, max=(2 ** 16) - 1, if_missing=69),
    )
    tftp_root = ConfigurationOption(
        "tftp_root",
        "The root directory for TFTP resources.",
        DirectoryString(
            # Don't validate values that are already stored.
            accept_python=True,
            if_missing=get_maas_data_path("boot-resources/current"),
        ),
    )

    # GRUB options.

    @property
    def grub_root(self):
        "The root directory for GRUB resources."
        return os.path.join(self.tftp_root, "grub")

    # NodeGroup UUID Option, used for migrating to rack controller
    cluster_uuid = ConfigurationOption(
        "cluster_uuid",
        "The UUID for this cluster controller",
        UUIDString(if_missing=UUID_NOT_SET),
    )

    # Debug options.
    debug = ConfigurationOption(
        "debug",
        "Enable debug mode for detailed error and log reporting.",
        OneWayStringBool(if_missing=False),
    )
Esempio n. 6
0
def set_maas_id(system_id):
    """Set the system_id for this rack/region permanently for MAAS."""
    global _maas_id
    system_id = _normalise_maas_id(system_id)
    with _maas_id_lock:
        maas_id_path = get_maas_data_path("maas_id")
        if system_id is None:
            try:
                atomic_delete(maas_id_path)
            except FileNotFoundError:
                _maas_id = None  # Job done already.
            else:
                _maas_id = None
        else:
            atomic_write(system_id.encode("ascii"), maas_id_path)
            _maas_id = system_id
Esempio n. 7
0
 def setUp(self):
     """Ensures each test starts cleanly, with no pre-existing secret."""
     get_secret = self.patch(security, "get_shared_secret_filesystem_path")
     # Ensure each test uses a different filename for the shared secret,
     # so that tests cannot interfere with each other.
     get_secret.return_value = Path(
         get_maas_data_path("secret-%s" % factory.make_string(16)))
     # Extremely unlikely, but just in case.
     self.delete_secret()
     self.addCleanup(
         setattr,
         security,
         "DEFAULT_ITERATION_COUNT",
         security.DEFAULT_ITERATION_COUNT,
     )
     # The default high iteration count would make the tests very slow.
     security.DEFAULT_ITERATION_COUNT = 2
     super().setUp()
Esempio n. 8
0
def get_maas_id():
    """Return the system_id for this rack/region controller that is created
    when either the rack or region first starts.
    """
    global _maas_id
    with _maas_id_lock:
        if _maas_id is None:
            maas_id_path = get_maas_data_path("maas_id")
            try:
                with open(maas_id_path, "r", encoding="ascii") as fp:
                    contents = fp.read().strip()
            except FileNotFoundError:
                return None
            else:
                _maas_id = _normalise_maas_id(contents)
                return _maas_id
        else:
            return _maas_id
Esempio n. 9
0
def toggle_cprofile(process_name, signum=None, stack=None):
    """Toggle cProfile profiling of the process.

    If it's called when no profiling is enabled, profiling will start.

    If it's called when profiling is enabled, profiling is stopped and
    the stats are written to $MAAS_DATA/profiling, with the
    process name and pid in the name.
    """
    global _profile
    if _profile is None:
        _profile = cProfile.Profile()
        _profile.enable()
        print("Profiling enabled")
    else:
        current_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
        profiling_dir = get_maas_data_path("profiling")
        os.makedirs(profiling_dir, exist_ok=True)
        output_filename = f"{process_name}-{os.getpid()}-{current_time}.pyprof"
        full_filepath = os.path.join(profiling_dir, output_filename)
        _profile.create_stats()
        _profile.dump_stats(full_filepath)
        _profile = None
        print(f"Profiling disabled. Output written to {full_filepath}")
Esempio n. 10
0
def get_maas_user_gpghome():
    """Return the GPG directory for the `maas` user.

    Set $GPGHOME to this value ad-hoc when needed.
    """
    return get_maas_data_path("gnupg")
Esempio n. 11
0
 def setUp(self):
     super().setUp()
     self.maas_id_path = get_maas_data_path("maas_id")
     self.addCleanup(env.set_maas_id, None)
     env.set_maas_id(None)
Esempio n. 12
0
def get_shared_secret_filesystem_path():
    """Return the path to shared-secret on the filesystem."""
    return get_maas_data_path("secret")
Esempio n. 13
0
 def test_can_delete_file_in_development(self):
     filename = get_maas_data_path("dhcpd.conf")
     with open(filename, "wb") as fd:
         fd.write(factory.make_bytes())
     sudo_delete_file(filename)
     self.assertThat(filename, Not(FileExists()))
Esempio n. 14
0
def get_ipc_socket_path():
    """Return the path to the IPC socket."""
    return os.environ.get("MAAS_IPC_SOCKET_PATH",
                          get_maas_data_path("maas-regiond.sock"))
Esempio n. 15
0
def get_socket_path():
    """Return path to dhcpd.sock."""
    return get_maas_data_path("dhcpd.sock")
Esempio n. 16
0
 def test_get_maas_data_path_env(self):
     path = os.environ.get("MAAS_DATA")
     self.assertEqual(get_maas_data_path("some/path"),
                      os.path.join(path, "some/path"))
Esempio n. 17
0
 def test_get_maas_data_path_no_env(self):
     del os.environ["MAAS_DATA"]
     self.assertEqual(get_maas_data_path("some/path"),
                      "/var/lib/maas/some/path")