Skip to content

Commit

Permalink
feature: Implement license manager stub
Browse files Browse the repository at this point in the history
  • Loading branch information
rg0now committed Nov 29, 2024
1 parent cf69799 commit 1e7148b
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 13 deletions.
19 changes: 16 additions & 3 deletions internal/object/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"

stnrv1 "github.com/l7mp/stunner/pkg/apis/v1"
licensemgr "github.com/l7mp/stunner/pkg/licensemanager"
)

const DefaultAdminObjectName = "DefaultAdmin"
Expand All @@ -25,6 +26,8 @@ type Admin struct {
MetricsEndpoint, HealthCheckEndpoint string
metricsServer, healthCheckServer *http.Server
health *http.ServeMux
licenseManager licensemgr.Manager
licenseConfig *stnrv1.LicenseConfig
log logging.LeveledLogger
}

Expand All @@ -36,9 +39,10 @@ func NewAdmin(conf stnrv1.Config, dryRun bool, rc ReadinessHandler, status Statu
}

admin := Admin{
DryRun: dryRun,
health: http.NewServeMux(),
log: logger.NewLogger("stunner-admin"),
DryRun: dryRun,
health: http.NewServeMux(),
licenseManager: licensemgr.New(logger.NewLogger("license-mgr")),
log: logger.NewLogger("admin"),
}
admin.log.Tracef("NewAdmin: %s", req.String())

Expand All @@ -49,6 +53,7 @@ func NewAdmin(conf stnrv1.Config, dryRun bool, rc ReadinessHandler, status Statu
w.WriteHeader(http.StatusOK)
w.Write([]byte("{}\n")) //nolint:errcheck
})

// readniness checker calls the checker from the factory
admin.health.HandleFunc("/ready", func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand All @@ -63,6 +68,7 @@ func NewAdmin(conf stnrv1.Config, dryRun bool, rc ReadinessHandler, status Statu
http.StatusOK, "READY")))
}
})

// status handler returns the status
admin.health.HandleFunc("/status", func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -118,6 +124,9 @@ func (a *Admin) Reconcile(conf stnrv1.Config) error {
return err
}

a.licenseManager.Update(req.LicenseConfig)
a.licenseConfig = req.LicenseConfig

return nil
}

Expand All @@ -144,6 +153,7 @@ func (a *Admin) GetConfig() stnrv1.Config {
LogLevel: a.LogLevel,
MetricsEndpoint: a.MetricsEndpoint,
HealthCheckEndpoint: &h,
LicenseConfig: a.licenseConfig,
}
}

Expand All @@ -167,6 +177,8 @@ func (a *Admin) Close() error {
}
}

a.licenseManager.Close()

return nil
}

Expand All @@ -177,6 +189,7 @@ func (a *Admin) Status() stnrv1.Status {
LogLevel: a.LogLevel,
MetricsEndpoint: a.MetricsEndpoint,
HealthCheckEndpoint: a.HealthCheckEndpoint,
LicensingInfo: a.licenseManager.Status(),
}

// add licensing status here
Expand Down
2 changes: 1 addition & 1 deletion internal/object/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func NewAuth(conf stnrv1.Config, logger logging.LoggerFactory) (Object, error) {
return nil, stnrv1.ErrInvalidConf
}

auth := Auth{Log: logger.NewLogger("stunner-auth")}
auth := Auth{Log: logger.NewLogger("auth")}
auth.Log.Tracef("NewAuth: %s", req.String())

if err := auth.Reconcile(req); err != nil && !errors.Is(err, ErrRestartRequired) {
Expand Down
2 changes: 1 addition & 1 deletion internal/object/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewCluster(conf stnrv1.Config, resolver resolver.DnsResolver, logger loggin
Domains: []string{},
Resolver: resolver,
logger: logger,
log: logger.NewLogger(fmt.Sprintf("stunner-cluster-%s", req.Name)),
log: logger.NewLogger(fmt.Sprintf("cluster-%s", req.Name)),
}

c.log.Tracef("NewCluster: %s", req.String())
Expand Down
2 changes: 1 addition & 1 deletion internal/object/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func NewListener(conf stnrv1.Config, net transport.Net, realmHandler RealmHandle
getRealm: realmHandler,
Conns: []any{},
logger: logger,
log: logger.NewLogger(fmt.Sprintf("stunner-listener-%s", req.Name)),
log: logger.NewLogger(fmt.Sprintf("listener-%s", req.Name)),
}

l.log.Tracef("NewListener: %s", req.String())
Expand Down
41 changes: 36 additions & 5 deletions pkg/apis/v1/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ type AdminConfig struct {
// health-checking at `http://0.0.0.0:8086`. Set to a pointer to an empty string to disable
// health-checking.
HealthCheckEndpoint *string `json:"healthcheck_endpoint,omitempty"`
// LicenseConfig describes the licensing info to be used to check subscription status with
// the license server.
LicenseConfig *LicenseConfig `json:"license_config,omitempty"`
}

// Licensing info to be used to check subscription status with the license server.
type LicenseConfig struct {
// Key is a comma-separated list of unlocked features plus a time-window during which the
// key is considered valid.
Key string `json:"key"`
// HMAC is a hash-based message authentication code for validating the license key.
HMAC string `json:"hmac"`
}

// Validate checks a configuration and injects defaults.
Expand Down Expand Up @@ -92,21 +104,39 @@ func (req *AdminConfig) String() string {
if req.HealthCheckEndpoint != nil {
status = append(status, fmt.Sprintf("health-check=%q", *req.HealthCheckEndpoint))
}
status = append(status, fmt.Sprintf("license_info=%s", LicensingStatus(req.LicenseConfig)))

return fmt.Sprintf("admin:{%s}", strings.Join(status, ","))
}

func LicensingStatus(req *LicenseConfig) string {
if req != nil {
key := "<MISSING>"
if req != nil {
key = "<SECRET>"
}
pass := "<MISSING>"
if req != nil {
pass = "<SECRET>"
}
return fmt.Sprintf("{key=%s,pass=%s}", key, pass)
}

return "<MISSING>"
}

// AdminStatus represents the administrative status.
type AdminStatus struct {
Name string `json:"name,omitempty"`
LogLevel string `json:"loglevel,omitempty"`
MetricsEndpoint string `json:"metrics_endpoint,omitempty"`
HealthCheckEndpoint string `json:"healthcheck_endpoint,omitempty"`
// licencing status comes here
LicensingInfo string `json:"licensing_info,omitempty"`
}

// String returns a string reprsentation of the administrative status.
func (a *AdminStatus) String() string {
status := []string{}
status := []string{fmt.Sprintf("id=%q", a.Name)}
if a.LogLevel != "" {
status = append(status, fmt.Sprintf("logLevel=%q", a.LogLevel))
}
Expand All @@ -116,8 +146,9 @@ func (a *AdminStatus) String() string {
if a.HealthCheckEndpoint != "" {
status = append(status, fmt.Sprintf("health-check=%q", a.HealthCheckEndpoint))
}
if a.LicensingInfo != "" {
status = append(status, fmt.Sprintf("license-info=%s", a.LicensingInfo))
}

// add licencing status here

return fmt.Sprintf("%s:{%s}", a.Name, strings.Join(status, ","))
return fmt.Sprintf("admin:{%s}", strings.Join(status, ","))
}
4 changes: 2 additions & 2 deletions pkg/apis/v1/stunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ func (s *StunnerStatus) String() string {
cs = append(cs, c.String())
}

return fmt.Sprintf("%s/%s/%s/%s/allocs:%d/status=%s",
s.Admin.String(), s.Auth.String(), ls, cs, s.AllocationCount, s.Status)
return fmt.Sprintf("%s/%s/%s/%s/allocs:%d/status=%s", s.Admin.String(), s.Auth.String(),
ls, cs, s.AllocationCount, s.Status)
}

// String summarizes the status.
Expand Down
41 changes: 41 additions & 0 deletions pkg/licensemanager/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package licensemanager

import (
"github.com/pion/logging"

stnrv1 "github.com/l7mp/stunner/pkg/apis/v1"
)

var constructor = NewStub
var _ Manager = &baseManager{}

type Manager interface {
Update(config *stnrv1.LicenseConfig)
Close()
Validate(feature string) bool
GetTier() string
GetConfig() *stnrv1.LicenseConfig
Status() string
}

func New(log logging.LeveledLogger) Manager {
return constructor(log)
}

// baseManager implements the basic functionality so that all license manager implementations can embed it
type baseManager struct {
config *stnrv1.LicenseConfig
log logging.LeveledLogger
}

func newBaseManager(log logging.LeveledLogger) baseManager {
m := baseManager{log: log}
return m
}

func (m *baseManager) Update(config *stnrv1.LicenseConfig) { m.config = config }
func (m *baseManager) Close() {}
func (m *baseManager) Validate(feature string) bool { return false }
func (m *baseManager) GetTier() string { return "<N/A>" }
func (m *baseManager) GetConfig() *stnrv1.LicenseConfig { return m.config }
func (m *baseManager) Status() string { return "<N/A>" }
29 changes: 29 additions & 0 deletions pkg/licensemanager/stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package licensemanager

import (
"fmt"

stnrv1 "github.com/l7mp/stunner/pkg/apis/v1"
"github.com/pion/logging"
)

var _ Manager = &Stub{}

// Stub is the default license manager that implements the free/open-source tier.
type Stub struct{ baseManager }

func NewStub(log logging.LeveledLogger) Manager {
s := &Stub{baseManager: newBaseManager(log)}
return s
}

func (s *Stub) Update(config *stnrv1.LicenseConfig) {
s.log.Tracef("Licensing status update triggered using config %q", stnrv1.LicensingStatus(config))
s.baseManager.Update(config)
}

func (s *Stub) GetTier() string { return "free" }

func (s *Stub) Status() string {
return fmt.Sprintf("{tier=%q,conf=%s}", s.GetTier(), stnrv1.LicensingStatus(s.GetConfig()))
}

0 comments on commit 1e7148b

Please sign in to comment.