Merge "UX: Fix: rtc-efi blacklist for Ubuntu targets."
[armband.git] / patches / opnfv-fuel / 0022-ipmi_adapter-simplify-retry-if-command-fails.patch
1 From: Josep Puigdemont <josep.puigdemont@enea.com>
2 Date: Fri, 6 May 2016 12:09:58 +0200
3 Subject: [PATCH] ipmi_adapter: simplify, retry if command fails
4
5 The method get_node_state has been added to the The IpmiAdapter class.
6
7 In addition, now the power on/off methods will try several times to
8 perform their IPMI command before giving up, instead of bailing out at
9 the first error.
10
11 After the power on/off command is completed, the method will wait until
12 the node is in the desired state.
13
14 FIXME: a command could potentially take several minutes if the defaults
15 are used; each IPMI command can take 1 minutes, and there can be three
16 commands issued per operation, one of them may be retried 20 times with
17 the current defaults. Ideally we would use eventlet or something alike
18 to allow each command a limited time to execute:
19     with eventlet.timeout.Timeout(seconds) as t:
20         power_on/off_command
21
22 FIXME: There is a potential dead-lock situation by issuing the command
23 and then checking the status, as someone could have intervened in
24 between the two commands.
25
26 Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com>
27 ---
28  deploy/dha_adapters/ipmi_adapter.py | 101 +++++++++++++++---------------------
29  1 file changed, 42 insertions(+), 59 deletions(-)
30
31 diff --git a/deploy/dha_adapters/ipmi_adapter.py b/deploy/dha_adapters/ipmi_adapter.py
32 index 8fda4f9..283bd57 100644
33 --- a/deploy/dha_adapters/ipmi_adapter.py
34 +++ b/deploy/dha_adapters/ipmi_adapter.py
35 @@ -1,5 +1,6 @@
36  ###############################################################################
37  # Copyright (c) 2015 Ericsson AB and others.
38 +#           (c) 2016 Enea Software AB
39  # szilard.cserey@ericsson.com
40  # All rights reserved. This program and the accompanying materials
41  # are made available under the terms of the Apache License, Version 2.0
42 @@ -20,8 +21,10 @@ from common import (
43  
44  class IpmiAdapter(HardwareAdapter):
45  
46 -    def __init__(self, yaml_path):
47 +    def __init__(self, yaml_path, attempts=20, delay=3):
48          super(IpmiAdapter, self).__init__(yaml_path)
49 +        self.attempts = attempts
50 +        self.delay = delay
51  
52      def get_access_info(self, node_id):
53          ip = self.get_node_property(node_id, 'ipmiIp')
54 @@ -40,69 +43,46 @@ class IpmiAdapter(HardwareAdapter):
55          mac_list.append(self.get_node_property(node_id, 'pxeMac').lower())
56          return mac_list
57  
58 +    def node_get_state(self, node_id):
59 +        state = exec_cmd('%s chassis power status' % self.ipmi_cmd(node_id),
60 +                         attempts=self.attempts, delay=self.delay,
61 +                         verbose=True)
62 +        return state
63 +
64 +    def __node_power_cmd__(self, node_id, cmd):
65 +        expected = 'Chassis Power is %s' % cmd
66 +        if self.node_get_state(node_id) == expected:
67 +            return
68 +
69 +        pow_cmd = '%s chassis power %s' % (self.ipmi_cmd(node_id), cmd)
70 +        exec_cmd(pow_cmd, attempts=self.attempts, delay=self.delay,
71 +                 verbose=True)
72 +
73 +        attempts = self.attempts
74 +        while attempts:
75 +            state = self.node_get_state(node_id)
76 +            attempts -= 1
77 +            if state == expected:
78 +                return
79 +            elif attempts != 0:
80 +                # reinforce our will, but allow the command to fail,
81 +                # we know our message got across once already...
82 +                exec_cmd(pow_cmd, check=False)
83 +
84 +        err('Could not set chassis %s for node %s' % (cmd, node_id))
85 +
86      def node_power_on(self, node_id):
87 -        WAIT_LOOP = 200
88 -        SLEEP_TIME = 3
89          log('Power ON Node %s' % node_id)
90 -        cmd_prefix = self.ipmi_cmd(node_id)
91 -        state = exec_cmd('%s chassis power status' % cmd_prefix)
92 -        if state == 'Chassis Power is off':
93 -            exec_cmd('%s chassis power on' % cmd_prefix)
94 -            done = False
95 -            for i in range(WAIT_LOOP):
96 -                state, _ = exec_cmd('%s chassis power status' % cmd_prefix,
97 -                                    False)
98 -                if state == 'Chassis Power is on':
99 -                    done = True
100 -                    break
101 -                else:
102 -                    time.sleep(SLEEP_TIME)
103 -            if not done:
104 -                err('Could Not Power ON Node %s' % node_id)
105 +        self.__node_power_cmd__(node_id, 'on')
106  
107      def node_power_off(self, node_id):
108 -        WAIT_LOOP = 200
109 -        SLEEP_TIME = 3
110          log('Power OFF Node %s' % node_id)
111 -        cmd_prefix = self.ipmi_cmd(node_id)
112 -        state = exec_cmd('%s chassis power status' % cmd_prefix)
113 -        if state == 'Chassis Power is on':
114 -            done = False
115 -            exec_cmd('%s chassis power off' % cmd_prefix)
116 -            for i in range(WAIT_LOOP):
117 -                state, _ = exec_cmd('%s chassis power status' % cmd_prefix,
118 -                                    False)
119 -                if state == 'Chassis Power is off':
120 -                    done = True
121 -                    break
122 -                else:
123 -                    time.sleep(SLEEP_TIME)
124 -            if not done:
125 -                err('Could Not Power OFF Node %s' % node_id)
126 +        self.__node_power_cmd__(node_id, 'off')
127  
128      def node_reset(self, node_id):
129 -        WAIT_LOOP = 600
130          log('RESET Node %s' % node_id)
131 -        cmd_prefix = self.ipmi_cmd(node_id)
132 -        state = exec_cmd('%s chassis power status' % cmd_prefix)
133 -        if state == 'Chassis Power is on':
134 -            was_shut_off = False
135 -            done = False
136 -            exec_cmd('%s chassis power reset' % cmd_prefix)
137 -            for i in range(WAIT_LOOP):
138 -                state, _ = exec_cmd('%s chassis power status' % cmd_prefix,
139 -                                    False)
140 -                if state == 'Chassis Power is off':
141 -                    was_shut_off = True
142 -                elif state == 'Chassis Power is on' and was_shut_off:
143 -                    done = True
144 -                    break
145 -                time.sleep(1)
146 -            if not done:
147 -                err('Could Not RESET Node %s' % node_id)
148 -        else:
149 -            err('Cannot RESET Node %s because it\'s not Active, state: %s'
150 -                % (node_id, state))
151 +        cmd = '%s chassis power reset' % self.ipmi_cmd(node_id)
152 +        exec_cmd(cmd, attempts=self.attempts, delay=self.delay, verbose=True)
153  
154      def node_set_boot_order(self, node_id, boot_order_list):
155          log('Set boot order %s on Node %s' % (boot_order_list, node_id))
156 @@ -111,9 +91,12 @@ class IpmiAdapter(HardwareAdapter):
157          for dev in boot_order_list:
158              if dev == 'pxe':
159                  exec_cmd('%s chassis bootdev pxe options=persistent'
160 -                         % cmd_prefix)
161 +                         % cmd_prefix, attempts=self.attempts, delay=self.delay,
162 +                         verbose=True)
163              elif dev == 'iso':
164 -                exec_cmd('%s chassis bootdev cdrom' % cmd_prefix)
165 +                exec_cmd('%s chassis bootdev cdrom' % cmd_prefix,
166 +                         attempts=self.attempts, delay=self.delay, verbose=True)
167              elif dev == 'disk':
168                  exec_cmd('%s chassis bootdev disk options=persistent'
169 -                         % cmd_prefix)
170 +                         % cmd_prefix, attempts=self.attempts, delay=self.delay,
171 +                         verbose=True)