Skip to content

Commit ee4b0cb

Browse files
authored
Add etcd and image configuration (#247)
* Introduce viper * Update error message * set env prefix to 'pg' and add an env key replacer (e.g. a get of 'my-key' will try to get the 'PG_MY_KEY' env var) * Temporarily remove viper env prefix for testing * Temporarily remove viper env prefix for testing * Bind env vars * Revert "Bind env vars" This reverts commit e457ab4. * Bind env vars... the easy way * go mod tidy * Add servicemonitor CRD to test cluster * Add TODOs * Add configurable docker_image and etcd_host params * Add crd validation config option * Force synchronous mode * Fix feature flag * Introduce struc to pass along options to operator manager * Introduce struc to pass along options to lb manager * Introduce configuration of operator image * Switch from reference to value * Switch from reference to value
1 parent 88d7d24 commit ee4b0cb

File tree

6 files changed

+115
-45
lines changed

6 files changed

+115
-45
lines changed

api/v1/postgres_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,11 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor
420420
z.Spec.Volume.Size = p.Spec.Size.StorageSize
421421
z.Spec.Volume.StorageClass = sc
422422

423+
// TODO make configurable?
424+
z.Spec.Patroni.TTL = 130
425+
z.Spec.Patroni.SynchronousMode = true
426+
z.Spec.Patroni.SynchronousModeStrict = false
427+
423428
// skip if the configmap does not exist
424429
if c != nil {
425430
z.Spec.AdditionalVolumes = p.buildAdditionalVolumes(c)

controllers/suite_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ var _ = BeforeSuite(func() {
117117
filepath.Join(externalYAMLDir, "svc-postgres-operator.yaml"),
118118
scheme,
119119
cr.Log.WithName("OperatorManager"),
120-
"test-psp")
120+
operatormanager.Options{PspName: "test-psp"})
121121
Expect(err).ToNot(HaveOccurred())
122122

123123
Expect((&PostgresReconciler{
@@ -126,7 +126,7 @@ var _ = BeforeSuite(func() {
126126
PartitionID: "sample-partition",
127127
Tenant: "sample-tenant",
128128
OperatorManager: opMgr,
129-
LBManager: lbmanager.New(svcClusterMgr.GetClient(), "127.0.0.1", int32(32000), int32(8000)),
129+
LBManager: lbmanager.New(svcClusterMgr.GetClient(), lbmanager.Options{LBIP: "127.0.0.1", PortRangeStart: int32(32000), PortRangeSize: int32(8000)}),
130130
Log: cr.Log.WithName("controllers").WithName("Postgres"),
131131
}).SetupWithManager(ctrlClusterMgr)).Should(Succeed())
132132

main.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ const (
4646
portRangeSizeFlg = "port-range-size"
4747
customPSPNameFlg = "custom-psp-name"
4848
storageClassFlg = "storage-class"
49+
postgresImageFlg = "postgres-image"
50+
etcdHostFlg = "etcd-host"
51+
crdValidationFlg = "enable-crd-validation"
52+
operatorImageFlg = "operator-image"
4953
)
5054

5155
var (
@@ -64,8 +68,8 @@ func init() {
6468
}
6569

6670
func main() {
67-
var metricsAddrCtrlMgr, metricsAddrSvcMgr, partitionID, tenant, ctrlClusterKubeconfig, pspName, lbIP, storageClass string
68-
var enableLeaderElection bool
71+
var metricsAddrCtrlMgr, metricsAddrSvcMgr, partitionID, tenant, ctrlClusterKubeconfig, pspName, lbIP, storageClass, postgresImage, etcdHost, operatorImage string
72+
var enableLeaderElection, enableCRDValidation bool
6973
var portRangeStart, portRangeSize int
7074

7175
// TODO enable Prefix and update helm chart
@@ -111,6 +115,14 @@ func main() {
111115

112116
storageClass = viper.GetString(storageClassFlg)
113117

118+
operatorImage = viper.GetString(operatorImageFlg)
119+
postgresImage = viper.GetString(postgresImageFlg)
120+
121+
etcdHost = viper.GetString(etcdHostFlg)
122+
123+
viper.SetDefault(crdValidationFlg, true)
124+
enableCRDValidation = viper.GetBool(crdValidationFlg)
125+
114126
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
115127

116128
ctrl.Log.Info("flag",
@@ -125,6 +137,10 @@ func main() {
125137
portRangeSizeFlg, portRangeSize,
126138
customPSPNameFlg, pspName,
127139
storageClassFlg, storageClass,
140+
operatorImageFlg, operatorImage,
141+
postgresImageFlg, postgresImage,
142+
etcdHostFlg, etcdHost,
143+
crdValidationFlg, enableCRDValidation,
128144
)
129145

130146
svcClusterConf := ctrl.GetConfigOrDie()
@@ -157,12 +173,24 @@ func main() {
157173
os.Exit(1)
158174
}
159175

160-
opMgr, err := operatormanager.New(svcClusterConf, "external/svc-postgres-operator.yaml", scheme, ctrl.Log.WithName("OperatorManager"), pspName)
176+
var opMgrOpts operatormanager.Options = operatormanager.Options{
177+
PspName: pspName,
178+
OperatorImage: operatorImage,
179+
DockerImage: postgresImage,
180+
EtcdHost: etcdHost,
181+
CRDValidation: enableCRDValidation,
182+
}
183+
opMgr, err := operatormanager.New(svcClusterConf, "external/svc-postgres-operator.yaml", scheme, ctrl.Log.WithName("OperatorManager"), opMgrOpts)
161184
if err != nil {
162185
setupLog.Error(err, "unable to create `OperatorManager`")
163186
os.Exit(1)
164187
}
165188

189+
var lbMgrOpts lbmanager.Options = lbmanager.Options{
190+
LBIP: lbIP,
191+
PortRangeStart: int32(portRangeStart),
192+
PortRangeSize: int32(portRangeSize),
193+
}
166194
if err = (&controllers.PostgresReconciler{
167195
CtrlClient: ctrlPlaneClusterMgr.GetClient(),
168196
SvcClient: svcClusterMgr.GetClient(),
@@ -172,7 +200,7 @@ func main() {
172200
Tenant: tenant,
173201
StorageClass: storageClass,
174202
OperatorManager: opMgr,
175-
LBManager: lbmanager.New(svcClusterMgr.GetClient(), lbIP, int32(portRangeStart), int32(portRangeSize)),
203+
LBManager: lbmanager.New(svcClusterMgr.GetClient(), lbMgrOpts),
176204
}).SetupWithManager(ctrlPlaneClusterMgr); err != nil {
177205
setupLog.Error(err, "unable to create controller", "controller", "Postgres")
178206
os.Exit(1)

pkg/lbmanager/lbmanager.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,23 @@ import (
1111
"sigs.k8s.io/controller-runtime/pkg/client"
1212
)
1313

14-
// LBManager Responsible for the creation and deletion of externally accessible Services to access the Postgresql clusters managed by the Postgreslet.
15-
type LBManager struct {
16-
client.Client
14+
type Options struct {
1715
LBIP string
1816
PortRangeStart int32
1917
PortRangeSize int32
2018
}
2119

20+
// LBManager Responsible for the creation and deletion of externally accessible Services to access the Postgresql clusters managed by the Postgreslet.
21+
type LBManager struct {
22+
client.Client
23+
options Options
24+
}
25+
2226
// New Creates a new LBManager with the given configuration
23-
func New(client client.Client, lbIP string, portRangeStart, portRangeSize int32) *LBManager {
27+
func New(client client.Client, opt Options) *LBManager {
2428
return &LBManager{
25-
Client: client,
26-
LBIP: lbIP,
27-
PortRangeStart: portRangeStart,
28-
PortRangeSize: portRangeSize,
29+
Client: client,
30+
options: opt,
2931
}
3032
}
3133

@@ -44,9 +46,9 @@ func (m *LBManager) CreateSvcLBIfNone(ctx context.Context, in *api.Postgres) err
4446
return fmt.Errorf("failed to get a free port for creating Service of type LoadBalancer: %w", err)
4547
}
4648
var lbIPToUse string
47-
if m.LBIP != "" {
49+
if m.options.LBIP != "" {
4850
// a specific IP was configured in the config, so use that one
49-
lbIPToUse = m.LBIP
51+
lbIPToUse = m.options.LBIP
5052
} else if existingLBIP != "" {
5153
// no ip was configured, but one is already in use, so use the existing one
5254
lbIPToUse = existingLBIP
@@ -88,7 +90,7 @@ func (m *LBManager) nextFreeSocket(ctx context.Context) (string, int32, error) {
8890

8991
// If there are none, this will be the first (managed) service we create, so start with PortRangeStart and return
9092
if len(lbs.Items) == 0 {
91-
return anyExistingLBIP, m.PortRangeStart, nil
93+
return anyExistingLBIP, m.options.PortRangeStart, nil
9294
}
9395

9496
// If there are already any managed services, store all the used ports in a slice.
@@ -109,7 +111,7 @@ func (m *LBManager) nextFreeSocket(ctx context.Context) (string, int32, error) {
109111
// Now try all ports in the configured port range to find a free one.
110112
// While not as effective as other implementations, this allows us to freely change PortRangeStart and PortRangeSize
111113
// retroactively without breaking the implementation.
112-
for port := m.PortRangeStart; port < m.PortRangeStart+m.PortRangeSize; port++ {
114+
for port := m.options.PortRangeStart; port < m.options.PortRangeStart+m.options.PortRangeSize; port++ {
113115
if containsElem(portsInUse, port) {
114116
// Port already in use, try the next one
115117
continue

pkg/lbmanager/lbmanager_test.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,64 @@ func TestLBManager_nextFreePort(t *testing.T) {
2424
{
2525
name: "no svc in the cluster",
2626
lbMgr: &LBManager{
27-
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts()).Build(),
28-
LBIP: "0.0.0.0",
29-
PortRangeStart: portRangeStart,
30-
PortRangeSize: portRangeSize,
27+
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts()).Build(),
28+
options: Options{
29+
LBIP: "0.0.0.0",
30+
PortRangeStart: portRangeStart,
31+
PortRangeSize: portRangeSize,
32+
},
3133
},
3234
portWant: 0,
3335
wantErr: false,
3436
},
3537
{
3638
name: "one svc already in the cluster",
3739
lbMgr: &LBManager{
38-
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0)).Build(),
39-
LBIP: "0.0.0.0",
40-
PortRangeStart: portRangeStart,
41-
PortRangeSize: portRangeSize,
40+
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0)).Build(),
41+
options: Options{
42+
LBIP: "0.0.0.0",
43+
PortRangeStart: portRangeStart,
44+
PortRangeSize: portRangeSize,
45+
},
4246
},
4347
portWant: 1,
4448
wantErr: false,
4549
},
4650
{
4751
name: "last free port left",
4852
lbMgr: &LBManager{
49-
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0, 1, 2, 3)).Build(),
50-
LBIP: "0.0.0.0",
51-
PortRangeStart: portRangeStart,
52-
PortRangeSize: portRangeSize,
53+
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0, 1, 2, 3)).Build(),
54+
options: Options{
55+
LBIP: "0.0.0.0",
56+
PortRangeStart: portRangeStart,
57+
PortRangeSize: portRangeSize,
58+
},
5359
},
5460
portWant: 4,
5561
wantErr: false,
5662
},
5763
{
5864
name: "no free port",
5965
lbMgr: &LBManager{
60-
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0, 1, 2, 3, 4)).Build(),
61-
LBIP: "0.0.0.0",
62-
PortRangeStart: portRangeStart,
63-
PortRangeSize: portRangeSize,
66+
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0, 1, 2, 3, 4)).Build(),
67+
options: Options{
68+
LBIP: "0.0.0.0",
69+
PortRangeStart: portRangeStart,
70+
PortRangeSize: portRangeSize,
71+
},
6472
},
6573
portWant: 0,
6674
wantErr: true,
6775
},
6876
{
6977
name: "re-use releaased port",
7078
lbMgr: &LBManager{
71-
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0, 2, 3)).Build(),
72-
LBIP: "0.0.0.0",
73-
PortRangeStart: portRangeStart,
74-
PortRangeSize: portRangeSize,
79+
Client: fake.NewClientBuilder().WithScheme(scheme()).WithLists(svcListWithPorts(0, 2, 3)).Build(),
80+
options: Options{
81+
LBIP: "0.0.0.0",
82+
PortRangeStart: portRangeStart,
83+
PortRangeSize: portRangeSize,
84+
},
7585
},
7686
portWant: 1,
7787
wantErr: false,

pkg/operatormanager/operatormanager.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ const (
5959
// operatorPodMatchingLabels is for listing operator pods
6060
var operatorPodMatchingLabels = client.MatchingLabels{operatorPodLabelName: operatorPodLabelValue}
6161

62+
// Options
63+
type Options struct {
64+
PspName string
65+
OperatorImage string
66+
DockerImage string
67+
EtcdHost string
68+
CRDValidation bool
69+
}
70+
6271
// OperatorManager manages the operator
6372
type OperatorManager struct {
6473
client.Client
@@ -67,13 +76,13 @@ type OperatorManager struct {
6776
log logr.Logger
6877
meta.MetadataAccessor
6978
*runtime.Scheme
70-
pspName string
79+
options Options
7180
}
7281

7382
// New creates a new `OperatorManager`
74-
func New(conf *rest.Config, fileName string, scheme *runtime.Scheme, log logr.Logger, pspName string) (*OperatorManager, error) {
83+
func New(confRest *rest.Config, fileName string, scheme *runtime.Scheme, log logr.Logger, opt Options) (*OperatorManager, error) {
7584
// Use no-cache client to avoid waiting for cashing.
76-
client, err := client.New(conf, client.Options{
85+
client, err := client.New(confRest, client.Options{
7786
Scheme: scheme,
7887
})
7988
if err != nil {
@@ -100,7 +109,7 @@ func New(conf *rest.Config, fileName string, scheme *runtime.Scheme, log logr.Lo
100109
list: list,
101110
Scheme: scheme,
102111
log: log,
103-
pspName: pspName,
112+
options: opt,
104113
}, nil
105114
}
106115

@@ -284,7 +293,7 @@ func (m *OperatorManager) createNewClientObject(ctx context.Context, obj client.
284293
APIGroups: []string{"extensions"},
285294
Verbs: []string{"use"},
286295
Resources: []string{"podsecuritypolicies"},
287-
ResourceNames: []string{m.pspName},
296+
ResourceNames: []string{m.options.PspName},
288297
}
289298
v.Rules = append(v.Rules, pspPolicyRule)
290299

@@ -339,7 +348,7 @@ func (m *OperatorManager) createNewClientObject(ctx context.Context, obj client.
339348
return nil
340349
case *v1.ConfigMap:
341350
m.log.Info("handling ConfigMap")
342-
m.editConfigMap(v, namespace)
351+
m.editConfigMap(v, namespace, m.options)
343352
err = m.Get(ctx, key, &v1.ConfigMap{})
344353
case *v1.Service:
345354
m.log.Info("handling Service")
@@ -353,6 +362,12 @@ func (m *OperatorManager) createNewClientObject(ctx context.Context, obj client.
353362
}
354363
case *appsv1.Deployment:
355364
m.log.Info("handling Deployment")
365+
if len(v.Spec.Template.Spec.Containers) != 1 {
366+
m.log.Info("Unexpected number of containers in deployment, ignoring.")
367+
} else if m.options.OperatorImage != "" {
368+
m.log.Info("Patching operator image", "image", m.options.OperatorImage)
369+
v.Spec.Template.Spec.Containers[0].Image = m.options.OperatorImage
370+
}
356371
err = m.Get(ctx, key, &appsv1.Deployment{})
357372
default:
358373
return errs.New("unknown `client.Object`")
@@ -381,7 +396,7 @@ func (m *OperatorManager) createNewClientObject(ctx context.Context, obj client.
381396
}
382397

383398
// editConfigMap adds info to cm
384-
func (m *OperatorManager) editConfigMap(cm *v1.ConfigMap, namespace string) {
399+
func (m *OperatorManager) editConfigMap(cm *v1.ConfigMap, namespace string, options Options) {
385400
cm.Data["watched_namespace"] = namespace
386401
// TODO don't use the same serviceaccount for operator and databases, see #88
387402
cm.Data["pod_service_account_name"] = serviceAccountName
@@ -391,6 +406,16 @@ func (m *OperatorManager) editConfigMap(cm *v1.ConfigMap, namespace string) {
391406
s := []string{pg.TenantLabelName, pg.ProjectIDLabelName, pg.UIDLabelName, pg.NameLabelName}
392407
// TODO maybe use a precompiled string here
393408
cm.Data["inherited_labels"] = strings.Join(s, ",")
409+
410+
if options.DockerImage != "" {
411+
cm.Data["docker_image"] = options.DockerImage
412+
}
413+
414+
if options.EtcdHost != "" {
415+
cm.Data["etcd_host"] = options.EtcdHost
416+
}
417+
418+
cm.Data["enable_crd_validation"] = strconv.FormatBool(options.CRDValidation)
394419
}
395420

396421
// ensureCleanMetadata ensures obj has clean metadata

0 commit comments

Comments
 (0)