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