diff --git a/bootstrap/load.go b/bootstrap/load.go index 0ce9c44..c72d7a9 100644 --- a/bootstrap/load.go +++ b/bootstrap/load.go @@ -10,12 +10,10 @@ import ( "strings" ) -const ConfDir = "./confs/" - func LoadApplications() []types.PackageApplication { var apps []types.PackageApplication - err := filepath.WalkDir(ConfDir, func(path string, d fs.DirEntry, err error) error { + err := filepath.WalkDir(types.ConfsDir, func(path string, d fs.DirEntry, err error) error { if err != nil || d == nil || d.IsDir() { return err } diff --git a/bootstrap/logs.go b/bootstrap/logs.go index f74aed3..c2e39f5 100644 --- a/bootstrap/logs.go +++ b/bootstrap/logs.go @@ -1,6 +1,7 @@ package bootstrap import ( + "bubble/types" "github.com/sirupsen/logrus" "gopkg.in/natefinch/lumberjack.v2" "io" @@ -14,7 +15,7 @@ func Logs() { PadLevelText: true, } logWriter := &lumberjack.Logger{ - Filename: "log.txt", + Filename: types.LogFile, Compress: true, MaxSize: 50, LocalTime: true, diff --git a/confs/repko.yaml b/confs/repko.yaml index 726cefc..d62135f 100644 --- a/confs/repko.yaml +++ b/confs/repko.yaml @@ -86,6 +86,15 @@ variables: - name: "gpg_mail" type: "string" default: "admin@repko.com" + - name: "gpg_key_id" + type: "string" + default: "123ABCD" + - name: "repko_login" + type: "string" + default: "admin_repko" + - name: "repko_pass" + type: "string" + default: "admin_repko" - name: "debian_root" type: "string" default: "/var/www/repko/debian" @@ -181,7 +190,7 @@ sections: - name: "Set rights 750" type: "command" command: "chmod 750 /opt/repko/repko" - error: "Ошибка установки прав 640" + error: "Ошибка установки прав 750" - name: "Set rights 640" type: "command" command: "chmod 640 /opt/repko/.env /etc/repko/config.ini" @@ -415,8 +424,59 @@ sections: error: "Не удалось создать ключ" - name: "get gpg key id" type: "command" - command: "sudo -u {{.repko_user}} gpg --homedir /var/lib/repko/gnupg --list-keys --with-colons | grep pub | cut -d: -f5 > /etc/repko/keyid" + command: "sudo -u {{.repko_user}} gpg --homedir /var/lib/repko/gnupg --list-keys --with-colons | grep pub | cut -d: -f5" error: "Не удалось получить и сохранить id gpg ключа" + assign-to: "gpg_key_id" + - name: "export gpg key" + type: "command" + command: "sudo -u {{.repko_user}} gpg --homedir /var/lib/repko/gnupg --armor --export {{.gpg_key_id}} > /usr/share/keyrings/repko.asc" + error: "Не удалось экспортировать gpg ключ" + - name: "write gpg key id" + type: "command" + command: "echo {{.gpg_key_id}} > /etc/repko/keyid" + error: "не удалось записать gpg key id в файл keyid" + - name: "set owner for exported key" + type: "command" + command: "chown -R root:root /usr/share/keyrings/repko.asc" + error: "Ошибка установки владельца файла экспортированного ключа" + - name: "set owner for keyid file" + type: "command" + command: "chown -R {{.repko_user}}:{{.repko_user}} /etc/repko/keyid" + error: "Ошибка установки владельца файла id ключа" + - name: "set rights for keys" + type: "command" + command: "chmod 644 /usr/share/keyrings/repko.asc /etc/repko/keyid" + error: "Ошибка установки прав для ключей" + - name: "basic auth" + description: "Настройка базовой аутентификации" + fields: + - name: "repko login" + variable-name: "repko_login" + field-type: "input" + description: "Логин для входа на сайт" + validate: + - rule: "regex_match(repko_login,`^[a-zA-Z0-9_-]+$`" + message: "Только строчные латинские буквы, цифры, _, -" + - name: "repko pass" + variable-name: "repko_pass" + field-type: "input" + description: "Пароль для входа на сайт" + validate: + - rule: "repko_pass!=''" + message: "Пароль не должен быть пустым" + actions: + - name: "generate htpasswd" + type: "command" + command: "htpasswd -c -b /etc/repko/.htpasswd {{.repko_login}} {{.repko_pass}}" + error: "Не удалось создать файл htpasswd" + - name: "set htpasswd owner" + type: "command" + command: "chown {{.repko_user}}:{{.repko_user}} /etc/repko/.htpasswd" + error: "Ошибка установки владельца файла " + - name: "set rights for htpasswd " + type: "command" + command: "chmod 640 /etc/repko/.htpasswd" + error: "Ошибку установки прав для файла" - name: "paths" description: "Настройка директорий" fields: @@ -427,6 +487,13 @@ sections: validate: - rule: "dir_exists(debian_root)" message: "Папка не существует" + - name: "archive_root" + variable-name: "archive_root" + field-type: "directory" + description: "Директория архива debian" + validate: + - rule: "dir_exists(archive_root)" + message: "Папка не существует" - name: "finale" description: "Последний этап, проверьте правильность введенных данных" type: "final" diff --git a/setup/main.go b/setup/main.go index 7563386..556a423 100644 --- a/setup/main.go +++ b/setup/main.go @@ -12,6 +12,7 @@ import ( func Start() { //Создаем новый объект Main для настройки. + //todo работа внутри apt, вывод интерфейса во время выполнения apt m := NewMain() p := tea.NewProgram(m, tea.WithAltScreen()) //Запускаем через bubble tea программу m.Program = p //Указываем объекту настроек, программу в которой запущен, чтобы передавать туда сигналы diff --git a/setup/utils/actions.go b/setup/utils/actions.go index af5b846..111ca70 100644 --- a/setup/utils/actions.go +++ b/setup/utils/actions.go @@ -57,7 +57,26 @@ func ExecuteAction(action *types.SectionAction, application *types.PackageApplic if cmdErr != nil { return fmt.Errorf("не удалось создать шаблон команды: %v", cmdErr) } - return RunCommand(cmdStr, action.RunAs) + output, err := RunCommand(cmdStr, action.RunAs) + if err != nil { + return err + } + if action.AssignTo != "" { + assigned := false + for i := range application.Variables { + v := &application.Variables[i] + if v.Name == action.AssignTo { + v.Value = output + assigned = true + logrus.Infof("Присвоение значения '%s' переменной '%s'", output, v.Name) + break + } + } + if !assigned { + return fmt.Errorf("переменная '%s' для присвоения не найдена", action.AssignTo) + } + } + return nil case "file_template": //Формируем 2 строки пути, с подставленными значениями и передаем её для выполнения source, sourceErr := RenderTemplate(action.FileSource, vars) @@ -75,9 +94,9 @@ func ExecuteAction(action *types.SectionAction, application *types.PackageApplic } // RunCommand запускает выполнение переданной команды от указанного лица -func RunCommand(cmdStr, runAs string) error { +func RunCommand(cmdStr, runAs string) (string, error) { if cmdStr == "" { - return nil + return "", nil } var cmd *exec.Cmd if runAs != "" && runAs != "root" { @@ -87,9 +106,9 @@ func RunCommand(cmdStr, runAs string) error { } output, err := cmd.CombinedOutput() if err != nil { - return fmt.Errorf("ошибка команды: %v\nВывод: %s", err, string(output)) + return string(output), fmt.Errorf("ошибка выполнения команды: %v\nВывод: %s", err, string(output)) } - return nil + return strings.TrimSpace(string(output)), nil } // RenderFileTemplate создает целевой файл на основе файла источника с подставленными значениями в нем diff --git a/types/names.go b/types/names.go index 5b1a858..05968eb 100644 --- a/types/names.go +++ b/types/names.go @@ -2,3 +2,6 @@ package types const SectionAbout = "about" const SectionFinal = "final" + +const ConfsDir = "/opt/gosetup/confs" +const LogFile = "/opt/gosetup/log.txt" diff --git a/types/types.go b/types/types.go index bb995b9..0278f98 100644 --- a/types/types.go +++ b/types/types.go @@ -76,6 +76,7 @@ type SectionAction struct { RunAs string `yaml:"run-as"` //Пользователь для запуска RequirePackages []string `yaml:"require-packages"` //Требуемые пакеты Error string `yaml:"error"` //Ошибка выполнения + AssignTo string `yaml:"assign-to"` //Переменная, которой надо присвоить значение } // BoolValidateFunc функция, которая возвращает ошибку, если данные checkbox неверны