X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e38ac44d14e9006c24c93bca9de1ee299b16d367..5c0a4eb517a5f0b81e11df1b610fafdf3fab1dcc:/services/nodemanager/arvnodeman/computenode/dispatch/__init__.py diff --git a/services/nodemanager/arvnodeman/computenode/dispatch/__init__.py b/services/nodemanager/arvnodeman/computenode/dispatch/__init__.py index c5dd1adef1..9106ea67cc 100644 --- a/services/nodemanager/arvnodeman/computenode/dispatch/__init__.py +++ b/services/nodemanager/arvnodeman/computenode/dispatch/__init__.py @@ -20,6 +20,7 @@ from .. import \ arvados_node_missing, RetryMixin from ...clientactor import _notify_subscribers from ... import config +from ... import status from .transitions import transitions QuotaExceeded = "QuotaExceeded" @@ -113,14 +114,16 @@ class ComputeNodeSetupActor(ComputeNodeStateChangeBase): @ComputeNodeStateChangeBase._finish_on_exception @RetryMixin._retry(config.ARVADOS_ERRORS) def create_arvados_node(self): - self.arvados_node = self._arvados.nodes().create(body={}).execute() + self.arvados_node = self._arvados.nodes().create( + body={}, assign_slot=True).execute() self._later.create_cloud_node() @ComputeNodeStateChangeBase._finish_on_exception @RetryMixin._retry(config.ARVADOS_ERRORS) def prepare_arvados_node(self, node): - self.arvados_node = self._clean_arvados_node( - node, "Prepared by Node Manager") + self._clean_arvados_node(node, "Prepared by Node Manager") + self.arvados_node = self._arvados.nodes().update( + uuid=node['uuid'], body={}, assign_slot=True).execute() self._later.create_cloud_node() @ComputeNodeStateChangeBase._finish_on_exception @@ -270,6 +273,9 @@ class ComputeNodeShutdownActor(ComputeNodeStateChangeBase): self.cancel_shutdown("No longer eligible for shut down because %s" % reason, try_resume=True) return + # If boot failed, count the event + if self._monitor.get_state().get() == 'unpaired': + status.tracker.counter_add('boot_failures') self._destroy_node() def _destroy_node(self): @@ -315,7 +321,8 @@ class ComputeNodeUpdateActor(config.actor_class, RetryMixin): @RetryMixin._retry() def sync_node(self, cloud_node, arvados_node): - return self._cloud.sync_node(cloud_node, arvados_node) + if self._cloud.node_fqdn(cloud_node) != arvados_node_fqdn(arvados_node): + return self._cloud.sync_node(cloud_node, arvados_node) class ComputeNodeMonitorActor(config.actor_class): @@ -326,14 +333,13 @@ class ComputeNodeMonitorActor(config.actor_class): for shutdown. """ def __init__(self, cloud_node, cloud_node_start_time, shutdown_timer, - cloud_fqdn_func, timer_actor, update_actor, cloud_client, + timer_actor, update_actor, cloud_client, arvados_node=None, poll_stale_after=600, node_stale_after=3600, boot_fail_after=1800 ): super(ComputeNodeMonitorActor, self).__init__() self._later = self.actor_ref.tell_proxy() self._shutdowns = shutdown_timer - self._cloud_node_fqdn = cloud_fqdn_func self._timer = timer_actor self._update = update_actor self._cloud = cloud_client @@ -364,9 +370,15 @@ class ComputeNodeMonitorActor(config.actor_class): def get_state(self): """Get node state, one of ['unpaired', 'busy', 'idle', 'down'].""" - # If this node is not associated with an Arvados node, return 'unpaired'. + # If this node is not associated with an Arvados node, return + # 'unpaired' if we're in the boot grace period, and 'down' if not, + # so it isn't counted towards usable nodes. if self.arvados_node is None: - return 'unpaired' + if timestamp_fresh(self.cloud_node_start_time, + self.boot_fail_after): + return 'unpaired' + else: + return 'down' state = self.arvados_node['crunch_worker_state'] @@ -401,6 +413,12 @@ class ComputeNodeMonitorActor(config.actor_class): #if state == 'idle' and self.arvados_node['job_uuid']: # state = 'busy' + # Update idle node times tracker + if state == 'idle': + status.tracker.idle_in(self.arvados_node['hostname']) + else: + status.tracker.idle_out(self.arvados_node['hostname']) + return state def in_state(self, *states): @@ -480,8 +498,11 @@ class ComputeNodeMonitorActor(config.actor_class): self._later.consider_shutdown() def update_arvados_node(self, arvados_node): - # If the cloud node's FQDN doesn't match what's in the Arvados node - # record, make them match. + """Called when the latest Arvados node record is retrieved. + + Calls the updater's sync_node() method. + + """ # This method is a little unusual in the way it just fires off the # request without checking the result or retrying errors. That's # because this update happens every time we reload the Arvados node @@ -490,7 +511,5 @@ class ComputeNodeMonitorActor(config.actor_class): # the logic to throttle those effective retries when there's trouble. if arvados_node is not None: self.arvados_node = arvados_node - if (self._cloud_node_fqdn(self.cloud_node) != - arvados_node_fqdn(self.arvados_node)): - self._update.sync_node(self.cloud_node, self.arvados_node) + self._update.sync_node(self.cloud_node, self.arvados_node) self._later.consider_shutdown()