diff --git a/docs/cloud-init.1 b/docs/cloud-init.1 index f26cdb4..87a429e 100644 --- a/docs/cloud-init.1 +++ b/docs/cloud-init.1 @@ -59,9 +59,16 @@ service URL. .PP \fB\-\-openstack\-metadata\-file\fR FILE .RS 4 -Path to an openstack metadata file\&. If omitted, \fBcloud-init\fR will -attempt to fetch metadata from the openstack link-local connected data -service URL. +Path to an openstack metadata file. + more information: \%http://docs.openstack.org/user-guide/cli_config_drive.html#openstack-metadata-format +.RE +.PP +\fB\-\-openstack\-config\-drive\fR PATH +.RS 4 +Path to openstack config drive (iso9660 or vfat filesystem), +it will be used to process metadata and userdata. + more information: +\%http://docs.openstack.org/user-guide/cli_config_drive.html#configuration-drive-contents .RE .PP \fB\-\-user\-data\fR diff --git a/src/datasources/openstack.c b/src/datasources/openstack.c index 35e5a85..13f3593 100644 --- a/src/datasources/openstack.c +++ b/src/datasources/openstack.c @@ -118,6 +118,115 @@ int openstack_main(struct datasource_options_struct* opts) { return EXIT_FAILURE; } +gboolean openstack_process_config_drive(const gchar* path) { + char mountpoint[] = "/tmp/config-2-XXXXXX"; + char userdata_file[] = "/tmp/userdata-XXXXXX"; + int fd_userdata_in = 0; + int fd_userdata_out = 0; + off_t bytes_copied = 0; + ssize_t send_result = 0; + struct stat userdata_info = { 0 }; + gchar metadata_drive_path[PATH_MAX] = { 0 }; + gchar userdata_drive_path[PATH_MAX] = { 0 }; + gchar* devtype = NULL; + gboolean result = false; + struct stat st; + gchar command[PATH_MAX] = { 0 }; + + if (!type_by_device(path, &devtype)) { + LOG("Unknown filesystem device '%s'\n", (char*)path); + return false; + } + + if (!mkdtemp(mountpoint)) { + LOG(MOD "Unable to create directory '%s'\n", mountpoint); + goto fail1; + } + + if (stat(path, &st)) { + LOG(MOD "stat failed\n"); + goto fail1; + } + + if ((st.st_mode & S_IFMT) != S_IFBLK) { + g_snprintf(command, PATH_MAX, "mount -o loop,ro -t %s %s %s", devtype, path, mountpoint ); + if (!exec_task(command)) { + LOG(MOD "Unable to mount config drive '%s'\n", (char*)path); + goto fail2; + } + } else if (mount(path, mountpoint, devtype, MS_NODEV|MS_NOEXEC|MS_RDONLY, NULL) != 0) { + LOG(MOD "Unable to mount config drive '%s'\n", (char*)path); + goto fail2; + } + + g_snprintf(metadata_drive_path, PATH_MAX, "%s%s", mountpoint, METADATA_DRIVE_PATH); + if (!openstack_process_metadata(metadata_drive_path)) { + LOG(MOD "Using config drive get and process metadata failed\n"); + goto fail3; + } + + result = true; + + g_snprintf(userdata_drive_path, PATH_MAX, "%s%s", mountpoint, USERDATA_DRIVE_PATH); + fd_userdata_in = open(userdata_drive_path, O_RDONLY); + if (-1 == fd_userdata_in) { + LOG(MOD "No userdata in config drive\n"); + goto fail3; + } + + if (fstat(fd_userdata_in, &userdata_info) == -1) { + LOG(MOD "Unable to get info from file '%s'\n", userdata_drive_path); + goto fail4; + } + + fd_userdata_out = mkstemp(userdata_file); + if (-1 == fd_userdata_out) { + LOG(MOD "Unable to create a temporal file\n"); + goto fail4; + } + + send_result = sendfile(fd_userdata_out, fd_userdata_in, &bytes_copied, (size_t)userdata_info.st_size); + if (-1 == send_result) { + LOG(MOD "Unable to copy file from '%s' to '%s'\n", userdata_drive_path, userdata_file); + goto fail5; + } + + close(fd_userdata_out); + close(fd_userdata_in); + fd_userdata_out = 0; + fd_userdata_in = 0; + + if (!userdata_process_file(userdata_file)) { + LOG(MOD "Unable to process userdata\n"); + } + + remove(userdata_file); + +fail5: + if (fd_userdata_out) { + close(fd_userdata_out); + } +fail4: + if (fd_userdata_in) { + close(fd_userdata_in); + } +fail3: + if ((st.st_mode & S_IFMT) != S_IFBLK) { + g_snprintf(command, PATH_MAX, "umount %s", mountpoint ); + if (!exec_task(command)) { + LOG(MOD "Using config drive cannot umount '%s'\n", mountpoint); + goto fail2; + } + } else if (umount(mountpoint) != 0) { + LOG(MOD "Using config drive cannot umount '%s'\n", mountpoint); + } +fail2: + rmdir(mountpoint); +fail1: + g_free(devtype); + return result; +} + gboolean openstack_process_metadata(const gchar* filename) { GError* error = NULL; JsonParser* parser = NULL; @@ -187,102 +296,26 @@ cleancurl: } static gboolean openstack_use_config_drive(void) { - char mountpoint[] = "/tmp/config-2-XXXXXX"; - char userdata_file[] = "/tmp/userdata-XXXXXX"; - int fd_userdata_in = 0; - int fd_userdata_out = 0; - off_t bytes_copied = 0; - ssize_t send_result = 0; - struct stat userdata_info = { 0 }; gboolean config_drive = false; - GString* metadata_drive_path; - GString* userdata_drive_path; - gchar* device; - gchar* devtype; + gchar* device = NULL; gboolean result = false; - config_drive = disk_by_label("config-2", &device, &devtype); + config_drive = disk_by_label("config-2", &device); if (!config_drive) { LOG(MOD "Config drive not found\n"); return false; } - if (!mkdtemp(mountpoint)) { - LOG(MOD "Cannot create directory '%s'\n", mountpoint); - goto failcfgdrive0; - } - - if (mount(device, mountpoint, devtype, MS_NODEV|MS_NOEXEC|MS_RDONLY, NULL) != 0) { - LOG(MOD "Cannot mount config drive '%s'\n", (char*)device); - goto failcfgdrive1; - } - - metadata_drive_path = g_string_new(mountpoint); - g_string_append(metadata_drive_path, METADATA_DRIVE_PATH); - userdata_drive_path = g_string_new(mountpoint); - g_string_append(userdata_drive_path, USERDATA_DRIVE_PATH); - - if (!openstack_process_metadata(metadata_drive_path->str)) { - LOG(MOD "Using config drive get and process metadata failed\n"); - goto failcfgdrive2; + if (!openstack_process_config_drive(device)) { + LOG(MOD "Process config drive failed\n"); + goto fail1; } result = true; - fd_userdata_in = open(userdata_drive_path->str, O_RDONLY); - if (-1 == fd_userdata_in) { - LOG(MOD "No userdata in config drive\n"); - goto failcfgdrive2; - } - - if (fstat(fd_userdata_in, &userdata_info) == -1) { - LOG(MOD "Cannot get info from file '%s'\n", userdata_drive_path->str); - goto failcfgdrive3; - } - - fd_userdata_out = mkstemp(userdata_file); - if (-1 == fd_userdata_out) { - LOG(MOD "Cannot create a temporal file\n"); - goto failcfgdrive3; - } - - send_result = sendfile(fd_userdata_out, fd_userdata_in, &bytes_copied, (size_t)userdata_info.st_size); - if (-1 == send_result) { - LOG(MOD "Cannot copy file from '%s' to '%s'\n", userdata_drive_path->str, userdata_file); - goto failcfgdrive4; - } - - close(fd_userdata_out); - close(fd_userdata_in); - fd_userdata_out = 0; - fd_userdata_in = 0; - - if (!userdata_process_file(userdata_file)) { - LOG(MOD "Unable to process userdata\n"); - } - - remove(userdata_file); - -failcfgdrive4: - if (fd_userdata_out) { - close(fd_userdata_out); - } -failcfgdrive3: - if (fd_userdata_in) { - close(fd_userdata_in); - } -failcfgdrive2: - g_string_free(metadata_drive_path, true); - g_string_free(userdata_drive_path, true); - if (umount(mountpoint) != 0) { - LOG(MOD "Using config drive cannot umount '%s'\n", mountpoint); - } -failcfgdrive1: - rmdir(mountpoint); -failcfgdrive0: +fail1: g_free(device); - g_free(devtype); return result; } diff --git a/src/datasources/openstack.h b/src/datasources/openstack.h index ef2061e..08bf1ee 100644 --- a/src/datasources/openstack.h +++ b/src/datasources/openstack.h @@ -35,3 +35,5 @@ #include gboolean openstack_process_metadata(const gchar* filename); + +gboolean openstack_process_config_drive(const gchar* path); diff --git a/src/disk.c b/src/disk.c index 35ec507..dcf095b 100644 --- a/src/disk.c +++ b/src/disk.c @@ -194,16 +194,12 @@ fail1: return result; } -gboolean disk_by_label(const gchar* label, gchar** device, gchar** type) { - gboolean result = false; +gboolean disk_by_label(const gchar* label, gchar** device) { const char* devpath = NULL; - const char *devtype = NULL; blkid_dev dev = NULL; blkid_cache cache = NULL; - blkid_probe probe = NULL; *device = NULL; - *type = NULL; if (blkid_get_cache(&cache, "/dev/null") != 0) { LOG(MOD "Cannot get cache!\n"); @@ -227,7 +223,18 @@ gboolean disk_by_label(const gchar* label, gchar** device, gchar** type) { return false; } - probe = blkid_new_probe_from_filename(devpath); + *device = g_strdup(devpath); + return true; +} + +gboolean type_by_device(const gchar* device, gchar** type) { + gboolean result = false; + const char *devtype = NULL; + blkid_probe probe = NULL; + + *type = NULL; + + probe = blkid_new_probe_from_filename(device); if(!probe) { LOG(MOD "Probe from filename failed!\n"); return false; @@ -245,10 +252,8 @@ gboolean disk_by_label(const gchar* label, gchar** device, gchar** type) { goto fail; } - result = true; - *device = g_strdup(devpath); *type = g_strdup(devtype); - + result = true; fail: blkid_free_probe(probe); return result; diff --git a/src/disk.h b/src/disk.h index 2a97d7c..04eaa31 100644 --- a/src/disk.h +++ b/src/disk.h @@ -39,4 +39,6 @@ gchar *disk_for_path(const gchar* path); gboolean disk_resize_grow(const gchar* disk_path, GChildWatchFunc async_func_watcher, gpointer data); -gboolean disk_by_label(const gchar* label, gchar** device, gchar** type); +gboolean disk_by_label(const gchar* label, gchar** device); + +gboolean type_by_device(const gchar* device, gchar** type); diff --git a/src/main.c b/src/main.c index 21c21ec..8c39889 100644 --- a/src/main.c +++ b/src/main.c @@ -59,6 +59,7 @@ /* Long options */ enum { OPT_OPENSTACK_METADATA_FILE=1001, + OPT_OPENSTACK_CONFIG_DRIVE, OPT_USER_DATA, OPT_METADATA, OPT_NO_GROWPART, @@ -72,6 +73,7 @@ enum { static struct option opts[] = { { "user-data-file", required_argument, NULL, 'u' }, { "openstack-metadata-file", required_argument, NULL, OPT_OPENSTACK_METADATA_FILE }, + { "openstack-config-drive", required_argument, NULL, OPT_OPENSTACK_CONFIG_DRIVE }, { "user-data", no_argument, NULL, OPT_USER_DATA }, { "metadata", no_argument, NULL, OPT_METADATA }, { "help", no_argument, NULL, 'h' }, @@ -197,7 +199,9 @@ int main(int argc, char *argv[]) { struct datasource_options_struct datasource_opts = { 0 }; char* userdata_filename = NULL; char* tmp_metadata_filename = NULL; + char* tmp_data_filesystem = NULL; char metadata_filename[PATH_MAX] = { 0 }; + char data_filesystem_path[PATH_MAX] = { 0 }; GError* error = NULL; GThread* async_tasks_thread = NULL; async_task_function func = NULL; @@ -224,6 +228,8 @@ int main(int argc, char *argv[]) { LOG("Usage: %s [options]\n", argv[0]); LOG("-u, --user-data-file [file] specify a custom user data file\n"); LOG(" --openstack-metadata-file [file] specify an Openstack metadata file\n"); + LOG(" --openstack-config-drive [path] specify an Openstack config drive to process\n"); + LOG(" metadata and user data (iso9660 or vfat filesystem)\n"); LOG(" --user-data get and process user data from data sources\n"); LOG(" --metadata get and process metadata from data sources\n"); LOG("-h, --help display this help message\n"); @@ -252,6 +258,11 @@ int main(int argc, char *argv[]) { tmp_metadata_filename = strdup(optarg); break; + case OPT_OPENSTACK_CONFIG_DRIVE: + datasource = DS_OPENSTACK; + tmp_data_filesystem = strdup(optarg); + break; + case OPT_USER_DATA: datasource_opts.user_data = true; break; @@ -342,6 +353,26 @@ int main(int argc, char *argv[]) { tmp_metadata_filename = NULL; } + /* process userdata/metadata using iso9660 or vfat filesystem */ + if (tmp_data_filesystem) { + if (realpath(tmp_data_filesystem, data_filesystem_path)) { + switch (datasource) { + case DS_OPENSTACK: + if (!openstack_process_config_drive(data_filesystem_path)) { + result_code = EXIT_FAILURE; + } + break; + default: + LOG("Unsupported datasource '%d'\n", datasource); + } + } else { + LOG("iso9660 or vfat filesystem not found '%s'\n", tmp_data_filesystem); + } + + free(tmp_data_filesystem); + tmp_data_filesystem = NULL; + } + /* process userdata file */ if (userdata_filename) { if (!userdata_process_file(userdata_filename)) {