Skip to content

Commit 5125262

Browse files
committed
feat: updated components
1 parent 87c5a0e commit 5125262

4 files changed

Lines changed: 1575 additions & 7 deletions

File tree

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/factory/cluster/sidecars/pgexporter/PostgresExporter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.stackgres.common.StackGresComponent;
3131
import io.stackgres.common.StackGresContainer;
3232
import io.stackgres.common.StackGresContext;
33+
import io.stackgres.common.StackGresVersion;
3334
import io.stackgres.common.StackGresVolume;
3435
import io.stackgres.common.YamlMapperProvider;
3536
import io.stackgres.common.crd.Volume;
@@ -62,7 +63,7 @@
6263

6364
@Singleton
6465
@Sidecar(StackGresContainer.POSTGRES_EXPORTER)
65-
@OperatorVersionBinder
66+
@OperatorVersionBinder(startAt = StackGresVersion.V_1_12)
6667
@RunningContainer(StackGresContainer.POSTGRES_EXPORTER)
6768
public class PostgresExporter implements ContainerFactory<ClusterContainerContext>,
6869
VolumeFactory<StackGresClusterContext> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*
2+
* Copyright (C) 2024 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation.factory.cluster.sidecars.pgexporter;
7+
8+
import static io.stackgres.common.StackGresUtil.getDefaultPullPolicy;
9+
10+
import java.io.IOException;
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.Map;
13+
import java.util.Objects;
14+
import java.util.Optional;
15+
import java.util.stream.Stream;
16+
17+
import com.fasterxml.jackson.core.JsonProcessingException;
18+
import com.fasterxml.jackson.databind.node.ObjectNode;
19+
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
20+
import com.google.common.io.Resources;
21+
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
22+
import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder;
23+
import io.fabric8.kubernetes.api.model.Container;
24+
import io.fabric8.kubernetes.api.model.ContainerBuilder;
25+
import io.fabric8.kubernetes.api.model.ContainerPortBuilder;
26+
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
27+
import io.fabric8.kubernetes.api.model.HasMetadata;
28+
import io.stackgres.common.ClusterPath;
29+
import io.stackgres.common.EnvoyUtil;
30+
import io.stackgres.common.StackGresComponent;
31+
import io.stackgres.common.StackGresContainer;
32+
import io.stackgres.common.StackGresContext;
33+
import io.stackgres.common.StackGresVersion;
34+
import io.stackgres.common.StackGresVolume;
35+
import io.stackgres.common.YamlMapperProvider;
36+
import io.stackgres.common.crd.Volume;
37+
import io.stackgres.common.crd.VolumeBuilder;
38+
import io.stackgres.common.crd.VolumeMountBuilder;
39+
import io.stackgres.common.crd.sgcluster.StackGresCluster;
40+
import io.stackgres.common.crd.sgcluster.StackGresClusterPods;
41+
import io.stackgres.common.crd.sgcluster.StackGresClusterSpec;
42+
import io.stackgres.common.labels.LabelFactoryForCluster;
43+
import io.stackgres.operator.common.Sidecar;
44+
import io.stackgres.operator.conciliation.OperatorVersionBinder;
45+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext;
46+
import io.stackgres.operator.conciliation.factory.ContainerFactory;
47+
import io.stackgres.operator.conciliation.factory.ContainerUserOverrideMounts;
48+
import io.stackgres.operator.conciliation.factory.ImmutableVolumePair;
49+
import io.stackgres.operator.conciliation.factory.PostgresSocketMount;
50+
import io.stackgres.operator.conciliation.factory.RunningContainer;
51+
import io.stackgres.operator.conciliation.factory.ScriptTemplatesVolumeMounts;
52+
import io.stackgres.operator.conciliation.factory.VolumeFactory;
53+
import io.stackgres.operator.conciliation.factory.VolumePair;
54+
import io.stackgres.operator.conciliation.factory.cluster.ClusterContainerContext;
55+
import io.stackgres.operator.conciliation.factory.cluster.patroni.PatroniSecret;
56+
import jakarta.inject.Inject;
57+
import jakarta.inject.Singleton;
58+
import org.jetbrains.annotations.NotNull;
59+
import org.jooq.lambda.Seq;
60+
import org.jooq.lambda.Unchecked;
61+
import org.slf4j.Logger;
62+
import org.slf4j.LoggerFactory;
63+
64+
@Singleton
65+
@Sidecar(StackGresContainer.POSTGRES_EXPORTER)
66+
@OperatorVersionBinder(stopAt = StackGresVersion.V_1_11)
67+
@RunningContainer(StackGresContainer.POSTGRES_EXPORTER)
68+
public class PostgresExporterV1M11 implements ContainerFactory<ClusterContainerContext>,
69+
VolumeFactory<StackGresClusterContext> {
70+
71+
public static final String POSTGRES_EXPORTER_PORT_NAME = "pgexporter";
72+
public static final String POSTGRES_EXPORTER_PGBOUNCER_QUERIES_PREFIX = "pgbouncer";
73+
public static final int POSTGRES_EXPORTER_PORT = 9187;
74+
75+
private static final Logger POSTGRES_EXPORTER_LOGGER = LoggerFactory.getLogger(
76+
"io.stackgres.prometheus-postgres-exporter");
77+
public static final String QUERIES_YAML = "queries.yaml";
78+
79+
private final LabelFactoryForCluster<StackGresCluster> labelFactory;
80+
private final ContainerUserOverrideMounts containerUserOverrideMounts;
81+
private final PostgresSocketMount postgresSocket;
82+
private final ScriptTemplatesVolumeMounts scriptTemplatesVolumeMounts;
83+
protected final YamlMapperProvider yamlMapperProvider;
84+
85+
@Inject
86+
public PostgresExporterV1M11(LabelFactoryForCluster<StackGresCluster> labelFactory,
87+
ContainerUserOverrideMounts containerUserOverrideMounts, PostgresSocketMount postgresSocket,
88+
ScriptTemplatesVolumeMounts scriptTemplatesVolumeMounts, YamlMapperProvider yamlMapperProvider) {
89+
super();
90+
this.labelFactory = labelFactory;
91+
this.containerUserOverrideMounts = containerUserOverrideMounts;
92+
this.postgresSocket = postgresSocket;
93+
this.scriptTemplatesVolumeMounts = scriptTemplatesVolumeMounts;
94+
this.yamlMapperProvider = yamlMapperProvider;
95+
}
96+
97+
public static String configName(StackGresClusterContext clusterContext) {
98+
final String name = clusterContext.getSource().getMetadata().getName();
99+
return StackGresVolume.EXPORTER_QUERIES.getResourceName(name);
100+
}
101+
102+
@Override
103+
public boolean isActivated(ClusterContainerContext context) {
104+
return !Optional.of(context.getClusterContext().getCluster())
105+
.map(StackGresCluster::getSpec)
106+
.map(StackGresClusterSpec::getPods)
107+
.map(StackGresClusterPods::getDisableMetricsExporter)
108+
.orElse(false);
109+
}
110+
111+
@Override
112+
public Container getContainer(ClusterContainerContext context) {
113+
StackGresCluster cluster = context.getClusterContext().getSource();
114+
String superuserUsername =
115+
PatroniSecret.getSuperuserCredentials(context.getClusterContext()).v1;
116+
ContainerBuilder container = new ContainerBuilder();
117+
container.withName(StackGresContainer.POSTGRES_EXPORTER.getName())
118+
.withImage(StackGresComponent.PROMETHEUS_POSTGRES_EXPORTER.get(cluster)
119+
.getLatestImageName())
120+
.withImagePullPolicy(getDefaultPullPolicy())
121+
.withCommand("/bin/sh", "-ex",
122+
ClusterPath.TEMPLATES_PATH.path()
123+
+ "/" + ClusterPath.LOCAL_BIN_START_POSTGRES_EXPORTER_SH_PATH.filename())
124+
.withEnv(
125+
new EnvVarBuilder()
126+
.withName("PGAPPNAME")
127+
.withValue(StackGresContainer.POSTGRES_EXPORTER.getName())
128+
.build(),
129+
new EnvVarBuilder()
130+
.withName("DATA_SOURCE_NAME")
131+
.withValue("postgresql://" + superuserUsername + "@:" + EnvoyUtil.PG_PORT
132+
+ "/postgres"
133+
+ "?host=" + ClusterPath.PG_RUN_PATH.path()
134+
+ "&sslmode=disable")
135+
.build(),
136+
new EnvVarBuilder()
137+
.withName("PG_EXPORTER_EXTEND_QUERY_PATH")
138+
.withValue("/var/opt/postgres-exporter/queries.yaml")
139+
.build(),
140+
new EnvVarBuilder()
141+
.withName("PG_EXPORTER_CONSTANT_LABELS")
142+
.withValue("cluster_name=" + cluster.getMetadata().getName()
143+
+ ", namespace=" + cluster.getMetadata().getNamespace())
144+
.build(),
145+
new EnvVarBuilder()
146+
.withName("PG_EXPORTER_LOG_LEVEL")
147+
.withValue(POSTGRES_EXPORTER_LOGGER.isTraceEnabled() ? "debug" : "info")
148+
.build(),
149+
new EnvVarBuilder()
150+
.withName("PG_PORT")
151+
.withValue(String.valueOf(EnvoyUtil.PG_PORT))
152+
.build())
153+
.withPorts(new ContainerPortBuilder()
154+
.withProtocol("TCP")
155+
.withName(POSTGRES_EXPORTER_PORT_NAME)
156+
.withContainerPort(POSTGRES_EXPORTER_PORT)
157+
.build())
158+
.addAllToEnv(postgresSocket.getDerivedEnvVars(context))
159+
.addAllToEnv(scriptTemplatesVolumeMounts.getDerivedEnvVars(context))
160+
.addAllToVolumeMounts(postgresSocket.getVolumeMounts(context))
161+
.addAllToVolumeMounts(scriptTemplatesVolumeMounts.getVolumeMounts(context))
162+
.addToVolumeMounts(
163+
new VolumeMountBuilder()
164+
.withName(StackGresVolume.EXPORTER_QUERIES.getName())
165+
.withMountPath("/var/opt/postgres-exporter/queries.yaml")
166+
.withSubPath("queries.yaml")
167+
.withReadOnly(true)
168+
.build()
169+
)
170+
.addAllToVolumeMounts(containerUserOverrideMounts.getVolumeMounts(context));
171+
172+
return container.build();
173+
}
174+
175+
@Override
176+
public Map<String, String> getComponentVersions(ClusterContainerContext context) {
177+
return Map.of(
178+
StackGresContext.PROMETHEUS_POSTGRES_EXPORTER_VERSION_KEY,
179+
StackGresComponent.PROMETHEUS_POSTGRES_EXPORTER
180+
.get(context.getClusterContext().getCluster()).getLatestVersion());
181+
}
182+
183+
@Override
184+
public @NotNull Stream<VolumePair> buildVolumes(StackGresClusterContext context) {
185+
return Stream.of(
186+
ImmutableVolumePair.builder()
187+
.volume(buildVolume(context))
188+
.source(buildSource(context))
189+
.build()
190+
);
191+
}
192+
193+
private Volume buildVolume(StackGresClusterContext context) {
194+
return new VolumeBuilder()
195+
.withName(StackGresVolume.EXPORTER_QUERIES.getName())
196+
.withConfigMap(new ConfigMapVolumeSourceBuilder()
197+
.withName(configName(context))
198+
.build())
199+
.build();
200+
}
201+
202+
private HasMetadata buildSource(StackGresClusterContext context) {
203+
204+
final ConfigMapBuilder builder = new ConfigMapBuilder()
205+
.withNewMetadata()
206+
.withName(configName(context))
207+
.withNamespace(context.getSource().getMetadata().getNamespace())
208+
.withLabels(labelFactory.genericLabels(context.getSource()))
209+
.endMetadata();
210+
211+
final boolean pgBouncerIsDisabled = Optional.of(context)
212+
.map(StackGresClusterContext::getCluster)
213+
.map(StackGresCluster::getSpec)
214+
.map(StackGresClusterSpec::getPods)
215+
.map(StackGresClusterPods::getDisableConnectionPooling)
216+
.orElse(false);
217+
218+
if (pgBouncerIsDisabled) {
219+
final YAMLMapper yamlMapper = yamlMapperProvider.get();
220+
final ObjectNode queries;
221+
final String data;
222+
try {
223+
queries = (ObjectNode) yamlMapper
224+
.readTree(PostgresExporterV1M11.class.getResource("/prometheus-postgres-exporter/queries-1.22.yaml"));
225+
226+
var fieldNames = Seq.seq(queries.fieldNames()).toList();
227+
for (var fieldName : fieldNames) {
228+
if (fieldName.startsWith(POSTGRES_EXPORTER_PGBOUNCER_QUERIES_PREFIX)) {
229+
queries.remove(fieldName);
230+
}
231+
}
232+
233+
data = yamlMapper.writeValueAsString(queries);
234+
235+
builder.withData(Map.of(QUERIES_YAML, data));
236+
237+
return builder.build();
238+
} catch (JsonProcessingException e) {
239+
throw new RuntimeException("couldn't serialize prometheus postgres exporter queries to a string", e);
240+
} catch (IOException e) {
241+
throw new RuntimeException("couldn't read prometheus postgres exporter queries file", e);
242+
}
243+
}
244+
245+
return builder
246+
.withData(Map.of(QUERIES_YAML,
247+
Unchecked.supplier(() ->
248+
Resources
249+
.asCharSource(Objects.requireNonNull(PostgresExporter.class.getResource(
250+
"/prometheus-postgres-exporter/queries.yaml")),
251+
StandardCharsets.UTF_8).read()).get()))
252+
.build();
253+
}
254+
255+
}

0 commit comments

Comments
 (0)