1 /*
2 * Copyright 2004-2019 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #include <crm_internal.h>
11
12 #include <crm/pengine/rules.h>
13 #include <crm/pengine/status.h>
14 #include <crm/pengine/internal.h>
15 #include <unpack.h>
16 #include <crm/msg_xml.h>
17
18 #define VARIANT_GROUP 1
19 #include "./variant.h"
20
21 gboolean
group_unpack(resource_t * rsc,pe_working_set_t * data_set)22 group_unpack(resource_t * rsc, pe_working_set_t * data_set)
23 {
24 xmlNode *xml_obj = rsc->xml;
25 xmlNode *xml_native_rsc = NULL;
26 group_variant_data_t *group_data = NULL;
27 const char *group_ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
28 const char *group_colocated = g_hash_table_lookup(rsc->meta, "collocated");
29 const char *clone_id = NULL;
30
31 pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
32
33 group_data = calloc(1, sizeof(group_variant_data_t));
34 group_data->num_children = 0;
35 group_data->first_child = NULL;
36 group_data->last_child = NULL;
37 rsc->variant_opaque = group_data;
38
39 group_data->ordered = TRUE;
40 group_data->colocated = TRUE;
41
42 if (group_ordered != NULL) {
43 crm_str_to_boolean(group_ordered, &(group_data->ordered));
44 }
45 if (group_colocated != NULL) {
46 crm_str_to_boolean(group_colocated, &(group_data->colocated));
47 }
48
49 clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION);
50
51 for (xml_native_rsc = __xml_first_child_element(xml_obj); xml_native_rsc != NULL;
52 xml_native_rsc = __xml_next_element(xml_native_rsc)) {
53 if (crm_str_eq((const char *)xml_native_rsc->name, XML_CIB_TAG_RESOURCE, TRUE)) {
54 resource_t *new_rsc = NULL;
55
56 crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id);
57 if (common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) {
58 pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID));
59 if (new_rsc != NULL && new_rsc->fns != NULL) {
60 new_rsc->fns->free(new_rsc);
61 }
62 continue;
63 }
64
65 group_data->num_children++;
66 rsc->children = g_list_append(rsc->children, new_rsc);
67
68 if (group_data->first_child == NULL) {
69 group_data->first_child = new_rsc;
70 }
71 group_data->last_child = new_rsc;
72 pe_rsc_trace(rsc, "Added %s member %s", rsc->id, new_rsc->id);
73 }
74 }
75
76 if (group_data->num_children == 0) {
77 #if 0
78 /* Bug #1287 */
79 crm_config_err("Group %s did not have any children", rsc->id);
80 return FALSE;
81 #else
82 crm_config_warn("Group %s did not have any children", rsc->id);
83 return TRUE;
84 #endif
85 }
86
87 pe_rsc_trace(rsc, "Added %d children to resource %s...", group_data->num_children, rsc->id);
88
89 return TRUE;
90 }
91
92 gboolean
group_active(resource_t * rsc,gboolean all)93 group_active(resource_t * rsc, gboolean all)
94 {
95 gboolean c_all = TRUE;
96 gboolean c_any = FALSE;
97 GListPtr gIter = rsc->children;
98
99 for (; gIter != NULL; gIter = gIter->next) {
100 resource_t *child_rsc = (resource_t *) gIter->data;
101
102 if (child_rsc->fns->active(child_rsc, all)) {
103 c_any = TRUE;
104 } else {
105 c_all = FALSE;
106 }
107 }
108
109 if (c_any == FALSE) {
110 return FALSE;
111 } else if (all && c_all == FALSE) {
112 return FALSE;
113 }
114 return TRUE;
115 }
116
117 static void
group_print_xml(resource_t * rsc,const char * pre_text,long options,void * print_data)118 group_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data)
119 {
120 GListPtr gIter = rsc->children;
121 char *child_text = crm_concat(pre_text, " ", ' ');
122
123 status_print("%s<group id=\"%s\" ", pre_text, rsc->id);
124 status_print("number_resources=\"%d\" ", g_list_length(rsc->children));
125 status_print(">\n");
126
127 for (; gIter != NULL; gIter = gIter->next) {
128 resource_t *child_rsc = (resource_t *) gIter->data;
129
130 child_rsc->fns->print(child_rsc, child_text, options, print_data);
131 }
132
133 status_print("%s</group>\n", pre_text);
134 free(child_text);
135 }
136
137 void
group_print(resource_t * rsc,const char * pre_text,long options,void * print_data)138 group_print(resource_t * rsc, const char *pre_text, long options, void *print_data)
139 {
140 char *child_text = NULL;
141 GListPtr gIter = rsc->children;
142
143 if (pre_text == NULL) {
144 pre_text = " ";
145 }
146
147 if (options & pe_print_xml) {
148 group_print_xml(rsc, pre_text, options, print_data);
149 return;
150 }
151
152 child_text = crm_concat(pre_text, " ", ' ');
153
154 status_print("%sResource Group: %s", pre_text ? pre_text : "", rsc->id);
155
156 if (options & pe_print_html) {
157 status_print("\n<ul>\n");
158
159 } else if ((options & pe_print_log) == 0) {
160 status_print("\n");
161 }
162
163 if (options & pe_print_brief) {
164 print_rscs_brief(rsc->children, child_text, options, print_data, TRUE);
165
166 } else {
167 for (; gIter != NULL; gIter = gIter->next) {
168 resource_t *child_rsc = (resource_t *) gIter->data;
169
170 if (options & pe_print_html) {
171 status_print("<li>\n");
172 }
173 child_rsc->fns->print(child_rsc, child_text, options, print_data);
174 if (options & pe_print_html) {
175 status_print("</li>\n");
176 }
177 }
178 }
179
180 if (options & pe_print_html) {
181 status_print("</ul>\n");
182 }
183 free(child_text);
184 }
185
186 void
group_free(resource_t * rsc)187 group_free(resource_t * rsc)
188 {
189 CRM_CHECK(rsc != NULL, return);
190
191 pe_rsc_trace(rsc, "Freeing %s", rsc->id);
192
193 for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
194 resource_t *child_rsc = (resource_t *) gIter->data;
195
196 CRM_ASSERT(child_rsc);
197 pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
198 child_rsc->fns->free(child_rsc);
199 }
200
201 pe_rsc_trace(rsc, "Freeing child list");
202 g_list_free(rsc->children);
203
204 common_free(rsc);
205 }
206
207 enum rsc_role_e
group_resource_state(const resource_t * rsc,gboolean current)208 group_resource_state(const resource_t * rsc, gboolean current)
209 {
210 enum rsc_role_e group_role = RSC_ROLE_UNKNOWN;
211 GListPtr gIter = rsc->children;
212
213 for (; gIter != NULL; gIter = gIter->next) {
214 resource_t *child_rsc = (resource_t *) gIter->data;
215 enum rsc_role_e role = child_rsc->fns->state(child_rsc, current);
216
217 if (role > group_role) {
218 group_role = role;
219 }
220 }
221
222 pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(group_role));
223 return group_role;
224 }
225