Пример #1
0
 def test_set_maas_url_accepts_very_short_hostnames(self):
     config = RegionConfiguration({})
     example_url = factory.make_simple_http_url(netloc=factory.make_string(
         size=1))
     config.maas_url = example_url
     self.assertEqual(example_url, config.maas_url)
     self.assertEqual({"maas_url": example_url}, config.store)
Пример #2
0
 def test__set_and_get(self):
     config = RegionConfiguration({})
     workers = random.randint(8, 12)
     config.num_workers = workers
     self.assertEqual(workers, config.num_workers)
     # It's also stored in the configuration database.
     self.assertEqual({"num_workers": workers}, config.store)
Пример #3
0
 def test_set_and_get_maas_url(self):
     config = RegionConfiguration({})
     example_url = factory.make_simple_http_url()
     config.maas_url = example_url
     self.assertEqual(example_url, config.maas_url)
     # It's also stored in the configuration database.
     self.assertEqual({"maas_url": example_url}, config.store)
Пример #4
0
 def test_set_maas_url_accepts_ipv6_addresses_with_brackets(self):
     config = RegionConfiguration({})
     example_url = factory.make_simple_http_url(netloc="[%s]" %
                                                factory.make_ipv6_address())
     config.maas_url = example_url
     self.assertEqual(example_url, config.maas_url)
     self.assertEqual({"maas_url": example_url}, config.store)
Пример #5
0
def global_options(request):
    version = get_maas_version_ui()
    uuid = RegionController.objects.get_or_create_uuid()
    with RegionConfiguration.open() as config:
        maas_url = config.maas_url
    user_completed_intro = False
    if hasattr(request.user, 'userprofile'):
        user_completed_intro = request.user.userprofile.completed_intro
    if request.user.is_authenticated:
        analytics_user_id = '%s-user%d' % (uuid, request.user.id)
    else:
        analytics_user_id = '%s-anon' % uuid
    return {
        'global_options': {
            'site_name': Config.objects.get_config('maas_name'),
            'enable_analytics': Config.objects.get_config('enable_analytics'),
        },
        'debug': settings.DEBUG,
        'version': version,
        'files_version': version.replace(" ", ""),
        'doc_version': get_maas_doc_version(),
        'register_url': maas_url,
        'register_secret': Config.objects.get_config('rpc_shared_secret'),
        'completed_intro': Config.objects.get_config('completed_intro'),
        'user_completed_intro': user_completed_intro,
        'analytics_user_id': analytics_user_id,
        'maas_uuid': uuid
    }
Пример #6
0
def absolute_url_reverse(view_name, query=None, *args, **kwargs):
    """Returns the absolute path (i.e. starting with '/') for the given view.

    This utility is meant to be used by methods that need to compute URLs but
    run outside of Django and thus don't have the 'script prefix' transparently
    added the the URL.

    :param view_name: Django's view function name/reference or URL pattern
        name for which to compute the absolute URL.
    :param query: Optional query argument which will be passed down to
        urllib.urlencode.  The result of that call will be appended to the
        resulting url.
    :param args: Positional arguments for Django's 'reverse' method.
    :param kwargs: Named arguments for Django's 'reverse' method.
    """
    with RegionConfiguration.open() as config:
        abs_path = urlparse(config.maas_url).path
    if not abs_path.endswith('/'):
        # Add trailing '/' to get urljoin to behave.
        abs_path = abs_path + '/'
    reverse_link = reverse(view_name, *args, **kwargs)
    if reverse_link.startswith('/'):
        # Drop the leading '/'.
        reverse_link = reverse_link[1:]
    url = urljoin(abs_path, reverse_link)
    if query is not None:
        url += '?%s' % urlencode(query, doseq=True)
    return url
Пример #7
0
def absolute_reverse(view_name,
                     default_region_ip=None,
                     query=None,
                     base_url=None,
                     *args,
                     **kwargs):
    """Return the absolute URL (i.e. including the URL scheme specifier and
    the network location of the MAAS server).  Internally this method simply
    calls Django's 'reverse' method and prefixes the result of that call with
    the configured MAAS URL.

    Consult the 'maas-region local_config_set --default-url' command for
    details on how to set the MAAS URL.

    :param view_name: Django's view function name/reference or URL pattern
        name for which to compute the absolute URL.
    :param default_region_ip: The default source IP address that should be
        used for the region controller.
    :param query: Optional query argument which will be passed down to
        urllib.urlencode.  The result of that call will be appended to the
        resulting url.
    :param base_url: Optional url used as base.  If None is provided, then
        configured MAAS URL will be used.
    :param args: Positional arguments for Django's 'reverse' method.
    :param kwargs: Named arguments for Django's 'reverse' method.
    """
    if not base_url:
        with RegionConfiguration.open() as config:
            base_url = config.maas_url
        if default_region_ip is not None:
            base_url = compose_URL(base_url, default_region_ip)
    url = urljoin(base_url, reverse(view_name, *args, **kwargs))
    if query is not None:
        url += '?%s' % urlencode(query, doseq=True)
    return url
Пример #8
0
 def test__dumps_plain_string_to_stdout(self):
     stdio = call_get(**{self.option: True, "dump": config.dump_plain})
     settings = stdio.getOutput()
     self.assertThat(settings, Not(Contains(self.option)))
     with RegionConfiguration.open() as configuration:
         self.assertThat(settings,
                         Contains(str(getattr(configuration, self.option))))
Пример #9
0
    def test__options_are_saved(self):
        self.useFixture(RegionConfigurationFixture())
        # Set the option to a random value.
        if self.option == "database_port":
            value = factory.pick_port()
        elif self.option == "database_conn_max_age":
            value = random.randint(0, 60)
        elif self.option == "num_workers":
            value = random.randint(1, 16)
        elif self.option in ["debug", "debug_queries"]:
            value = random.choice(['true', 'false'])
        else:
            value = factory.make_name("foobar")

        # Values are coming from the command-line so stringify.
        stdio = call_set(**{self.option: str(value)})

        # Nothing is echoed back to the user.
        self.assertThat(stdio.getOutput(), Equals(""))
        self.assertThat(stdio.getError(), Equals(""))

        # Some validators alter the given option, like adding an HTTP scheme
        # to a "bare" URL, so we merely check that the value contains the
        # given value, not that it exactly matches. Values are converted to a
        # str so Contains works with int values.
        with RegionConfiguration.open() as configuration:
            self.assertThat(str(getattr(configuration, self.option)),
                            Contains(str(value)))
Пример #10
0
def inner_start_up(master=False):
    """Startup jobs that must run serialized w.r.t. other starting servers."""
    # Register our MAC data type with psycopg.
    register_mac_type(connection.cursor())

    # All commissioning and testing scripts are stored in the database. For
    # a commissioning ScriptSet to be created Scripts must exist first. Call
    # this early, only on the master process, to ensure they exist and are
    # only created once. If get_or_create_running_controller() is called before
    # this it will fail on first run.
    if master:
        load_builtin_scripts()

    # Ensure the this region is represented in the database. The first regiond
    # to pass through inner_start_up on this host can do this; it should NOT
    # be restricted to masters only. This also ensures that the MAAS ID is set
    # on the filesystem; it will be done in a post-commit hook and will thus
    # happen before `locks.startup` is released.
    node = RegionController.objects.get_or_create_running_controller()
    # Update region version
    ControllerInfo.objects.set_version(node, get_running_version())
    # Ensure that uuid is created after creating
    RegionController.objects.get_or_create_uuid()

    # Only perform the following if the master process for the
    # region controller.
    if master:
        # Freshen the kms SRV records.
        dns_kms_setting_changed()

        # Make sure the commissioning distro series is still a supported LTS.
        commissioning_distro_series = Config.objects.get_config(
            name="commissioning_distro_series"
        )
        ubuntu = UbuntuOS()
        if commissioning_distro_series not in (
            ubuntu.get_supported_commissioning_releases()
        ):
            Config.objects.set_config(
                "commissioning_distro_series",
                ubuntu.get_default_commissioning_release(),
            )
            Notification.objects.create_info_for_admins(
                "Ubuntu %s is no longer a supported commissioning "
                "series. Ubuntu %s has been automatically selected."
                % (
                    commissioning_distro_series,
                    ubuntu.get_default_commissioning_release(),
                ),
                ident="commissioning_release_deprecated",
            )

        with RegionConfiguration.open() as config:
            Config.objects.set_config("maas_url", config.maas_url)

        # Update deprecation notifications if needed
        sync_deprecation_notifications()
Пример #11
0
 def handle(self, *args, **options):
     with RegionConfiguration.open() as config:
         output = {
             name: getattr(config, name)
             for name, option in gen_configuration_options()
             if options.get(name)
         }
     dump = options["dump"]
     dump(output)
Пример #12
0
 def test__set_and_get(self):
     config = RegionConfiguration({})
     example_value = random.choice(["true", "yes", "True"])
     # Argument values will most often be passed in from the command-line,
     # so convert to a string before use to reflect that usage.
     setattr(config, self.option, example_value)
     self.assertTrue(getattr(config, self.option))
     # It's also stored in the configuration database.
     self.assertEqual({self.option: True}, config.store)
Пример #13
0
 def test_register_info(self):
     admin = factory.make_admin()
     handler = ControllerHandler(admin, {}, None)
     observed = handler.register_info({})
     rpc_shared_secret = Config.objects.get_config("rpc_shared_secret")
     with RegionConfiguration.open() as config:
         maas_url = config.maas_url
     self.assertEqual(
         {"url": maas_url, "secret": rpc_shared_secret}, observed
     )
Пример #14
0
 def handle(self, *args, **options):
     with RegionConfiguration.open_for_update() as config:
         for name, option in gen_configuration_options():
             value = options.get(name)
             if value is not None:
                 try:
                     setattr(config, name, value)
                 except formencode.Invalid as error:
                     message = str(error).rstrip(".")
                     raise CommandError("%s: %s." %
                                        (name.replace("_", "-"), message))
Пример #15
0
 def test__set_and_get(self):
     config = RegionConfiguration({})
     if isinstance(getattr(config, self.option), str):
         example_value = factory.make_name(self.option)
     else:
         example_value = factory.pick_port()
     # Argument values will most often be passed in from the command-line,
     # so convert to a string before use to reflect that usage.
     setattr(config, self.option, str(example_value))
     self.assertEqual(example_value, getattr(config, self.option))
     # It's also stored in the configuration database.
     self.assertEqual({self.option: example_value}, config.store)
Пример #16
0
def absolute_reverse(
    view_name,
    default_region_ip=None,
    query=None,
    base_url=None,
    *args,
    **kwargs,
):
    """Return the absolute URL (i.e. including the URL scheme specifier and
    the network location of the MAAS server).  Internally this method simply
    calls Django's 'reverse' method and prefixes the result of that call with
    the configured MAAS URL.

    Consult the 'maas-region local_config_set --default-url' command for
    details on how to set the MAAS URL.

    :param view_name: Django's view function name/reference or URL pattern
        name for which to compute the absolute URL.
    :param default_region_ip: The default source IP address that should be
        used for the region controller.
    :param query: Optional query argument which will be passed down to
        urllib.urlencode.  The result of that call will be appended to the
        resulting url.
    :param base_url: Optional url used as base.  If None is provided, then
        configured MAAS URL will be used.
    :param args: Positional arguments for Django's 'reverse' method.
    :param kwargs: Named arguments for Django's 'reverse' method.
    """
    if not base_url:
        with RegionConfiguration.open() as config:
            base_url = config.maas_url
        if default_region_ip is not None:
            base_url = compose_URL(base_url, default_region_ip)
    if not base_url.endswith("/"):
        # Add trailing '/' to get urljoin to behave.
        base_url = base_url + "/"
    if view_name.startswith("/"):
        reverse_link = view_name
    else:
        reverse_link = reverse(view_name, *args, **kwargs)
    if reverse_link.startswith("/"):
        # Drop the leading '/'.
        reverse_link = reverse_link[1:]
    script_name = settings.FORCE_SCRIPT_NAME.lstrip("/")
    if base_url.endswith(script_name) and reverse_link.startswith(script_name):
        # This would double up the SCRIPT_NAME we only need one so remove the
        # prefix from the reverse_link.
        reverse_link = reverse_link[len(script_name):]
    url = urljoin(base_url, reverse_link)
    if query is not None:
        url += "?%s" % urlencode(query, doseq=True)
    return url
Пример #17
0
    def register_info(self, params):
        """Return the registration info for a new controller.

        User must be a superuser to perform this action.
        """
        if not self.user.is_superuser:
            raise HandlerPermissionError()

        rpc_shared_secret = Config.objects.get_config("rpc_shared_secret")
        with RegionConfiguration.open() as config:
            maas_url = config.maas_url

        return {"url": maas_url, "secret": rpc_shared_secret}
Пример #18
0
def get_maas_facing_server_host(rack_controller=None):
    """Return configured MAAS server hostname, for use by nodes or workers.

    :param rack_controller: The `RackController` from the point of view of
        which the server host should be computed.
    :return: Hostname or IP address, as configured in the MAAS URL config
        setting or as configured on rack_controller.url.
    """
    if rack_controller is None or not rack_controller.url:
        with RegionConfiguration.open() as config:
            maas_url = config.maas_url
    else:
        maas_url = rack_controller.url
    return urlparse(maas_url).hostname
Пример #19
0
def run():
    """Run the maas-regiond master service.

    Spawns children workers up to the number of CPU's minimum is 4 workers.
    """
    args = parse()

    # Remove all the command line arguments, so they don't interfere with
    # the twistd argument parser.
    sys.argv = sys.argv[:1]

    # Workers are spawned with environment so it knows that it would only
    # be a worker.
    if os.environ.get("MAAS_REGIOND_PROCESS_MODE") == "worker":
        # Ignore interrupt on the workers. The master will kill them directly.
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        runWorkerServices()
        return

    # Circular imports.
    from maasserver.workers import set_max_workers_count

    # Debug mode, run the all-in-one mode.
    if args.debug:
        set_max_workers_count(1)
        runAllInOneServices()
        return

    # Calculate the number of workers.
    worker_count = args.workers
    if not worker_count:
        from maasserver.config import RegionConfiguration

        try:
            with RegionConfiguration.open() as config:
                worker_count = config.num_workers
        except Exception:
            worker_count = 4
    if worker_count <= 0:
        raise ValueError("Number of workers must be greater than zero.")

    # Set the maximum number of workers.
    set_max_workers_count(worker_count)

    # Start the master services, which will spawn the required workers.
    runMasterServices()
Пример #20
0
 def test__options_are_reset(self):
     self.useFixture(RegionConfigurationFixture())
     with RegionConfiguration.open_for_update() as configuration:
         # Give the option a random value.
         if isinstance(getattr(configuration, self.option), str):
             value = factory.make_name("foobar")
         else:
             value = factory.pick_port()
         setattr(configuration, self.option, value)
     stdio = call_reset(**{self.option: True})
     # Nothing is echoed back to the user.
     self.assertThat(stdio.getOutput(), Equals(""))
     self.assertThat(stdio.getError(), Equals(""))
     # There is no custom value in the configuration file.
     with open(RegionConfiguration.DEFAULT_FILENAME, "rb") as fd:
         settings = yaml.safe_load(fd)
     self.assertThat(settings, Equals({}))
Пример #21
0
def get_maas_facing_server_host(rack_controller=None, default_region_ip=None):
    """Return configured MAAS server hostname, for use by nodes or workers.

    :param rack_controller: The `RackController` from the point of view of
        which the server host should be computed.
    :param default_region_ip: The default source IP address to be used, if a
        specific URL is not defined.
    :return: Hostname or IP address, as configured in the MAAS URL config
        setting or as configured on rack_controller.url.
    """
    if rack_controller is None or not rack_controller.url:
        if default_region_ip is not None:
            return default_region_ip
        with RegionConfiguration.open() as config:
            maas_url = config.maas_url
    else:
        maas_url = rack_controller.url
    return urlparse(maas_url).hostname
Пример #22
0
 def test__set_and_get(self):
     config = RegionConfiguration({})
     if isinstance(getattr(config, self.option), str):
         example_value = factory.make_name(self.option)
     elif self.option == "database_keepalive":
         example_value = random.choice([True, False])
     else:
         example_value = factory.pick_port()
     # Argument values will most often be passed in from the command-line,
     # so convert to a string before use to reflect that usage.
     setattr(config, self.option, str(example_value))
     self.assertEqual(example_value, getattr(config, self.option))
     # It's also stored in the configuration database.
     expected_value = example_value
     if example_value == "true":
         expected_value = True
     elif expected_value == "false":
         expected_value = False
     self.assertEqual({self.option: expected_value}, config.store)
Пример #23
0
 def test_dns_config_has_NS_record(self):
     self.patch(settings, "DNS_CONNECT", True)
     ip = factory.make_ipv4_address()
     with RegionConfiguration.open_for_update() as config:
         config.maas_url = "http://%s/" % ip
     domain = factory.make_Domain()
     node, static = self.create_node_with_static_ip(domain=domain)
     dns_update_all_zones()
     # Creating the domain triggered writing the zone file and updating the
     # DNS.
     self.dns_wait_soa(domain.name)
     # Get the NS record for the zone 'domain.name'.
     ns_record = dig_call(port=self.bind.config.port,
                          commands=[domain.name, "NS", "+short"])
     self.assertGreater(len(ns_record), 0, "No NS record for domain.name.")
     # Resolve that hostname.
     self.dns_wait_soa(ns_record)
     ip_of_ns_record = dig_call(port=self.bind.config.port,
                                commands=[ns_record, "+short"])
     self.assertEqual(ip, ip_of_ns_record)
Пример #24
0
def global_options(request):
    version = get_maas_version_ui()
    uuid = RegionController.objects.get_or_create_uuid()
    with RegionConfiguration.open() as config:
        maas_url = config.maas_url
    configs = Config.objects.get_configs([
        "maas_name",
        "enable_analytics",
        "rpc_shared_secret",
        "completed_intro",
    ])
    user_completed_intro = False
    completed_intro = configs["completed_intro"]
    if not hasattr(request, "user"):
        return {}
    if hasattr(request.user, "userprofile"):
        user_completed_intro = request.user.userprofile.completed_intro
    if not completed_intro and not request.user.is_superuser:
        # Only administrators can completed the main intro, normal users
        # cannot complete it so to them it has been done.
        completed_intro = True
    if request.user.is_authenticated:
        analytics_user_id = "%s-user%d" % (uuid, request.user.id)
    else:
        analytics_user_id = "%s-anon" % uuid
    return {
        "global_options": {
            "site_name": configs["maas_name"],
            "enable_analytics": configs["enable_analytics"],
        },
        "debug": settings.DEBUG,
        "version": version,
        "files_version": version.replace(" ", ""),
        "doc_version": get_maas_doc_version(),
        "register_url": maas_url,
        "register_secret": configs["rpc_shared_secret"],
        "completed_intro": completed_intro,
        "user_completed_intro": user_completed_intro,
        "analytics_user_id": analytics_user_id,
        "maas_uuid": uuid,
    }
Пример #25
0
def global_options(request):
    version = get_maas_version_ui()
    with RegionConfiguration.open() as config:
        maas_url = config.maas_url
    user_completed_intro = False
    if hasattr(request.user, 'userprofile'):
        user_completed_intro = request.user.userprofile.completed_intro
    return {
        'global_options': {
            'site_name': Config.objects.get_config('maas_name'),
            'enable_analytics': Config.objects.get_config('enable_analytics'),
        },
        'debug': settings.DEBUG,
        'version': version,
        'files_version': version.replace(" ", ""),
        'doc_version': get_maas_doc_version(),
        'register_url': maas_url,
        'register_secret': Config.objects.get_config('rpc_shared_secret'),
        'completed_intro': Config.objects.get_config('completed_intro'),
        'user_completed_intro': user_completed_intro,
    }
Пример #26
0
def global_options(request):
    version = get_maas_version_ui()
    uuid = RegionController.objects.get_or_create_uuid()
    with RegionConfiguration.open() as config:
        maas_url = config.maas_url
    configs = Config.objects.get_configs([
        'maas_name', 'enable_analytics', 'rpc_shared_secret', 'completed_intro'
    ])
    user_completed_intro = False
    completed_intro = configs['completed_intro']
    if not hasattr(request, 'user'):
        return {}
    if hasattr(request.user, 'userprofile'):
        user_completed_intro = request.user.userprofile.completed_intro
    if not completed_intro and not request.user.is_superuser:
        # Only administrators can completed the main intro, normal users
        # cannot complete it so to them it has been done.
        completed_intro = True
    if request.user.is_authenticated:
        analytics_user_id = '%s-user%d' % (uuid, request.user.id)
    else:
        analytics_user_id = '%s-anon' % uuid
    return {
        'global_options': {
            'site_name': configs['maas_name'],
            'enable_analytics': configs['enable_analytics'],
        },
        'debug': settings.DEBUG,
        'version': version,
        'files_version': version.replace(" ", ""),
        'doc_version': get_maas_doc_version(),
        'register_url': maas_url,
        'register_secret': configs['rpc_shared_secret'],
        'completed_intro': completed_intro,
        'user_completed_intro': user_completed_intro,
        'analytics_user_id': analytics_user_id,
        'maas_uuid': uuid
    }
Пример #27
0
 def test__default(self):
     config = RegionConfiguration({})
     self.assertEqual(self.default, getattr(config, self.option))
Пример #28
0
 def test_set_maas_url_rejects_bare_ipv6_addresses(self):
     config = RegionConfiguration({})
     example_url = factory.make_simple_http_url(
         netloc=factory.make_ipv6_address())
     with ExpectedException(formencode.api.Invalid):
         config.maas_url = example_url
Пример #29
0
 def test_set_maas_url_accepts_hostnames(self):
     config = RegionConfiguration({})
     example_url = factory.make_simple_http_url()
     config.maas_url = example_url
     self.assertEqual(example_url, config.maas_url)
     self.assertEqual({"maas_url": example_url}, config.store)
Пример #30
0
 def test_default_database_conn_max_age(self):
     config = RegionConfiguration({})
     self.assertEqual(60 * 5, config.database_conn_max_age)