This commit is contained in:
Philippe Caseiro 2022-06-27 15:58:37 +02:00
parent 983939046d
commit eb50773656
12 changed files with 344 additions and 33 deletions

View File

@ -2,10 +2,10 @@ LINT_ARGS ?= ./...
DESTDIR ?= "/usr/local" DESTDIR ?= "/usr/local"
bin: bin:
GOOS=linux go build -o bin/templater-linux cmd/templater/main.go GOOS=linux CGO_ENABLED=0 go build -o bin/templater-linux cmd/templater/main.go
GOOS=linux go build -o bin/bootstraper-linux cmd/bootstraper/main.go GOOS=linux CGO_ENABLED=0 go build -o bin/bootstraper-linux cmd/bootstraper/main.go
upx bin/templater-linux upx bin/templater-linux
upx bin/templaster-server upx bin/bootstraper-linux
install: install:
cp bin/templater-linux $(DESTDIR)/bin/templater cp bin/templater-linux $(DESTDIR)/bin/templater

View File

@ -1,9 +1,6 @@
package api package api
import ( import (
"net/http"
"forge.cadoles.com/pcaseiro/templatefile/pkg/templater"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -13,6 +10,12 @@ type Template struct {
Config string Config string
} }
func Generate(c *gin.Context) {
return
}
/*
func Generate(c *gin.Context) { func Generate(c *gin.Context) {
var template Template var template Template
@ -42,3 +45,4 @@ func Generate(c *gin.Context) {
} }
} }
*/

View File

@ -1,11 +1,7 @@
{ {
"Name": "LokiStack", "Name": "LokiStack",
"Global": { "Global": {
"Vars": { "Vars": {},
"EnableLoki": true,
"EnableGrafana": false,
"EnablePrometheus" : false
},
"ConfigFiles": [ "ConfigFiles": [
{ {
"destination": "/etc/hosts", "destination": "/etc/hosts",
@ -18,7 +14,6 @@
}, },
"Services": { "Services": {
"Loki": { "Loki": {
"EnabledBy": { "var": "EnableLoki", "value": true },
"ConfigFiles": [ "ConfigFiles": [
{ {
"destination": "/etc/loki/loki-local-config.yaml", "destination": "/etc/loki/loki-local-config.yaml",
@ -28,6 +23,29 @@
"group": "grafana" "group": "grafana"
} }
], ],
"Repositories": {
"Grafana": {
"type": "helm",
"name": "grafana",
"url": "https://grafana.github.io/helm-charts",
"enabled": true
}
},
"Packages": {
"loki": {
"name": "loki",
"action": "install"
},
"promtail": {
"name": "loki-promtail",
"action": "install"
},
"loki-helm": {
"type": "helm",
"name": "loki",
"repo": "grafana/loki-simple-scalable"
}
},
"Vars": { "Vars": {
"AuthEnabled": false, "AuthEnabled": false,
"User": "loki", "User": "loki",
@ -60,7 +78,6 @@
} }
}, },
"Grafana": { "Grafana": {
"EnabledBy": { "var": "EnableGrafana", "value": true },
"ConfigFiles": [ "ConfigFiles": [
{ {
"destination": "/etc/grafana.ini", "destination": "/etc/grafana.ini",
@ -70,6 +87,12 @@
"group": "grafana" "group": "grafana"
} }
], ],
"Packages": {
"grafana": {
"name": "grafana",
"action": "install"
}
},
"Vars": { "Vars": {
"AuthEnabled": false, "AuthEnabled": false,
"User": "toto", "User": "toto",
@ -83,9 +106,12 @@
"shell": "/bin/nologin" "shell": "/bin/nologin"
} }
}, },
"Daemon": { "Daemons": {
"name": "grafana", "grafana": {
"enabled": true "name": "grafana",
"type": "auto",
"enabled": true
}
} }
} }
} }

View File

@ -10,11 +10,6 @@ import (
var CacheFilePath = "/var/cache/templater.db" var CacheFilePath = "/var/cache/templater.db"
type SimpleCondition struct {
Var string `json:"var"`
Value bool `json:"value"`
}
type TemplaterConfig struct { type TemplaterConfig struct {
Name string `json:"Name"` Name string `json:"Name"`
TemplateDirectory string `json:"TemplateDirectory"` TemplateDirectory string `json:"TemplateDirectory"`

73
pkg/templater/packages.go Normal file
View File

@ -0,0 +1,73 @@
package templater
import (
"fmt"
"runtime"
"forge.cadoles.com/pcaseiro/templatefile/pkg/utils"
)
type SystemPackage struct {
Name string `json:"name"`
Type string `json:"type"`
Action string `json:"action"`
OS string `json:"os"`
Distribution string `json:"distribution"`
}
func (p *SystemPackage) SetDistribution() error {
OSConfig, err := utils.ReadOSRelease()
if err != nil {
return err
}
p.Distribution = OSConfig["ID_LIKE"]
return nil
}
func (p *SystemPackage) SetOS() error {
p.OS = runtime.GOOS
return nil
}
func (p *SystemPackage) Manage() error {
var pkErr error
var stdErr []byte
if p.OS == "" {
if err := p.SetOS(); err != nil {
return err
}
}
if p.Distribution == "" {
if err := p.SetDistribution(); err != nil {
return err
}
}
fmt.Printf("Processing %s package\n", p.Name)
switch os := p.Distribution; os {
case "debian", "ubuntu":
_, stdErr, pkErr = utils.RunSystemCommand("apt", "install", "-y", p.Name)
case "alpine":
_, stdErr, pkErr = utils.RunSystemCommand("apk", "add", p.Name)
case "redhat":
_, stdErr, pkErr = utils.RunSystemCommand("yum", "install", "-y", p.Name)
case "arch":
_, stdErr, pkErr = utils.RunSystemCommand("pacman", "-Suy", p.Name)
default:
pkErr = fmt.Errorf("Unsupported OS %s [%s]", p.OS, stdErr)
}
if pkErr != nil {
var msg string
if len(stdErr) != 0 {
msg = string(stdErr)
} else {
msg = pkErr.Error()
}
return fmt.Errorf("Package %s, os %s, failed with error: %v", p.Name, p.OS, msg)
}
return nil
}

View File

@ -0,0 +1,57 @@
package templater
import (
"fmt"
"io/ioutil"
"os"
"strings"
"forge.cadoles.com/pcaseiro/templatefile/pkg/utils"
)
type APKRepository struct {
Name string `json:"name"`
Type string `json:"type"`
URL string `json:"url"`
Enabled bool `json:"enabled"`
}
func (hr *APKRepository) Add() error {
data := fmt.Sprintf("%s", hr.URL)
file, err := os.OpenFile("/etc/apk/repositories", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
if _, err := file.WriteString(data); err != nil {
return err
}
return nil
}
func (hr *APKRepository) Update() error {
if _, stdErr, err := utils.RunSystemCommand("apk", "update"); err != nil {
return fmt.Errorf("%s [%s]", stdErr, err)
}
return nil
}
func (hr *APKRepository) Delete() error {
fileBytes, err := ioutil.ReadFile("/etc/apk/repositories")
if err != nil {
return err
}
lines := strings.Split(string(fileBytes), "\n")
for i, line := range lines {
}
return nil
}
func (hr *APKRepository) Manage() error {
if hr.Enabled {
return hr.Add()
} else {
return hr.Delete()
}
}

View File

@ -0,0 +1,46 @@
package templater
import (
"fmt"
"os"
"forge.cadoles.com/pcaseiro/templatefile/pkg/utils"
)
type DebRepository struct {
Name string `json:"name"`
Type string `json:"type"`
URL string `json:"url"`
Enabled bool `json:"enabled"`
}
func (hr *DebRepository) Add() error {
//deb http://fr.archive.ubuntu.com/ubuntu/ focal main restricted
data := fmt.Sprintf("deb %s", hr.URL)
if err := os.WriteFile("/etc/apt/source.list.d", []byte(data)); err != nil {
return err
}
return nil
}
func (hr *DebRepository) Update() error {
if _, stdErr, err := utils.RunSystemCommand("apt", "update", "-y"); err != nil {
return fmt.Errorf("%s [%s]", stdErr, err)
}
return nil
}
func (hr *DebRepository) Delete() error {
//TODO
return nil
}
func (hr *DebRepository) Manage() error {
if hr.Enabled {
return hr.Add()
} else {
return hr.Delete()
}
}

View File

@ -0,0 +1,23 @@
package templater
type HelmRepository struct {
Name string `json:"name"`
Type string `json:"type"`
URL string `json:"url"`
Enabled bool `json:"enabled"`
}
func (hr *HelmRepository) Add() error {
return nil
}
func (hr *HelmRepository) Update() error {
return nil
}
func (hr *HelmRepository) Delete() error {
return nil
}
func (hr *HelmRepository) Manage() error {
return nil
}

View File

@ -0,0 +1,8 @@
package templater
type PackageRepository interface { // création de L'interface Forme
Manage() error // signature de la méthode Perimetre()
Update() error
Add() error
Delete() error
}

View File

@ -7,22 +7,32 @@ import (
) )
type Service struct { type Service struct {
EnabledBy SimpleCondition `json:"EnabledBy"` ConfigFiles []ConfigFile `json:"ConfigFiles"`
ConfigFiles []ConfigFile `json:"ConfigFiles"` Vars map[string]interface{} `json:"Vars"`
Vars map[string]interface{} `json:"Vars"` Daemons map[string]SystemService `json:"Daemons"`
Daemon SystemService `json:"Daemon"` Users map[string]SystemUser `json:"Users"`
Users map[string]SystemUser `json:"Users"` Packages map[string]SystemPackage `json:"Packages"`
} }
func (s *Service) Manage(templateDir string) error { func (s *Service) Manage(templateDir string) error {
// Manage system packages
for _, pack := range s.Packages {
err := pack.Manage()
if err != nil {
return err
}
}
err := processConfigFiles(s.ConfigFiles, s.Vars, templateDir) err := processConfigFiles(s.ConfigFiles, s.Vars, templateDir)
if err != nil { if err != nil {
return fmt.Errorf("ProcessingTemplatesFailed with error: %v", err) return fmt.Errorf("ProcessingTemplatesFailed with error: %v", err)
} }
err = s.Daemon.Manage() for _, daemon := range s.Daemons {
if err != nil { err = daemon.Manage()
return fmt.Errorf("Error managing service daemons: %v", err) if err != nil {
return fmt.Errorf("Error managing service daemons: %v", err)
}
} }
return nil return nil
} }

View File

@ -11,6 +11,7 @@ type SystemService struct {
Name string `json:"name"` Name string `json:"name"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Type string `json:"type"` Type string `json:"type"`
ToStart bool `json:"start"`
} }
func (sys *SystemService) SetType() { func (sys *SystemService) SetType() {
@ -34,8 +35,16 @@ func (sys *SystemService) SetType() {
} }
} }
func (sys *SystemService) Action() error {
if sys.ToStart {
return sys.Start()
}
return nil
}
func (sys *SystemService) Manage() error { func (sys *SystemService) Manage() error {
if sys.Type == "" { // By default if the property sys.ToStart is empty
if sys.Type == "" || sys.Type == "auto" {
sys.SetType() sys.SetType()
} }
if sys.Enabled { if sys.Enabled {
@ -43,6 +52,10 @@ func (sys *SystemService) Manage() error {
if err != nil { if err != nil {
return err return err
} }
if err = sys.Action(); err != nil {
return err
}
} else { } else {
fmt.Printf("Nothing to do for daemon %s\n", sys.Name) fmt.Printf("Nothing to do for daemon %s\n", sys.Name)
} }
@ -50,12 +63,38 @@ func (sys *SystemService) Manage() error {
} }
func (sys *SystemService) Start() error { func (sys *SystemService) Start() error {
fmt.Printf("Starting %s\n", sys.Name) fmt.Printf("Starting system service : %s\n", sys.Name)
if sys.Type == "systemd" {
_, stdErr, err := utils.RunSystemCommand("systemctl", "start", sys.Name)
if err != nil {
return fmt.Errorf("System service %s \n * Start error:\n - %s", sys.Name, stdErr)
}
} else if sys.Type == "openrc" {
_, stdErr, err := utils.RunSystemCommand("service", sys.Name, "stop")
if err != nil {
return fmt.Errorf("System service %s \n * Enable error:\n - %s", sys.Name, stdErr)
}
} else {
return fmt.Errorf("Unsupported service type %s for service %s", sys.Type, sys.Name)
}
return nil return nil
} }
func (sys *SystemService) Stop() error { func (sys *SystemService) Stop() error {
fmt.Printf("Stoping %s\n", sys.Name) fmt.Printf("Stoping system service : %s\n", sys.Name)
if sys.Type == "systemd" {
_, stdErr, err := utils.RunSystemCommand("systemctl", "stop", sys.Name)
if err != nil {
return fmt.Errorf("System service %s \n * Stop error:\n - %s", sys.Name, stdErr)
}
} else if sys.Type == "openrc" {
_, stdErr, err := utils.RunSystemCommand("service", sys.Name, "stop")
if err != nil {
return fmt.Errorf("System service %s \n * Enable error:\n - %s", sys.Name, stdErr)
}
} else {
return fmt.Errorf("Unsupported service type %s for service %s", sys.Type, sys.Name)
}
return nil return nil
} }
@ -66,7 +105,10 @@ func (sys *SystemService) Enable() error {
return fmt.Errorf("System service %s \n * Enable error:\n - %s", sys.Name, stdErr) return fmt.Errorf("System service %s \n * Enable error:\n - %s", sys.Name, stdErr)
} }
} else if sys.Type == "openrc" { } else if sys.Type == "openrc" {
return nil _, stdErr, err := utils.RunSystemCommand("rc-update", "add", sys.Name, "default")
if err != nil {
return fmt.Errorf("System service %s \n * Enable error:\n - %s", sys.Name, stdErr)
}
} else { } else {
return fmt.Errorf("Unsupported service type %s for service %s", sys.Type, sys.Name) return fmt.Errorf("Unsupported service type %s for service %s", sys.Type, sys.Name)
} }

27
pkg/utils/os.go Normal file
View File

@ -0,0 +1,27 @@
package utils
import (
"fmt"
ini "gopkg.in/ini.v1"
)
var osReleaseFile = "/etc/os-release"
func ReadOSRelease() (map[string]string, error) {
cfg, err := ini.Load(osReleaseFile)
if err != nil {
return nil, fmt.Errorf("Fail to read file: %v ", err)
}
ConfigParams := make(map[string]string)
ConfigParams["ID"] = cfg.Section("").Key("ID").String()
idLike := cfg.Section("").Key("ID_LIKE").String()
if idLike != "" {
ConfigParams["ID_LIKE"] = idLike
} else {
ConfigParams["ID_LIKE"] = ConfigParams["ID"]
}
return ConfigParams, nil
}