Coverage for nova/virt/libvirt/instancejobtracker.py: 74%
32 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-24 11:16 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-24 11:16 +0000
1# Copyright 2015 NTT corp.
2# All Rights Reserved.
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
16import collections
17import errno
18import os
19import signal
21from oslo_log import log as logging
24LOG = logging.getLogger(__name__)
27class InstanceJobTracker(object):
28 def __init__(self):
29 self.jobs = collections.defaultdict(list)
31 def add_job(self, instance, pid):
32 """Appends process_id of instance to cache.
34 This method will store the pid of a process in cache as
35 a key: value pair which will be used to kill the process if it
36 is running while deleting the instance. Instance uuid is used as
37 a key in the cache and pid will be the value.
39 :param instance: Object of instance
40 :param pid: Id of the process
41 """
42 self.jobs[instance.uuid].append(pid)
44 def remove_job(self, instance, pid):
45 """Removes pid of process from cache.
47 This method will remove the pid of a process from the cache.
49 :param instance: Object of instance
50 :param pid: Id of the process
51 """
52 uuid = instance.uuid
53 if uuid in self.jobs and pid in self.jobs[uuid]: 53 ↛ 57line 53 didn't jump to line 57 because the condition on line 53 was always true
54 self.jobs[uuid].remove(pid)
56 # remove instance.uuid if no pid's remaining
57 if not self.jobs[uuid]:
58 self.jobs.pop(uuid, None)
60 def terminate_jobs(self, instance):
61 """Kills the running processes for given instance.
63 This method is used to kill all running processes of the instance if
64 it is deleted in between.
66 :param instance: Object of instance
67 """
68 pids_to_remove = list(self.jobs.get(instance.uuid, []))
69 for pid in pids_to_remove:
70 try:
71 # Try to kill the process
72 os.kill(pid, signal.SIGKILL)
73 except OSError as exc:
74 if exc.errno != errno.ESRCH:
75 LOG.error('Failed to kill process %(pid)s '
76 'due to %(reason)s, while deleting the '
77 'instance.', {'pid': pid, 'reason': exc},
78 instance=instance)
80 try:
81 # Check if the process is still alive.
82 os.kill(pid, 0)
83 except OSError as exc:
84 if exc.errno != errno.ESRCH:
85 LOG.error('Unexpected error while checking process '
86 '%(pid)s.', {'pid': pid}, instance=instance)
87 else:
88 # The process is still around
89 LOG.warning("Failed to kill a long running process "
90 "%(pid)s related to the instance when "
91 "deleting it.", {'pid': pid}, instance=instance)
93 self.remove_job(instance, pid)