This commit is contained in:
parent
db49ea2c51
commit
6693ceabcc
8 changed files with 275 additions and 167 deletions
|
@ -1,4 +1,3 @@
|
|||
.git
|
||||
app.db
|
||||
uploads
|
||||
Dockerfile
|
|
@ -5,7 +5,10 @@ WORKDIR /app
|
|||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN make release
|
||||
|
||||
ARG APP_VERSION
|
||||
|
||||
RUN make build
|
||||
|
||||
FROM registry.altlinux.org/sisyphus/alt:20241211
|
||||
|
||||
|
|
14
Makefile
14
Makefile
|
@ -1,7 +1,10 @@
|
|||
GIT_VERSION = $(shell git describe --tags )
|
||||
GOLANGCI_LINT := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
|
||||
SWAG := go run github.com/swaggo/swag/cmd/swag@v1.16.4
|
||||
|
||||
GIT_VERSION = $(shell git describe --tags)
|
||||
APP_VERSION ?= $(GIT_VERSION)
|
||||
DOCKER_TAG ?= $(APP_VERSION)
|
||||
|
||||
format:
|
||||
@echo "🛠️ Format and Lint code with golangci-lint"
|
||||
$(GOLANGCI_LINT) run
|
||||
|
@ -19,16 +22,19 @@ swag:
|
|||
|
||||
build:
|
||||
go build \
|
||||
-ldflags="-X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(GIT_VERSION)'" \
|
||||
-ldflags="-X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(APP_VERSION)'" \
|
||||
-o aides-repo-api \
|
||||
./cmd/aides-repo-api/main.go
|
||||
|
||||
release:
|
||||
go build \
|
||||
-ldflags="-s -w -X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(GIT_VERSION)'" \
|
||||
-ldflags="-s -w -X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(APP_VERSION)'" \
|
||||
-o aides-repo-api \
|
||||
./cmd/aides-repo-api/main.go
|
||||
|
||||
build-docker:
|
||||
docker build -t ghcr.io/aides-infra/aides-repo-api .
|
||||
docker build \
|
||||
--build-arg APP_VERSION=${APP_VERSION} \
|
||||
-t ghcr.io/aides-infra/aides-repo-api:${DOCKER_TAG}\
|
||||
.
|
||||
|
||||
|
|
|
@ -22,6 +22,6 @@ func main() {
|
|||
}
|
||||
|
||||
app.Init()
|
||||
|
||||
defer app.Shutdown()
|
||||
app.Run()
|
||||
}
|
||||
|
|
|
@ -121,10 +121,20 @@ func (app *App) Run() {
|
|||
},
|
||||
)
|
||||
|
||||
app.repo.ForceUpdate()
|
||||
err := app.repo.ForceUpdate()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%d", app.config.Port), app.router.Setup())
|
||||
err = http.ListenAndServe(
|
||||
fmt.Sprintf(":%d", app.config.Port),
|
||||
app.router.Setup(),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) Shutdown() {
|
||||
app.cron.Shutdown()
|
||||
}
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
package cronservice
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger"
|
||||
)
|
||||
|
||||
type RepoService interface {
|
||||
ForceUpdate()
|
||||
ForceUpdate() error
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
|
@ -19,9 +17,12 @@ type Service struct {
|
|||
}
|
||||
|
||||
func New(repo RepoService) *Service {
|
||||
log := logger.GetLogger()
|
||||
scheduler, err := gocron.NewScheduler()
|
||||
if err != nil {
|
||||
log.Fatalf("Не удалось создать планировщик: %v", err)
|
||||
log.Fatal("Не удалось создать планировщик", map[string]interface{}{
|
||||
"err": err,
|
||||
})
|
||||
}
|
||||
|
||||
return &Service{
|
||||
|
@ -31,18 +32,25 @@ func New(repo RepoService) *Service {
|
|||
}
|
||||
|
||||
func (s *Service) SetupCronJobs() {
|
||||
log := logger.GetLogger()
|
||||
_, err := s.scheduler.NewJob(
|
||||
gocron.CronJob("0 4 * * *", false),
|
||||
gocron.NewTask(func() {
|
||||
log := logger.GetLogger()
|
||||
log.Info(
|
||||
"[cron] force update is started",
|
||||
)
|
||||
s.repoService.ForceUpdate()
|
||||
err := s.repoService.ForceUpdate()
|
||||
if err != nil {
|
||||
log.Error("[cron] force update error", map[string]interface{}{
|
||||
"err": err,
|
||||
})
|
||||
}
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Не удалось создать задание cron: %v", err)
|
||||
log.Fatal("Не удалось создать задание cron", map[string]interface{}{
|
||||
"err": err,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,8 +59,11 @@ func (s *Service) Start() {
|
|||
}
|
||||
|
||||
func (s *Service) Shutdown() {
|
||||
log := logger.GetLogger()
|
||||
err := s.scheduler.Shutdown()
|
||||
if err != nil {
|
||||
log.Printf("Не удалось корректно завершить работу планировщика: %v", err)
|
||||
log.Error("Не удалось корректно завершить работу планировщика", map[string]interface{}{
|
||||
"err": err,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package reposervice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
|
@ -29,170 +27,160 @@ func New(db *gorm.DB, cfg Config) *Service {
|
|||
}
|
||||
}
|
||||
|
||||
func createSymlink(target, link string) error {
|
||||
if _, err := os.Lstat(link); err == nil {
|
||||
if err := os.Remove(link); err != nil {
|
||||
return fmt.Errorf("failed to remove existing file or symlink: %w", err)
|
||||
func (s *Service) futureRepoPathPrefix() string {
|
||||
return path.Join(
|
||||
s.config.GetUploadDir(),
|
||||
".future_repo",
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Service) currentRepoPathPrefix() string {
|
||||
return path.Join(
|
||||
s.config.GetUploadDir(),
|
||||
"repo",
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Service) oldRepoPathPrefix() string {
|
||||
return path.Join(
|
||||
s.config.GetUploadDir(),
|
||||
".old_repo",
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Service) ForceUpdate() error {
|
||||
const REPO_NAME = "aides"
|
||||
|
||||
architectures := []string{
|
||||
"x86_64",
|
||||
"noarch",
|
||||
}
|
||||
|
||||
repos := []string{
|
||||
"Sisyphus",
|
||||
}
|
||||
|
||||
log := logger.GetLogger()
|
||||
log.Info("Start repo update")
|
||||
|
||||
err := os.MkdirAll(s.futureRepoPathPrefix(), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(s.futureRepoPathPrefix())
|
||||
|
||||
err = os.MkdirAll(s.oldRepoPathPrefix(), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(s.oldRepoPathPrefix())
|
||||
|
||||
err = os.MkdirAll(s.currentRepoPathPrefix(), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range repos {
|
||||
var tasks []models.Task
|
||||
altRepo := models.ALTRepo{
|
||||
Name: r,
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Symlink(target, link); err != nil {
|
||||
return fmt.Errorf("failed to create symlink: %w", err)
|
||||
}
|
||||
s.db.
|
||||
Where(&altRepo).
|
||||
First(&altRepo)
|
||||
|
||||
return nil
|
||||
}
|
||||
s.db.
|
||||
Model(&models.GitRepoAltRepoTask{}).
|
||||
Select("tasks.*").
|
||||
Joins("JOIN tasks ON tasks.id = git_repo_alt_repo_tasks.last_task_id").
|
||||
Where(&models.GitRepoAltRepoTask{
|
||||
ALTRepoID: altRepo.ID,
|
||||
}).
|
||||
Preload("Files").
|
||||
Find(&tasks)
|
||||
|
||||
func runGenbasedir(repoDir, arch, repoName string) {
|
||||
log := logger.GetLogger()
|
||||
cmd := exec.Command(
|
||||
"genbasedir",
|
||||
"--bloat",
|
||||
"--progress",
|
||||
fmt.Sprintf("--topdir=%s", repoDir),
|
||||
arch,
|
||||
repoName,
|
||||
)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Error(
|
||||
"Failed to run genbasedir",
|
||||
map[string]interface{}{
|
||||
"arch": arch,
|
||||
"error": err,
|
||||
},
|
||||
futureRepoPath := path.Join(
|
||||
s.futureRepoPathPrefix(),
|
||||
altRepo.Name,
|
||||
)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Info("Successfully ran genbasedir", map[string]interface{}{
|
||||
"arch": arch,
|
||||
})
|
||||
}
|
||||
|
||||
func createRepoDirs(repoDir, repoName, arch string) {
|
||||
log := logger.GetLogger()
|
||||
// Create the 'base' directory
|
||||
baseDir := path.Join(repoDir, arch, "base")
|
||||
err := os.MkdirAll(baseDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Error("Failed to create directory", map[string]interface{}{
|
||||
"directory": baseDir,
|
||||
"err": err,
|
||||
})
|
||||
os.Exit(1)
|
||||
}
|
||||
err := os.MkdirAll(
|
||||
futureRepoPath,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the 'RPMS.<REPO_NAME>' directory
|
||||
rpmsDir := path.Join(repoDir, arch, fmt.Sprintf("RPMS.%s", repoName))
|
||||
err = os.MkdirAll(rpmsDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Error("Failed to create directory", map[string]interface{}{
|
||||
"directory": rpmsDir,
|
||||
"err": err,
|
||||
})
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) ForceUpdate() {
|
||||
var tasks []models.Task
|
||||
altRepo := models.ALTRepo{
|
||||
Name: "Sisyphus",
|
||||
}
|
||||
|
||||
s.db.
|
||||
Where(&altRepo).
|
||||
First(&altRepo)
|
||||
|
||||
s.db.
|
||||
Model(&models.GitRepoAltRepoTask{}).
|
||||
Select("tasks.*").
|
||||
Joins("JOIN tasks ON tasks.id = git_repo_alt_repo_tasks.last_task_id").
|
||||
Where(&models.GitRepoAltRepoTask{
|
||||
ALTRepoID: altRepo.ID,
|
||||
}).
|
||||
Preload("Files").
|
||||
Find(&tasks)
|
||||
|
||||
repoPath := path.Join(s.config.GetUploadDir(), "future_repo", "Sisyphus")
|
||||
|
||||
err := os.MkdirAll(
|
||||
repoPath,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
repoName := "aides"
|
||||
architectures := []string{"x86_64", "noarch"}
|
||||
|
||||
for _, arch := range architectures {
|
||||
createRepoDirs(repoPath, repoName, arch)
|
||||
}
|
||||
|
||||
for _, el := range tasks {
|
||||
for _, fileInfo := range el.Files {
|
||||
localFilePath := path.Join(
|
||||
strconv.FormatUint(uint64(el.ID), 10), fileInfo.Name,
|
||||
)
|
||||
symLink := path.Join(
|
||||
s.config.GetUploadDir(),
|
||||
"future_repo",
|
||||
"Sisyphus",
|
||||
fileInfo.Arch,
|
||||
"RPMS.aides",
|
||||
fileInfo.Name,
|
||||
)
|
||||
targetPath := path.Join("../../../../tasks/", localFilePath)
|
||||
err := createSymlink(targetPath, symLink)
|
||||
for _, arch := range architectures {
|
||||
err = createRepoDirs(futureRepoPath, REPO_NAME, arch)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, arch := range architectures {
|
||||
runGenbasedir(repoPath, arch, repoName)
|
||||
}
|
||||
for _, el := range tasks {
|
||||
for _, fileInfo := range el.Files {
|
||||
localFilePath := path.Join(
|
||||
strconv.FormatUint(uint64(el.ID), 10), fileInfo.Name,
|
||||
)
|
||||
symLink := path.Join(
|
||||
futureRepoPath,
|
||||
fileInfo.Arch,
|
||||
"RPMS.aides",
|
||||
fileInfo.Name,
|
||||
)
|
||||
targetPath := path.Join("../../../../tasks/", localFilePath)
|
||||
err := createSymlink(targetPath, symLink)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.db.
|
||||
Model(&models.GitRepoAltRepoTask{}).
|
||||
Where(&models.GitRepoAltRepoTask{
|
||||
ALTRepoID: altRepo.ID,
|
||||
}).
|
||||
Update(
|
||||
"current_task_id", gorm.Expr("last_task_id"),
|
||||
for _, arch := range architectures {
|
||||
err = runGenbasedir(futureRepoPath, arch, REPO_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.db.
|
||||
Model(&models.GitRepoAltRepoTask{}).
|
||||
Where(&models.GitRepoAltRepoTask{
|
||||
ALTRepoID: altRepo.ID,
|
||||
}).
|
||||
Update(
|
||||
"current_task_id", gorm.Expr("last_task_id"),
|
||||
)
|
||||
|
||||
currentRepoPath := path.Join(
|
||||
s.currentRepoPathPrefix(),
|
||||
altRepo.Name,
|
||||
)
|
||||
|
||||
err = os.MkdirAll(path.Join(s.config.GetUploadDir(), "repo"), os.ModePerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
oldRepoPath := path.Join(
|
||||
s.oldRepoPathPrefix(),
|
||||
altRepo.Name,
|
||||
)
|
||||
|
||||
aPath := path.Join(s.config.GetUploadDir(), "future_repo", "Sisyphus")
|
||||
bPath := path.Join(s.config.GetUploadDir(), "repo", "Sisyphus")
|
||||
cPath := path.Join(s.config.GetUploadDir(), "repo", ".Sisyphus")
|
||||
|
||||
if _, err := os.Stat(bPath); err == nil {
|
||||
if err := os.Rename(bPath, cPath); err != nil {
|
||||
panic(err)
|
||||
if err := renameIfExists(
|
||||
currentRepoPath,
|
||||
oldRepoPath,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
panic(err)
|
||||
|
||||
if err := os.Rename(
|
||||
futureRepoPath,
|
||||
currentRepoPath,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := os.Rename(aPath, bPath); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(cPath); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(path.Join(s.config.GetUploadDir(), "future_repo")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Info("Successful repo update")
|
||||
return nil
|
||||
}
|
||||
|
|
91
internal/services/reposervice/utils.go
Normal file
91
internal/services/reposervice/utils.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
package reposervice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger"
|
||||
)
|
||||
|
||||
func createRepoDirs(repoDir, repoName, arch string) error {
|
||||
log := logger.GetLogger()
|
||||
// Create the 'base' directory
|
||||
baseDir := path.Join(repoDir, arch, "base")
|
||||
err := os.MkdirAll(baseDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Error("Failed to create directory", map[string]interface{}{
|
||||
"directory": baseDir,
|
||||
"err": err,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the 'RPMS.<REPO_NAME>' directory
|
||||
rpmsDir := path.Join(repoDir, arch, fmt.Sprintf("RPMS.%s", repoName))
|
||||
err = os.MkdirAll(rpmsDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Error("Failed to create directory", map[string]interface{}{
|
||||
"directory": rpmsDir,
|
||||
"err": err,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGenbasedir(repoDir, arch, repoName string) error {
|
||||
log := logger.GetLogger()
|
||||
cmd := exec.Command(
|
||||
"genbasedir",
|
||||
"--bloat",
|
||||
"--progress",
|
||||
fmt.Sprintf("--topdir=%s", repoDir),
|
||||
arch,
|
||||
repoName,
|
||||
)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Error(
|
||||
"Failed to run genbasedir",
|
||||
map[string]interface{}{
|
||||
"arch": arch,
|
||||
"error": err,
|
||||
"cmd_error": cmd.Stderr,
|
||||
},
|
||||
)
|
||||
return err
|
||||
}
|
||||
log.Debug("Successfully ran genbasedir", map[string]interface{}{
|
||||
"arch": arch,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSymlink(target, link string) error {
|
||||
if _, err := os.Lstat(link); err == nil {
|
||||
if err := os.Remove(link); err != nil {
|
||||
return fmt.Errorf("failed to remove existing file or symlink: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Symlink(target, link); err != nil {
|
||||
return fmt.Errorf("failed to create symlink: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func renameIfExists(oldPath, newPath string) error {
|
||||
if _, err := os.Stat(oldPath); err == nil {
|
||||
return os.Rename(oldPath, newPath)
|
||||
} else if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue