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

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. 

14 

15 

16import collections 

17import errno 

18import os 

19import signal 

20 

21from oslo_log import log as logging 

22 

23 

24LOG = logging.getLogger(__name__) 

25 

26 

27class InstanceJobTracker(object): 

28 def __init__(self): 

29 self.jobs = collections.defaultdict(list) 

30 

31 def add_job(self, instance, pid): 

32 """Appends process_id of instance to cache. 

33 

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. 

38 

39 :param instance: Object of instance 

40 :param pid: Id of the process 

41 """ 

42 self.jobs[instance.uuid].append(pid) 

43 

44 def remove_job(self, instance, pid): 

45 """Removes pid of process from cache. 

46 

47 This method will remove the pid of a process from the cache. 

48 

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) 

55 

56 # remove instance.uuid if no pid's remaining 

57 if not self.jobs[uuid]: 

58 self.jobs.pop(uuid, None) 

59 

60 def terminate_jobs(self, instance): 

61 """Kills the running processes for given instance. 

62 

63 This method is used to kill all running processes of the instance if 

64 it is deleted in between. 

65 

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) 

79 

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) 

92 

93 self.remove_job(instance, pid)