discover: Support DHCP "pathprefix" configuration option
authorJeremy Kerr <jk@ozlabs.org>
Fri, 17 Jan 2014 07:51:54 +0000 (15:51 +0800)
committerJeremy Kerr <jk@ozlabs.org>
Fri, 17 Jan 2014 09:01:47 +0000 (17:01 +0800)
This change implements support for the DHCP "pathprefix" option. We use
the following logic:

 - If pathprefix is present and a full URL, we base the config file
   location on pathprefix + conffile

 - If pathprefix is present but not a full URL, we use it as the path
   component of the URL, and pick up the host from other parameters in
   the DHCP response

 - If no pathprefix is present, we determine the configuration prefix
   from the DHCP bootfile parameter.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
discover/network.c
discover/user-event.c
test/parser/Makefile.am
test/parser/test-pxe-non-url-pathprefix-with-conf.c [new file with mode: 0644]
test/parser/test-pxe-pathprefix-discover.c [new file with mode: 0644]
test/parser/test-pxe-pathprefix-with-conf.c [new file with mode: 0644]
utils/pb-udhcpc

index 8cc01833d5875990358ea0bc897eea0bf5ab6fe0..2857076902cd4b23554b4bb405f74a923a2e0190 100644 (file)
@@ -220,6 +220,7 @@ static void configure_interface_dhcp(struct interface *interface)
                "-R",
                "-n",
                "-O", "pxeconffile",
+               "-O", "pxepathprefix",
                "-p", pidfile,
                "-i", interface->name,
                NULL,
index 11a54df39f2fb6b966cd863f0b9ac431f6a235dc..7acd237234848d453740592cc0d16c2cad09a78d 100644 (file)
@@ -232,61 +232,82 @@ static char *parse_ip_addr(struct discover_context *ctx, const char *ip)
 struct pb_url *user_event_parse_conf_url(struct discover_context *ctx,
                struct event *event, bool *is_complete)
 {
-       const char *conffile, *host, *bootfile;
+       const char *conffile, *pathprefix, *host, *bootfile;
        char *p, *basedir, *url_str;
        struct pb_url *url;
 
        conffile = event_get_param(event, "pxeconffile");
-       if (conffile) {
-               if (is_url(conffile)) {
-                       url = pb_url_parse(ctx, conffile);
-               } else {
-                       host = parse_host_addr(event);
-                       if (!host) {
-                               pb_log("%s: host address not found\n",
-                                               __func__);
-                               return NULL;
-                       }
-
-                       url_str = talloc_asprintf(ctx, "%s%s/%s", "tftp://",
-                                       host, conffile);
-                       url = pb_url_parse(ctx, url_str);
+       pathprefix = event_get_param(event, "pxepathprefix");
+       bootfile = event_get_param(event, "bootfile");
+
+       /* If we're given a conf file, we're able to generate a complete URL to
+        * the configuration file, and the parser doesn't need to do any
+        * further autodiscovery */
+       *is_complete = !!conffile;
+
+       /* if conffile is a URL, that's all we need */
+       if (conffile && is_url(conffile)) {
+               url = pb_url_parse(ctx, conffile);
+               return url;
+       }
 
+       /* If we can create a URL from pathprefix (optionally with
+        * conffile appended to create a complete URL), use that */
+       if (pathprefix && is_url(pathprefix)) {
+               if (conffile) {
+                       url_str = talloc_asprintf(ctx, "%s%s",
+                                       pathprefix, conffile);
+                       url = pb_url_parse(ctx, url_str);
                        talloc_free(url_str);
+               } else {
+                       url = pb_url_parse(ctx, pathprefix);
                }
 
-               *is_complete = true;
-       } else {
-               host = parse_host_addr(event);
-               if (!host) {
-                       pb_log("%s: host address not found\n", __func__);
-                       return NULL;
-               }
+               return url;
+       }
 
-               bootfile = event_get_param(event, "bootfile");
-               if (!bootfile) {
-                       pb_log("%s: bootfile param not found\n", __func__);
-                       return NULL;
-               }
+       host = parse_host_addr(event);
+       if (!host) {
+               pb_log("%s: host address not found\n", __func__);
+               return NULL;
+       }
+
+       url_str = talloc_asprintf(ctx, "tftp://%s/", host);
+
+       /* if we have a pathprefix, use that directly.. */
+       if (pathprefix) {
+               /* strip leading slashes */
+               while (pathprefix[0] == '/')
+                       pathprefix++;
+               url_str = talloc_asprintf_append(url_str, "%s", pathprefix);
+
+       /* ... otherwise, add a path based on the bootfile name, but only
+        * if conffile isn't an absolute path itself */
+       } else if (bootfile && !(conffile && conffile[0] == '/')) {
 
                basedir = talloc_strdup(ctx, bootfile);
-               p = strchr(basedir, '/');
+
+               /* strip filename from the bootfile path, leaving only a
+                * directory */
+               p = strrchr(basedir, '/');
                if (p)
                        *p = '\0';
 
-               if (!strcmp(basedir,"") || !strcmp(basedir, "."))
-                       url_str = talloc_asprintf(ctx, "%s%s/", "tftp://",host);
-               else
-                       url_str = talloc_asprintf(ctx, "%s%s/%s/", "tftp://",host,
+               if (strlen(basedir))
+                       url_str = talloc_asprintf_append(url_str, "%s/",
                                        basedir);
 
-               url = pb_url_parse(ctx, url_str);
-
-               talloc_free(url_str);
                talloc_free(basedir);
-               *is_complete = false;
        }
 
+       /* finally, append conffile */
+       if (conffile)
+               url_str = talloc_asprintf_append(url_str, "%s", conffile);
+
+       url = pb_url_parse(ctx, url_str);
+
+       talloc_free(url_str);
+
        return url;
 }
 
index 47fd458892dabd877451a7c9072e9e66621214a1..fdc53e30ee372154b43789cb5680f8781c761870 100644 (file)
@@ -62,6 +62,9 @@ TESTS = \
        test-pxe-ip-without-conf \
        test-pxe-non-url-conf \
        test-pxe-local \
+       test-pxe-pathprefix-with-conf \
+       test-pxe-non-url-pathprefix-with-conf \
+       test-pxe-pathprefix-discover \
        test-unresolved-remove
 
 $(TESTS): %: %.embedded-config.o
diff --git a/test/parser/test-pxe-non-url-pathprefix-with-conf.c b/test/parser/test-pxe-non-url-pathprefix-with-conf.c
new file mode 100644 (file)
index 0000000..36d4726
--- /dev/null
@@ -0,0 +1,38 @@
+
+#include "parser-test.h"
+
+#if 0 /* PARSER_EMBEDDED_CONFIG */
+default linux
+
+label linux
+kernel ./kernel
+append command line
+initrd /initrd
+#endif
+
+void run_test(struct parser_test *test)
+{
+       struct discover_boot_option *opt;
+       struct discover_context *ctx;
+
+       test_read_conf_embedded_url(test, "tftp://host/path/to/conf.txt");
+
+       test_set_event_source(test);
+       test_set_event_param(test->ctx->event, "tftp", "host");
+       test_set_event_param(test->ctx->event, "pxepathprefix", "/path/to/");
+       test_set_event_param(test->ctx->event, "pxeconffile", "conf.txt");
+
+       test_run_parser(test, "pxe");
+
+       ctx = test->ctx;
+
+       check_boot_option_count(ctx, 1);
+       opt = get_boot_option(ctx, 0);
+
+       check_name(opt, "linux");
+       check_args(opt, "command line");
+
+       check_resolved_url_resource(opt->boot_image,
+                       "tftp://host/path/to/./kernel");
+       check_resolved_url_resource(opt->initrd, "tftp://host/initrd");
+}
diff --git a/test/parser/test-pxe-pathprefix-discover.c b/test/parser/test-pxe-pathprefix-discover.c
new file mode 100644 (file)
index 0000000..de2feac
--- /dev/null
@@ -0,0 +1,38 @@
+
+#include "parser-test.h"
+
+#if 0 /* PARSER_EMBEDDED_CONFIG */
+default linux
+
+label linux
+kernel ./kernel
+append command line
+initrd /initrd
+#endif
+
+void run_test(struct parser_test *test)
+{
+       struct discover_boot_option *opt;
+       struct discover_context *ctx;
+
+       test_read_conf_embedded_url(test, "tftp://host/path/to/C0A8");
+
+       test_set_event_source(test);
+       test_set_event_param(test->ctx->event, "ip", "192.168.0.1");
+       test_set_event_param(test->ctx->event, "pxepathprefix",
+                       "tftp://host/path/to/");
+
+       test_run_parser(test, "pxe");
+
+       ctx = test->ctx;
+
+       check_boot_option_count(ctx, 1);
+       opt = get_boot_option(ctx, 0);
+
+       check_name(opt, "linux");
+       check_args(opt, "command line");
+
+       check_resolved_url_resource(opt->boot_image,
+                       "tftp://host/path/to/./kernel");
+       check_resolved_url_resource(opt->initrd, "tftp://host/initrd");
+}
diff --git a/test/parser/test-pxe-pathprefix-with-conf.c b/test/parser/test-pxe-pathprefix-with-conf.c
new file mode 100644 (file)
index 0000000..57f942d
--- /dev/null
@@ -0,0 +1,38 @@
+
+#include "parser-test.h"
+
+#if 0 /* PARSER_EMBEDDED_CONFIG */
+default linux
+
+label linux
+kernel ./kernel
+append command line
+initrd /initrd
+#endif
+
+void run_test(struct parser_test *test)
+{
+       struct discover_boot_option *opt;
+       struct discover_context *ctx;
+
+       test_read_conf_embedded_url(test, "tftp://host/path/to/conf.txt");
+
+       test_set_event_source(test);
+       test_set_event_param(test->ctx->event, "pxepathprefix",
+                       "tftp://host/path/to/");
+       test_set_event_param(test->ctx->event, "pxeconffile", "conf.txt");
+
+       test_run_parser(test, "pxe");
+
+       ctx = test->ctx;
+
+       check_boot_option_count(ctx, 1);
+       opt = get_boot_option(ctx, 0);
+
+       check_name(opt, "linux");
+       check_args(opt, "command line");
+
+       check_resolved_url_resource(opt->boot_image,
+                       "tftp://host/path/to/./kernel");
+       check_resolved_url_resource(opt->initrd, "tftp://host/initrd");
+}
index 4ff0dcf2dc9328d71cd8deaff2b69e4120a2dc58..714d5b4c74200feebaaec4ee2076794a327b8bbf 100644 (file)
@@ -18,7 +18,8 @@ pb_add () {
        paramstr=''
 
        # Collect relevant DHCP response parameters into $paramstr
-       for name in pxeconffile bootfile mac ip siaddr serverid tftp
+       for name in pxeconffile pxepathprefix bootfile mac ip siaddr \
+               serverid tftp
        do
                value=$(eval "echo \${$name}")
                [ -n "$value" ] || continue;