def test_get_db_state_returns_db_state(self): status = factory.getRandomChoice(NODE_STATUS_CHOICES) node = factory.make_node(status=status) another_status = factory.getRandomChoice(NODE_STATUS_CHOICES, but_not=[status]) node.status = another_status self.assertEqual(status, get_db_state(node, 'status'))
def test_get_db_state_returns_db_state(self): status = factory.getRandomChoice(NODE_STATUS_CHOICES) node = factory.make_node(status=status) another_status = factory.getRandomChoice( NODE_STATUS_CHOICES, but_not=[status]) node.status = another_status self.assertEqual(status, get_db_state(node, 'status'))
def test_admin_can_edit_nodes(self): node = factory.make_node(owner=factory.make_user()) node_edit_link = reverse('node-edit', args=[node.system_id]) params = { 'hostname': factory.getRandomString(), 'after_commissioning_action': factory.getRandomEnum( NODE_AFTER_COMMISSIONING_ACTION), 'power_type': factory.getRandomChoice(POWER_TYPE_CHOICES), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), } response = self.client.post(node_edit_link, params) node = reload_object(node) self.assertEqual(httplib.FOUND, response.status_code) self.assertAttributes(node, params)
def test_POST_new_creates_node_with_subarchitecture(self): # The API allows a Node to be created. architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': 'diane', 'architecture': architecture.split('/')[0], 'subarchitecture': architecture.split('/')[1], 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertIn('application/json', response['Content-Type']) self.assertEqual('diane', parsed_result['hostname']) self.assertNotEqual(0, len(parsed_result.get('system_id'))) [diane] = Node.objects.filter(hostname='diane') self.assertEqual(architecture, diane.architecture)
def test_POST_returns_limited_fields(self): response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) parsed_result = json.loads(response.content) self.assertItemsEqual([ 'hostname', 'owner', 'system_id', 'macaddress_set', 'architecture', 'status', 'netboot', 'power_type', 'resource_uri', 'tag_names', 'ip_addresses', 'cpu_count', 'storage', 'memory', 'routers', ], list(parsed_result))
def test_full_clean_passes_if_status_unchanged(self): status = factory.getRandomChoice(NODE_STATUS_CHOICES) node = factory.make_node(status=status) node.status = status node.full_clean() # The test is that this does not raise an error. pass
def test_POST_returns_limited_fields(self): response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) parsed_result = json.loads(response.content) self.assertItemsEqual( [ 'hostname', 'owner', 'system_id', 'macaddress_set', 'architecture', 'status', 'netboot', 'power_type', 'resource_uri', 'tag_names', 'ip_addresses', 'cpu_count', 'storage', 'memory', 'routers', ], list(parsed_result))
def test_POST_new_creates_node_with_power_parameters(self): # We're setting power parameters so we disable start_commissioning to # prevent anything from attempting to issue power instructions. self.patch(Node, "start_commissioning") hostname = factory.make_name("hostname") architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) power_type = POWER_TYPE.IPMI power_parameters = { "power_user": factory.make_name("power-user"), "power_pass": factory.make_name("power-pass"), } response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': architecture, 'mac_addresses': factory.getRandomMACAddress(), 'power_parameters': json.dumps(power_parameters), 'power_type': power_type, }) self.assertEqual(httplib.OK, response.status_code) [node] = Node.objects.filter(hostname=hostname) self.assertEqual(power_parameters, node.power_parameters) self.assertEqual(power_type, node.power_type)
def test_created_node_has_domain_from_cluster(self): hostname_without_domain = factory.make_name('hostname') hostname_with_domain = '%s.%s' % (hostname_without_domain, factory.getRandomString()) domain = factory.make_name('domain') factory.make_node_group( status=NODEGROUP_STATUS.ACCEPTED, name=domain, management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname_with_domain, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }) self.assertEqual(httplib.OK, response.status_code, response.content) parsed_result = json.loads(response.content) expected_hostname = '%s.%s' % (hostname_without_domain, domain) self.assertEqual(expected_hostname, parsed_result.get('hostname'))
def test_full_clean_passes_if_status_unchanged(self): status = factory.getRandomChoice(NODE_STATUS_CHOICES) node = factory.make_node(status=status) node.status = status node.full_clean() # The test is that this does not raise an error. pass
def test_PUT_non_admin_cannot_change_power_type(self): original_power_type = factory.getRandomChoice( POWER_TYPE_CHOICES) new_power_type = factory.getRandomChoice( POWER_TYPE_CHOICES, but_not=original_power_type) node = factory.make_node( owner=self.logged_in_user, power_type=original_power_type, after_commissioning_action=( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT)) self.client_put( self.get_node_uri(node), {'power_type': new_power_type} ) self.assertEqual( original_power_type, reload_object(node).power_type)
def test_PUT_omitted_hostname(self): hostname = factory.make_name('hostname') node = factory.make_node(hostname=hostname, owner=self.logged_in_user) response = self.client_put( self.get_node_uri(node), {'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES)}) self.assertEqual(httplib.OK, response.status_code, response.content) self.assertTrue(Node.objects.filter(hostname=hostname).exists())
def test_NodeForm_changes_node(self): node = factory.make_node() hostname = factory.getRandomString() after_commissioning_action = factory.getRandomChoice( NODE_AFTER_COMMISSIONING_ACTION_CHOICES) form = NodeForm( data={ 'hostname': hostname, 'after_commissioning_action': after_commissioning_action, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), }, instance=node) form.save() self.assertEqual(hostname, node.hostname) self.assertEqual( after_commissioning_action, node.after_commissioning_action)
def test_power_type_set_but_no_parameters(self): # When power_type is valid, it is set. However, if power_parameters is # not specified, the node's power_parameters is left alone, and the # node is saved. power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) self.request.POST = {"power_type": power_type} store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.assertEqual("", self.node.power_parameters) self.save.assert_called_once_with()
def test_power_type_set_but_no_parameters(self): # When power_type is valid, it is set. However, if power_parameters is # not specified, the node's power_parameters is left alone, and the # node is saved. power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) self.request.POST = {"power_type": power_type} store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.assertEqual("", self.node.power_parameters) self.save.assert_called_once_with()
def test_POST_with_no_hostname_auto_populates_hostname(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'mac_addresses': [factory.getRandomMACAddress()], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(5, len(strip_domain(node.hostname)))
def test_POST_new_initializes_nodegroup_to_master_by_default(self): hostname = factory.make_name('host') self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'mac_addresses': [factory.getRandomMACAddress()], }) self.assertEqual(NodeGroup.objects.ensure_master(), Node.objects.get(hostname=hostname).nodegroup)
def test_POST_new_power_type_defaults_to_asking_config(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'mac_addresses': ['00:11:22:33:44:55'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(POWER_TYPE.DEFAULT, node.power_type)
def test_power_type_set_with_invalid_parameters(self): # When power_type is valid, but power_parameters is invalid JSON, the # node is not saved, and an exception is raised. power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) self.request.POST = { "power_type": power_type, "power_parameters": "Not JSON.", } self.assertRaises(MAASAPIBadRequest, store_node_power_parameters, self.node, self.request) self.save.assert_has_calls([])
def test_POST_new_power_type_defaults_to_asking_config(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'mac_addresses': ['00:11:22:33:44:55'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(POWER_TYPE.DEFAULT, node.power_type)
def test_POST_with_no_hostname_auto_populates_hostname(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'mac_addresses': [factory.getRandomMACAddress()], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(5, len(strip_domain(node.hostname)))
def test_POST_new_sets_power_type_if_admin(self): response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'mac_addresses': ['00:11:22:33:44:55'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(POWER_TYPE.WAKE_ON_LAN, node.power_type) self.assertEqual('', node.power_parameters)
def test_power_type_set_with_invalid_parameters(self): # When power_type is valid, but power_parameters is invalid JSON, the # node is not saved, and an exception is raised. power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) self.request.POST = { "power_type": power_type, "power_parameters": "Not JSON.", } self.assertRaises( MAASAPIBadRequest, store_node_power_parameters, self.node, self.request) self.save.assert_has_calls([])
def test_POST_new_sets_power_type_if_admin(self): response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'mac_addresses': ['00:11:22:33:44:55'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(POWER_TYPE.WAKE_ON_LAN, node.power_type) self.assertEqual('', node.power_parameters)
def test_power_type_set_with_parameters(self): # When power_type is valid, and power_parameters is valid JSON, both # fields are set on the node, and the node is saved. power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) power_parameters = {"foo": [1, 2, 3]} self.request.POST = { "power_type": power_type, "power_parameters": json.dumps(power_parameters), } store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.assertEqual(power_parameters, self.node.power_parameters) self.save.assert_called_once_with()
def test_power_type_set_with_parameters(self): # When power_type is valid, and power_parameters is valid JSON, both # fields are set on the node, and the node is saved. power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) power_parameters = {"foo": [1, 2, 3]} self.request.POST = { "power_type": power_type, "power_parameters": json.dumps(power_parameters), } store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.assertEqual(power_parameters, self.node.power_parameters) self.save.assert_called_once_with()
def test_POST_new_initializes_nodegroup_to_master_by_default(self): hostname = factory.make_name('host') self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'mac_addresses': [factory.getRandomMACAddress()], }) self.assertEqual( NodeGroup.objects.ensure_master(), Node.objects.get(hostname=hostname).nodegroup)
def test_POST_new_creates_node(self): # The API allows a non-admin logged-in user to create a Node. architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': architecture, 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code)
def test_AdminNodeForm_changes_node_with_skip_check(self): node = factory.make_node() hostname = factory.getRandomString() after_commissioning_action = factory.getRandomChoice( NODE_AFTER_COMMISSIONING_ACTION_CHOICES) power_type = factory.getRandomChoice(POWER_TYPE_CHOICES) power_parameters_field = factory.getRandomString() form = AdminNodeForm( data={ 'hostname': hostname, 'after_commissioning_action': after_commissioning_action, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': power_type, 'power_parameters_field': power_parameters_field, 'power_parameters_skip_check': True, }, instance=node) form.save() self.assertEqual( (hostname, after_commissioning_action, power_type, {'field': power_parameters_field}), (node.hostname, node.after_commissioning_action, node.power_type, node.power_parameters))
def test_POST_updates_power_parameters_rejects_unknown_param(self): hostname = factory.getRandomString() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters_unknown_param': factory.getRandomString(), 'mac_addresses': [factory.getRandomMACAddress()], }) self.assertEqual((httplib.BAD_REQUEST, { 'power_parameters': ["Unknown parameter(s): unknown_param."] }), (response.status_code, json.loads(response.content))) self.assertFalse(Node.objects.filter(hostname=hostname).exists())
def test_POST_new_creates_node_default_values_for_power_settings(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) mac_address = 'AA:BB:CC:DD:EE:FF' response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'mac_addresses': [mac_address], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertAttributes( node, dict(architecture=architecture, power_type=POWER_TYPE.DEFAULT, power_parameters=''))
def test_POST_new_creates_node_default_values_for_power_settings(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) mac_address = 'AA:BB:CC:DD:EE:FF' response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'mac_addresses': [mac_address], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertAttributes( node, dict( architecture=architecture, power_type=POWER_TYPE.DEFAULT, power_parameters=''))
def test_POST_new_creates_node(self): # The API allows a non-admin logged-in user to create a Node. architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': architecture, 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code)
def test_created_node_uses_default_nodegroup_if_origin_not_found(self): unknown_host = factory.make_name('host') response = self.client.post( reverse('nodes_handler'), data={ 'op': 'new', 'hostname': factory.make_name('hostname'), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }, HTTP_HOST=unknown_host) self.assertEqual(httplib.OK, response.status_code, response.content) parsed_result = json.loads(response.content) node = Node.objects.get(system_id=parsed_result.get('system_id')) self.assertEqual(NodeGroup.objects.ensure_master(), node.nodegroup)
def test_POST_new_sets_power_parameters_field(self): # The api allows the setting of a Node's power_parameters field. # Create a power_parameter valid for the selected power_type. new_mac_address = factory.getRandomMACAddress() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters_mac_address': new_mac_address, 'mac_addresses': ['AA:BB:CC:DD:EE:FF'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(httplib.OK, response.status_code) self.assertEqual({'mac_address': new_mac_address}, reload_object(node).power_parameters)
def test_POST_new_fails_node_with_double_subarchitecture(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': 'diane', 'architecture': architecture, 'subarchitecture': architecture.split('/')[1], 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.BAD_REQUEST, response.status_code) self.assertIn('text/plain', response['Content-Type']) self.assertEqual( "Subarchitecture cannot be specified twice.", response.content)
def test_POST_new_generates_hostname_if_ip_based_hostname(self): hostname = '192-168-5-19.domain' response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }) parsed_result = json.loads(response.content) self.assertEqual(httplib.OK, response.status_code) system_id = parsed_result.get('system_id') node = Node.objects.get(system_id=system_id) self.assertNotEqual(hostname, node.hostname)
def test_POST_new_associates_mac_addresses(self): # The API allows a Node to be created and associated with MAC # Addresses. architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': 'diane', 'architecture': architecture, 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) diane = get_one(Node.objects.filter(hostname='diane')) self.assertItemsEqual( ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], [mac.mac_address for mac in diane.macaddress_set.all()])
def test_POST_fails_if_mac_duplicated(self): # Mac Addresses should be unique. mac = 'aa:bb:cc:dd:ee:ff' factory.make_mac_address(mac) architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': architecture, 'hostname': factory.getRandomString(), 'mac_addresses': [mac], }) parsed_result = json.loads(response.content) self.assertEqual(httplib.BAD_REQUEST, response.status_code) self.assertIn('application/json', response['Content-Type']) self.assertEqual(["Mac address %s already in use." % mac], parsed_result['mac_addresses'])
def test_POST_admin_creates_node_in_commissioning_state(self): # When an admin user enlists a node, it goes into the # Commissioning state. response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) system_id = json.loads(response.content)['system_id'] self.assertEqual( NODE_STATUS.COMMISSIONING, Node.objects.get(system_id=system_id).status)
def test_POST_non_admin_creates_node_in_declared_state(self): # Upon non-admin enlistment, a node goes into the Declared # state. Deliberate approval is required before we start # reinstalling the system, wiping its disks etc. response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) system_id = json.loads(response.content)['system_id'] self.assertEqual( NODE_STATUS.DECLARED, Node.objects.get(system_id=system_id).status)
def test_POST_new_sets_power_parameters_field(self): # The api allows the setting of a Node's power_parameters field. # Create a power_parameter valid for the selected power_type. new_mac_address = factory.getRandomMACAddress() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters_mac_address': new_mac_address, 'mac_addresses': ['AA:BB:CC:DD:EE:FF'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(httplib.OK, response.status_code) self.assertEqual( {'mac_address': new_mac_address}, reload_object(node).power_parameters)
def test_POST_updates_power_parameters_rejects_unknown_param(self): hostname = factory.getRandomString() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters_unknown_param': factory.getRandomString(), 'mac_addresses': [factory.getRandomMACAddress()], }) self.assertEqual( ( httplib.BAD_REQUEST, {'power_parameters': ["Unknown parameter(s): unknown_param."]} ), (response.status_code, json.loads(response.content))) self.assertFalse(Node.objects.filter(hostname=hostname).exists())
def test_POST_simple_user_can_set_power_type_and_parameters(self): new_power_address = factory.getRandomString() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters': json.dumps( {"power_address": new_power_address}), 'mac_addresses': ['AA:BB:CC:DD:EE:FF'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual( (httplib.OK, {"power_address": new_power_address}, POWER_TYPE.WAKE_ON_LAN), (response.status_code, node.power_parameters, node.power_type))
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.getRandomString() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters_param': param, 'power_parameters_skip_check': 'true', 'mac_addresses': ['AA:BB:CC:DD:EE:FF'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(httplib.OK, response.status_code) self.assertEqual({'param': param}, reload_object(node).power_parameters)
def test_POST_new_when_logged_in_creates_node_in_declared_state(self): # When a user enlists a node, it goes into the Declared state. # This will change once we start doing proper commissioning. response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) system_id = json.loads(response.content)['system_id'] self.assertEqual(NODE_STATUS.DECLARED, Node.objects.get(system_id=system_id).status)
def test_POST_new_creates_node(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': 'diane', 'architecture': architecture, 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertIn('application/json', response['Content-Type']) self.assertEqual('diane', parsed_result['hostname']) self.assertNotEqual(0, len(parsed_result.get('system_id'))) [diane] = Node.objects.filter(hostname='diane') self.assertEqual(architecture, diane.architecture)
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.getRandomString() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters_param': param, 'power_parameters_skip_check': 'true', 'mac_addresses': ['AA:BB:CC:DD:EE:FF'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual(httplib.OK, response.status_code) self.assertEqual( {'param': param}, reload_object(node).power_parameters)
def test_PUT_updates_nodegroup(self): # The api allows the updating of a NodeGroup. nodegroup = factory.make_node_group() self.become_admin() new_name = factory.make_name("new-name") new_cluster_name = factory.make_name("new-cluster-name") new_status = factory.getRandomChoice(NODEGROUP_STATUS_CHOICES, but_not=[nodegroup.status]) response = self.client_put( reverse('nodegroup_handler', args=[nodegroup.uuid]), { 'name': new_name, 'cluster_name': new_cluster_name, 'status': new_status, }) self.assertEqual(httplib.OK, response.status_code, response.content) nodegroup = reload_object(nodegroup) self.assertEqual( (new_name, new_cluster_name, new_status), (nodegroup.name, nodegroup.cluster_name, nodegroup.status))
def test_POST_non_admin_creates_node_in_declared_state(self): # Upon non-admin enlistment, a node goes into the Declared # state. Deliberate approval is required before we start # reinstalling the system, wiping its disks etc. response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) system_id = json.loads(response.content)['system_id'] self.assertEqual(NODE_STATUS.DECLARED, Node.objects.get(system_id=system_id).status)
def test_POST_new_generates_hostname_if_ip_based_hostname(self): hostname = '192-168-5-19.domain' response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': hostname, 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }) parsed_result = json.loads(response.content) self.assertEqual(httplib.OK, response.status_code) system_id = parsed_result.get('system_id') node = Node.objects.get(system_id=system_id) self.assertNotEqual(hostname, node.hostname)
def test_created_node_nodegroup_is_inferred_from_origin_network(self): network = IPNetwork('192.168.0.3/24') origin_ip = factory.getRandomIPInNetwork(network) NodeGroup.objects.ensure_master() nodegroup = factory.make_node_group(network=network) response = self.client.post( reverse('nodes_handler'), data={ 'op': 'new', 'hostname': factory.make_name('hostname'), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': ( NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }, REMOTE_ADDR=origin_ip) self.assertEqual(httplib.OK, response.status_code, response.content) parsed_result = json.loads(response.content) node = Node.objects.get(system_id=parsed_result.get('system_id')) self.assertEqual(nodegroup, node.nodegroup)
def test_POST_new_associates_mac_addresses(self): # The API allows a Node to be created and associated with MAC # Addresses. architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': 'diane', 'architecture': architecture, 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) diane = get_one(Node.objects.filter(hostname='diane')) self.assertItemsEqual( ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], [mac.mac_address for mac in diane.macaddress_set.all()])
def test_POST_new_fails_node_with_double_subarchitecture(self): architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'hostname': 'diane', 'architecture': architecture, 'subarchitecture': architecture.split('/')[1], 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.BAD_REQUEST, response.status_code) self.assertIn('text/plain', response['Content-Type']) self.assertEqual("Subarchitecture cannot be specified twice.", response.content)
def test_created_node_uses_default_nodegroup_if_origin_not_found(self): unknown_host = factory.make_name('host') response = self.client.post( reverse('nodes_handler'), data={ 'op': 'new', 'hostname': factory.make_name('hostname'), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }, HTTP_HOST=unknown_host) self.assertEqual(httplib.OK, response.status_code, response.content) parsed_result = json.loads(response.content) node = Node.objects.get(system_id=parsed_result.get('system_id')) self.assertEqual(NodeGroup.objects.ensure_master(), node.nodegroup)
def test_handle_when_URL_is_repeated(self): # bin/maas-enlist (in the maas-enlist package) has a bug where the # path it uses is doubled up. This was not discovered previously # because the API URL patterns were not anchored (see bug 1131323). # For compatibility, MAAS will handle requests to obviously incorrect # paths. It does *not* redirect because (a) it's not clear that curl # (used by maas-enlist) supports HTTP 307 redirects, which are needed # to support redirecting POSTs, and (b) curl does not follow redirects # by default anyway. architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) response = self.client.post( '/api/1.0/nodes/MAAS/api/1.0/nodes/', { 'op': 'new', 'hostname': factory.getRandomString(), 'architecture': architecture, 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], }) self.assertEqual(httplib.OK, response.status_code) system_id = json.loads(response.content)['system_id'] nodes = Node.objects.filter(system_id=system_id) self.assertIsNotNone(get_one(nodes))
def test_POST_simple_user_can_set_power_type_and_parameters(self): new_power_address = factory.getRandomString() response = self.client.post( reverse('nodes_handler'), { 'op': 'new', 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'power_type': POWER_TYPE.WAKE_ON_LAN, 'power_parameters': json.dumps({"power_address": new_power_address}), 'mac_addresses': ['AA:BB:CC:DD:EE:FF'], }) node = Node.objects.get( system_id=json.loads(response.content)['system_id']) self.assertEqual( (httplib.OK, { "power_address": new_power_address }, POWER_TYPE.WAKE_ON_LAN), (response.status_code, node.power_parameters, node.power_type))
def test_created_node_nodegroup_is_inferred_from_origin_network(self): network = IPNetwork('192.168.0.3/24') origin_ip = factory.getRandomIPInNetwork(network) NodeGroup.objects.ensure_master() nodegroup = factory.make_node_group(network=network) response = self.client.post( reverse('nodes_handler'), data={ 'op': 'new', 'hostname': factory.make_name('hostname'), 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), 'after_commissioning_action': (NODE_AFTER_COMMISSIONING_ACTION.DEFAULT), 'mac_addresses': [factory.getRandomMACAddress()], }, REMOTE_ADDR=origin_ip) self.assertEqual(httplib.OK, response.status_code, response.content) parsed_result = json.loads(response.content) node = Node.objects.get(system_id=parsed_result.get('system_id')) self.assertEqual(nodegroup, node.nodegroup)