diff --git a/deps.Dockerfile b/deps.Dockerfile index 9ac0d57..0ece8ed 100644 --- a/deps.Dockerfile +++ b/deps.Dockerfile @@ -15,6 +15,7 @@ RUN ["locale-gen", "-j", "4"] RUN ["bash", "-exo", "pipefail", "-c", "export DEBIAN_FRONTEND=noninteractive; apt-get update; apt-get install --no-install-{recommends,suggests} -y apache2 libapache2-mod-php7.3 php-{imagick,redis} php7.3-{bcmath,bz2,common,curl,dba,enchant,gd,gmp,imap,interbase,intl,json,ldap,mbstring,mysql,odbc,opcache,pgsql,pspell,readline,recode,snmp,soap,sqlite3,sybase,tidy,xml,xmlrpc,xsl,zip}; apt-get clean; rm -vrf /var/lib/apt/lists/*"] COPY --from=entrypoint /entrypoint/entrypoint /entrypoint +COPY entrypoint/db-init /entrypoint-db-init RUN ["a2enmod", "rewrite"] RUN ["ln", "-vsf", "/dev/stdout", "/var/log/apache2/access.log"] diff --git a/entrypoint/db-init/application/clicommands/DbCommand.php b/entrypoint/db-init/application/clicommands/DbCommand.php new file mode 100644 index 0000000..5f39137 --- /dev/null +++ b/entrypoint/db-init/application/clicommands/DbCommand.php @@ -0,0 +1,82 @@ +get('global', 'config_backend') === 'db') { + $configResource = $config->get('global', 'config_resource'); + + if ($configResource !== null) { + $resources[$configResource] = null; + } + } + + foreach (['authentication', 'groups'] as $file) { + foreach (Config::app($file) as $backend) { + if ($backend->backend === 'db') { + $resource = $backend->resource; + + if ($resource !== null) { + $resources[$resource] = null; + } + } + } + } + + ksort($resources); + + echo Json::encode(array_keys($resources)); + } + + public function initializedAction() + { + echo (int) (array_search('icingaweb_group', $this->getDb()->listTables(), true) !== false); + } + + public function initAction() + { + $db = $this->getDb(); + + $db->import( + Config::module('setup') + ->get('schema', 'path', Icinga::app()->getBaseDir('etc/schema')) . "/{$db->dbType}.schema.sql" + ); + } + + /** + * @return DbTool + */ + protected function getDb() + { + $config = ResourceFactory::getResourceConfig($this->params->getRequired('resource'))->toArray(); + $type = isset($config['db']) ? $config['db'] : 'mysql'; + + if (! isset($config['port'])) { + switch ($type) { + case 'mysql': + $config['port'] = 3306; + break; + case 'pgsql': + $config['port'] = 5432; + } + } + + $db = new DbTool($config); + $db->connectToDb(); + $db->dbType = $type; + return $db; + } +} diff --git a/entrypoint/main.go b/entrypoint/main.go index 40de1b6..d5244ce 100644 --- a/entrypoint/main.go +++ b/entrypoint/main.go @@ -2,6 +2,8 @@ package main import ( "bufio" + "bytes" + "encoding/json" "fmt" "github.com/go-ini/ini" "io/ioutil" @@ -15,6 +17,7 @@ import ( ) const confDir = "/data/etc/icingaweb2" +const modsDir = "/usr/share/icingaweb2/modules" const dirMode = 0750 var enModsDir = path.Join(confDir, "enabledModules") @@ -126,12 +129,16 @@ func entrypoint() error { for mod := range enabledModules { logf("trace1", "Enabling module %#v", mod) - errSl := os.Symlink(path.Join("/usr/share/icingaweb2/modules", mod), path.Join(enModsDir, mod)) + errSl := os.Symlink(path.Join(modsDir, mod), path.Join(enModsDir, mod)) if errSl != nil { return errSl } } } + + if errID := initDb(); errID != nil { + return errID + } } path := os.Args[1] @@ -150,6 +157,78 @@ func entrypoint() error { return syscall.Exec(path, os.Args[1:], os.Environ()) } +func initDb() error { + logf("info", "Checking database resources used as backends") + + { + enMod := path.Join(enModsDir, "dockerentrypoint") + if errSl := os.Symlink("/entrypoint-db-init", enMod); errSl != nil { + return errSl + } + + defer os.Remove(enMod) + } + + { + enMod := path.Join(enModsDir, "setup") + + errSl := os.Symlink(path.Join(modsDir, "setup"), enMod) + if errSl != nil { + if le, ok := errSl.(*os.LinkError); !ok || !os.IsNotExist(le.Err) { + return errSl + } + } + + if errSl == nil { + defer os.Remove(enMod) + } + } + + var resources []string + if errIJ := icingacliJson(&resources, "dockerentrypoint", "db", "backends"); errIJ != nil { + return errIJ + } + + for _, resource := range resources { + logf("debug", "Checking database resource %#v", resource) + + var initialized uint8 + + errIJ := icingacliJson(&initialized, "dockerentrypoint", "db", "initialized", "--resource="+resource) + if errIJ != nil { + return errIJ + } + + if initialized == 0 { + logf("debug", "Importing schema into database resource %#v", resource) + + cmd := exec.Command("icingacli", "dockerentrypoint", "db", "init", "--resource="+resource) + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + + if errRn := cmd.Run(); errRn != nil { + return errRn + } + } + } + + return nil +} + +func icingacliJson(v interface{}, arg ...string) error { + cmd := exec.Command("icingacli", arg...) + var out bytes.Buffer + + cmd.Stdout = &out + cmd.Stderr = os.Stderr + + if errRn := cmd.Run(); errRn != nil { + return errRn + } + + return json.Unmarshal(out.Bytes(), v) +} + var out = bufio.NewWriter(os.Stderr) func logf(severity, format string, a ...interface{}) {