@@ -35,6 +35,18 @@ type Config struct {
3535 PluginConfigPath string
3636 AlertmanagerUrl string
3737 ThanosQuerierUrl string
38+ TLSMinVersion uint16
39+ TLSMaxVersion uint16
40+ TLSCipherSuites []uint16
41+ }
42+
43+ func (c * Config ) IsTLSEnabled () bool {
44+ return c .CertFile != "" && c .PrivateKeyFile != ""
45+ }
46+
47+ type PluginServer struct {
48+ * http.Server
49+ Config * Config
3850}
3951
4052type PluginConfig struct {
@@ -61,19 +73,47 @@ func (pluginConfig *PluginConfig) MarshalJSON() ([]byte, error) {
6173 })
6274}
6375
64- func Start (cfg * Config ) {
76+ func CreateServer (ctx context.Context , cfg * Config ) (* PluginServer , error ) {
77+ httpServer , err := createHTTPServer (ctx , cfg )
78+ if err != nil {
79+ return nil , err
80+ }
81+
82+ return & PluginServer {
83+ Config : cfg ,
84+ Server : httpServer ,
85+ }, nil
86+ }
87+
88+ func (s * PluginServer ) StartHTTPServer () error {
89+ if s .Config .IsTLSEnabled () {
90+ log .Infof ("listening for https on %s" , s .Server .Addr )
91+ return s .Server .ListenAndServeTLS (s .Config .CertFile , s .Config .PrivateKeyFile )
92+ }
93+ log .Infof ("listening for http on %s" , s .Server .Addr )
94+ return s .Server .ListenAndServe ()
95+ }
96+
97+ func (s * PluginServer ) Shutdown (ctx context.Context ) error {
98+ if s .Server != nil {
99+ return s .Server .Shutdown (ctx )
100+ }
101+ return nil
102+ }
103+
104+ func createHTTPServer (ctx context.Context , cfg * Config ) (* http.Server , error ) {
65105 acmMode := cfg .Features [AcmAlerting ]
66106 acmLocationsLength := len (cfg .AlertmanagerUrl ) + len (cfg .ThanosQuerierUrl )
67107
68108 if acmLocationsLength > 0 && ! acmMode {
69- log . Panic ("alertmanager and thanos-querier cannot be set without the 'acm-alerting' feature flag" )
109+ return nil , fmt . Errorf ("alertmanager and thanos-querier cannot be set without the 'acm-alerting' feature flag" )
70110 }
71111 if acmLocationsLength == 0 && acmMode {
72- log . Panic ("alertmanager and thanos-querier must be set to use the 'acm-alerting' feature flag" )
112+ return nil , fmt . Errorf ("alertmanager and thanos-querier must be set to use the 'acm-alerting' feature flag" )
73113 }
74114
75115 if cfg .Port == int (proxy .AlertmanagerPort ) || cfg .Port == int (proxy .ThanosQuerierPort ) {
76- log . Panic ( fmt .Printf ( "Cannot set default port to reserved port %d" , cfg .Port ) )
116+ return nil , fmt .Errorf ( "cannot set default port to reserved port %d" , cfg .Port )
77117 }
78118
79119 // Uncomment the following line for local development:
@@ -86,12 +126,12 @@ func Start(cfg *Config) {
86126 k8sconfig , err := rest .InClusterConfig ()
87127
88128 if err != nil {
89- panic ( fmt .Errorf ("cannot get in cluster config: %w" , err ) )
129+ return nil , fmt .Errorf ("cannot get in cluster config: %w" , err )
90130 }
91131
92132 k8sclient , err = dynamic .NewForConfig (k8sconfig )
93133 if err != nil {
94- panic ( fmt .Errorf ("error creating dynamicClient: %w" , err ) )
134+ return nil , fmt .Errorf ("error creating dynamicClient: %w" , err )
95135 }
96136 } else {
97137 k8sclient = nil
@@ -100,15 +140,27 @@ func Start(cfg *Config) {
100140 router , pluginConfig := setupRoutes (cfg )
101141 router .Use (corsHeaderMiddleware ())
102142
103- tlsConfig := & tls.Config {
104- MinVersion : tls .VersionTLS12 ,
105- }
106- tlsEnabled := cfg .CertFile != "" && cfg .PrivateKeyFile != ""
143+ tlsConfig := & tls.Config {}
144+
145+ tlsEnabled := cfg .IsTLSEnabled ()
107146 if tlsEnabled {
147+ // Set MinVersion - default to TLS 1.2 if not specified
148+ if cfg .TLSMinVersion != 0 {
149+ tlsConfig .MinVersion = cfg .TLSMinVersion
150+ } else {
151+ tlsConfig .MinVersion = tls .VersionTLS12
152+ }
153+
154+ if cfg .TLSMaxVersion != 0 {
155+ tlsConfig .MaxVersion = cfg .TLSMaxVersion
156+ }
157+
158+ if len (cfg .TLSCipherSuites ) > 0 {
159+ tlsConfig .CipherSuites = cfg .TLSCipherSuites
160+ }
161+
108162 // Build and run the controller which reloads the certificate and key
109163 // files whenever they change.
110- ctx := context .Background ()
111-
112164 certKeyPair , err := dynamiccertificates .NewDynamicServingContentFromFiles ("serving-cert" , cfg .CertFile , cfg .PrivateKeyFile )
113165 if err != nil {
114166 log .WithError (err ).Fatal ("unable to create TLS controller" )
@@ -138,6 +190,7 @@ func Start(cfg *Config) {
138190 // Notify cert/key file changes to the controller.
139191 certKeyPair .AddListener (ctrl )
140192
193+ // Start certificate controllers in background
141194 go ctrl .Run (1 , ctx .Done ())
142195 go certKeyPair .Run (ctx , 1 )
143196 }
@@ -160,18 +213,13 @@ func Start(cfg *Config) {
160213 httpServer .Handler = loggedRouter
161214 }
162215
163- if tlsEnabled {
164- if acmMode {
165- startProxy (cfg , k8sclient , tlsConfig , timeout , proxy .AlertManagerKind , proxy .AlertmanagerPort )
166- startProxy (cfg , k8sclient , tlsConfig , timeout , proxy .ThanosQuerierKind , proxy .ThanosQuerierPort )
167- }
168-
169- log .Infof ("listening for https on %s" , httpServer .Addr )
170- panic (httpServer .ListenAndServeTLS (cfg .CertFile , cfg .PrivateKeyFile ))
171- } else {
172- log .Infof ("listening for http on %s" , httpServer .Addr )
173- panic (httpServer .ListenAndServe ())
216+ // Start proxy servers if in ACM mode
217+ if tlsEnabled && acmMode {
218+ startProxy (cfg , k8sclient , tlsConfig , timeout , proxy .AlertManagerKind , proxy .AlertmanagerPort )
219+ startProxy (cfg , k8sclient , tlsConfig , timeout , proxy .ThanosQuerierKind , proxy .ThanosQuerierPort )
174220 }
221+
222+ return httpServer , nil
175223}
176224
177225func setupRoutes (cfg * Config ) (* mux.Router , * PluginConfig ) {
@@ -210,17 +258,32 @@ func setupProxyRoutes(cfg *Config, k8sclient *dynamic.DynamicClient, kind proxy.
210258 return router
211259}
212260
213- func filesHandler ( root http. FileSystem ) http. Handler {
214- fileServer := http .FileServer ( root )
215- return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
216- filePath := r . URL . Path
261+ type headerPreservingWriter struct {
262+ http.ResponseWriter
263+ wroteHeader bool
264+ }
217265
218- // disable caching for plugin entry point
219- if strings .HasPrefix (filePath , "/plugin-entry.js" ) {
266+ func (w * headerPreservingWriter ) WriteHeader (statusCode int ) {
267+ if ! w .wroteHeader {
268+ if w .Header ().Get ("Cache-Control" ) == "" {
220269 w .Header ().Set ("Cache-Control" , "no-cache, no-store, must-revalidate" )
270+ }
271+ if w .Header ().Get ("Expires" ) == "" {
221272 w .Header ().Set ("Expires" , "0" )
222273 }
274+ w .wroteHeader = true
275+ }
276+ w .ResponseWriter .WriteHeader (statusCode )
277+ }
223278
279+ func filesHandler (root http.FileSystem ) http.Handler {
280+ fileServer := http .FileServer (root )
281+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
282+ // disable caching for plugin entry point
283+ if strings .HasPrefix (r .URL .Path , "/plugin-entry.js" ) {
284+ fileServer .ServeHTTP (& headerPreservingWriter {ResponseWriter : w }, r )
285+ return
286+ }
224287 fileServer .ServeHTTP (w , r )
225288 })
226289}
0 commit comments