)]}'
{"watcher/decision_engine/model/collector/nova.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"e92733aaf3a3d92e383027e557e026fa2c9d402e","unresolved":false,"context_lines":[{"line_number":452,"context_line":"            \"state\": node.state,"},{"line_number":453,"context_line":"            \"status\": node.status,"},{"line_number":454,"context_line":"            \"disabled_reason\": node.service_disabled_reason,"},{"line_number":455,"context_line":"            \"availability_zone\": self._host_az_map.get(node.service_host, \u0027\u0027),"},{"line_number":456,"context_line":"        }"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":"        compute_node \u003d element.ComputeNode(**node_attributes)"}],"source_content_type":"text/x-python","patch_set":1,"id":"606536a5_cb9b68bc","line":455,"updated":"2026-11-06 14:22:10.000000000","message":"The change adds availability_zone to ComputeNode and populates it only in NovaModelBuilder.build_compute_node. The notification handler VersionedNotification.create_compute_node (watcher/decision_engine/model/notification/nova.py:210-228) keeps its own copy of the node_attributes dict and was not updated. Nodes added incrementally to the cached cluster data model via service_updated, instance_created, instance_updated, or instance_deleted all funnel through get_or_create_node -\u003e create_compute_node, so those nodes keep the field default \u0027\u0027 even when the builder\u0027s _host_az_map has the zone. The two constructors are parallel implementations of the same node-attribute invariant and have now drifted apart in the same change that introduced the field.\n\n**Severity**: SUGGESTION | **Confidence**: 0.85\n\n**Impact**: A strategy or the planned zone-drain patch reading node.availability_zone will see an empty zone for hosts that entered the model through notifications (for example a newly added compute host that runs an instance before the next full model rebuild), misclassifying it as zone-less. The duplicated constructor also means every future node-attribute addition must be applied twice or the two node shapes silently diverge.\n\n**Recommendation**:\nPopulate availability_zone in create_compute_node as well (e.g., resolve the host zone from nova_helper.get_service_list()), or factor the node_attributes construction shared by build_compute_node and create_compute_node into a single helper so the attribute set cannot drift.","commit_id":"b4217faf58921431379eac928c6aa36b3257bbc0"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"e3beecd0822661cc5143a8566ad6fcf6c8c67e2b","unresolved":false,"context_lines":[{"line_number":452,"context_line":"            \"state\": node.state,"},{"line_number":453,"context_line":"            \"status\": node.status,"},{"line_number":454,"context_line":"            \"disabled_reason\": node.service_disabled_reason,"},{"line_number":455,"context_line":"            \"availability_zone\": self._host_az_map.get(node.service_host, \u0027\u0027),"},{"line_number":456,"context_line":"        }"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":"        compute_node \u003d element.ComputeNode(**node_attributes)"}],"source_content_type":"text/x-python","patch_set":1,"id":"bfead8ed_c58c4e7b","line":455,"in_reply_to":"606536a5_cb9b68bc","updated":"2026-11-06 20:12:03.000000000","message":"Ack, makes sense, it should retrieve the AZ for these nodes.","commit_id":"b4217faf58921431379eac928c6aa36b3257bbc0"}],"watcher/decision_engine/model/notification/nova.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"b7a9cba712bf79cb1b46e1a746d4446e2e28bd65","unresolved":false,"context_lines":[{"line_number":223,"context_line":"                \"state\": _node.state,"},{"line_number":224,"context_line":"                \"status\": _node.status,"},{"line_number":225,"context_line":"                \"disabled_reason\": _node.service_disabled_reason,"},{"line_number":226,"context_line":"                \"availability_zone\": ("},{"line_number":227,"context_line":"                    self.nova.get_availability_zone_by_hostname("},{"line_number":228,"context_line":"                        _node.service_host"},{"line_number":229,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":2,"id":"88419a72_a667b575","line":226,"updated":"2026-11-06 20:14:36.000000000","message":"create_compute_node() populates the new availability_zone attribute via self.nova.get_availability_zone_by_hostname(), but no such method exists on NovaHelper (watcher/common/nova_helper.py:389 extends BaseConnectionMixin; a repo-wide search finds no definition and the mixin has no __getattr__ fallback). At runtime this raises AttributeError every time a compute node must be created from a notification. The surrounding except Exception (nova.py:238-241) converts it into exception.ComputeNodeNotFound, so service.create/service.update events never add the new node, instance events leave instances on unknown hosts unmapped, and service_deleted cannot remove unknown nodes.\n\n**Severity**: HIGH | **Confidence**: 0.95\n\n**Impact**: Every notification path that needs to create a not-yet-modeled compute node fails: newly added compute services are never added to the cluster data model, instances arriving on unknown hosts stay unmapped, and stale unknown nodes cannot be removed. The CDM remains incomplete or stale until the next full collection and each affected notification logs an exception, breaking the supported incremental-update operation introduced for this purpose.\n\n**Priority**: Before merge\n**Recommendation**:\nAdd NovaHelper.get_availability_zone_by_hostname() (for example, resolve the host\u0027s zone from get_service_list(), mirroring the collector\u0027s host-to-AZ map, or query the compute service API), or populate the attribute from data already fetched in create_compute_node(). Also stub the helper with spec\u003dNovaHelper (or autospec) in test_nova_notifications.py so calls to methods that do not exist fail the tests instead of being silently accepted.","commit_id":"c3bcf8712d801adcb3c78bf57009b937354c7c2c"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"3648bc2108045cb002d2be9766ca8a9a3de66822","unresolved":false,"context_lines":[{"line_number":223,"context_line":"                \"state\": _node.state,"},{"line_number":224,"context_line":"                \"status\": _node.status,"},{"line_number":225,"context_line":"                \"disabled_reason\": _node.service_disabled_reason,"},{"line_number":226,"context_line":"                \"availability_zone\": ("},{"line_number":227,"context_line":"                    self.nova.get_availability_zone_by_hostname("},{"line_number":228,"context_line":"                        _node.service_host"},{"line_number":229,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":2,"id":"b8704e32_8e904ea9","line":226,"in_reply_to":"88419a72_a667b575","updated":"2026-11-06 20:32:09.000000000","message":"oops, missing that.","commit_id":"c3bcf8712d801adcb3c78bf57009b937354c7c2c"}]}
