summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--README34
-rw-r--r--src/GNUmakefile42
-rw-r--r--src/biruda.c154
-rw-r--r--src/biruda.conf28
-rw-r--r--src/biruda.ggo43
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
diff --git a/README b/README
new file mode 100644
index 0000000..9c5aee8
--- /dev/null
+++ b/README
@@ -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( &params );
+
+ cmdline_parser_init( args_info );
+
+ if( cmdline_parser_ext( argc, argv, args_info, &params ) != 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