def get_context_data(self, **kwargs): context = super(NodeView, self).get_context_data(**kwargs) node = self.get_object() context['can_edit'] = self.request.user.has_perm( NODE_PERMISSION.EDIT, node) if node.status in (NODE_STATUS.COMMISSIONING, NODE_STATUS.READY): messages.info(self.request, NODE_BOOT_INFO) if node.power_type == POWER_TYPE.DEFAULT: messages.error(self.request, NO_POWER_SET) context['error_text'] = (node.error if node.status == NODE_STATUS.FAILED_TESTS else None) context['status_text'] = ( node.error if node.status != NODE_STATUS.FAILED_TESTS else None) kernel_opts = node.get_effective_kernel_options() context['kernel_opts'] = { 'is_global': kernel_opts[0] is None, 'is_tag': isinstance(kernel_opts[0], Tag), 'tag': kernel_opts[0], 'value': kernel_opts[1] } # Produce a "clean" composite details document. probed_details = merge_details_cleanly( get_single_probed_details(node.system_id)) # We check here if there's something to show instead of after # the call to get_single_probed_details() because here the # details will be guaranteed well-formed. if len(probed_details.xpath('/*/*')) == 0: context["probed_details"] = None else: context["probed_details"] = etree.tostring(probed_details, encoding=unicode, pretty_print=True) return context
def get_context_data(self, **kwargs): context = super(NodeView, self).get_context_data(**kwargs) node = self.get_object() context['can_edit'] = self.request.user.has_perm( NODE_PERMISSION.EDIT, node) if node.status in (NODE_STATUS.COMMISSIONING, NODE_STATUS.READY): messages.info(self.request, NODE_BOOT_INFO) if node.power_type == POWER_TYPE.DEFAULT: messages.error(self.request, NO_POWER_SET) context['error_text'] = ( node.error if node.status == NODE_STATUS.FAILED_TESTS else None) context['status_text'] = ( node.error if node.status != NODE_STATUS.FAILED_TESTS else None) kernel_opts = node.get_effective_kernel_options() context['kernel_opts'] = { 'is_global': kernel_opts[0] is None, 'is_tag': isinstance(kernel_opts[0], Tag), 'tag': kernel_opts[0], 'value': kernel_opts[1] } # Produce a "clean" composite details document. probed_details = merge_details_cleanly( get_single_probed_details(node.system_id)) # We check here if there's something to show instead of after # the call to get_single_probed_details() because here the # details will be guaranteed well-formed. if len(probed_details.xpath('/*/*')) == 0: context["probed_details"] = None else: context["probed_details"] = etree.tostring( probed_details, encoding=unicode, pretty_print=True) return context
def test__returns_all_details(self): node = factory.make_Node(with_empty_script_sets=True) script_set = node.current_commissioning_script_set for script_name, stdout in ((LSHW_OUTPUT_NAME, b"<lshw-data/>"), (LLDP_OUTPUT_NAME, b"<lldp-data/>")): script_result = script_set.find_script_result( script_name=script_name) script_result.store_result(exit_status=0, stdout=stdout) self.assertDictEqual({ "lshw": b"<lshw-data/>", "lldp": b"<lldp-data/>" }, get_single_probed_details(node))
def populate_tags_for_single_node(tags, node): """Reevaluate all tags for a single node. Presumably this node's details have recently changed. Use `populate_tags` when many nodes need reevaluating. """ probed_details = get_single_probed_details(node.system_id) probed_details_doc = merge_details(probed_details) # Same document, many queries: use XPathEvaluator. evaluator = etree.XPathEvaluator(probed_details_doc, namespaces=tag_nsmap) evaluator = partial(try_match_xpath, doc=evaluator, logger=logger) tags_defined = ((tag, tag.definition) for tag in tags if tag.is_defined) tags_matching, tags_nonmatching = classify(evaluator, tags_defined) node.tags.remove(*tags_nonmatching) node.tags.add(*tags_matching)
def test_calls_through_to_get_probed_details(self): node = factory.make_node() get_probed_details = self.patch( nodeprobeddetails, "get_probed_details", create_autospec(nodeprobeddetails.get_probed_details)) get_probed_details.return_value = { node.system_id: { "lshw": b"<lshw-data/>", "lldp": b"<lldp-data/>", }, } self.assertDictEqual( {"lshw": b"<lshw-data/>", "lldp": b"<lldp-data/>"}, nodeprobeddetails.get_single_probed_details(node.system_id)) get_probed_details.assert_called_once_with((node.system_id,))
def test_calls_through_to_get_probed_details(self): node = factory.make_node() get_probed_details = self.patch( nodeprobeddetails, "get_probed_details", create_autospec(nodeprobeddetails.get_probed_details)) get_probed_details.return_value = { node.system_id: { "lshw": b"<lshw-data/>", "lldp": b"<lldp-data/>", }, } self.assertDictEqual({ "lshw": b"<lshw-data/>", "lldp": b"<lldp-data/>" }, nodeprobeddetails.get_single_probed_details(node.system_id)) get_probed_details.assert_called_once_with((node.system_id, ))
def populate_tags_for_single_node(tags, node): """Reevaluate all tags for a single node. Presumably this node's details have recently changed. Use `populate_tags` when many nodes need reevaluating AND there are rack controllers available to which to farm-out work. Use `populate_tag_for_multiple_nodes` when many nodes need reevaluating locally, i.e. when there are no rack controllers connected. """ probed_details = get_single_probed_details(node) probed_details_doc = merge_details(probed_details) # Same document, many queries: use XPathEvaluator. evaluator = etree.XPathEvaluator(probed_details_doc, namespaces=tag_nsmap) evaluator = partial(try_match_xpath, doc=evaluator, logger=logger) tags_defined = ((tag, tag.definition) for tag in tags if tag.is_defined) tags_matching, tags_nonmatching = classify(evaluator, tags_defined) node.tags.remove(*tags_nonmatching) node.tags.add(*tags_matching)
def dehydrate_summary_output(self, obj, data): """Dehydrate the machine summary output.""" # Produce a "clean" composite details document. probed_details = merge_details_cleanly(get_single_probed_details(obj)) # We check here if there's something to show instead of after # the call to get_single_probed_details() because here the # details will be guaranteed well-formed. if len(probed_details.xpath('/*/*')) == 0: data['summary_xml'] = None data['summary_yaml'] = None else: data['summary_xml'] = etree.tostring(probed_details, encoding=str, pretty_print=True) data['summary_yaml'] = XMLToYAML( etree.tostring(probed_details, encoding=str, pretty_print=True)).convert() return data
def details(self, request, system_id): """@description-title Get system details @description Returns system details -- for example, LLDP and ``lshw`` XML dumps. Returns a ``{detail_type: xml, ...}`` map, where ``detail_type`` is something like "lldp" or "lshw". Note that this is returned as BSON and not JSON. This is for efficiency, but mainly because JSON can't do binary content without applying additional encoding like base-64. The example output below is represented in ASCII using ``bsondump example.bson`` and is for demonstrative purposes. @param (string) "{system_id}" [required=true] The node's system_id. @success (http-status-code) "200" 200 @success (content) "success-content" A BSON object represented here in ASCII using ``bsondump example.bson``. @success-example "success-content" [exkey=details] placeholder text @error (http-status-code) "404" 404 @error (content) "not-found" The requested node is not found. @error-example "not-found" Not Found """ node = get_object_or_404(self.model, system_id=system_id) probe_details = get_single_probed_details(node) probe_details_report = { name: None if data is None else bson.Binary(data) for name, data in probe_details.items() } return HttpResponse( bson.BSON.encode(probe_details_report), # Not sure what media type to use here. content_type="application/bson", )
def details(self, request, system_id): """Obtain various system details. For example, LLDP and ``lshw`` XML dumps. Returns a ``{detail_type: xml, ...}`` map, where ``detail_type`` is something like "lldp" or "lshw". Note that this is returned as BSON and not JSON. This is for efficiency, but mainly because JSON can't do binary content without applying additional encoding like base-64. Returns 404 if the node is not found. """ node = get_object_or_404(self.model, system_id=system_id) probe_details = get_single_probed_details(node) probe_details_report = { name: None if data is None else bson.Binary(data) for name, data in probe_details.items() } return HttpResponse( bson.BSON.encode(probe_details_report), # Not sure what media type to use here. content_type='application/bson')
def details(self, request, system_id): """Obtain various system details. For example, LLDP and ``lshw`` XML dumps. Returns a ``{detail_type: xml, ...}`` map, where ``detail_type`` is something like "lldp" or "lshw". Note that this is returned as BSON and not JSON. This is for efficiency, but mainly because JSON can't do binary content without applying additional encoding like base-64. Returns 404 if the node is not found. """ node = get_object_or_404(Node, system_id=system_id) probe_details = get_single_probed_details(node.system_id) probe_details_report = { name: None if data is None else bson.Binary(data) for name, data in probe_details.items() } return HttpResponse( bson.BSON.encode(probe_details_report), # Not sure what media type to use here. content_type='application/bson')
def test__returns_null_details_when_there_are_none(self): node = factory.make_Node() self.assertDictEqual({ "lshw": None, "lldp": None }, get_single_probed_details(node))