Merge lp:~gandelman-a/ubuntu/precise/cobbler-enlist/868492 into lp:ubuntu/precise/cobbler-enlist

Proposed by Adam Gandelman
Status: Merged
Merge reported by: Dave Walker
Merged at revision: not available
Proposed branch: lp:~gandelman-a/ubuntu/precise/cobbler-enlist/868492
Merge into: lp:ubuntu/precise/cobbler-enlist
Diff against target: 441 lines (+238/-75)
4 files modified
cobbler-enlist.c (+32/-15)
cobbler-enlist.h (+168/-40)
cobbler-xmlrpc.h (+30/-20)
debian/changelog (+8/-0)
To merge this branch: bzr merge lp:~gandelman-a/ubuntu/precise/cobbler-enlist/868492
Reviewer Review Type Date Requested Status
Dave Walker (community) Approve
Review via email: mp+80642@code.launchpad.net

Description of the change

  Register all valid network interfaces when enlisting (LP: #868492)

  This converts enlister->netif to a linked-list (enlister->netifs). Each node
  of the LL is of struct netif, which contains an interface name and macaddr.

  Any number of interfaces can be supplied via the command line. Each interface
  is appended to the link list as a struct netif with the macaddr left NULL.

  If no interfaces are supplied via argv, the list is populated with every
  interface on the system (the macaddr for each left NULL).

  What is contained in the enlister->netifs list is then verified. In the event
  a non-existent interface was supplied via argv, it is removed from the list.
  If enlister->netifs is empty (ie, none of the interfaces supplied actually
  exist), die.

  Nodes remaining in enlister->netifs get their mac addr's populated via ioctl.
  Non-standard devices (ie, bridges not backed by any device) may contain a bad
  mac addr, these are skipped. After populating, error out if the list does not
  contain at least one valid mac address.

  During system registration, loop over enlister->netifs and register each device.

  On the cobbler side, the system ends up with something like:

  # cobbler system dumpvars --name=testnode | grep mac_address_
  mac_address_eth0 : 90:e6:ba:54:93:b9
  mac_address_eth1 : 00:04:5a:5e:62:5f
  mac_address_virbr1 : 52:54:00:c2:5d:94
  mac_address_vnet0 : fe:16:3e:3e:a9:1a
  mac_address_vnet1 : fe:54:00:4d:7e:a0

  Cobbler will serve the profile via netboot to any of the interfaces.

To post a comment you must log in.
Revision history for this message
C de-Avillez (hggdh2) wrote :

We should keep an option to select specific interfaces, both on install and run-time. There are environments where strict separation of interface usage is enforced, and selecting all interfaces will trigger an audit finding.

Revision history for this message
Dave Walker (davewalker) wrote :

@Carlos, If i read the comment correctly.. It should default to sending all mac addresses, but support comma separated list of interfaces it should use. This should also work via preseed (the real target), but I am concerned how this will work with cobbler generic preseeds (as it was my intention to ship default of register all interfaces)

thoughts?

Revision history for this message
Adam Gandelman (gandelman-a) wrote :

To be clear, the default behavior after this patch is to register ALL valid interfaces+mac addrs on the system. If one or multiple interfaces is specified on the command line, those (and only those) interfaces+macaddrs will be registered.

It seems we're still determining how best to gather system information and post back. This change set provides the necessary internals to register multiple NICs + mac addrs, which is something that will be desired regardless of how decide to gather them. I predict we'll move from obtaining mac addrs via ioctl() to parsing it outside of cobbler-enlist. While the front end argv handling will likely change over time, the internal enlister->netifs changes here (which is the bulk of the patch) should meet our needs regardless.

9. By Adam Gandelman

Fix malloc() casting and memory initialization

Revision history for this message
C de-Avillez (hggdh2) wrote :

@Daviey: A generic cobbler preseed could (and should, I think) default to all interfaces; those that need to enforce separation of usage can then adjust the preseed(s) as needed (I believe this is possible ;-). I would also expect that these customers would probably restrict to one, at most two interfaces.

Hum. We do not support, anymore, d-i selection of interfaces?

10. By Adam Gandelman

Add support for multiple network interfaces (convert enlister->netif
to linked list enlister->netifs). When no interfaces specified, defaults
to registering all interfaces on the system. (LP: #868492)

11. By Adam Gandelman

Merge trunk

Revision history for this message
Dave Walker (davewalker) wrote :

Changed the pocket and version, and uploaded

Thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cobbler-enlist.c'
2--- cobbler-enlist.c 2011-08-02 15:49:55 +0000
3+++ cobbler-enlist.c 2011-11-21 19:59:24 +0000
4@@ -48,13 +48,14 @@
5 main (int const argc, char **argv)
6 {
7 int rc;
8-
9 struct cobbler_client *enlister;
10 enlister = (struct cobbler_client *) malloc(sizeof(struct cobbler_client));
11+ if (enlister == NULL)
12+ die("malloc() failed for enlister- main()");
13+ memset(enlister, 0, sizeof(struct cobbler_client));
14 init_client(enlister);
15 int c;
16
17- //int this_option_optind = optind ? optind : 1;
18 int option_index = 0;
19
20 const char* const short_options = "hds:u:p:n:P:i:m:";
21@@ -67,7 +68,6 @@
22 {"netif", 1, 0, 'i'},
23 {"manclass", 1, 0, 'm'},
24 {"help", 0, 0, 'h'},
25- //{"default-interface", 1, 0, 0},
26 {0, 0, 0, 0}
27 };
28
29@@ -111,9 +111,8 @@
30 break;
31
32 case 'i':
33- enlister->netif = optarg;
34+ append_netif(enlister, optarg);
35 break;
36-
37 case 'm':
38 enlister->mgmt_class = optarg;
39 break;
40@@ -145,16 +144,30 @@
41 (enlister->name == NULL) ||
42 (enlister->profile == NULL))
43 {
44- fprintf(stderr, "[%s] ERROR: not all required parameters were passed\n", argv[0]);
45 help(argv[0]);
46- exit (1);
47- }
48-
49-
50- if ((rc = get_mac_address(enlister)) != 0) {
51- printf("ERROR: Could not determine mac address for any interface on system.\n");
52- exit(1);
53- }
54+ die("Not all required parameters were passed");
55+ }
56+
57+ /* if no interfaces were specified on command line, add all interfaces on
58+ the system */
59+ if (!enlister->netifs) {
60+ if (debug)
61+ printf("[DEBUG] Populating netifs list with all interfaces on system.\n");
62+ struct if_nameindex *ifs = if_nameindex();
63+ while (ifs && ifs->if_name) {
64+ if (strcasecmp(ifs->if_name, "lo") != 0)
65+ append_netif(enlister, ifs->if_name);
66+ ifs++;
67+ }
68+ }
69+
70+ /* ensure list isn't empty and all interfaces exist */
71+ if (verify_netifs(enlister) != 0)
72+ die("Could not verify any of specified interfaces");
73+
74+ /* get mac addresses for interfaces contained in enlister->netifs */
75+ if (get_mac_addresses(enlister) != 0)
76+ die("Could not determine mac address for any interface on system.");
77
78 if (debug)
79 display_config(enlister);
80@@ -162,12 +175,16 @@
81 /* Initialize our error-handling environment. */
82 if ((rc = init_xmlrpc_env(enlister)) != 0)
83 goto out;
84+ /* Initialize the client */
85 if ((rc = init_xmlrpc_client(enlister)) != 0)
86 goto out;
87+ /* Login to cobbler */
88 if ((rc = cobbler_login(enlister)) != 0)
89 goto out;
90- if ((rc = cobbler_register_system(enlister)) != 0)
91+ /* Register new system with everything contained in the enlister */
92+ if ((rc = cobbler_register_system(enlister)) != 0)
93 goto out;
94+ /* Save the system */
95 if ((rc = cobbler_save_system(enlister)) != 0)
96 goto out;
97
98
99=== modified file 'cobbler-enlist.h'
100--- cobbler-enlist.h 2011-09-28 00:43:36 +0000
101+++ cobbler-enlist.h 2011-11-21 19:59:24 +0000
102@@ -38,6 +38,8 @@
103 #define OPT_NETIF 5
104 #define OPT_HELP 6
105
106+#define NO_MACADDR "00:00:00:00:00:00"
107+
108 static int debug = 0;
109
110 struct cobbler_client {
111@@ -54,7 +56,16 @@
112 const char *netif;
113 const char *mgmt_class;
114 const char *macaddr;
115-};
116+ struct netif *netifs;
117+};
118+
119+struct netif {
120+ const char *interface;
121+ const char *macaddr;
122+ struct netif *next;
123+};
124+
125+void get_netifs(struct cobbler_client *enlister);
126
127 int init_client(struct cobbler_client *enlister) {
128 enlister->client = NULL;
129@@ -68,6 +79,7 @@
130 enlister->netif = NULL;
131 enlister->mgmt_class = NULL;
132 enlister->macaddr = NULL;
133+ enlister->netifs = NULL;
134 return 0;
135 }
136
137@@ -78,11 +90,80 @@
138 printf("\tpassword: %s\n", enlister->password);
139 printf("\tname: %s\n", enlister->name);
140 printf("\tprofile: %s\n", enlister->profile);
141- if (enlister->netif)
142- printf("\tnetif: %s\n", enlister->netif);
143+ if (enlister->netifs) {
144+ get_netifs(enlister);
145+ }
146 if (enlister->mgmt_class)
147 printf("\tmgmt class: %s\n", enlister->mgmt_class);
148- printf("\tmac addr: %s\n", enlister->macaddr);
149+}
150+
151+void get_netifs(struct cobbler_client *enlister) {
152+ struct netif *current = enlister->netifs;
153+ if (current == NULL) {
154+ printf("Interface list is empty\n");
155+ return;
156+ }
157+ int i = 0;
158+ while (current != NULL) {
159+ printf("\tinterface %d: %s - %s\n", i, current->interface, current->macaddr);
160+ i++;
161+ current = current->next;
162+ }
163+}
164+
165+void die(char *msg) {
166+ fprintf(stderr, "[ERROR] %s\n", msg);
167+ exit(1);
168+}
169+
170+/* append a new interface to the netifs list. macaddr remains empty
171+ until populated by get_macaddresses() */
172+int append_netif(struct cobbler_client *enlister, char *netif) {
173+ if (debug)
174+ printf("[DEBUG] Appending interface %s to enlister's netif list\n", netif);
175+ struct netif *new_netif, *current;
176+ new_netif = (struct netif *) malloc(sizeof(struct netif));
177+ if (new_netif == NULL)
178+ die("malloc() - append_netif()");
179+ memset(new_netif, 0, sizeof(struct netif));
180+ new_netif->interface = netif;
181+ new_netif->macaddr = NULL;
182+ new_netif->next = NULL;
183+ if (enlister->netifs == NULL) {
184+ enlister->netifs = new_netif;
185+ return 0;
186+ }
187+ int i;
188+ current = enlister->netifs;
189+ while (current->next != NULL) {
190+ current = current->next;
191+ i++;
192+ }
193+ current->next = new_netif;
194+ return 0;
195+}
196+
197+/* delete an interface from the netifs list */
198+int remove_netif(struct cobbler_client *enlister, const char *interface) {
199+ if (debug)
200+ printf("[DEBUG] Removing from interface list: %s\n", interface);
201+ struct netif *current = enlister->netifs;
202+ int i = 0;
203+ if (strcasecmp(current->interface, interface) == 0) {
204+ enlister->netifs = current->next;
205+ return 0;
206+ }
207+ i++;
208+ while (current->next) {
209+ if (strcasecmp(current->next->interface, interface) == 0) {
210+ current->next = current->next->next;
211+ return 0;
212+ }
213+ current = current->next;
214+ i++;
215+ }
216+ printf("ERROR: NEtif: %s doesn't exist in enlister->netifs\n", interface);
217+ return 1;
218 }
219
220 // Overide ether_ntoa_r because stock decides the convention of leading zeros is silly.
221@@ -96,46 +177,93 @@
222 return buf;
223 }
224
225-int get_mac_address(struct cobbler_client *enlister) {
226- if (debug)
227- printf("[DEBUG] get_mac_address()\n");
228-
229- int fd;
230- struct if_nameindex *curif, *ifs;
231- char mac_str[25];
232- char interface[255];
233- char *macaddr = malloc(sizeof(mac_str));
234-
235+int interface_exists(const char *interface) {
236+ if (debug)
237+ printf("[DEBUG] Checking for interface: %s\n", interface);
238+ struct if_nameindex *curif, *ifs = if_nameindex();
239+ for (curif = ifs; curif && curif->if_name; curif++) {
240+ if (strcasecmp(interface, curif->if_name) == 0)
241+ return 0;
242+ }
243+ return 1;
244+}
245+
246+/* inspect each enlister->netifs. Make sure the interface exists on the system
247+ Remove it from the list if it doesn't.
248+ If we've cleaned the entire list because none of them exist, return 1.
249+ Can/should be extended to do more verification?
250+*/
251+int verify_netifs(struct cobbler_client *enlister) {
252+ struct netif *current = enlister->netifs;
253+ while (current) {
254+ if (interface_exists(current->interface) != 0) {
255+ printf("[WARNING] Interface %s doesn't exist, removing.\n", current->interface);
256+ remove_netif(enlister, current->interface);
257+ }
258+ current = current->next;
259+ }
260+ if (enlister->netifs == NULL)
261+ return 1;
262+ return 0;
263+}
264+
265+/* utility function to test whether the netifs list contains at least
266+ one mac address
267+*/
268+int contains_one_macaddr(struct cobbler_client *enlister) {
269+ struct netif *current = enlister->netifs;
270+ while (current) {
271+ if ((current->macaddr != NULL) &&
272+ (strcasecmp(current->macaddr, NO_MACADDR) != 0)) {
273+ return 0;
274+ }
275+ }
276+ return 1;
277+}
278+
279+char *get_interface_macaddr(const char *interface) {
280+ if (debug)
281+ printf("[DEBUG] Getting mac addr for interface %s\n", interface);
282+ char mac_str[255];
283+ char *macaddr;
284 int ioctl_data = 0;
285 struct ifreq ifr;
286-
287- if ((fd = socket (PF_INET, SOCK_DGRAM, 0)) != -1) {
288- ifs = if_nameindex ();
289- for (curif = ifs; curif && curif->if_name; curif++) {
290- if (((enlister->netif == NULL) ||
291- (strcasecmp(enlister->netif, curif->if_name) == 0))
292- && (strcasecmp(curif->if_name, "lo") !=0)) {
293-
294- ioctl_data = socket (PF_INET, SOCK_STREAM, 0);
295- memset (&ifr, 0, sizeof (ifr));
296- strncpy (ifr.ifr_name, curif->if_name, sizeof (ifr.ifr_name));
297- strncpy (interface, curif->if_name, sizeof (interface));
298- ioctl (ioctl_data, SIOCGIFHWADDR, &ifr);
299- ether_ntoa_r( (const struct ether_addr *)
300- &(ifr.ifr_hwaddr.sa_data), mac_str);
301- if (debug)
302- printf("[DEBUG] Using interface: %s Addr: %s\n", interface, mac_str);
303- if (enlister->netif == NULL)
304- enlister->netif = curif->if_name;
305- strncpy(macaddr, mac_str, sizeof(mac_str));
306- enlister->macaddr = macaddr;
307- return 0;
308- }
309- }
310+ ioctl_data = socket(PF_INET, SOCK_STREAM, 0);
311+ memset(&ifr, 0, sizeof(ifr));
312+ strncpy(ifr.ifr_name, interface, sizeof(interface));
313+ ioctl(ioctl_data, SIOCGIFHWADDR, &ifr);
314+ ether_ntoa_r((const struct ether_addr *) &(ifr.ifr_hwaddr.sa_data), mac_str);
315+ macaddr = malloc(sizeof(mac_str));
316+ if (macaddr == NULL)
317+ die("malloc() - get_interface_macaddr()");
318+ strncpy(macaddr, mac_str, sizeof(mac_str));
319+ return macaddr;
320+}
321+
322+/* iterate through enlister->netifs, populating macaddr for each.
323+ if we can't determine a valid mac addr, remove from list and continue
324+ returns non-zero if the resulting enlister->netifs does not contain at least
325+ one mac addr.
326+*/
327+int get_mac_addresses(struct cobbler_client *enlister) {
328+ if (debug)
329+ printf("[DEBUG] get_mac_address()\n");
330+ const char *addr;
331+ struct netif *current = enlister->netifs;
332+ while (current != NULL) {
333+ addr = get_interface_macaddr(current->interface);
334+ if (strcasecmp(addr, NO_MACADDR) == 0) {
335+ printf("[WARNING] Could not determine mac addr for %s, skipping.\n",
336+ current->interface);
337+ remove_netif(enlister, current->interface);
338+ } else {
339+ current->macaddr = addr;
340+ };
341+ current = current->next;
342 }
343+ return contains_one_macaddr(enlister);
344+}
345
346- return 1;
347-}
348 void help(char *progname)
349 {
350 printf("Usage: %s --help -- provides this help\n" , progname);
351
352=== modified file 'cobbler-xmlrpc.h'
353--- cobbler-xmlrpc.h 2011-08-02 15:49:55 +0000
354+++ cobbler-xmlrpc.h 2011-11-21 19:59:24 +0000
355@@ -109,7 +109,7 @@
356 xmlrpc_value *token = xmlrpc_string_new(&enlister->env, enlister->token);
357 xmlrpc_value *name = xmlrpc_string_new(&enlister->env, enlister->name);
358 xmlrpc_value *profile = xmlrpc_string_new(&enlister->env, enlister->profile);
359- xmlrpc_value *macaddr = xmlrpc_string_new(&enlister->env, enlister->macaddr);
360+// xmlrpc_value *macaddr = xmlrpc_string_new(&enlister->env, enlister->macaddr);
361
362 /* used for forming modify_interface request */
363 xmlrpc_value *macaddr_struct = xmlrpc_struct_new(&enlister->env);
364@@ -162,23 +162,35 @@
365 if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0)
366 goto out;
367 if (debug)
368- printf("[DEBUG] Modified system profile: %d\n", rc);
369-
370- /* set its mac address */
371- sprintf(macaddr_form_item, "macaddress-%s", enlister->netif);
372- xmlrpc_struct_set_value(&enlister->env, macaddr_struct,
373- macaddr_form_item, macaddr);
374- argument_array = xmlrpc_array_new(&enlister->env);
375- xmlrpc_array_append_item(&enlister->env, argument_array, system);
376- xmlrpc_array_append_item(&enlister->env, argument_array,
377- xmlrpc_string_new(&enlister->env, "modify_interface"));
378- xmlrpc_array_append_item(&enlister->env, argument_array, macaddr_struct);
379- xmlrpc_array_append_item(&enlister->env, argument_array, token);
380- if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0)
381- goto out;
382- if (debug)
383- printf("[DEBUG] Modified interface: %d\n", rc);
384-
385+ printf("[DEBUG] Modified system profile: %d\n", rc);
386+
387+ /* set its mac addresses */
388+ struct netif *current_netif = enlister->netifs;
389+ while (current_netif != NULL) {
390+ if (debug) {
391+ printf("[DEBUG] Registering interface and macaddr: %s %s\n",
392+ current_netif->interface, current_netif->macaddr);
393+ }
394+ xmlrpc_value *macaddr = xmlrpc_string_new(&enlister->env,
395+ current_netif->macaddr);
396+ sprintf(macaddr_form_item, "macaddress-%s", current_netif->interface);
397+ xmlrpc_struct_set_value(&enlister->env, macaddr_struct,
398+ macaddr_form_item, macaddr);
399+ argument_array = xmlrpc_array_new(&enlister->env);
400+ xmlrpc_array_append_item(&enlister->env, argument_array, system);
401+ xmlrpc_array_append_item(&enlister->env, argument_array,
402+ xmlrpc_string_new(&enlister->env, "modify_interface"));
403+ xmlrpc_array_append_item(&enlister->env, argument_array, macaddr_struct);
404+ xmlrpc_array_append_item(&enlister->env, argument_array, token);
405+ if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0) {
406+ xmlrpc_DECREF(macaddr);
407+ xmlrpc_DECREF(macaddr_struct);
408+ goto out;
409+ }
410+ if (debug)
411+ printf("[DEBUG] Modified interface: %d\n", rc);
412+ current_netif = current_netif->next;
413+ }
414 /* assign a mgmt class */
415 if (enlister->mgmt_class) {
416 xmlrpc_value *mgmt_class = xmlrpc_string_new(&enlister->env,
417@@ -202,8 +214,6 @@
418 xmlrpc_DECREF(name);
419 xmlrpc_DECREF(profile);
420 xmlrpc_DECREF(system);
421- xmlrpc_DECREF(macaddr);
422- xmlrpc_DECREF(macaddr_struct);
423 xmlrpc_DECREF(argument_array);
424 return rc;
425 }
426
427=== modified file 'debian/changelog'
428--- debian/changelog 2011-11-12 11:07:07 +0000
429+++ debian/changelog 2011-11-21 19:59:24 +0000
430@@ -1,3 +1,11 @@
431+cobbler-enlist (0.2-1ubuntu1) oneiric; urgency=low
432+
433+ * Add support for multiple network interfaces (convert enlister->netif
434+ to linked list enlister->netifs). When no interfaces specified, defaults
435+ to registering all interfaces on the system. (LP: #868492)
436+
437+ -- Adam Gandelman <adamg@canonical.com> Mon, 21 Nov 2011 11:40:37 -0800
438+
439 cobbler-enlist (0.2-1build2) precise; urgency=low
440
441 * Rebuild for libxmlrpc-core-c3-udeb.

Subscribers

People subscribed via source and target branches