discover/handler: Implement temporary autoboot messages
authorJeremy Kerr <jk@ozlabs.org>
Tue, 3 Jul 2018 06:34:45 +0000 (16:34 +1000)
committerSamuel Mendoza-Jonas <sam@mendozajonas.com>
Tue, 10 Jul 2018 03:46:01 +0000 (13:46 +1000)
Handle incoming requests for temporary autoboot settings.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
[indenting fixup]
Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
discover/device-handler.c
discover/device-handler.h
discover/discover-server.c

index d1fdffe14b3e7b3533324fa49dca63501fb8de06..b8e933088b28f5c7eb3aed788287af48ab0df365 100644 (file)
@@ -43,8 +43,9 @@
 #include "ipmi.h"
 
 enum default_priority {
-       DEFAULT_PRIORITY_REMOTE         = 1,
-       DEFAULT_PRIORITY_LOCAL_FIRST    = 2,
+       DEFAULT_PRIORITY_TEMP_USER      = 1,
+       DEFAULT_PRIORITY_REMOTE         = 2,
+       DEFAULT_PRIORITY_LOCAL_FIRST    = 3,
        DEFAULT_PRIORITY_LOCAL_LAST     = 0xfe,
        DEFAULT_PRIORITY_DISABLED       = 0xff,
 };
@@ -77,6 +78,7 @@ struct device_handler {
        struct waiter           *timeout_waiter;
        bool                    autoboot_enabled;
        unsigned int            sec_to_boot;
+       struct autoboot_option  *temp_autoboot;
 
        struct discover_boot_option *default_boot_option;
        int                     default_boot_option_priority;
@@ -833,15 +835,27 @@ static int autoboot_option_priority(const struct config *config,
  * for these options.
  */
 static enum default_priority default_option_priority(
+               struct device_handler *handler,
                struct discover_boot_option *opt)
 {
        const struct config *config;
 
+       /* Temporary user-provided autoboot options have highest priority */
+       if (handler->temp_autoboot) {
+               if (autoboot_option_matches(handler->temp_autoboot,
+                                       opt->device))
+                       return DEFAULT_PRIORITY_TEMP_USER;
+
+               pb_debug("handler: disabled default priority due to "
+                               "temporary user override\n");
+               return DEFAULT_PRIORITY_DISABLED;
+       }
+
        config = config_get();
 
-       /* We give highest priority to IPMI-configured boot options. If
-        * we have an IPMI bootdev configuration set, then we don't allow
-        * any other defaults */
+       /* Next highest priority to IPMI-configured boot options. If we have an
+        * IPMI bootdev configuration set, then we don't allow any other
+        * defaults */
        if (config->ipmi_bootdev) {
                bool ipmi_match = ipmi_device_type_matches(config->ipmi_bootdev,
                                opt->device->device->type);
@@ -881,7 +895,7 @@ static void set_default(struct device_handler *handler,
 
        pb_debug("handler: new default option: %s\n", opt->option->id);
 
-       new_prio = default_option_priority(opt);
+       new_prio = default_option_priority(handler, opt);
 
        /* Anything outside our range prevents a default boot */
        if (new_prio >= DEFAULT_PRIORITY_DISABLED)
@@ -921,6 +935,43 @@ static void set_default(struct device_handler *handler,
        default_timeout(handler);
 }
 
+void device_handler_apply_temp_autoboot(struct device_handler *handler,
+               struct autoboot_option *opt)
+{
+       unsigned int i;
+
+       handler->temp_autoboot = talloc_steal(handler, opt);
+
+       if (!handler->autoboot_enabled)
+               return;
+
+       if (!handler->default_boot_option)
+               return;
+
+       if (autoboot_option_matches(opt, handler->default_boot_option->device))
+               return;
+
+       /* cancel the default, and rescan available options */
+       device_handler_cancel_default(handler);
+
+       handler->autoboot_enabled = true;
+
+       for (i = 0; i < handler->n_devices; i++) {
+               struct discover_device *dev = handler->devices[i];
+               struct discover_boot_option *boot_opt;
+
+               if (!autoboot_option_matches(opt, dev))
+                       continue;
+
+               list_for_each_entry(&dev->boot_options, boot_opt, list) {
+                       if (boot_opt->option->is_default) {
+                               set_default(handler, boot_opt);
+                               break;
+                       }
+               }
+       }
+}
+
 static bool resource_is_resolved(struct resource *res)
 {
        return !res || res->resolved;
index 427a94a7a2e7abbaeeabe0ef9a832269643ccbfe..3ca88e4e07d9adbd968f36c8d5867ca2d93ff9b9 100644 (file)
@@ -167,6 +167,8 @@ void device_handler_process_url(struct device_handler *handler,
 void device_handler_install_plugin(struct device_handler *handler,
                const char *plugin_file);
 void device_handler_reinit(struct device_handler *handler);
+void device_handler_apply_temp_autoboot(struct device_handler *handler,
+               struct autoboot_option *opt);
 
 int device_request_write(struct discover_device *dev, bool *release);
 void device_release_write(struct discover_device *dev, bool release);
index 814053dc02106a544fadba561a54c9f615101efd..3377fa66621fc29be47b0c4cb388342641000bfa 100644 (file)
@@ -247,6 +247,7 @@ static int write_config_message(struct discover_server *server,
 
 static int discover_server_process_message(void *arg)
 {
+       struct autoboot_option *autoboot_opt;
        struct pb_protocol_message *message;
        struct boot_command *boot_command;
        struct client *client = arg;
@@ -311,6 +312,21 @@ static int discover_server_process_message(void *arg)
                device_handler_install_plugin(client->server->device_handler,
                                url);
                break;
+
+       case PB_PROTOCOL_ACTION_TEMP_AUTOBOOT:
+               autoboot_opt = talloc_zero(client, struct autoboot_option);
+               rc = pb_protocol_deserialise_temp_autoboot(autoboot_opt,
+                               message);
+               if (rc) {
+                       pb_log("can't parse temporary autoboot message\n");
+                       return 0;
+               }
+
+               device_handler_apply_temp_autoboot(
+                               client->server->device_handler,
+                               autoboot_opt);
+               break;
+
        default:
                pb_log("%s: invalid action %d\n", __func__, message->action);
                return 0;