Exemple #1
0
    def test_POST_calls_import_boot_images_on_all_clusters(self):
        self.become_admin()

        from maasserver.clusterrpc import boot_images

        self.patch(boot_images, "RackControllersImporter")

        name = factory.make_name("name")
        architecture = make_usable_architecture(self)
        params = {
            "name": name,
            "architecture": architecture,
            "content": (factory.make_file_upload(content=sample_binary_data)),
        }
        response = self.client.post(reverse("boot_resources_handler"), params)
        self.assertEqual(http.client.CREATED, response.status_code)
        self.assertThat(boot_images.RackControllersImporter.schedule,
                        MockCalledOnceWith())
Exemple #2
0
    def test_mac_in_use_on_current_node_passes(self):
        node = factory.make_Node_with_Interface_on_Subnet(
            address="aa:bb:cc:dd:ee:ff")
        architecture = make_usable_architecture(self)
        form = MachineWithMACAddressesForm(
            data=self.make_params(
                mac_addresses=["aa:bb:cc:dd:ee:ff", "9a:bb:c3:33:e5:7f"],
                architecture=architecture,
            ),
            instance=node,
        )

        self.assertTrue(form.is_valid(), dict(form.errors))
        self.assertEqual(
            ["aa:bb:cc:dd:ee:ff", "9a:bb:c3:33:e5:7f"],
            form.cleaned_data["mac_addresses"],
        )
        self.assertEqual(architecture, form.cleaned_data["architecture"])
Exemple #3
0
 def test_POST_admin_creates_machine_in_commissioning_state(self):
     # When an admin user enlists a machine, it goes into the
     # Commissioning state.
     response = self.client.post(
         reverse("machines_handler"),
         {
             "hostname": factory.make_string(),
             "architecture": make_usable_architecture(self),
             "power_type": "manual",
             "mac_addresses": ["aa:bb:cc:dd:ee:ff"],
         },
     )
     self.assertEqual(http.client.OK, response.status_code)
     system_id = json_load_bytes(response.content)["system_id"]
     self.assertEqual(
         NODE_STATUS.COMMISSIONING,
         Machine.objects.get(system_id=system_id).status,
     )
Exemple #4
0
 def test_create_with_form_uses_form_from_get_form_class(self):
     hostname = factory.make_name("hostname")
     arch = make_usable_architecture(self)
     handler = self.make_nodes_handler(fields=['hostname', 'architecture'])
     self.patch(
         handler,
         "get_form_class").return_value = AdminMachineWithMACAddressesForm
     json_obj = handler.create({
         "hostname":
         hostname,
         "architecture":
         arch,
         "mac_addresses": [factory.make_mac_address()],
     })
     self.expectThat({
         "hostname": hostname,
         "architecture": arch,
     }, Equals(json_obj))
Exemple #5
0
 def test_rejects_invalid_osystem_distro_series(self):
     self.client_log_in()
     node = factory.make_Node(owner=self.logged_in_user)
     osystem = make_usable_osystem(self)
     release = factory.make_name('release')
     form = MachineForm(data={
         'hostname':
         factory.make_name('host'),
         'architecture':
         make_usable_architecture(self),
         'osystem':
         osystem['name'],
         'distro_series':
         '%s/%s' % (osystem['name'], release),
     },
                        instance=node)
     self.assertFalse(form.is_valid())
     self.assertItemsEqual(['distro_series'], form._errors.keys())
Exemple #6
0
    def test_POST_new_generates_hostname_if_ip_based_hostname(self):
        Domain.objects.get_or_create(name="domain")
        hostname = "192-168-5-19.domain"
        response = self.client.post(
            reverse("machines_handler"),
            {
                "hostname": hostname,
                "architecture": make_usable_architecture(self),
                "power_type": "manual",
                "mac_addresses": [factory.make_mac_address()],
            },
        )
        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json_load_bytes(response.content)

        system_id = parsed_result.get("system_id")
        machine = Machine.objects.get(system_id=system_id)
        self.assertNotEqual(hostname, machine.hostname)
Exemple #7
0
    def test_with_mac_in_use_on_uknown_interface_passes(self):
        factory.make_Interface(
            INTERFACE_TYPE.UNKNOWN, mac_address="aa:bb:cc:dd:ee:ff"
        )
        architecture = make_usable_architecture(self)
        form = MachineWithMACAddressesForm(
            data=self.make_params(
                mac_addresses=["aa:bb:cc:dd:ee:ff", "9a:bb:c3:33:e5:7f"],
                architecture=architecture,
            )
        )

        self.assertTrue(form.is_valid(), dict(form.errors))
        self.assertEqual(
            ["aa:bb:cc:dd:ee:ff", "9a:bb:c3:33:e5:7f"],
            form.cleaned_data["mac_addresses"],
        )
        self.assertEqual(architecture, form.cleaned_data["architecture"])
Exemple #8
0
 def test_accepts_osystem_distro_series(self):
     user = factory.make_User()
     self.client.login(user=user)
     node = factory.make_Node(owner=user)
     osystem = make_usable_osystem(self)
     release = osystem['default_release']
     form = MachineForm(data={
         'hostname':
         factory.make_name('host'),
         'architecture':
         make_usable_architecture(self),
         'osystem':
         osystem['name'],
         'distro_series':
         '%s/%s' % (osystem['name'], release),
     },
                        instance=node)
     self.assertTrue(form.is_valid(), form._errors)
Exemple #9
0
 def test_set_distro_series_accepts_short_distro_series(self):
     user = factory.make_User()
     self.client.login(user=user)
     node = factory.make_Node(owner=user)
     release = factory.make_name("release")
     make_usable_osystem(
         self, releases=[release + "6", release + "0", release + "3"]
     )
     form = MachineForm(
         data={
             "hostname": factory.make_name("host"),
             "architecture": make_usable_architecture(self),
         },
         instance=node,
     )
     form.set_distro_series(release)
     form.save()
     self.assertEqual(release + "6", node.distro_series)
Exemple #10
0
 def test_rejects_mismatch_osystem_distro_series(self):
     user = factory.make_User()
     self.client.login(user=user)
     node = factory.make_Node(owner=user)
     osystem = make_usable_osystem(self)
     release = osystem["default_release"]
     invalid = factory.make_name("invalid_os")
     form = MachineForm(
         data={
             "hostname": factory.make_name("host"),
             "architecture": make_usable_architecture(self),
             "osystem": osystem["name"],
             "distro_series": "%s/%s" % (invalid, release),
         },
         instance=node,
     )
     self.assertFalse(form.is_valid())
     self.assertItemsEqual(["distro_series"], form._errors.keys())
Exemple #11
0
    def test_saves_power_parameters(self):
        self.prepare_rack_rpc()

        mac_addresses = [factory.make_mac_address() for _ in range(3)]
        architecture = make_usable_architecture(self)
        power_parameters = {
            "power_address": factory.make_ip_address(),  # XXX: URLs break.
            "power_pass": factory.make_name("power_pass"),
            "power_id": factory.make_name("power_id"),
        }

        node = create_node(architecture, "virsh", power_parameters,
                           mac_addresses)

        # Reload the object from the DB so that we're sure its power
        # parameters are being persisted.
        node = reload_object(node)
        self.assertEqual(power_parameters, node.power_parameters)
Exemple #12
0
    def test_POST_updates_power_parameters_rejects_unknown_param(self):
        hostname = factory.make_string()
        response = self.client.post(
            reverse('machines_handler'), {
                'hostname': hostname,
                'architecture': make_usable_architecture(self),
                'power_type': 'manual',
                'power_parameters_unknown_param': factory.make_string(),
                'mac_addresses': [factory.make_mac_address()],
                })

        self.assertEqual(
            (
                http.client.BAD_REQUEST,
                {'power_parameters': ["Unknown parameter(s): unknown_param."]}
            ),
            (response.status_code, json_load_bytes(response.content)))
        self.assertFalse(Machine.objects.filter(hostname=hostname).exists())
Exemple #13
0
 def test_POST_create_creates_machine(self):
     hostname = factory.make_name("hostname")
     architecture = make_usable_architecture(self)
     response = self.client.post(
         reverse('machines_handler'),
         {
             'hostname': hostname,
             'architecture': architecture,
             'power_type': 'manual',
             'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],
         })
     self.assertEqual(http.client.OK, response.status_code)
     node_metadata = NodeMetadata.objects.get(key='enlisting')
     self.assertEqual(node_metadata.value, 'True')
     [machine] = Machine.objects.filter(hostname=hostname)
     self.assertEqual(architecture, machine.architecture)
     self.assertEqual(
         machine.system_id, json_load_bytes(response.content)['system_id'])
Exemple #14
0
 def test_created_machine_gets_default_domain_appended(self):
     hostname_without_domain = factory.make_name('hostname')
     response = self.client.post(
         reverse('machines_handler'),
         {
             'hostname': hostname_without_domain,
             'architecture': make_usable_architecture(self),
             'power_type': 'manual',
             'mac_addresses': [factory.make_mac_address()],
         })
     self.assertEqual(
         http.client.OK, response.status_code, response.content)
     parsed_result = json_load_bytes(response.content)
     expected_hostname = '%s.%s' % (
         hostname_without_domain,
         Domain.objects.get_default_domain().name)
     self.assertEqual(
         expected_hostname, parsed_result.get('fqdn'))
Exemple #15
0
 def test_POST_create_associates_mac_addresses(self):
     # The API allows a Machine to be created and associated with MAC
     # Addresses.
     architecture = make_usable_architecture(self)
     self.client.post(
         reverse("machines_handler"),
         {
             "hostname": "diane",
             "architecture": architecture,
             "power_type": "manual",
             "mac_addresses": ["aa:bb:cc:dd:ee:ff", "22:bb:cc:dd:ee:ff"],
         },
     )
     diane = get_one(Machine.objects.filter(hostname="diane"))
     self.assertItemsEqual(
         ["aa:bb:cc:dd:ee:ff", "22:bb:cc:dd:ee:ff"],
         [interface.mac_address for interface in diane.interface_set.all()],
     )
Exemple #16
0
 def test_prevents_unsupported_osystem(self):
     reserved_name = "%s/%s" % (
         factory.make_name("osystem"),
         factory.make_name("series"),
     )
     upload_type, filetype = self.pick_filetype()
     size = random.randint(1024, 2048)
     content = factory.make_string(size).encode("utf-8")
     upload_name = factory.make_name("filename")
     uploaded_file = SimpleUploadedFile(content=content, name=upload_name)
     data = {
         "name": reserved_name,
         "title": factory.make_name("title"),
         "architecture": make_usable_architecture(self),
         "filetype": upload_type,
     }
     form = BootResourceForm(data=data, files={"content": uploaded_file})
     self.assertFalse(form.is_valid())
Exemple #17
0
    def test_POST_create_creates_machine_with_arch_only(self):
        architecture = make_usable_architecture(self, subarch_name="generic")
        response = self.client.post(
            reverse('machines_handler'), {
                'hostname': 'diane',
                'architecture': architecture.split('/')[0],
                'power_type': 'manual',
                'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],
            })

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json_load_bytes(response.content)
        self.assertIn('application/json', response['Content-Type'])
        domain_name = Domain.objects.get_default_domain().name
        self.assertEqual('diane.%s' % domain_name, parsed_result['fqdn'])
        self.assertNotEqual(0, len(parsed_result.get('system_id')))
        [diane] = Machine.objects.filter(hostname='diane')
        self.assertEqual(architecture, diane.architecture)
Exemple #18
0
 def test_create_with_form_creates_node(self):
     hostname = factory.make_name("hostname")
     arch = make_usable_architecture(self)
     handler = self.make_nodes_handler(
         fields=['hostname', 'architecture'],
         form=AdminMachineWithMACAddressesForm)
     handler.user = factory.make_admin()
     json_obj = handler.create({
         "hostname":
         hostname,
         "architecture":
         arch,
         "mac_addresses": [factory.make_mac_address()],
     })
     self.expectThat({
         "hostname": hostname,
         "architecture": arch,
     }, Equals(json_obj))
Exemple #19
0
 def test_POST_power_on_returns_machine(self):
     self.patch(node_module.Machine, "_start")
     machine = factory.make_Node(
         owner=self.user,
         interface=True,
         power_type="manual",
         architecture=make_usable_architecture(self),
     )
     osystem = make_usable_osystem(self)
     distro_series = osystem["default_release"]
     response = self.client.post(
         self.get_node_uri(machine),
         {"op": "power_on", "distro_series": distro_series},
     )
     self.assertEqual(http.client.OK, response.status_code)
     self.assertEqual(
         machine.system_id, json_load_bytes(response.content)["system_id"]
     )
Exemple #20
0
 def test_POST_create_returns_machine_with_matching_power_parameters(self):
     mock_create_machine = self.patch(machines_module, "create_machine")
     hostname = factory.make_name("hostname")
     architecture = make_usable_architecture(self)
     power_type = "ipmi"
     power_parameters = {
         "power_address": factory.make_ip_address(),
         "power_user": factory.make_name("power-user"),
         "power_pass": factory.make_name("power-pass"),
         "power_driver": "LAN_2_0",
         "mac_address": "",
         "power_boot_type": "auto",
     }
     machine = factory.make_Machine(
         hostname=hostname,
         status=NODE_STATUS.NEW,
         architecture="",
         power_type=power_type,
         power_parameters=power_parameters,
     )
     # Simulate creating the MAAS IPMI user
     power_parameters["power_user"] = "******"
     power_parameters["power_pass"] = factory.make_name("power-pass")
     response = self.client.post(
         reverse("machines_handler"),
         {
             "hostname": "maas-enlistment",
             "architecture": architecture,
             "power_type": power_type,
             "mac_addresses": factory.make_mac_address(),
             "power_parameters": json.dumps(power_parameters),
         },
     )
     self.assertEqual(http.client.OK, response.status_code)
     machine = reload_object(machine)
     self.assertEqual(hostname, machine.hostname)
     self.assertEqual(architecture, machine.architecture)
     self.assertDictContainsSubset(
         machine.bmc.power_parameters, power_parameters
     )
     self.assertThat(mock_create_machine, MockNotCalled())
     self.assertEqual(
         machine.system_id, json_load_bytes(response.content)["system_id"]
     )
Exemple #21
0
    def test_POST_new_sets_power_parameters_skip_check(self):
        # The api allows to skip the validation step and set arbitrary
        # power parameters.
        param = factory.make_string()
        response = self.client.post(
            reverse('machines_handler'), {
                'architecture': make_usable_architecture(self),
                'power_type': 'manual',
                'power_parameters_param': param,
                'power_parameters_skip_check': 'true',
                'mac_addresses': ['AA:BB:CC:DD:EE:FF'],
            })

        self.assertEqual(http.client.OK, response.status_code,
                         response.content)
        machine = Machine.objects.get(
            system_id=json_load_bytes(response.content)['system_id'])
        self.assertEqual({'param': param},
                         reload_object(machine).power_parameters)
Exemple #22
0
    def test_POST_creates_boot_resource_with_default_filetype(self):
        prevent_scheduling_of_image_imports(self)
        self.become_admin()

        name = factory.make_name('name')
        architecture = make_usable_architecture(self)
        params = {
            'name': name,
            'architecture': architecture,
            'content': (factory.make_file_upload(content=sample_binary_data)),
        }
        response = self.client.post(reverse('boot_resources_handler'), params)
        self.assertEqual(http.client.CREATED, response.status_code)
        parsed_result = json_load_bytes(response.content)

        resource = BootResource.objects.get(id=parsed_result['id'])
        resource_set = resource.sets.first()
        rfile = resource_set.files.first()
        self.assertEqual(BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ, rfile.filetype)
Exemple #23
0
 def test_created_machine_gets_default_domain_appended(self):
     hostname_without_domain = factory.make_name("hostname")
     response = self.client.post(
         reverse("machines_handler"),
         {
             "hostname": hostname_without_domain,
             "architecture": make_usable_architecture(self),
             "power_type": "manual",
             "mac_addresses": [factory.make_mac_address()],
         },
     )
     self.assertEqual(http.client.OK, response.status_code,
                      response.content)
     parsed_result = json_load_bytes(response.content)
     expected_hostname = "%s.%s" % (
         hostname_without_domain,
         Domain.objects.get_default_domain().name,
     )
     self.assertEqual(expected_hostname, parsed_result.get("fqdn"))
Exemple #24
0
 def test_POST_create_creates_machine(self):
     hostname = factory.make_name("hostname")
     architecture = make_usable_architecture(self)
     response = self.client.post(
         reverse("machines_handler"),
         {
             "hostname": hostname,
             "architecture": architecture,
             "power_type": "manual",
             "mac_addresses": ["aa:bb:cc:dd:ee:ff", "22:bb:cc:dd:ee:ff"],
         },
     )
     self.assertEqual(http.client.OK, response.status_code)
     node_metadata = NodeMetadata.objects.get(key="enlisting")
     self.assertIsNone(node_metadata)
     [machine] = Machine.objects.filter(hostname=hostname)
     self.assertEqual(architecture, machine.architecture)
     self.assertEqual(machine.system_id,
                      json_load_bytes(response.content)["system_id"])
Exemple #25
0
    def test_AdminMachineForm_changes_power_parameters_with_skip_check(self):
        node = factory.make_Node()
        hostname = factory.make_string()
        power_type = factory.pick_power_type()
        power_parameters_field = factory.make_string()
        arch = make_usable_architecture(self)
        form = AdminMachineForm(data={
            'hostname': hostname,
            'architecture': arch,
            'power_type': power_type,
            'power_parameters_field': power_parameters_field,
            'power_parameters_skip_check': 'true',
        },
                                instance=node)
        form.save()

        self.assertEqual((hostname, power_type, {
            'field': power_parameters_field
        }), (node.hostname, node.power_type, node.power_parameters))
Exemple #26
0
    def test__creates_node_with_explicit_hostname(self):
        self.prepare_rack_rpc()

        mac_addresses = [factory.make_mac_address() for _ in range(3)]
        architecture = make_usable_architecture(self)
        hostname = factory.make_hostname()

        node = create_node(architecture,
                           'manual', {},
                           mac_addresses,
                           hostname=hostname)

        self.assertEqual((architecture, 'manual', {}, hostname),
                         (node.architecture, node.power_type,
                          node.power_parameters, node.hostname))
        self.expectThat(node.id, Not(Is(None)))
        self.assertItemsEqual(
            mac_addresses,
            [nic.mac_address for nic in node.interface_set.all()])
Exemple #27
0
 def test_POST_non_admin_creates_machine_in_declared_state(self):
     # Upon non-admin enlistment, a machine goes into the New
     # state.  Deliberate approval is required before we start
     # reinstalling the system, wiping its disks etc.
     response = self.client.post(
         reverse("machines_handler"),
         {
             "hostname": factory.make_string(),
             "architecture": make_usable_architecture(self),
             "mac_addresses": ["aa:bb:cc:dd:ee:ff"],
         },
     )
     self.assertEqual(
         http.client.OK, response.status_code, response.content
     )
     system_id = json_load_bytes(response.content)["system_id"]
     self.assertEqual(
         NODE_STATUS.NEW, Machine.objects.get(system_id=system_id).status
     )
Exemple #28
0
    def test_POST_creates_boot_resource_with_already_existing_largefile(self):
        self.become_admin()

        largefile = factory.make_LargeFile()
        name = factory.make_name('name')
        architecture = make_usable_architecture(self)
        params = {
            'name': name,
            'architecture': architecture,
            'sha256': largefile.sha256,
            'size': largefile.total_size,
        }
        response = self.client.post(reverse('boot_resources_handler'), params)
        self.assertEqual(http.client.CREATED, response.status_code)
        parsed_result = json_load_bytes(response.content)

        resource = BootResource.objects.get(id=parsed_result['id'])
        resource_set = resource.sets.first()
        rfile = resource_set.files.first()
        self.assertEqual(largefile, rfile.largefile)
Exemple #29
0
    def test_POST_create_creates_machine(self):
        architecture = make_usable_architecture(self)
        response = self.client.post(
            reverse("machines_handler"),
            {
                "hostname": "diane",
                "architecture": architecture,
                "power_type": "manual",
                "mac_addresses": ["aa:bb:cc:dd:ee:ff", "22:bb:cc:dd:ee:ff"],
            },
        )

        self.assertEqual(http.client.OK, response.status_code)
        parsed_result = json_load_bytes(response.content)
        self.assertIn("application/json", response["Content-Type"])
        domain_name = Domain.objects.get_default_domain().name
        self.assertEqual("diane.%s" % domain_name, parsed_result["fqdn"])
        self.assertNotEqual(0, len(parsed_result.get("system_id")))
        [diane] = Machine.objects.filter(hostname="diane")
        self.assertEqual(architecture, diane.architecture)
Exemple #30
0
 def test__returns_global_kernel_params_for_enlisting_node(self):
     # An 'enlisting' node means it looks like a node with details but we
     # don't know about it yet.  It should still receive the global
     # kernel options.
     rack_controller = factory.make_RackController()
     local_ip = factory.make_ip_address()
     remote_ip = factory.make_ip_address()
     value = factory.make_string()
     Config.objects.set_config("kernel_opts", value)
     architecture = make_usable_architecture(self)
     arch = architecture.split('/')[0]
     factory.make_default_ubuntu_release_bootable(arch)
     mac = factory.make_mac_address(delimiter='-')
     observed_config = get_config(rack_controller.system_id,
                                  local_ip,
                                  remote_ip,
                                  arch=arch,
                                  subarch='generic',
                                  mac=mac)
     self.assertEqual(value, observed_config['extra_opts'])