mirror of
https://github.com/Icinga/docker-icingaweb2.git
synced 2025-08-07 06:47:10 +02:00
275 lines
6.1 KiB
Go
275 lines
6.1 KiB
Go
// Icinga Web 2 Docker image | (c) 2020 Icinga GmbH | GPLv2+
|
|
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/go-ini/ini"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
const confDir = "/data/etc/icingaweb2"
|
|
const modsDir = "/usr/share/icingaweb2/modules"
|
|
const dirMode = 0750
|
|
|
|
var enModsDir = path.Join(confDir, "enabledModules")
|
|
|
|
func main() {
|
|
if err := entrypoint(); err != nil {
|
|
logf("crit", "%s", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func entrypoint() error {
|
|
if len(os.Args) < 2 {
|
|
logf("warn", "Nothing to do.")
|
|
return nil
|
|
}
|
|
|
|
if os.Getpid() == 1 {
|
|
logf("info", "Initializing /data as we're the init process")
|
|
|
|
for _, dir := range []string{enModsDir, "/data/var/lib/icingaweb2"} {
|
|
logf("debug", "Creating %#v", dir)
|
|
if errMA := os.MkdirAll(dir, dirMode); errMA != nil {
|
|
return errMA
|
|
}
|
|
}
|
|
|
|
logf("debug", "Translating env vars to .ini config")
|
|
|
|
cfgs := map[string]*ini.File{}
|
|
var enabledModules map[string]struct{} = nil
|
|
passwords := map[string]map[string]string{}
|
|
|
|
EnvVars:
|
|
for _, env := range os.Environ() {
|
|
if kv := strings.SplitN(env, "=", 2); len(kv) == 2 {
|
|
if strings.HasPrefix(kv[0], "icingaweb") {
|
|
if kv[0] = strings.TrimPrefix(kv[0], "icingaweb"); len(kv[0]) > 0 {
|
|
directive := strings.Split(kv[0][1:], kv[0][:1])
|
|
for _, component := range directive {
|
|
if component == "" {
|
|
continue EnvVars
|
|
}
|
|
}
|
|
|
|
if len(directive) == 1 {
|
|
if directive[0] == "enabledModules" {
|
|
if enabledModules == nil {
|
|
enabledModules = map[string]struct{}{}
|
|
}
|
|
|
|
for _, mod := range strings.Split(kv[1], ",") {
|
|
if mod = strings.TrimSpace(mod); mod != "" {
|
|
enabledModules[mod] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
} else if len(directive) >= 3 {
|
|
if len(directive) == 3 && directive[0] == "passwords" {
|
|
users, ok := passwords[directive[1]]
|
|
if !ok {
|
|
users = map[string]string{}
|
|
passwords[directive[1]] = users
|
|
}
|
|
|
|
users[directive[2]] = kv[1]
|
|
} else {
|
|
file := path.Join(directive[:len(directive)-2]...)
|
|
cfg, ok := cfgs[file]
|
|
|
|
if !ok {
|
|
cfg = ini.Empty()
|
|
cfgs[file] = cfg
|
|
}
|
|
|
|
_, errNK := cfg.Section(directive[len(directive)-2]).NewKey(
|
|
directive[len(directive)-1], kv[1],
|
|
)
|
|
if errNK != nil {
|
|
return errNK
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for file, cfg := range cfgs {
|
|
file = path.Join(confDir, file+".ini")
|
|
logf("trace1", "Writing %#v", file)
|
|
|
|
if errMA := os.MkdirAll(path.Dir(file), dirMode); errMA != nil {
|
|
return errMA
|
|
}
|
|
|
|
if errST := cfg.SaveTo(file); errST != nil {
|
|
return errST
|
|
}
|
|
}
|
|
|
|
if enabledModules != nil {
|
|
logf("debug", "Enabling/disabling modules")
|
|
|
|
mods, errRD := ioutil.ReadDir(enModsDir)
|
|
if errRD != nil {
|
|
return errRD
|
|
}
|
|
|
|
for _, mod := range mods {
|
|
mod := mod.Name()
|
|
if _, ok := enabledModules[mod]; ok {
|
|
delete(enabledModules, mod)
|
|
} else {
|
|
logf("trace1", "Disabling module %#v", mod)
|
|
if errRm := os.Remove(path.Join(enModsDir, mod)); errRm != nil {
|
|
return errRm
|
|
}
|
|
}
|
|
}
|
|
|
|
for mod := range enabledModules {
|
|
logf("trace1", "Enabling module %#v", mod)
|
|
|
|
errSl := os.Symlink(path.Join(modsDir, mod), path.Join(enModsDir, mod))
|
|
if errSl != nil {
|
|
return errSl
|
|
}
|
|
}
|
|
}
|
|
|
|
if errID := initDb(passwords); errID != nil {
|
|
return errID
|
|
}
|
|
}
|
|
|
|
path := os.Args[1]
|
|
if filepath.Base(path) == path {
|
|
logf("info", "Looking up %#v in $PATH", path)
|
|
|
|
abs, errLP := exec.LookPath(path)
|
|
if errLP != nil {
|
|
return errLP
|
|
}
|
|
|
|
path = abs
|
|
}
|
|
|
|
logf("info", "Running %#v", path)
|
|
return syscall.Exec(path, os.Args[1:], os.Environ())
|
|
}
|
|
|
|
func initDb(passwords map[string]map[string]string) 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
|
|
}
|
|
}
|
|
}
|
|
|
|
for backend, users := range passwords {
|
|
for name, password := range users {
|
|
logf(
|
|
"info", `Ensuring database authentication backend %#v to have a user %#v with the password "***"`,
|
|
backend, name,
|
|
)
|
|
|
|
cmd := exec.Command("icingacli", "dockerentrypoint", "db", "user", "--backend="+backend, "--name="+name)
|
|
cmd.Stdout = os.Stderr
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Env = append(os.Environ(), "PASSWORD="+password)
|
|
|
|
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{}) {
|
|
_, _ = fmt.Fprintf(out, "[%s] ", time.Now().Format("Mon Jan 2 15:04:05.999999999 2006"))
|
|
_, _ = fmt.Fprintf(out, "[docker_entrypoint:%s] [pid %d] DOCKERE: ", severity, os.Getpid())
|
|
_, _ = fmt.Fprintf(out, format, a...)
|
|
|
|
_, _ = fmt.Fprintln(out)
|
|
_ = out.Flush()
|
|
}
|