Skip to content

Commit a55a143

Browse files
committed
Create standalone daemon for non-k8s orchestration
1 parent 0365d9f commit a55a143

6 files changed

Lines changed: 347 additions & 76 deletions

File tree

cmd/bootstrap_manager.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
package cmd
5+
6+
import (
7+
"fmt"
8+
"os"
9+
"strings"
10+
11+
"github.com/microsoft/retina/cmd/standard"
12+
"github.com/microsoft/retina/internal/buildinfo"
13+
"github.com/microsoft/retina/pkg/config"
14+
"github.com/microsoft/retina/pkg/log"
15+
"github.com/microsoft/retina/pkg/telemetry"
16+
"go.uber.org/zap"
17+
"k8s.io/client-go/rest"
18+
"k8s.io/client-go/tools/clientcmd"
19+
kcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
20+
)
21+
22+
const (
23+
logFileName = "retina.log"
24+
)
25+
26+
type BootstrapManager struct {
27+
metricsAddr string
28+
probeAddr string
29+
enableLeaderElection bool
30+
configFile string
31+
}
32+
33+
func NewBootstrapManager(metricsAddr, probeAddr, configFile string, enableLeaderElection bool) *BootstrapManager {
34+
return &BootstrapManager{
35+
metricsAddr: metricsAddr,
36+
probeAddr: probeAddr,
37+
enableLeaderElection: enableLeaderElection,
38+
configFile: configFile,
39+
}
40+
}
41+
42+
func (b *BootstrapManager) Start() error {
43+
fmt.Printf("Bootstrapping Retina")
44+
45+
if buildinfo.ApplicationInsightsID != "" {
46+
telemetry.InitAppInsights(buildinfo.ApplicationInsightsID, buildinfo.Version)
47+
defer telemetry.ShutdownAppInsights()
48+
defer telemetry.TrackPanic()
49+
}
50+
51+
daemonConfig, err := config.GetConfig(b.configFile)
52+
if err != nil {
53+
panic(err)
54+
}
55+
56+
fmt.Println("init logger")
57+
zl, err := log.SetupZapLogger(&log.LogOpts{
58+
Level: daemonConfig.LogLevel,
59+
File: false,
60+
FileName: logFileName,
61+
MaxFileSizeMB: 100, //nolint:gomnd // defaults
62+
MaxBackups: 3, //nolint:gomnd // defaults
63+
MaxAgeDays: 30, //nolint:gomnd // defaults
64+
ApplicationInsightsID: buildinfo.ApplicationInsightsID,
65+
EnableTelemetry: daemonConfig.EnableTelemetry,
66+
},
67+
zap.String("version", buildinfo.Version),
68+
zap.String("plugins", strings.Join(daemonConfig.EnabledPlugin, `,`)),
69+
zap.String("data aggregation level", daemonConfig.DataAggregationLevel.String()),
70+
)
71+
if err != nil {
72+
panic(err)
73+
}
74+
defer zl.Close()
75+
76+
// Check what mode should be activated
77+
if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" {
78+
fmt.Println("KUBECONFIG detected, using kubeconfig: ", kubeconfig)
79+
cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
80+
if err != nil {
81+
return fmt.Errorf("creating controller-runtime manager: %w", err)
82+
}
83+
return b.startDaemon(cfg, daemonConfig, zl)
84+
}
85+
86+
cfg, err := kcfg.GetConfig()
87+
if err != nil {
88+
sm, err := NewStandaloneDaemon(daemonConfig, zl)
89+
if err != nil {
90+
zl.Fatal("Failed to create standalone daemon")
91+
}
92+
defer sm.Stop()
93+
sm.Start()
94+
return nil
95+
}
96+
return b.startDaemon(cfg, daemonConfig, zl)
97+
98+
}
99+
100+
func (b *BootstrapManager) startDaemon(cfg *rest.Config, daemoncfg *config.Config, zl *log.ZapLogger) error {
101+
fmt.Println("Starting Retina Agent")
102+
d := standard.NewDaemon(daemoncfg, cfg, b.metricsAddr, b.probeAddr, b.enableLeaderElection)
103+
104+
if err := d.Start(zl); err != nil {
105+
return fmt.Errorf("starting daemon: %w", err)
106+
}
107+
return nil
108+
}

cmd/root.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"fmt"
77
"os"
88

9-
"github.com/microsoft/retina/cmd/standard"
109
"github.com/spf13/cobra"
1110
)
1211

@@ -28,8 +27,8 @@ var (
2827
RunE: func(cmd *cobra.Command, args []string) error {
2928
// Do Stuff Here
3029
fmt.Println("Starting Retina Agent")
31-
d := standard.NewDaemon(metricsAddr, probeAddr, cfgFile, enableLeaderElection)
32-
if err := d.Start(); err != nil {
30+
b := NewBootstrapManager(metricsAddr, probeAddr, cfgFile, enableLeaderElection)
31+
if err := b.Start(); err != nil {
3332
return fmt.Errorf("starting daemon: %w", err)
3433
}
3534
return nil

cmd/standalone_daemon.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
package cmd
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"strings"
10+
11+
"github.com/microsoft/retina/internal/buildinfo"
12+
"github.com/microsoft/retina/pkg/log"
13+
"github.com/microsoft/retina/pkg/telemetry"
14+
"go.uber.org/zap"
15+
"golang.org/x/sync/errgroup"
16+
17+
"github.com/microsoft/retina/pkg/config"
18+
"github.com/microsoft/retina/pkg/controllers/cache"
19+
pm "github.com/microsoft/retina/pkg/managers/pluginmanager"
20+
sm "github.com/microsoft/retina/pkg/managers/servermanager"
21+
)
22+
23+
type StandaloneDaemon struct {
24+
l *log.ZapLogger
25+
cache *cache.StandaloneCache
26+
httpServer *sm.HTTPServer
27+
pluginManager *pm.PluginManager
28+
config *config.Config
29+
tel telemetry.Telemetry
30+
}
31+
32+
func NewStandaloneDaemon(config *config.Config, zl *log.ZapLogger) (*StandaloneDaemon, error) {
33+
fmt.Println("starting Standalone Retina daemon")
34+
sdLogger := zl.Named("standalone-daemon")
35+
36+
var tel telemetry.Telemetry
37+
var err error
38+
if config.EnableTelemetry {
39+
if buildinfo.ApplicationInsightsID == "" {
40+
panic("telemetry enabled, but ApplicationInsightsID is empty")
41+
}
42+
sdLogger.Info("telemetry enabled", zap.String("applicationInsightsID", buildinfo.ApplicationInsightsID))
43+
tel, err = telemetry.NewAppInsightsTelemetryClient("standalone-retina-agent", map[string]string{
44+
"version": buildinfo.Version,
45+
"plugins": strings.Join(config.EnabledPlugin, `,`),
46+
})
47+
if err != nil {
48+
sdLogger.Error("failed to create telemetry client", zap.Error(err))
49+
return nil, fmt.Errorf("error when creating telemetry client: %w", err)
50+
}
51+
} else {
52+
sdLogger.Info("telemetry disabled")
53+
tel = telemetry.NewNoopTelemetry()
54+
}
55+
56+
pMgr, err := pm.NewPluginManager(
57+
config,
58+
tel,
59+
)
60+
if err != nil {
61+
return nil, err
62+
}
63+
64+
// create HTTP server for API server
65+
httpServer := sm.NewHTTPServer(
66+
config.APIServer.Host,
67+
config.APIServer.Port,
68+
)
69+
70+
return &StandaloneDaemon{
71+
l: sdLogger,
72+
httpServer: httpServer,
73+
pluginManager: pMgr,
74+
config: config,
75+
tel: tel,
76+
}, nil
77+
}
78+
79+
func (sm *StandaloneDaemon) Start() {
80+
sm.l.Info("Starting standalone daemon")
81+
82+
// Start the HTTP server and initialize the cache
83+
if err := sm.httpServer.Init(); err != nil {
84+
sm.l.Error("failed to start http server")
85+
}
86+
sm.cache = cache.NewStandaloneCache()
87+
88+
ctx, cancel := context.WithCancel(context.Background())
89+
defer cancel()
90+
91+
// start heartbeat goroutine for application insights
92+
go sm.tel.Heartbeat(ctx, sm.config.TelemetryInterval)
93+
94+
var g *errgroup.Group
95+
g, ctx = errgroup.WithContext(ctx)
96+
97+
g.Go(func() error {
98+
return sm.pluginManager.Start(ctx)
99+
})
100+
g.Go(func() error {
101+
return sm.httpServer.Start(ctx)
102+
})
103+
104+
if err := g.Wait(); err != nil {
105+
sm.l.Panic("Error running standalone daemon", zap.Error(err))
106+
}
107+
108+
sm.l.Info("Started standalone daemon")
109+
}
110+
111+
func (sm *StandaloneDaemon) Stop() {
112+
// Clean up plugin resources
113+
sm.pluginManager.Stop()
114+
sm.l.Info("Stopped the standalone daemon")
115+
}

0 commit comments

Comments
 (0)