コード例 #1
0
ファイル: test_utils.py プロジェクト: th3architect/maas
 def test_data_values_override_defaults(self):
     key = factory.make_name("key")
     defaults = {key: factory.make_name("key")}
     data_value = factory.make_name("value")
     data = {key: data_value}
     results = get_overridden_query_dict(defaults, data, [key])
     self.assertEqual([data_value], results.getlist(key))
コード例 #2
0
ファイル: test_utils.py プロジェクト: th3architect/maas
 def test_returns_QueryDict(self):
     fields = [factory.make_name("field")]
     defaults = {fields[0]: factory.make_name("field")}
     results = get_overridden_query_dict(defaults, QueryDict(""), fields)
     expected_results = QueryDict("").copy()
     expected_results.update(defaults)
     self.assertEqual(expected_results, results)
コード例 #3
0
ファイル: test_utils.py プロジェクト: th3architect/maas
 def test_querydict_data_values_override_defaults(self):
     key = factory.make_name("key")
     defaults = {key: factory.make_name("name")}
     data_values = [factory.make_name("value") for _ in range(2)]
     data = QueryDict("").copy()
     data.setlist(key, data_values)
     results = get_overridden_query_dict(defaults, data, [key])
     self.assertEqual(data_values, results.getlist(key))
コード例 #4
0
ファイル: test_utils.py プロジェクト: th3architect/maas
 def test_fields_filter_results(self):
     key1 = factory.make_string()
     key2 = factory.make_string()
     defaults = {key1: factory.make_string(), key2: factory.make_string()}
     data_value1 = factory.make_string()
     data_value2 = factory.make_string()
     data = {key1: data_value1, key2: data_value2}
     results = get_overridden_query_dict(defaults, data, [key1])
     self.assertEqual([data_value2], results.getlist(key2))
コード例 #5
0
ファイル: nodes.py プロジェクト: ocni-dtu/maas
def create_node(
    architecture,
    power_type,
    power_parameters,
    mac_addresses,
    domain=None,
    hostname=None,
):
    """Create a new `Node` and return it.

    :param architecture: The architecture of the new node.
    :param power_type: The power type of the new node.
    :param power_parameters: A JSON-encoded string of power parameters
        for the new node.
    :param mac_addresses: An iterable of MAC addresses that belong to
        the node.
    :param domain: The domain the node should join.
    :param hostname: the desired hostname for the new node
    """
    # Check that there isn't already a node with one of our MAC
    # addresses, and bail out early if there is.
    nodes = Node.objects.filter(interface__mac_address__in=mac_addresses)
    if nodes.count() > 0:
        raise NodeAlreadyExists(
            "One of the MACs %s is already in use by a node." % mac_addresses
        )

    # It is possible that the enlistment code did not provide a subarchitecture
    # for the give architecture; assume 'generic'.
    if "/" not in architecture:
        architecture = "%s/generic" % architecture

    data = {
        "power_type": power_type,
        "power_parameters": power_parameters,
        "architecture": architecture,
        "mac_addresses": mac_addresses,
    }

    if domain is not None:
        data["domain"] = domain

    if hostname is not None:
        data["hostname"] = hostname.strip()

    data_query_dict = get_overridden_query_dict(
        {}, data, AdminMachineWithMACAddressesForm.Meta.fields
    )
    form = AdminMachineWithMACAddressesForm(data_query_dict)
    if form.is_valid():
        node = form.save()
        return node
    else:
        raise ValidationError(form.errors)
コード例 #6
0
ファイル: test_utils.py プロジェクト: th3architect/maas
 def test_expands_dict_fields(self):
     field_name = factory.make_name("field_name")
     sub_fields = {
         factory.make_name("sub_field"): CharField()
         for _ in range(3)
     }
     fields = {field_name: DictCharField(sub_fields)}
     defaults = {
         "%s_%s" % (field_name, field): factory.make_name("subfield")
         for field in sub_fields.keys()
     }
     data = {field_name: DictCharField(fields)}
     results = get_overridden_query_dict(defaults, data, fields)
     expected = {key: Equals(value) for key, value in defaults.items()}
     expected.update({
         name: IsInstance(value.__class__)
         for name, value in fields.items()
     })
     self.assertThat(results, MatchesDict(expected))
コード例 #7
0
    def query(self, request):
        """@description-title List node events
        @description List node events, optionally filtered by various criteria
        via URL query parameters.

        @param (string) "hostname" [required=false] An optional hostname. Only
        events relating to the node with the matching hostname will be
        returned. This can be specified multiple times to get events relating
        to more than one node.

        @param (string) "mac_address" [required=false] An optional list of MAC
        addresses.  Only nodes with matching MAC addresses will be returned.

        @param (string) "id" [required=false] An optional list of system ids.
        Only nodes with matching system ids will be returned.

        @param (string) "zone" [required=false] An optional name for a physical
        zone. Only nodes in the zone will be returned.

        @param (string) "agent_name" [required=false] An optional agent name.
        Only nodes with matching agent names will be returned.

        @param (string) "level" [required=false] Desired minimum log level of
        returned events. Returns this level of events and greater. Choose from:
        %(log_levels)s.  The default is INFO.

        @param (string) "limit" [required=false] Optional number of events to
        return. Default 100.  Maximum: 1000.

        @param (string) "before" [required=false] Optional event id.  Defines
        where to start returning older events.

        @param (string) "after" [required=false] Optional event id.  Defines
        where to start returning newer events.

        @param (string) "owner" [required=false] If specified, filters the list
        to show only events owned by the specified username.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing a list of
        events objects.
        @success-example "success-json" [exkey=events-query] placeholder text
        """
        # Extract & validate optional parameters from the request.
        after = get_optional_param(request.GET, 'after', None, Int)
        before = get_optional_param(request.GET, 'before', None, Int)
        level = get_optional_param(request.GET, 'level', 'INFO')
        limit = get_optional_param(
            request.GET, "limit", DEFAULT_EVENT_LOG_LIMIT, Int)
        owner = get_optional_param(request.GET, 'owner', default=None)

        # Limit what we'll return to avoid being swamped.
        if limit > MAX_EVENT_LOG_COUNT:
            raise MAASAPIBadRequest((
                "Requested number of events %d is greater than"
                " limit: %d") % (limit, MAX_EVENT_LOG_COUNT))
        else:
            # The limit should never be less than 1.
            limit = 1 if limit < 1 else limit

        # Filter first by optional node ID, hostname, MAC, etc.
        nodes = filtered_nodes_list_from_request(request)
        # Event lists aren't supported on devices.
        nodes = nodes.exclude(node_type=NODE_TYPE.DEVICE)

        # Check first for AUDIT level.
        if level == LOGGING_LEVELS[AUDIT]:
            events = Event.objects.filter(type__level=AUDIT)
        elif level in LOGGING_LEVELS_BY_NAME:
            events = Event.objects.filter(node__in=nodes)
            # Eliminate logs below the requested level.
            events = events.exclude(
                type__level__lt=LOGGING_LEVELS_BY_NAME[level])
        elif level is not None:
            raise MAASAPIBadRequest(
                "Unrecognised log level: %s" % level)

        events = (
            events.all()
            .select_related('type')
            .select_related('node'))

        # Filter events for owner.
        if owner is not None:
            events = events.filter(username=owner)

        # Future feature:
        # This is where we would filter for events 'since last node deployment'
        # using a query param like since_last_deployed=true, but we aren't
        # right now because we don't currently record a timestamp of the last
        # deployment, and we don't have an event subtype for node status
        # changes to filter for the deploying status event.

        if after is None and before is None:
            # Get `limit` events, newest first.
            events = events.order_by('-id')
            events = events[:limit]
        elif after is None:
            # Get `limit` events, newest first, all before `before`.
            events = events.filter(id__lt=before)
            events = events.order_by('-id')
            events = events[:limit]
        elif before is None:
            # Get `limit` events, OLDEST first, all after `after`, then
            # reverse the results.
            events = events.filter(id__gt=after)
            events = events.order_by('id')
            events = reversed(events[:limit])
        else:
            raise MAASAPIBadRequest(
                "There is undetermined behaviour when both "
                "`after` and `before` are specified.")

        # We need to load all of these events at some point, so save them
        # into a list now so that len() is cheap.
        events = list(events)

        # Helper for building prev_uri and next_uri.
        def make_uri(params, base=reverse('events_handler')):
            query = urllib.parse.urlencode(params, doseq=True)
            url = urllib.parse.urlparse(base)._replace(query=query)
            return url.geturl()

        # Figure out a URI to obtain a set of newer events.
        next_uri_params = get_overridden_query_dict(
            request.GET, {"before": []}, self.all_params)
        if len(events) == 0:
            if before is None:
                # There are no newer events NOW, but there may be later.
                next_uri = make_uri(next_uri_params)
            else:
                # Without limiting to `before`, we might find some more events.
                next_uri_params["after"] = before - 1
                next_uri = make_uri(next_uri_params)
        else:
            # The first event is the newest.
            next_uri_params["after"] = str(events[0].id)
            next_uri = make_uri(next_uri_params)

        # Figure out a URI to obtain a set of older events.
        prev_uri_params = get_overridden_query_dict(
            request.GET, {"after": []}, self.all_params)
        if len(events) == 0:
            if after is None:
                # There are no older events and never will be.
                prev_uri = None
            else:
                # Without limiting to `after`, we might find some more events.
                prev_uri_params["before"] = after + 1
                prev_uri = make_uri(prev_uri_params)
        else:
            # The last event is the oldest.
            prev_uri_params["before"] = str(events[-1].id)
            prev_uri = make_uri(prev_uri_params)

        return {
            "count": len(events),
            "events": [event_to_dict(event) for event in events],
            "next_uri": next_uri,
            "prev_uri": prev_uri,
        }
コード例 #8
0
 def __init__(self, dict, fields, user=None):
     if user is None:
         user = factory.make_User()
     self.user = user
     self.GET = get_overridden_query_dict(dict, QueryDict(""), fields)
コード例 #9
0
 def __init__(self, dict, fields):
     self.user = factory.make_User()
     self.GET = get_overridden_query_dict(dict, QueryDict(''), fields)
コード例 #10
0
ファイル: test_utils.py プロジェクト: th3architect/maas
 def test_takes_multiple_values_in_default_parameters(self):
     values = [factory.make_name("value") for _ in range(2)]
     key = factory.make_name("key")
     defaults = {key: values}
     results = get_overridden_query_dict(defaults, {}, [key])
     self.assertEqual(values, results.getlist(key))