Semaphore/db_lib/AnsibleApp.go
2024-10-26 12:56:17 +00:00

156 lines
3.8 KiB
Go

package db_lib
import (
"crypto/md5"
"fmt"
"io"
"os"
"path"
"github.com/semaphoreui/semaphore/db"
"github.com/semaphoreui/semaphore/pkg/task_logger"
)
func getMD5Hash(filepath string) (string, error) {
file, err := os.Open(filepath)
if err != nil {
return "", err
}
defer file.Close()
hash := md5.New()
if _, err := io.Copy(hash, file); err != nil {
return "", err
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
func hasRequirementsChanges(requirementsFilePath string, requirementsHashFilePath string) bool {
oldFileMD5HashBytes, err := os.ReadFile(requirementsHashFilePath)
if err != nil {
return true
}
newFileMD5Hash, err := getMD5Hash(requirementsFilePath)
if err != nil {
return true
}
return string(oldFileMD5HashBytes) != newFileMD5Hash
}
func writeMD5Hash(requirementsFile string, requirementsHashFile string) error {
newFileMD5Hash, err := getMD5Hash(requirementsFile)
if err != nil {
return err
}
return os.WriteFile(requirementsHashFile, []byte(newFileMD5Hash), 0644)
}
type AnsibleApp struct {
Logger task_logger.Logger
Playbook *AnsiblePlaybook
Template db.Template
Repository db.Repository
}
func (t *AnsibleApp) SetLogger(logger task_logger.Logger) task_logger.Logger {
t.Logger = logger
t.Playbook.Logger = logger
return logger
}
func (t *AnsibleApp) Run(args []string, environmentVars *[]string, inputs map[string]string, cb func(*os.Process)) error {
return t.Playbook.RunPlaybook(args, environmentVars, inputs, cb)
}
func (t *AnsibleApp) Log(msg string) {
t.Logger.Log(msg)
}
func (t *AnsibleApp) InstallRequirements(environmentVars *[]string) error {
if err := t.installCollectionsRequirements(); err != nil {
return err
}
if err := t.installRolesRequirements(); err != nil {
return err
}
return nil
}
func (t *AnsibleApp) getRepoPath() string {
repo := GitRepository{
Logger: t.Logger,
TemplateID: t.Template.ID,
Repository: t.Repository,
Client: CreateDefaultGitClient(),
}
return repo.GetFullPath()
}
func (t *AnsibleApp) installGalaxyRequirementsFile(requirementsType GalaxyRequirementsType, requirementsFilePath string) error {
requirementsHashFilePath := fmt.Sprintf("%s.md5", requirementsFilePath)
if _, err := os.Stat(requirementsFilePath); err != nil {
t.Log("No " + requirementsFilePath + " file found. Skip galaxy install process.\n")
return nil
}
if hasRequirementsChanges(requirementsFilePath, requirementsHashFilePath) {
if err := t.runGalaxy([]string{
string(requirementsType),
"install",
"-r",
requirementsFilePath,
"--force",
}); err != nil {
return err
}
if err := writeMD5Hash(requirementsFilePath, requirementsHashFilePath); err != nil {
return err
}
} else {
t.Log(requirementsFilePath + " has no changes. Skip galaxy install process.\n")
}
return nil
}
func (t *AnsibleApp) GetPlaybookDir() string {
playbookPath := path.Join(t.getRepoPath(), t.Template.Playbook)
return path.Dir(playbookPath)
}
type GalaxyRequirementsType string
const (
GalaxyRole GalaxyRequirementsType = "role"
GalaxyCollection GalaxyRequirementsType = "collection"
)
func (t *AnsibleApp) installRolesRequirements() (err error) {
err = t.installGalaxyRequirementsFile(GalaxyRole, path.Join(t.GetPlaybookDir(), "roles", "requirements.yml"))
if err != nil {
return
}
err = t.installGalaxyRequirementsFile(GalaxyRole, path.Join(t.GetPlaybookDir(), "requirements.yml"))
return
}
func (t *AnsibleApp) installCollectionsRequirements() (err error) {
err = t.installGalaxyRequirementsFile(GalaxyCollection, path.Join(t.GetPlaybookDir(), "collections", "requirements.yml"))
if err != nil {
return
}
err = t.installGalaxyRequirementsFile(GalaxyCollection, path.Join(t.GetPlaybookDir(), "requirements.yml"))
return
}
func (t *AnsibleApp) runGalaxy(args []string) error {
return t.Playbook.RunGalaxy(args)
}