aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/service.go
blob: 4f955dadf53bf5f4de6680d5c11e360eb35aa4ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package admin

import (
	"errors"
	"fmt"
	"log/slog"
	"strconv"

	casbin "github.com/casbin/casbin/v2"
)

// Servicer container for dependencies and functions
type Servicer struct {
	*casbin.SyncedEnforcer
	Conf             *ServerRepos
	serverConfigPath string
	reposDir         string
	mgmtRepo         bool
}

// Reload reoload server config and sync policies
func (s *Servicer) Reload() {
	tmpConfig, err := loadServerConfig(s.mgmtRepo, s.reposDir, s.serverConfigPath)
	if err != nil {
		// log.error
		slog.Error("failed to load config", "error", err)
		slog.Error("refusing to reload config")
		return
	}
	oldConfig := s.Conf
	s.Conf = tmpConfig
	if err := s.InitServer(); err != nil {
		slog.Error("couldn't init server with new config, falling back", err)
		s.Conf = oldConfig
		if err := s.InitServer(); err != nil {
			slog.Error("couldn't init server with old config, falling back", err)
			panic("new and old config couldn't init server, no available config to run")
		}
		slog.Error("server has fallen back to old config but it lives in memory only, in fragile state")
	}
}

// InitServer initialize a git server and configure
func (s *Servicer) InitServer() error {
	policies := s.Conf.ServerPolicies()
	numAdded := 0
	slog.Debug(fmt.Sprintf("number of repos %s", strconv.Itoa(len(s.Conf.Repos))))
	for _, policy := range policies {
		added, err := s.AddPolicy(policy[0], policy[1], policy[2])
		if err != nil {
			// log.error
			slog.Error("error adding policy", "role", policy[0], "slug", policy[1], "action", policy[2], "err", err)
			continue
		}
		if added {
			numAdded++
		}
	}
	slog.Info("policy generated", "added", numAdded)
	if err := s.SavePolicy(); err != nil {
		return fmt.Errorf("policy couldn't be saved %w", err)
	}
	slog.Info("policy saved")
	if err := s.LoadPolicy(); err != nil {
		return fmt.Errorf("cloudn't load policy %w", err)
	}
	slog.Info("policy loaded")
	if err := s.Conf.ConfigureRepos(); err != nil {
		return fmt.Errorf("couldn't configure repos %w", err)
	}
	slog.Info("configured repos")
	return nil
}

// NewService create a new admin service, load config, and generate policies
func NewService(modelPath, policyPath, serverConfigPath, reposDir string, mgmtRepo bool) (*Servicer, error) {
	workingPolicyPath, err := setupPolicyFile(policyPath)
	if err != nil {
		return &Servicer{}, err
	}
	slog.Debug(fmt.Sprintf("policy path %s", workingPolicyPath))
	enf, err := casbin.NewSyncedEnforcer(modelPath, workingPolicyPath)
	if err != nil {
		return &Servicer{}, fmt.Errorf("Couldn't load the enforcer encountered the following error: %w", err)
	}
	conf, err := loadServerConfig(mgmtRepo, reposDir, serverConfigPath)
	if errors.Is(err, ErrMgmtRepoNotFound) {
		slog.Info("no server config found, using default")
		conf = defaultServerConfig

	} else if err != nil {
		return &Servicer{}, fmt.Errorf("Coudln't load server config. %w", err)
	}
	conf.basePath = reposDir
	svc := &Servicer{
		enf,
		conf,
		serverConfigPath,
		reposDir,
		mgmtRepo,
	}
	if err := svc.InitServer(); err != nil {
		return nil, err
	}
	return svc, nil
}