Example #1
0
 def test_POST_update_nodes_refuses_unidentified_rack_controller(self):
     tag = factory.make_Tag()
     rack_controller = factory.make_RackController()
     node = factory.make_Node()
     client = make_worker_client(rack_controller)
     # We don't pass rack controller system_id so we get refused.
     response = client.post(
         self.get_tag_uri(tag),
         {
             "op": "update_nodes",
             "add": [node.system_id]
         },
     )
     self.assertEqual(http.client.FORBIDDEN, response.status_code)
     self.assertItemsEqual([], tag.node_set.all())
Example #2
0
    def test_PUT_updates_tag(self):
        self.become_admin()
        tag = factory.make_Tag()
        # Note that 'definition' is not being sent
        response = self.client.put(
            self.get_tag_uri(tag),
            {"name": "new-tag-name", "comment": "A random comment"},
        )

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json.loads(response.content.decode("ascii"))
        self.assertEqual("new-tag-name", parsed_result["name"])
        self.assertEqual("A random comment", parsed_result["comment"])
        self.assertEqual(tag.definition, parsed_result["definition"])
        self.assertFalse(Tag.objects.filter(name=tag.name).exists())
        self.assertTrue(Tag.objects.filter(name="new-tag-name").exists())
Example #3
0
    def test_PUT_invalid_definition(self):
        self.become_admin()
        node = factory.make_Node()
        tag = factory.make_Tag(definition="//child")
        node.tags.add(tag)
        self.assertItemsEqual([tag.name], node.tag_names())
        response = self.client.put(
            self.get_tag_uri(tag),
            {"name": "bad tag", "definition": "invalid::tag"},
        )

        self.assertEqual(http.client.BAD_REQUEST, response.status_code)
        # The tag should not be modified
        tag = reload_object(tag)
        self.assertItemsEqual([tag.name], node.tag_names())
        self.assertEqual("//child", tag.definition)
Example #4
0
    def test_PUT_updates_tag(self):
        self.become_admin()
        tag = factory.make_Tag()
        # Note that 'definition' is not being sent
        response = self.client.put(self.get_tag_uri(tag), {
            'name': 'new-tag-name',
            'comment': 'A random comment'
        })

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json.loads(response.content.decode('ascii'))
        self.assertEqual('new-tag-name', parsed_result['name'])
        self.assertEqual('A random comment', parsed_result['comment'])
        self.assertEqual(tag.definition, parsed_result['definition'])
        self.assertFalse(Tag.objects.filter(name=tag.name).exists())
        self.assertTrue(Tag.objects.filter(name='new-tag-name').exists())
Example #5
0
 def test_POST_update_nodes_refuses_non_rack_controller(self):
     tag = factory.make_Tag()
     rack_controller = factory.make_RackController()
     node = factory.make_Node()
     token = create_auth_token(rack_controller.owner)
     token.save()
     creds = convert_tuple_to_string(get_creds_tuple(token))
     response = self.client.post(
         self.get_tag_uri(tag), {
             'op': 'update_nodes',
             'add': [node.system_id],
             'rack_controller': rack_controller.system_id,
             'credentials': creds,
         })
     self.assertEqual(http.client.FORBIDDEN, response.status_code)
     self.assertItemsEqual([], tag.node_set.all())
Example #6
0
    def test_GET_machines_query_count(self):
        # Patch middleware so it does not affect query counting.
        self.patch(
            middleware.ExternalComponentsMiddleware,
            "_check_rack_controller_connectivity",
        )

        tag = factory.make_Tag()
        for _ in range(3):
            machine = factory.make_Node_with_Interface_on_Subnet()
            machine.tags.add(tag)
        # XXX ltrager 2019-08-16 - Work around for LP:1840491
        Node.objects.update(boot_disk=None)
        num_queries1, response1 = count_queries(self.client.get,
                                                self.get_tag_uri(tag),
                                                {"op": "machines"})

        for _ in range(3):
            machine = factory.make_Node_with_Interface_on_Subnet()
            machine.tags.add(tag)
        # XXX ltrager 2019-08-16 - Work around for LP:1840491
        Node.objects.update(boot_disk=None)
        num_queries2, response2 = count_queries(self.client.get,
                                                self.get_tag_uri(tag),
                                                {"op": "machines"})

        # Make sure the responses are ok as it's not useful to compare the
        # number of queries if they are not.
        parsed_result_1 = json.loads(
            response1.content.decode(settings.DEFAULT_CHARSET))
        parsed_result_2 = json.loads(
            response2.content.decode(settings.DEFAULT_CHARSET))
        self.assertEqual(
            [http.client.OK, http.client.OK, 3, 6],
            [
                response1.status_code,
                response2.status_code,
                len(extract_system_ids(parsed_result_1)),
                len(extract_system_ids(parsed_result_2)),
            ],
        )

        # Because of fields `status_action`, `status_message`,
        # `default_gateways`, `health_status` and 'resource_pool', the number
        # of queries is not the same but it is proportional to the number of
        # machines.
        self.assertEquals(num_queries1, num_queries2 - (3 * 7))
Example #7
0
 def test_POST_update_nodes_ignores_unknown_nodes(self):
     tag = factory.make_Tag()
     self.become_admin()
     unknown_add_system_id = generate_node_system_id()
     unknown_remove_system_id = generate_node_system_id()
     self.assertItemsEqual([], tag.node_set.all())
     response = self.client.post(
         self.get_tag_uri(tag), {
             'op': 'update_nodes',
             'add': [unknown_add_system_id],
             'remove': [unknown_remove_system_id],
         })
     self.assertEqual(http.client.OK, response.status_code)
     parsed_result = json.loads(
         response.content.decode(settings.DEFAULT_CHARSET))
     self.assertItemsEqual([], tag.node_set.all())
     self.assertEqual({'added': 0, 'removed': 0}, parsed_result)
Example #8
0
    def test_GET_region_controllers_query_count(self):
        # Patch middleware so it does not affect query counting.
        self.patch(
            middleware.ExternalComponentsMiddleware,
            "_check_rack_controller_connectivity",
        )
        self.become_admin()

        tag = factory.make_Tag()
        for _ in range(3):
            region = factory.make_RegionController()
            region.tags.add(tag)
        num_queries1, response1 = count_queries(
            self.client.get,
            self.get_tag_uri(tag),
            {"op": "region_controllers"},
        )

        for _ in range(3):
            region = factory.make_RegionController()
            region.tags.add(tag)
        num_queries2, response2 = count_queries(
            self.client.get,
            self.get_tag_uri(tag),
            {"op": "region_controllers"},
        )

        # Make sure the responses are ok as it's not useful to compare the
        # number of queries if they are not.
        parsed_result_1 = json.loads(
            response1.content.decode(settings.DEFAULT_CHARSET)
        )
        parsed_result_2 = json.loads(
            response2.content.decode(settings.DEFAULT_CHARSET)
        )
        self.assertEqual(
            [http.client.OK, http.client.OK, 3, 6],
            [
                response1.status_code,
                response2.status_code,
                len(extract_system_ids(parsed_result_1)),
                len(extract_system_ids(parsed_result_2)),
            ],
        )
        self.assertEqual(num_queries1, num_queries2 - 6)
Example #9
0
 def test_POST_update_nodes_changes_associations(self):
     tag = factory.make_Tag()
     self.become_admin()
     node_first = factory.make_Node()
     node_second = factory.make_Node()
     node_first.tags.add(tag)
     self.assertItemsEqual([node_first], tag.node_set.all())
     response = self.client.post(
         self.get_tag_uri(tag), {
             'op': 'update_nodes',
             'add': [node_second.system_id],
             'remove': [node_first.system_id],
         })
     self.assertEqual(http.client.OK, response.status_code)
     parsed_result = json.loads(
         response.content.decode(settings.DEFAULT_CHARSET))
     self.assertItemsEqual([node_second], tag.node_set.all())
     self.assertEqual({'added': 1, 'removed': 1}, parsed_result)
Example #10
0
 def test_POST_update_nodes_ignores_incorrect_definition(self):
     tag = factory.make_Tag()
     orig_def = tag.definition
     rack_controller = factory.make_RackController()
     node = factory.make_Node()
     client = make_worker_client(rack_controller)
     tag.definition = '//new/node/definition'
     tag.save(populate=False)
     response = client.post(
         self.get_tag_uri(tag), {
             'op': 'update_nodes',
             'add': [node.system_id],
             'rack_controller': rack_controller.system_id,
             'definition': orig_def,
         })
     self.assertEqual(http.client.CONFLICT, response.status_code)
     self.assertItemsEqual([], tag.node_set.all())
     self.assertItemsEqual([], node.tags.all())
Example #11
0
    def test_GET_nodes_query_count(self):
        # Patch middleware so it does not affect query counting.
        self.patch(
            middleware.ExternalComponentsMiddleware,
            '_check_rack_controller_connectivity')

        tag = factory.make_Tag()
        for _ in range(3):
            machine = factory.make_Node_with_Interface_on_Subnet()
            machine.tags.add(tag)
        for _ in range(3):
            device = factory.make_Device()
            device.tags.add(tag)
        num_queries1, response1 = count_queries(
            self.client.get, self.get_tag_uri(tag), {'op': 'nodes'})

        for _ in range(3):
            machine = factory.make_Node_with_Interface_on_Subnet()
            machine.tags.add(tag)
        for _ in range(3):
            device = factory.make_Device()
            device.tags.add(tag)
        num_queries2, response2 = count_queries(
            self.client.get, self.get_tag_uri(tag), {'op': 'nodes'})

        # Make sure the responses are ok as it's not useful to compare the
        # number of queries if they are not.
        parsed_result_1 = json.loads(
            response1.content.decode(settings.DEFAULT_CHARSET))
        parsed_result_2 = json.loads(
            response2.content.decode(settings.DEFAULT_CHARSET))
        self.assertEqual(
            [http.client.OK, http.client.OK, 3, 6],
            [
                response1.status_code,
                response2.status_code,
                len(extract_system_ids(parsed_result_1)),
                len(extract_system_ids(parsed_result_2)),
            ])

        # Because of fields `status_action`, `status_message`,
        # `default_gateways`, and `health_status` the number of queries is not
        # the same but it is proportional to the number of machines.
        self.assertEquals(num_queries1, num_queries2 - (3 * 4))
Example #12
0
    def test_GET_devices_returns_devices(self):
        tag = factory.make_Tag()
        machine = factory.make_Node()
        device = factory.make_Device()
        rack = factory.make_RackController()
        region = factory.make_RegionController()
        # Create a second node that isn't tagged.
        factory.make_Node()
        machine.tags.add(tag)
        device.tags.add(tag)
        rack.tags.add(tag)
        region.tags.add(tag)
        response = self.client.get(self.get_tag_uri(tag), {"op": "devices"})

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json.loads(
            response.content.decode(settings.DEFAULT_CHARSET))
        self.assertItemsEqual([device.system_id],
                              [r["system_id"] for r in parsed_result])
Example #13
0
    def test_yields_configuration_with_ubuntu(self):
        tag = factory.make_Tag(name='wedge100')
        node = factory.make_Node(osystem='ubuntu', netboot=False)
        node.tags.add(tag)
        configuration = generate_rack_controller_configuration(node)

        secret = '1234'
        Config.objects.set_config("rpc_shared_secret", secret)
        channel = version.get_maas_version_track_channel()
        maas_url = "http://%s:5240/MAAS" % get_maas_facing_server_host(
            node.get_boot_rack_controller())
        cmd = "/bin/snap/maas init --mode rack"

        self.assertThat(dict(configuration), KeysEqual({
            "runcmd": [
                "snap install maas --devmode --channel=%s" % channel,
                "%s --maas-url %s --secret %s" % (cmd, maas_url, secret),
                ]
            }))
Example #14
0
    def test_GET_region_controllers_returns_no_controllers_nonadmin(self):
        tag = factory.make_Tag()
        machine = factory.make_Node()
        device = factory.make_Device()
        rack = factory.make_RackController()
        region = factory.make_RegionController()
        # Create a second node that isn't tagged.
        factory.make_Node()
        machine.tags.add(tag)
        device.tags.add(tag)
        rack.tags.add(tag)
        region.tags.add(tag)
        response = self.client.get(
            self.get_tag_uri(tag), {'op': 'region_controllers'})

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json.loads(
            response.content.decode(settings.DEFAULT_CHARSET))
        self.assertItemsEqual([], parsed_result)
Example #15
0
 def test_POST_update_nodes_refuses_no_token(self):
     tag = factory.make_Tag()
     rack_controller = factory.make_RackController()
     node = factory.make_Node()
     # create a token for a different user
     token = create_auth_token(factory.make_User())
     token.save()
     creds = convert_tuple_to_string(get_creds_tuple(token))
     response = self.client.post(
         self.get_tag_uri(tag),
         {
             "op": "update_nodes",
             "add": [node.system_id],
             "rack_controller": rack_controller.system_id,
             "credentials": creds,
         },
     )
     self.assertEqual(http.client.FORBIDDEN, response.status_code)
     self.assertItemsEqual([], tag.node_set.all())
Example #16
0
    def test_calls_are_made_to_all_clusters(self):
        rpc_fixture = self.prepare_live_rpc()
        rack_controllers = [factory.make_RackController() for _ in range(3)]
        protocols = []
        rack_creds = []
        for rack in rack_controllers:
            tokens = list(get_auth_tokens(rack.owner))
            if len(tokens) > 0:
                # Use the latest token.
                token = tokens[-1]
            else:
                token = create_auth_token(rack.owner)
            creds = convert_tuple_to_string(get_creds_tuple(token))
            rack_creds.append(creds)

            protocol = rpc_fixture.makeCluster(rack, EvaluateTag)
            protocol.EvaluateTag.side_effect = always_succeed_with({})
            protocols.append(protocol)
        tag = factory.make_Tag(populate=False)

        [d] = populate_tags(tag)

        # `d` is a testing-only convenience. We must wait for it to fire, and
        # we must do that from the reactor thread.
        wait_for_populate = asynchronous(lambda: d)
        wait_for_populate().wait(10)

        for rack, protocol, creds in zip(rack_controllers, protocols,
                                         rack_creds):
            self.expectThat(
                protocol.EvaluateTag,
                MockCalledOnceWith(
                    protocol,
                    tag_name=tag.name,
                    tag_definition=tag.definition,
                    system_id=rack.system_id,
                    tag_nsmap=ANY,
                    credentials=creds,
                    nodes=ANY,
                ),
            )
Example #17
0
 def test_POST_update_nodes_doesnt_require_add_or_remove(self):
     tag = factory.make_Tag()
     node = factory.make_Node()
     self.become_admin()
     self.assertItemsEqual([], tag.node_set.all())
     response = self.client.post(self.get_tag_uri(tag), {
         'op': 'update_nodes',
         'add': [node.system_id],
     })
     self.assertEqual(http.client.OK, response.status_code)
     parsed_result = json.loads(
         response.content.decode(settings.DEFAULT_CHARSET))
     self.assertEqual({'added': 1, 'removed': 0}, parsed_result)
     response = self.client.post(self.get_tag_uri(tag), {
         'op': 'update_nodes',
         'remove': [node.system_id],
     })
     self.assertEqual(http.client.OK, response.status_code)
     parsed_result = json.loads(
         response.content.decode(settings.DEFAULT_CHARSET))
     self.assertEqual({'added': 0, 'removed': 1}, parsed_result)
Example #18
0
    def test_GET_nodes_hides_invisible_nodes(self):
        user2 = factory.make_User()
        node1 = factory.make_Node()
        node2 = factory.make_Node(status=NODE_STATUS.ALLOCATED, owner=user2)
        tag = factory.make_Tag()
        node1.tags.add(tag)
        node2.tags.add(tag)

        response = self.client.get(self.get_tag_uri(tag), {'op': 'nodes'})

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json.loads(
            response.content.decode(settings.DEFAULT_CHARSET))
        self.assertEqual([node1.system_id],
                         [r['system_id'] for r in parsed_result])
        # The other user can also see his node
        client2 = MAASSensibleOAuthClient(user2)
        response = client2.get(self.get_tag_uri(tag), {'op': 'nodes'})
        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json.loads(
            response.content.decode(settings.DEFAULT_CHARSET))
        self.assertItemsEqual([node1.system_id, node2.system_id],
                              [r['system_id'] for r in parsed_result])
Example #19
0
    def test__returns_kparams_for_known_node(self):
        rack_controller = factory.make_RackController()
        local_ip = factory.make_ip_address()
        remote_ip = factory.make_ip_address()

        """
        The make_node function will result in a boot resource being created
        with an architecture that looks like "arch-YYY/hwe-Z", with YYY being
        a random string and Z being the first letter of the default
        commissioning image. If we don't create a node with this same kernel
        name, the node will use an architecture name of arch-YYY/generic which
        means the get_config won't find the matching boot resource file with
        the kparams attribute.
        """
        default_series = Config.objects.get_config(
            name='commissioning_distro_series')
        release = get_release_from_distro_info(default_series)
        hwe_kernel = "hwe-%s" % (release['version'].split()[0])

        node = self.make_node_with_extra(status=NODE_STATUS.DEPLOYING,
                                         extra={'kparams': 'a=b'},
                                         hwe_kernel=hwe_kernel)

        """
        Create a tag so that we can make sure the kparams attribute got merged
        with the tag's kernel_opts attribute.
        """
        tag = factory.make_Tag(kernel_opts="b=c")
        node.tags.add(tag)

        mac = node.get_boot_interface().mac_address
        config = get_config(rack_controller.system_id, local_ip, remote_ip,
                            mac=mac)
        extra = config.get('extra_opts', None)

        self.assertIn('b=c', extra)
        self.assertIn('a=b', extra)
Example #20
0
 def create_tag(self, params=None):
     if params is None:
         params = {}
     return factory.make_Tag(**params)
Example #21
0
 def test_PUT_refuses_non_superuser(self):
     tag = factory.make_Tag()
     response = self.client.put(
         self.get_tag_uri(tag), {'comment': 'A special comment'})
     self.assertEqual(http.client.FORBIDDEN, response.status_code)
Example #22
0
 def test_POST_rebuild_requires_admin(self):
     tag = factory.make_Tag(definition='/foo/bar')
     response = self.client.post(
         self.get_tag_uri(tag), {'op': 'rebuild'})
     self.assertEqual(http.client.FORBIDDEN, response.status_code)
Example #23
0
 def test_list(self):
     user = factory.make_User()
     handler = TagHandler(user, {})
     factory.make_Tag()
     expected_tags = [self.dehydrate_tag(tag) for tag in Tag.objects.all()]
     self.assertItemsEqual(expected_tags, handler.list({}))
Example #24
0
 def test_DELETE_requires_admin(self):
     tag = factory.make_Tag()
     response = self.client.delete(self.get_tag_uri(tag))
     self.assertEqual(http.client.FORBIDDEN, response.status_code)
     self.assertItemsEqual([tag], Tag.objects.filter(id=tag.id))
Example #25
0
 def test_valid_tag_names(self):
     for valid in ["valid-dash", "under_score", "long" * 50]:
         tag = factory.make_Tag(name=valid)
         self.assertEqual(valid, tag.name)
Example #26
0
 def test_get(self):
     user = factory.make_User()
     handler = TagHandler(user, {})
     tag = factory.make_Tag()
     self.assertEqual(self.dehydrate_tag(tag), handler.get({"id": tag.id}))
Example #27
0
 def test_yields_nothing_when_node_is_not_ubuntu(self):
     tag = factory.make_Tag(name='switch')
     node = factory.make_Node(osystem='centos', netboot=False)
     node.tags.add(tag)
     configuration = generate_rack_controller_configuration(node)
     self.assertThat(dict(configuration), Equals({}))
Example #28
0
 def test_populate_tags_fails_called_in_transaction(self):
     with transaction.atomic():
         tag = factory.make_Tag(populate=False)
         self.assertRaises(transaction.TransactionManagementError,
                           populate_tags, tag)
Example #29
0
 def test_DELETE_removes_tag(self):
     self.become_admin()
     tag = factory.make_Tag()
     response = self.client.delete(self.get_tag_uri(tag))
     self.assertEqual(http.client.NO_CONTENT, response.status_code)
     self.assertFalse(Tag.objects.filter(id=tag.id).exists())
Example #30
0
 def test_will_not_save_invalid_xpath(self):
     tag = factory.make_Tag(definition="//node/foo")
     tag.definition = "invalid::tag"
     self.assertRaises(ValidationError, tag.save)