diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | README | 34 | ||||
-rw-r--r-- | src/GNUmakefile | 42 | ||||
-rw-r--r-- | src/biruda.c | 154 | ||||
-rw-r--r-- | src/biruda.conf | 28 | ||||
-rw-r--r-- | src/biruda.ggo | 43 |
6 files changed, 305 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..460aded --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +src/biruda +*.o +*_cmdline.c +*_cmdline.h @@ -0,0 +1,34 @@ +biruda +------ + +The successor of 'build' (birua - Japanese for builder). + +The master: +* receives build commands, orchestrates the build + +The coordinator: +* manages resources (virtual machines, CPUs per chroot, etc.) + +The builder: +* does the job (this can be build, test, etc.) + +Requirements +------------ + +* biruda is written in plain C and uses libraries written in plain C. + You need a C compiler and GNU make. +* gengetopt: for command argument line parsing + http://www.gnu.org/software/gengetopt/gengetopt.html +* confuse: configuration library + http://www.nongnu.org/confuse/ +* nanomsg: for communication between nodes (on the same machine or on several machines) + http://nanomsg.org/ +* libmicrohttpd: for an embedded web interface + http://www.gnu.org/software/libmicrohttpd/ + +Other projects +-------------- + +* my own shell-script-based predecessor at http://github.com/Wolframe/build +* buildbot +* OpenSuseBuild service diff --git a/src/GNUmakefile b/src/GNUmakefile new file mode 100644 index 0000000..cd74947 --- /dev/null +++ b/src/GNUmakefile @@ -0,0 +1,42 @@ +.PHONY: all clean install + +all: biruda + +CFLAGS = -g -std=c99 -Wall -pedantic +LDFLAGS = +LIBS = -lconfuse + +%.o : %.c + $(CC) $(CFLAGS) -c -o $@ $< + +biruda: biruda.o biruda_cmdline.o + $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) + +biruda_cmdline.o: biruda_cmdline.c +biruda.o: biruda.c biruda_cmdline.h + +biruda_cmdline.c: biruda.ggo + gengetopt -F biruda_cmdline --unamed-opts --conf-parser --include-getopt -i $< + +biruda_cmdline.h: biruda.ggo + gengetopt -F biruda_cmdline --unamed-opts --conf-parser --include-getopt -i $< + +clean: + @-rm *.o + @-rm biruda + @-rm biruda_cmdline.[ch] + +# default values +DESTDIR ?= +prefix ?= /usr + +# standard directories following FHS +execdir=$(prefix) +sbindir=$(execdir)/sbin +sysconfdir=$(execdir)/etc + +install: + @test -d $(DESTDIR)$(sbindir) || install -d -m 0755 $(DESTDIR)$(sbindir) + install -m 0775 biruda $(DESTDIR)$(sbindir) + @test -d $(DESTDIR)$(sysconfdir)/biruda || install -d -m 0755 $(DESTDIR)$(sysconfdir)/biruda + install -m 0644 biruda.conf $(DESTDIR)$(sysconfdir)/biruda diff --git a/src/biruda.c b/src/biruda.c new file mode 100644 index 0000000..6c23e6c --- /dev/null +++ b/src/biruda.c @@ -0,0 +1,154 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "biruda_cmdline.h" +#include "confuse.h" + +static const char *DEFAULT_CONFIG_FILE = "/etc/biruda/biruda.conf"; +static const unsigned int DEFAULT_WEBSERVER_PORT = 8080; +static const char *DEFAULT_WEBSERVER_HOST = "localhost"; +static const unsigned int DEFAULT_WEBSERVER_THREADS = 4; + +static struct gengetopt_args_info *global_args_info = NULL; + +static int parse_options_and_arguments( int argc, char *argv[], struct gengetopt_args_info *args_info ) +{ + struct cmdline_parser_params params; + + cmdline_parser_params_init( ¶ms ); + + cmdline_parser_init( args_info ); + + if( cmdline_parser_ext( argc, argv, args_info, ¶ms ) != 0 ) { + cmdline_parser_free( args_info ); + return 1; + } + + return 0; +} + +static int test_config( const struct gengetopt_args_info *args_info ) +{ + return 0; +} + +static int read_config( const char *filename, cfg_t **cfg ) +{ + cfg_opt_t opts_master[] = { + CFG_STR( "control", 0, CFGF_NODEFAULT ), + CFG_END( ) + }; + + cfg_opt_t opts_coordinator[] = { + CFG_STR( "control", 0, CFGF_NODEFAULT ), + CFG_END( ) + }; + + cfg_opt_t opts_worker[] = { + CFG_STR( "control", 0, CFGF_NODEFAULT ), + CFG_END( ) + }; + + cfg_opt_t opts_webserver[] = { + CFG_STR( "host", (char *)DEFAULT_WEBSERVER_HOST, CFGF_NONE ), + CFG_INT( "port", DEFAULT_WEBSERVER_PORT, CFGF_NONE ), + CFG_INT( "threads", DEFAULT_WEBSERVER_THREADS, CFGF_NONE ), + CFG_END( ) + }; + + cfg_opt_t opts[] = { + CFG_SEC( "master", opts_master, 0 ), + CFG_SEC( "coordinator", opts_coordinator, 0 ), + CFG_SEC( "worker", opts_worker, CFGF_MULTI | CFGF_TITLE ), + CFG_SEC( "webserver", opts_webserver, 0 ), + CFG_END( ) + }; + + *cfg = cfg_init( opts, CFGF_NONE ); + + switch( cfg_parse( *cfg, filename ) ) { + case CFG_FILE_ERROR: + fprintf( stderr, "ERROR: configuration file '%s' could not be read: %s\n", + filename, strerror( errno ) ); + return 1; + + case CFG_PARSE_ERROR: + return 1; + + case CFG_SUCCESS: + break; + } + + return 0; +} + +static void print_config( struct gengetopt_args_info *args_info, cfg_t *cfg ) +{ + cfg_t *master_cfg = cfg_getnsec( cfg, "master", 0 ); + + puts( "Master:" ); + printf( " Control channel: %s\n", cfg_getstr( master_cfg, "control" ) ); + puts( "" ); + + cfg_t *coordinator_cfg = cfg_getnsec( cfg, "coordinator", 0 ); + + puts( "Coordinator:" ); + printf( " Control channel: %s\n", cfg_getstr( coordinator_cfg, "control" ) ); + puts( "" ); + + printf( "Workers:\n" ); + + unsigned int nof_workers = cfg_size( cfg, "worker" ); + for( unsigned int i = 0; i < nof_workers; i++ ) { + cfg_t *worker_cfg = cfg_getnsec( cfg, "worker", i ); + + printf( " Worker %d:\n", i ); + printf( " Control channel: %s\n", cfg_getstr( worker_cfg, "control" ) ); + } + puts( "" ); + + cfg_t *webserver_cfg = cfg_getnsec( cfg, "webserver", 0 ); + + puts( "Webserver:" ); + printf( " Host: %s\n", cfg_getstr( webserver_cfg, "host" ) ); + printf( " Port: %ld\n", cfg_getint( webserver_cfg, "port" ) ); + printf( " Number of threads: %ld\n", cfg_getint( webserver_cfg, "threads" ) ); + puts( "" ); +} + +int main( int argc, char *argv[] ) +{ + struct gengetopt_args_info args_info; + cfg_t *cfg; + + if( parse_options_and_arguments( argc, argv, &args_info ) ) { + exit( EXIT_FAILURE ); + } + + if( read_config( args_info.config_file_given ? + args_info.config_file_arg : DEFAULT_CONFIG_FILE, &cfg ) ) { + cfg_free( cfg ); + cmdline_parser_free( &args_info ); + return 1; + } + + if( args_info.test_given ) { + cfg_free( cfg ); + cmdline_parser_free( &args_info ); + return( ( test_config( &args_info ) == 0 ) ? EXIT_SUCCESS : EXIT_FAILURE ); + } + + if( args_info.print_given ) { + print_config( &args_info, cfg ); + cfg_free( cfg ); + cmdline_parser_free( &args_info ); + return( ( test_config( &args_info ) == 0 ) ? EXIT_SUCCESS : EXIT_FAILURE ); + } + + cfg_free( cfg ); + cmdline_parser_free( &args_info ); + + exit( EXIT_SUCCESS ); +} diff --git a/src/biruda.conf b/src/biruda.conf new file mode 100644 index 0000000..b5ec9d2 --- /dev/null +++ b/src/biruda.conf @@ -0,0 +1,28 @@ +# single-node configuration + +master +{ + control = "ipc:///tmp/biruda.ipc" +} + +coordinator +{ + control = "ipc:///tmp/biruda.ipc" +} + +worker worker1 +{ + control = "ipc:///tmp/biruda.ipc" +} + +worker worker2 +{ + control = "ipc:///tmp/biruda.ipc" +} + +webserver +{ + threads = 4 + host = localhost + port = 8080 +} diff --git a/src/biruda.ggo b/src/biruda.ggo new file mode 100644 index 0000000..7d4c215 --- /dev/null +++ b/src/biruda.ggo @@ -0,0 +1,43 @@ +package "Biruda build service" +version "0.0.1" +usage "biruda [options]" +description "Biruda node" + +section "Main Options" + option "config-file" c + "the location of the service configuration file (optional, default is /etc/biruda/biruda.conf)" + string typestr="file" + optional + + option "test" t + "test the configuration, don't start the service" + optional + + option "print" p + "print the configuration, don't start the service" + optional + + option "verbose" v + "increase verbosity (can be given multiple times)" + optional multiple + +section "Unix Daemon" + + option "foreground" f + "run in foreground, don't daemonize" + optional + + option "pidfile" - + "where to store the PID of the daemon" + string typestr="filename" + optional + + option "group" - + "the unpriviledged group the daemon should run as" + string typestr="group" + optional + + option "user" - + "the unpriviledged user the daemon should run as" + string typestr="user" + optional |