Skip to content

Commit

Permalink
[argocd] basic argocd integration
Browse files Browse the repository at this point in the history
  • Loading branch information
rmannibucau committed Dec 25, 2023
1 parent 7c6acdc commit 3248a2c
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
import org.eclipse.microprofile.config.Config;

import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.util.AnnotationLiteral;
import javax.json.JsonValue;
import javax.json.spi.JsonProvider;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -37,6 +41,8 @@
import java.util.stream.StreamSupport;

import static java.util.Locale.ROOT;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toMap;

@Log
public final class BundleBee {
Expand All @@ -52,14 +58,23 @@ public void launch(final String... args) {
final var initializer = SeContainerInitializer.newInstance();
final var cmd = args.length == 0 ? "help" : args[0];
try (final var container = initializer.initialize()) {
// enrich the config with cli args
StreamSupport.stream(container.select(Config.class).get().getConfigSources().spliterator(), false)
// enrich the config with cli/specific args
final var properties = StreamSupport.stream(container.select(Config.class).get().getConfigSources().spliterator(), false)
.filter(ConfigurableConfigSource.class::isInstance)
.map(ConfigurableConfigSource.class::cast)
.findFirst()
.orElseThrow()
.getProperties()
.putAll(Args.toProperties(cmd, args));
.getProperties();
properties.putAll(Args.toProperties(cmd, args));
ofNullable(System.getenv("ARGOCD_APP_PARAMETERS")).ifPresent(props -> {
final var jsonProvider = container.select(JsonProvider.class, new AnnotationLiteral<io.yupiik.bundlebee.core.qualifier.BundleBee>() {
}).get();
try (final var reader = jsonProvider.createReader(new StringReader(props))) {
properties.putAll(reader.readArray().stream()
.map(JsonValue::asJsonObject)
.collect(toMap(o -> o.getString("name"), o -> o.getString("string"))));
}
});

boolean foundCommand = false;
try { // we vetoed all other executable except the one we want
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,11 @@ private CompletableFuture<?> fetchNext(final ReentrantLock lock, final Iterator<
}

public enum ActualStatus {
MISSING, EXISTS
@Description("The resource is missing.")
MISSING,

@Description("Just resource exists.")
EXISTS
}

@Data
Expand All @@ -536,10 +540,18 @@ public static class Item {
}

public enum DiffType {
AUTO, JSON_PATCH, JSON
@Description("Use the most adapted diff type.")
AUTO,
@Description("Use JSON-Patch form.")
JSON_PATCH,
@Description("Use the JSON output directly, no diff.")
JSON
}

public enum OutputType {
LOG, FILE
@Description("Log the output.")
LOG,
@Description("Write the output to a file.")
FILE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.json.JsonArrayBuilder;
import javax.json.JsonString;
import javax.json.spi.JsonProvider;
import java.io.IOException;
Expand All @@ -43,6 +44,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

import static java.util.stream.Collectors.groupingBy;
Expand Down Expand Up @@ -140,13 +142,22 @@ public CompletionStage<?> execute() {
Stream.of(this.descriptions.split(","))
.map(String::strip)
.filter(Predicate.not(String::isBlank))
.map(Path::of)
.filter(Files::exists)
.forEach(file -> {
try (final var reader = Files.newBufferedReader(file)) {
descriptions.load(reader);
} catch (final IOException e) {
throw new IllegalArgumentException("Can't read '" + file + "'", e);
if (file.startsWith("env:")) {
try (final var reader = new StringReader(System.getenv(file.substring("env:".length())))) {
descriptions.load(reader);
} catch (final IOException e) {
throw new IllegalArgumentException("Can't read '" + file + "'", e);
}
} else {
final var path = Path.of(file);
if (Files.exists(path)) {
try (final var reader = Files.newBufferedReader(path)) {
descriptions.load(reader);
} catch (final IOException e) {
throw new IllegalArgumentException("Can't read '" + file + "'", e);
}
}
}
});

Expand Down Expand Up @@ -179,28 +190,47 @@ public CompletionStage<?> execute() {
})
.collect(toList());

if (!"skip".equals(propertiesFilename)) {
doWrite("Sample",
() -> Path.of(dumpLocation).resolve(propertiesFilename), () -> placeholders.stream()
.map(p -> {
final var key = p.getName();
final var desc = descriptions.getProperty(key, key);
final var defaultValue = p.getDefaultValue();
return (desc != null && !desc.isBlank() ? "# HELP: " + desc.replace("\n", "\n# HELP: ") + "\n" : "") +
"# " + key + " = " + (defaultValue != null ? formatSampleDefault(defaultValue) : (p.getDefaultValues() != null ? p.getDefaultValues().stream().map(this::formatSampleDefault).collect(joining(" OR ")) : "-"));
})
.collect(joining("\n\n", "", "\n")));
}

if (!"skip".equals(completionFilename)) {
doWrite("Completion",
() -> Path.of(dumpLocation).resolve(completionFilename), () -> placeholders.stream()
.map(p -> p.getName() + " = " + descriptions.getProperty(p.getName(), p.getName()).replace("\n", " "))
.collect(joining("\n", "", "\n")));
}

if (!"skip".equals(docFilename)) {
doWrite("Doc", () -> Path.of(dumpLocation).resolve(docFilename), () -> formatDoc(placeholders, descriptions));
if (outputType == OutputType.ARGOCD) {
final var argoCdDynamicConf = placeholders.stream()
.collect(Collector.of(
json::createArrayBuilder,
(a, p) -> {
final var conf = json.createObjectBuilder()
.add("name", p.getName());
if (p.getDefaultValue() != null) {
conf.add("string", p.getDefaultValue());
} else if (p.getDefaultValues() != null) {
conf.add("string", String.join(",", p.getDefaultValues()));
}
a.add(conf);
},
JsonArrayBuilder::addAll,
JsonArrayBuilder::build));
System.out.println(argoCdDynamicConf);
} else {
if (!"skip".equals(propertiesFilename)) {
doWrite("Sample",
() -> Path.of(dumpLocation).resolve(propertiesFilename), () -> placeholders.stream()
.map(p -> {
final var key = p.getName();
final var desc = descriptions.getProperty(key, key);
final var defaultValue = p.getDefaultValue();
return (desc != null && !desc.isBlank() ? "# HELP: " + desc.replace("\n", "\n# HELP: ") + "\n" : "") +
"# " + key + " = " + (defaultValue != null ? formatSampleDefault(defaultValue) : (p.getDefaultValues() != null ? p.getDefaultValues().stream().map(this::formatSampleDefault).collect(joining(" OR ")) : "-"));
})
.collect(joining("\n\n", "", "\n")));
}

if (!"skip".equals(completionFilename)) {
doWrite("Completion",
() -> Path.of(dumpLocation).resolve(completionFilename), () -> placeholders.stream()
.map(p -> p.getName() + " = " + descriptions.getProperty(p.getName(), p.getName()).replace("\n", " "))
.collect(joining("\n", "", "\n")));
}

if (!"skip".equals(docFilename)) {
doWrite("Doc", () -> Path.of(dumpLocation).resolve(docFilename), () -> formatDoc(placeholders, descriptions));
}
}
})
.whenComplete((ok, ko) -> placeholderSpy.setListener(oldListener));
Expand Down Expand Up @@ -278,7 +308,14 @@ private void doWrite(final String what, final Supplier<Path> location, final Sup
}

public enum OutputType {
LOG, FILE
@Description("Just log the output.")
LOG,

@Description("Write the output to a file.")
FILE,

@Description("Use an output formatting ArgoCD understands.")
ARGOCD
}

@Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public class ProcessCommand extends BaseLabelEnricherCommand implements Completi
private String excludedLocations;

@Inject
@Description("If set, represents where to dump processed descriptors.")
@Description("If set, represents where to dump processed descriptors. Note that `stdout` enables to log on `System.out` (java `stdout`) directly - useful for ArgoCD for example. In this case formatting and `concat` are skipped.")
@ConfigProperty(name = "bundlebee.process.output", defaultValue = UNSET)
private String output;

Expand Down Expand Up @@ -146,12 +146,14 @@ public CompletionStage<?> execute() {
public CompletionStage<?> doExecute(final String from, final String manifest, final String alveolus,
final boolean injectTimestamp, final boolean injectBundleBeeMetadata,
final ArchiveReader.Cache cache) {
final var out = output == null || UNSET.equals(output) ? null : Path.of(output);
final var out = output == null || UNSET.equals(output) || "stdout".equals(output) ? null : Path.of(output);
final var jsonReaderFactory = provider.createReaderFactory(Map.of());
final var jsonWriterFactory = provider.createWriterFactory(Map.of(JsonGenerator.PRETTY_PRINTING, true));
final var collector = new ArrayList<String>();
final BiConsumer<String, JsonObject> onDescriptor = out == null ?
(name, content) -> log.info(() -> name + ":\n" + format(content, jsonReaderFactory, jsonWriterFactory)) :
("stdout".equals(output) ?
(name, content) -> System.out.println(content) :
(name, content) -> log.info(() -> name + ":\n" + format(content, jsonReaderFactory, jsonWriterFactory))) :
(name, content) -> {
final var formatted = format(content, jsonReaderFactory, jsonWriterFactory);
if (concat) {
Expand Down Expand Up @@ -191,7 +193,7 @@ public CompletionStage<?> doExecute(final String from, final String manifest, fi
if (out.getParent() != null) {
Files.createDirectories(out.getParent());
}
Files.writeString(out, String .join("\n---\n", collector));
Files.writeString(out, String.join("\n---\n", collector));
} catch (final IOException ioe) {
throw new IllegalStateException(ioe);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#! /bin/sh

java -Dio.yupiik.bundlebee.level=WARNING -jar \
/opt/yupiik/bundlebee/lib/bundlebee.jar placeholder-extract \
--outputType ARGOCD \
--bundlebee-kube-namespace "${ARGOCD_APP_NAMESPACE}" \
--from "$ARGOCD_APP_SOURCE_PATH" --manifest "${ARGOCD_APP_SOURCE_PATH}/bundlebee/manifest.json" --alveolus "$ARGOCD_APP_NAME"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#! /bin/sh

java -Dio.yupiik.bundlebee.level=WARNING -jar \
/opt/yupiik/bundlebee/lib/bundlebee.jar process \
--injectTimestamp false --injectBundleBeeMetadata false \
--output stdout \
--bundlebee-kube-namespace "${ARGOCD_APP_NAMESPACE}" \
--from "$ARGOCD_APP_SOURCE_PATH" --manifest "${ARGOCD_APP_SOURCE_PATH}/bundlebee/manifest.json" --alveolus "$ARGOCD_APP_NAME"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: argoproj.io/v1alpha1
kind: ConfigManagementPlugin
metadata:
name: bundlebee-plugin
spec:
version: v1.0
init:
# if you use any kind of secret management, it can be neat to run a command there to decipher the secrets and prepare generate command
command: [sh]
args: [-c, 'echo "BundleBee plugin"']
generate:
command: [ "/opt/yupiik/bundlebee/bin/bundlebee.sh" ]
discover:
find:
glob: "**/bundlebee/manifest.json"
parameters:
dynamic:
command: [ "/opt/yupiik/bundlebee/bin/bundlebee.placeholders.sh" ]
preserveFileMode: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM ossyupiik/java:17.0.9.1
RUN mkdir -p /opt/yupiik/bundlebee/lib /opt/yupiik/bundlebee/bin && \
wget https://repo.maven.apache.org/maven2/io/yupiik/bundlebee-core/1.0.24/bundlebee-core-1.0.24-fat.jar -O /opt/yupiik/bundlebee/lib/bundlebee.jar <1>
COPY ./bundlebee.argocd-plugin.yaml /home/argocd/cmp-server/config/plugin.yaml <2>
COPY ./bundlebee.plugin.sh /opt/yupiik/bundlebee/bin/bundlebee.sh
RUN chmod +x /opt/yupiik/bundlebee/bin/*.sh && chown 999:0 -R /opt/yupiik/
USER 999
ENTRYPOINT ["/opt/yupiik/bundlebee/bin/bundlebee.sh"]

0 comments on commit 3248a2c

Please sign in to comment.