add command line option to process openstack config drive

add --openstack-config-drive option to process metadata and
userdata using as datasource an openstack config drive
(iso9660 or vfat filesystem)

add type_by_device function to get the disk type
This commit is contained in:
Julio Montes
2016-01-14 15:01:26 -06:00
parent f04ab8e1bc
commit 3be58dcd04
6 changed files with 175 additions and 95 deletions
+10 -3
View File
@@ -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
+115 -82
View File
@@ -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;
}
+2
View File
@@ -35,3 +35,5 @@
#include <glib.h>
gboolean openstack_process_metadata(const gchar* filename);
gboolean openstack_process_config_drive(const gchar* path);
+14 -9
View File
@@ -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;
+3 -1
View File
@@ -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);
+31
View File
@@ -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)) {