~ubuntu-branches/debian/stretch/resource-agents/stretch

« back to all changes in this revision

Viewing changes to rgmanager/src/resources/default_event_script.sl

  • Committer: Bazaar Package Importer
  • Author(s): Andres Rodriguez
  • Date: 2011-06-10 16:26:35 UTC
  • Revision ID: james.westby@ubuntu.com-20110610162635-yiy0vfopqw4trzgx
Tags: upstream-3.9.0
ImportĀ upstreamĀ versionĀ 3.9.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%
 
2
% Copyright (C) 1997-2003 Sistina Software, Inc.  All rights reserved.
 
3
% Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 
4
%
 
5
% This program is free software; you can redistribute it and/or
 
6
% modify it under the terms of the GNU General Public License
 
7
% as published by the Free Software Foundation; either version 2
 
8
% of the License, or (at your option) any later version.
 
9
%
 
10
% This program is distributed in the hope that it will be useful,
 
11
% but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
% GNU General Public License for more details.
 
14
%
 
15
% You should have received a copy of the GNU General Public License
 
16
% along with this program; if not, write to the Free Software
 
17
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
18
%
 
19
 
 
20
 
 
21
define node_in_set(node_list, node)
 
22
{
 
23
        variable x, len;
 
24
 
 
25
        len = length(node_list);
 
26
        for (x = 0; x < len; x++) {
 
27
                if (node_list[x] == node)
 
28
                        return 1;
 
29
        }
 
30
 
 
31
        return 0;
 
32
}
 
33
 
 
34
 
 
35
%
 
36
% Returns 3 node lists:
 
37
% (1) Nodes with no services
 
38
% (2) Nodes with non-exclusive services
 
39
% (3) Nodes with exclusive services
 
40
%
 
41
% NOTE: This function currently defenstrates failover domain rules
 
42
%
 
43
define separate_nodes(node_list)
 
44
{
 
45
        variable services = service_list();
 
46
        variable nodes_empty, nodes_services, nodes_excl;
 
47
        variable x, len;
 
48
        variable owner, state, excl, ns = 0, nx = 0;
 
49
 
 
50
        nodes_empty = node_list;
 
51
 
 
52
        % Most Awesome Initializer EVER!!!
 
53
        nodes_services = subtract([0], 0);
 
54
        nodes_excl = subtract([0], 0);
 
55
 
 
56
        len = length(services);
 
57
        for (x = 0; x < len; x++) {
 
58
 
 
59
                (,,, owner, state) = service_status(services[x]);
 
60
                if (owner < 0) {
 
61
                        continue;
 
62
                }
 
63
 
 
64
                excl = atoi(service_property(services[x], "exclusive"));
 
65
                nodes_empty = subtract(nodes_empty, owner);
 
66
                if (excl) {
 
67
                        nodes_excl = union(nodes_excl, owner);
 
68
                } else {
 
69
                        nodes_services = union(nodes_services, owner);
 
70
                }
 
71
        }
 
72
 
 
73
        return (nodes_empty, nodes_services, nodes_excl);
 
74
}
 
75
 
 
76
 
 
77
define exclusive_prioritize(svc, node_list)
 
78
{
 
79
        variable services = service_list();
 
80
        variable len, x, y, owner, state, preferred_owner;
 
81
        variable svc_excl, other_excl;
 
82
        variable nodes_x, nodes_s, nodes_e;
 
83
 
 
84
        %
 
85
        % Not exclusive?  Don't care!
 
86
        %
 
87
        svc_excl = atoi(service_property(svc, "exclusive"));
 
88
        if (svc_excl == 0) {
 
89
                return node_list;
 
90
        }
 
91
 
 
92
        (nodes_e, nodes_s, nodes_x) = separate_nodes(node_list);
 
93
        debug("Nodes - Empty: ", nodes_e, " w/Services: ", nodes_s, " w/Excl: ", nodes_x);
 
94
        if (length(nodes_e) > 0) {
 
95
                %
 
96
                % If we've got an exclusive service, only allow it to start on 
 
97
                % empty nodes.
 
98
                %
 
99
                return nodes_e;
 
100
        }
 
101
 
 
102
        if (length(nodes_x) == 0) {
 
103
                %
 
104
                % If we've got NO nodes with other exclusive services
 
105
                % and no empty nodes, the service can not be started
 
106
                %
 
107
                notice("No empty / exclusive nodes available; cannot restart ", svc);
 
108
                return nodes_x;
 
109
        }
 
110
 
 
111
        %
 
112
        % Prioritization of exclusive services: pancake a service and replace it
 
113
        % with this service if this services is a higher priority.
 
114
        %
 
115
        len = length(services);
 
116
        for (x = 0; x < len; x++) {
 
117
                if (svc == services[x]) {
 
118
                        % don't do anything to ourself! 
 
119
                        continue;
 
120
                }
 
121
 
 
122
                (,,, owner, state) = service_status(services[x]);
 
123
                if (owner < 0) {
 
124
                        continue;
 
125
                }
 
126
 
 
127
                if (node_in_set(node_list, owner) == 0) {
 
128
                        continue;
 
129
                }
 
130
 
 
131
                other_excl = atoi(service_property(services[x], "exclusive"));
 
132
                if (other_excl == 0) {
 
133
                        continue;
 
134
                }
 
135
 
 
136
                %
 
137
                % If we're a higher priority (lower #) exclusive
 
138
                % Stop the exclusive service that node and move that
 
139
                % node to the front.
 
140
                %
 
141
                if (svc_excl >= other_excl) {
 
142
                        continue;
 
143
                }
 
144
 
 
145
                %
 
146
                % 
 
147
                %
 
148
                warning("STOPPING service ", services[x], " because ", svc, " is a higher priority.");
 
149
                () = service_stop(services[x]);
 
150
 
 
151
                %
 
152
                % Return just the one node.
 
153
                %
 
154
                node_list = subtract([0], 0);
 
155
                node_list = union(node_list, owner);
 
156
                return node_list;
 
157
        }
 
158
 
 
159
        return node_list;
 
160
}
 
161
 
 
162
 
 
163
define move_or_start(service, node_list)
 
164
{
 
165
        variable len;
 
166
        variable state, owner;
 
167
        variable depends;
 
168
 
 
169
        depends = service_property(service, "depend");
 
170
        if (depends != "") {
 
171
                (,,, owner, state) = service_status(depends);
 
172
                if (owner < 0) {
 
173
                        debug(service, " is not runnable; dependency not met");
 
174
                        return ERR_DEPEND;
 
175
                }
 
176
        }
 
177
 
 
178
        (,,, owner, state) = service_status(service);
 
179
        debug("Evaluating ", service, " state=", state, " owner=", owner);
 
180
        if ((event_type == EVENT_NODE) and (node_id == owner) and
 
181
            (node_state == NODE_OFFLINE)) {
 
182
                info("Marking service ", service, " on down member ",
 
183
                     owner, " as stopped");
 
184
                if (service_stop(service) < 0) {
 
185
                        return ERR_ABORT;
 
186
                }
 
187
        }
 
188
 
 
189
        len = length(node_list);
 
190
        if (len == 0) {
 
191
                notice(service, " is not runnable - restricted domain offline");
 
192
                ()=service_stop(service);
 
193
                return ERR_DOMAIN;
 
194
        }
 
195
 
 
196
        if (((event_type != EVENT_USER) and (state == "disabled")) or
 
197
            ((state == "failed") or (state == "frozen"))) {
 
198
                %
 
199
                % Commenting out this block will -not- allow you to
 
200
                % recover failed services from event scripts.  Sorry.
 
201
                % All it will get you is a false log message about
 
202
                % starting this service.
 
203
                %
 
204
                % You may enable disabled services, but I recommend
 
205
                % against it.
 
206
                %
 
207
                debug(service, " is not runnable");
 
208
                return -1;
 
209
        }
 
210
 
 
211
        if (node_list[0] == owner) {
 
212
                debug(service, " is already running on best node");
 
213
                return ERR_RUNNING;
 
214
        }
 
215
 
 
216
        if ((owner >= 0) and (node_in_set(node_list, owner) == 1)) {
 
217
                notice("Moving ", service, " from ", owner,
 
218
                       " to ", node_list);
 
219
                if (service_stop(service) < 0) {
 
220
                        return ERR_ABORT;
 
221
                }
 
222
        } else {
 
223
                node_list = exclusive_prioritize(service, node_list);
 
224
                notice("Starting ", service, " on ", node_list);
 
225
        }
 
226
 
 
227
        if (length(node_list) == 0) {
 
228
                return ERR_DOMAIN; 
 
229
        }
 
230
        return service_start(service, node_list);
 
231
}
 
232
 
 
233
 
 
234
%
 
235
% Returns the set of online nodes in preferred/shuffled order which
 
236
% are allowed to run this service.  Gives highest preference to current
 
237
% owner if nofailback is specified.
 
238
 
239
define allowed_nodes(service)
 
240
{
 
241
        variable anodes;
 
242
        variable online;
 
243
        variable nodes_domain;
 
244
        variable ordered, restricted, nofailback;
 
245
        variable state, owner;
 
246
        variable depends;
 
247
 
 
248
        (nofailback, restricted, ordered, nodes_domain) =
 
249
                        service_domain_info(service);
 
250
 
 
251
        (,,, owner, state) = service_status(service);
 
252
 
 
253
        anodes = nodes_online();
 
254
 
 
255
        % Shuffle the array so we don't start all services on the same
 
256
        % node.  TODO - add RR, Least-services, placement policies...
 
257
        online = shuffle(anodes);
 
258
 
 
259
        if (restricted == 1) {
 
260
                anodes = intersection(nodes_domain, online);
 
261
        } else {
 
262
                % Ordered failover domains (nodes_domain) unioned with the
 
263
                % online nodes basically just reorders the online node list
 
264
                % according to failover domain priority rules.
 
265
                anodes = union(intersection(nodes_domain, online),
 
266
                               online);
 
267
        }
 
268
 
 
269
        if ((nofailback == 1) or (ordered == 0)) {
 
270
                
 
271
                if ((owner < 0) or (node_in_set(anodes, owner) == 0)) {
 
272
                        return anodes;
 
273
                }
 
274
                
 
275
                % Because union takes left as priority, we can
 
276
                % return the union of the current owner with the
 
277
                % allowed node list.  This means the service will
 
278
                % remain on the same node it's currently on.
 
279
                return union(owner, anodes);
 
280
        }
 
281
 
 
282
        return anodes;
 
283
}
 
284
 
 
285
%
 
286
% Returns the set of online nodes in preferred/shuffled order which
 
287
% are allowed to run this service.  Gives highest preference to current
 
288
% owner if nofailback is specified.
 
289
 
290
define allowed_nodes(service)
 
291
{
 
292
        variable anodes;
 
293
        variable online;
 
294
        variable nodes_domain;
 
295
        variable ordered, restricted, nofailback;
 
296
        variable state, owner;
 
297
        variable depends;
 
298
 
 
299
        (nofailback, restricted, ordered, nodes_domain) =
 
300
                        service_domain_info(service);
 
301
        (,,, owner, state) = service_status(service);
 
302
 
 
303
        anodes = nodes_online();
 
304
 
 
305
        % Shuffle the array so we don't start all services on the same
 
306
        % node.  TODO - add RR, Least-services, placement policies...
 
307
        online = shuffle(anodes);
 
308
 
 
309
        if (restricted == 1) {
 
310
                anodes = intersection(nodes_domain, online);
 
311
        } else {
 
312
                % Ordered failover domains (nodes_domain) unioned with the
 
313
                % online nodes basically just reorders the online node list
 
314
                % according to failover domain priority rules.
 
315
                anodes = union(intersection(nodes_domain, online),
 
316
                               online);
 
317
        }
 
318
 
 
319
        if ((nofailback == 1) or (ordered == 0)) {
 
320
                
 
321
                if ((owner < 0) or (node_in_set(anodes, owner) == 0)) {
 
322
                        return anodes;
 
323
                }
 
324
                
 
325
                % Because union takes left as priority, we can
 
326
                % return the union of the current owner with the
 
327
                % allowed node list.  This means the service will
 
328
                % remain on the same node it's currently on.
 
329
                return union(owner, anodes);
 
330
        }
 
331
 
 
332
        return anodes;
 
333
}
 
334
 
 
335
define string_list(thelist, delimiter)
 
336
{
 
337
        variable index;
 
338
        variable output="";
 
339
 
 
340
        if (length(thelist) == 0) {
 
341
                return output;
 
342
        }
 
343
  
 
344
        for (index=0; index < length(thelist)-1; index++) {
 
345
                output=output+string(thelist[index])+delimiter;
 
346
        }
 
347
        return output+thelist[index];
 
348
}
 
349
 
 
350
% this function gets the smallest property from a given list of services
 
351
% if the list only exists of one element the property itself is returned
 
352
% if the given property is not found 0 is returned
 
353
define services_min_attribute(services, property)
 
354
{
 
355
        variable x;
 
356
        variable min_property=-1;
 
357
        variable tmp_property;
 
358
 
 
359
        for (x = 0; x < length(services); x++) {
 
360
                tmp_property=service_property(services[x], property);
 
361
                if (tmp_property == NULL) {
 
362
                        tmp_property=0;
 
363
                } else {
 
364
                        tmp_property=atoi(tmp_property);
 
365
                }
 
366
                if ((min_property < 0) or (tmp_property < min_property)) {
 
367
                        min_property=tmp_property;
 
368
                }
 
369
                %debug("services_min_attribute: ",services[x]," attribute: ",min_property, "tmp: ", tmp_property, " min: ", min_property);
 
370
        }
 
371
 
 
372
        %debug("services_min_attribute: (", string_list(services, ", "),")[",property,"]: ",min_property);
 
373
 
 
374
        return min_property;
 
375
}
 
376
 
 
377
% This function will sort a given service_list by the given attribute name and
 
378
% return the list
 
379
define sorted_service_list(services, attribute)
 
380
{
 
381
        variable work_queue={};
 
382
        variable sorted_list={}, tmp, tmp2;
 
383
        variable x, y;
 
384
        variable cur_min_prop=0;
 
385
        variable service_prop=0;
 
386
 
 
387
        y=0;
 
388
        %debug("sorted_service_list: ", strjoin(services, ", "));
 
389
        for (x=0; x<length(services); x++) {
 
390
                list_append(work_queue, string(services[x]));
 
391
        }
 
392
 
 
393
        %debug("sorted_service_list: work_queue ", string_list(work_queue, ", "));
 
394
        while (length(work_queue) > 0) {
 
395
                cur_min_prop=services_min_attribute(work_queue, attribute);
 
396
                %debug("sorted_service_list sorting services list for attribute ", attribute, " cur_min: ",cur_min_prop);
 
397
                for (x = 0; x < length(work_queue); x++) {
 
398
                        service_prop=service_property(work_queue[x], "priority");
 
399
                        if (service_prop == NULL) {
 
400
                                service_prop=0;
 
401
                        } else {
 
402
                                service_prop=atoi(service_prop);
 
403
                        }
 
404
                        %debug("sorted_service_list: ",work_queue[x], " property[", attribute,"]: ",service_prop);
 
405
                        if (cur_min_prop==service_prop) {
 
406
                                %debug("sorted_service_list: adding service ",work_queue[x]," to sorted. work_queue: ", string_list(work_queue, ", "));
 
407
                                list_append(sorted_list, work_queue[x]);
 
408
                                %debug("sorted_service_list: sorted_list: ", string_list(sorted_list, ", "));
 
409
                                %debug("sorted_service_list: removing service ",work_queue[x], " from work_queue ", string_list(work_queue, ", "));
 
410
                                list_delete(work_queue, x);
 
411
                                x=x-1;
 
412
                                %debug("sorted_service_list: work_queue: ",string_list(work_queue, ", "));
 
413
                                y=y+1;
 
414
                        }
 
415
                }
 
416
        }
 
417
 
 
418
        debug("sorted_service_list ", string_list(sorted_list, ", "));
 
419
        return sorted_list;
 
420
}
 
421
 
 
422
define sortedservices_node_event_handler(services, attribute) {
 
423
        variable x;
 
424
        variable nodes;
 
425
 
 
426
        services=sorted_service_list(services, attribute);
 
427
        for (x = 0; x < length(services); x++) {
 
428
                debug("Executing sortedservices node event handler for service: ", services[x]);
 
429
                nodes = allowed_nodes(services[x]);
 
430
                ()=move_or_start(services[x], nodes);
 
431
        }
 
432
}
 
433
 
 
434
define default_node_event_handler()
 
435
{
 
436
        variable services = service_list();
 
437
        variable x;
 
438
        variable nodes;
 
439
 
 
440
        debug("Executing default node event handler");
 
441
        for (x = 0; x < length(services); x++) {
 
442
                nodes = allowed_nodes(services[x]);
 
443
                ()=move_or_start(services[x], nodes);
 
444
        }
 
445
}
 
446
 
 
447
 
 
448
define default_service_event_handler()
 
449
{
 
450
        variable services = service_list();
 
451
        variable x;
 
452
        variable depends;
 
453
        variable depend_mode;
 
454
        variable policy;
 
455
        variable nodes;
 
456
        variable tmp;
 
457
        variable owner;
 
458
        variable state;
 
459
 
 
460
        debug("Executing default service event handler");
 
461
 
 
462
        if (service_state == "recovering") {
 
463
 
 
464
                policy = service_property(service_name, "recovery");
 
465
                debug("Recovering",
 
466
                      " Service: ", service_name,
 
467
                      " Last owner: ", service_last_owner,
 
468
                      " Policy: ", policy,
 
469
                      " RTE: ", service_restarts_exceeded);
 
470
 
 
471
                if (policy == "disable") {
 
472
                        () = service_stop(service_name, 1);
 
473
                        return;
 
474
                }
 
475
 
 
476
                nodes = allowed_nodes(service_name);
 
477
                if (policy == "restart" and service_restarts_exceeded == 0) {
 
478
                        nodes = union(service_last_owner, nodes);
 
479
                } else {
 
480
                        % relocate 
 
481
                        tmp = subtract(nodes, service_last_owner);
 
482
                        if (length(tmp) == 0) {
 
483
                                () = service_stop(service_name,0);
 
484
                                return;
 
485
                        }
 
486
 
 
487
                        nodes = union(tmp, service_last_owner);
 
488
                }
 
489
 
 
490
                ()=move_or_start(service_name, nodes);
 
491
 
 
492
                return;
 
493
        }
 
494
 
 
495
        for (x = 0; x < length(services); x++) {
 
496
                if (service_name == services[x]) {
 
497
                        % don't do anything to ourself! 
 
498
                        continue;
 
499
                }
 
500
 
 
501
                %
 
502
                % Simplistic dependency handling
 
503
                %
 
504
                depends = service_property(services[x], "depend");
 
505
                depend_mode = service_property(services[x], "depend_mode");
 
506
 
 
507
                % No dependency; do nothing
 
508
                if (depends != service_name) {
 
509
                        continue;
 
510
                }
 
511
 
 
512
                (,,, owner, state) = service_status(services[x]);
 
513
                if ((service_state == "started") and (owner < 0) and
 
514
                    (state == "stopped")) {
 
515
                        info("Dependency met; starting ", services[x]);
 
516
                        nodes = allowed_nodes(services[x]);
 
517
                        ()=move_or_start(services[x], nodes);
 
518
                }
 
519
 
 
520
                % service died - stop service(s) that depend on the dead
 
521
                if ((service_owner < 0) and (owner >= 0) and
 
522
                    (depend_mode != "soft")) {
 
523
                        info("Dependency lost; stopping ", services[x]);
 
524
                        ()=service_stop(services[x]);
 
525
                }
 
526
        }
 
527
}
 
528
 
 
529
define default_config_event_handler()
 
530
{
 
531
        debug("Executing default config event handler");
 
532
}
 
533
 
 
534
define default_user_event_handler()
 
535
{
 
536
        variable ret;
 
537
        variable nodes;
 
538
        variable reordered;
 
539
        variable x;
 
540
        variable target = user_target;
 
541
        variable found = 0;
 
542
        variable owner, state;
 
543
 
 
544
        nodes = allowed_nodes(service_name);
 
545
        (,,, owner, state) = service_status(service_name);
 
546
 
 
547
        if (user_request == USER_RESTART) {
 
548
 
 
549
                if (owner >= 0) {
 
550
                        reordered = union(owner, nodes);
 
551
                        nodes = reordered;
 
552
                }
 
553
 
 
554
                notice("Stopping ", service_name, " for relocate to ", nodes);
 
555
 
 
556
                found = service_stop(service_name);
 
557
                if (found < 0) {
 
558
                        return ERR_ABORT;
 
559
                }
 
560
 
 
561
                ret = move_or_start(service_name, nodes);
 
562
 
 
563
        } else if ((user_request == USER_RELOCATE) or 
 
564
                   (user_request == USER_ENABLE)) {
 
565
 
 
566
                if (user_target > 0) {
 
567
                        for (x = 0; x < length(nodes); x++) {
 
568
                                %
 
569
                                % Put the preferred node at the front of the 
 
570
                                % list for a user-relocate operation
 
571
                                %
 
572
                                if (nodes[x] == user_target) {
 
573
                                        reordered = union(user_target, nodes);
 
574
                                        nodes = reordered;
 
575
                                        found = 1;
 
576
                                }
 
577
                        }
 
578
        
 
579
                        if (found == 0) {
 
580
                                warning("User specified node ", user_target,
 
581
                                        " is offline");
 
582
                        }
 
583
                }
 
584
 
 
585
                if ((owner >= 0) and (user_request == USER_RELOCATE)) {
 
586
                        if (service_stop(service_name) < 0) {
 
587
                                return ERR_ABORT;
 
588
                        }
 
589
 
 
590
                        %
 
591
                        % The current owner shouldn't be the default
 
592
                        % for a relocate operation
 
593
                        %
 
594
                        reordered = subtract(nodes, owner);
 
595
                        nodes = union(reordered, owner);
 
596
                }
 
597
 
 
598
                ret = move_or_start(service_name, nodes);
 
599
 
 
600
        } else if (user_request == USER_DISABLE) {
 
601
 
 
602
                ret = service_stop(service_name, 1);
 
603
 
 
604
        } else if (user_request == USER_STOP) {
 
605
 
 
606
                ret = service_stop(service_name);
 
607
 
 
608
        } else if (user_request == USER_FREEZE) {
 
609
 
 
610
                ret = service_freeze(service_name);
 
611
 
 
612
        } else if (user_request == USER_UNFREEZE) {
 
613
 
 
614
                ret = service_unfreeze(service_name);
 
615
 
 
616
        } else if (user_request == USER_MIGRATE) {
 
617
 
 
618
                ret = service_migrate(service_name, user_target);
 
619
 
 
620
        } else if (user_request == USER_CONVALESCE) {
 
621
 
 
622
                ret = service_convalesce(service_name);
 
623
 
 
624
        }
 
625
 
 
626
        return ret;
 
627
}
 
628
 
 
629
if (event_type == EVENT_NODE)
 
630
        sortedservices_node_event_handler(service_list(), "priority");
 
631
if (event_type == EVENT_SERVICE)
 
632
        default_service_event_handler();
 
633
if (event_type == EVENT_CONFIG)
 
634
        default_config_event_handler();
 
635
if (event_type == EVENT_USER)
 
636
        user_return=default_user_event_handler();
 
637