Skip to content

Commit e6098ee

Browse files
authored
fix the reverted configmap PR (#846)
* Revert "Revert "First minimal PoC version for moving the configuration to configmap (#827)" (#845)" This reverts commit d589796. * fix possibly negative time values
1 parent d589796 commit e6098ee

18 files changed

+945
-171
lines changed

Diff for: manifests/03-clusterrole.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ rules:
103103
- get
104104
- list
105105
- delete
106+
- apiGroups:
107+
- ""
108+
resources:
109+
- configmaps
110+
verbs:
111+
- get
112+
- list
113+
- watch
114+
106115
---
107116
apiVersion: rbac.authorization.k8s.io/v1
108117
kind: RoleBinding
@@ -298,6 +307,13 @@ rules:
298307
verbs:
299308
- get
300309
- list
310+
- apiGroups:
311+
- ""
312+
resources:
313+
- secrets
314+
verbs:
315+
- get
316+
- list
301317
---
302318
apiVersion: rbac.authorization.k8s.io/v1
303319
kind: ClusterRoleBinding

Diff for: pkg/config/configobserver/config_aggregator.go

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package configobserver
2+
3+
import (
4+
"context"
5+
"sync"
6+
7+
"github.com/openshift/insights-operator/pkg/config"
8+
"k8s.io/apimachinery/pkg/api/errors"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/client-go/kubernetes"
11+
"k8s.io/klog/v2"
12+
)
13+
14+
const insightsNamespaceName = "openshift-insights"
15+
16+
type Interface interface {
17+
Config() *config.InsightsConfiguration
18+
ConfigChanged() (<-chan struct{}, func())
19+
Listen(ctx context.Context)
20+
}
21+
22+
// ConfigAggregator is an auxiliary structure that should obviate the need for the use of
23+
// legacy secret configurator and the new config map informer
24+
type ConfigAggregator struct {
25+
lock sync.Mutex
26+
legacyConfigurator Configurator
27+
configMapInformer ConfigMapInformer
28+
config *config.InsightsConfiguration
29+
listeners map[chan struct{}]struct{}
30+
usingInformer bool
31+
kubeClient kubernetes.Interface
32+
}
33+
34+
func NewConfigAggregator(ctrl Configurator, configMapInf ConfigMapInformer) Interface {
35+
confAggreg := &ConfigAggregator{
36+
legacyConfigurator: ctrl,
37+
configMapInformer: configMapInf,
38+
listeners: make(map[chan struct{}]struct{}),
39+
usingInformer: true,
40+
}
41+
confAggreg.mergeUsingInformer()
42+
return confAggreg
43+
}
44+
45+
// NewStaticConfigAggregator is a constructor used mainly for the techpreview configuration reading.
46+
// There is no reason to create and start any informer in the techpreview when data gathering runs as a job.
47+
// It is sufficient to read the config once when the job is created and/or starting.
48+
func NewStaticConfigAggregator(ctrl Configurator, cli kubernetes.Interface) Interface {
49+
confAggreg := &ConfigAggregator{
50+
legacyConfigurator: ctrl,
51+
configMapInformer: nil,
52+
kubeClient: cli,
53+
}
54+
55+
confAggreg.mergeStatically()
56+
return confAggreg
57+
}
58+
59+
// mergeUsingInformer merges config values for the legacy "support" secret configuration and
60+
// from the new configmap informer. The "insights-config" configmap always takes
61+
// precedence if it exists and is not empty.
62+
func (c *ConfigAggregator) mergeUsingInformer() {
63+
c.lock.Lock()
64+
defer c.lock.Unlock()
65+
newConf := c.configMapInformer.Config()
66+
conf := c.legacyConfigToInsightsConfiguration()
67+
68+
if newConf == nil {
69+
c.config = conf
70+
return
71+
}
72+
73+
c.merge(conf, newConf)
74+
}
75+
76+
// mergeStatically merges config values for the legacy "support" secret configuration and
77+
// from the "insights-config" configmap by getting and reading the confimap directly without
78+
// using an informer.
79+
func (c *ConfigAggregator) mergeStatically() {
80+
c.lock.Lock()
81+
defer c.lock.Unlock()
82+
conf := c.legacyConfigToInsightsConfiguration()
83+
c.config = conf
84+
ctx, cancel := context.WithCancel(context.Background())
85+
defer cancel()
86+
87+
cm, err := c.kubeClient.CoreV1().ConfigMaps(insightsNamespaceName).Get(ctx, insightsConfigMapName, metav1.GetOptions{})
88+
if err != nil {
89+
if errors.IsNotFound(err) {
90+
return
91+
}
92+
klog.Error(err)
93+
}
94+
95+
cmConf, err := readConfigAndDecode(cm)
96+
if err != nil {
97+
klog.Error("Failed to read configmap configuration: %v", err)
98+
return
99+
}
100+
101+
c.merge(conf, cmConf)
102+
}
103+
104+
func (c *ConfigAggregator) merge(defaultCfg, newCfg *config.InsightsConfiguration) {
105+
// read config map values and merge
106+
if newCfg.DataReporting.Interval != 0 {
107+
defaultCfg.DataReporting.Interval = newCfg.DataReporting.Interval
108+
}
109+
110+
if newCfg.DataReporting.UploadEndpoint != "" {
111+
defaultCfg.DataReporting.UploadEndpoint = newCfg.DataReporting.UploadEndpoint
112+
}
113+
114+
if newCfg.DataReporting.DownloadEndpoint != "" {
115+
defaultCfg.DataReporting.DownloadEndpoint = newCfg.DataReporting.DownloadEndpoint
116+
}
117+
118+
if newCfg.DataReporting.DownloadEndpointTechPreview != "" {
119+
defaultCfg.DataReporting.DownloadEndpointTechPreview = newCfg.DataReporting.DownloadEndpointTechPreview
120+
}
121+
122+
if newCfg.DataReporting.ProcessingStatusEndpoint != "" {
123+
defaultCfg.DataReporting.ProcessingStatusEndpoint = newCfg.DataReporting.ProcessingStatusEndpoint
124+
}
125+
126+
if newCfg.DataReporting.ConditionalGathererEndpoint != "" {
127+
defaultCfg.DataReporting.ConditionalGathererEndpoint = newCfg.DataReporting.ConditionalGathererEndpoint
128+
}
129+
130+
if newCfg.DataReporting.StoragePath != "" {
131+
defaultCfg.DataReporting.StoragePath = newCfg.DataReporting.StoragePath
132+
}
133+
c.config = defaultCfg
134+
}
135+
136+
func (c *ConfigAggregator) Config() *config.InsightsConfiguration {
137+
if c.usingInformer {
138+
c.mergeUsingInformer()
139+
} else {
140+
c.mergeStatically()
141+
}
142+
return c.config
143+
}
144+
145+
// Listen listens to the legacy Secret configurator/observer as well as the
146+
// new config map informer. When any configuration change is observed then all the listeners
147+
// are notified.
148+
func (c *ConfigAggregator) Listen(ctx context.Context) {
149+
legacyCh, legacyCloseFn := c.legacyConfigurator.ConfigChanged()
150+
cmCh, cmICloseFn := c.configMapInformer.ConfigChanged()
151+
defer func() {
152+
legacyCloseFn()
153+
cmICloseFn()
154+
}()
155+
156+
for {
157+
select {
158+
case <-legacyCh:
159+
c.notifyListeners()
160+
case <-cmCh:
161+
c.notifyListeners()
162+
case <-ctx.Done():
163+
return
164+
}
165+
}
166+
}
167+
168+
func (c *ConfigAggregator) notifyListeners() {
169+
for ch := range c.listeners {
170+
ch <- struct{}{}
171+
}
172+
}
173+
174+
func (c *ConfigAggregator) ConfigChanged() (configCh <-chan struct{}, closeFn func()) {
175+
c.lock.Lock()
176+
defer c.lock.Unlock()
177+
ch := make(chan struct{}, 1)
178+
c.listeners[ch] = struct{}{}
179+
return ch, func() {
180+
c.lock.Lock()
181+
defer c.lock.Unlock()
182+
close(ch)
183+
delete(c.listeners, ch)
184+
}
185+
}
186+
187+
func (c *ConfigAggregator) legacyConfigToInsightsConfiguration() *config.InsightsConfiguration {
188+
legacyConfig := c.legacyConfigurator.Config()
189+
return &config.InsightsConfiguration{
190+
DataReporting: config.DataReporting{
191+
Interval: legacyConfig.Interval,
192+
UploadEndpoint: legacyConfig.Endpoint,
193+
DownloadEndpoint: legacyConfig.ReportEndpoint,
194+
ConditionalGathererEndpoint: legacyConfig.ConditionalGathererEndpoint,
195+
ProcessingStatusEndpoint: legacyConfig.ProcessingStatusEndpoint,
196+
DownloadEndpointTechPreview: legacyConfig.ReportEndpointTechPreview,
197+
// This can't be overridden by the config map - it's not merged in the merge function.
198+
// The value is based on the presence of the token in the pull-secret and the config map
199+
// doesn't know anything about secrets
200+
Enabled: legacyConfig.Report,
201+
StoragePath: legacyConfig.StoragePath,
202+
ReportPullingDelay: legacyConfig.ReportPullingDelay,
203+
},
204+
}
205+
}

0 commit comments

Comments
 (0)