Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6.8.x #994

Merged
merged 20 commits into from
Nov 8, 2024
Merged

6.8.x #994

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ce04d19
fix: inherit secrets needed when calling Quarkiverse workflow (#989)
gastaldi Oct 31, 2024
fde498d
refactor: start encapsulating access to CRD information
metacosm Oct 31, 2024
8b3e8c3
refactor: rename more appropriately
metacosm Oct 31, 2024
5994526
refactor: remove unused methods
metacosm Oct 31, 2024
83e3020
refactor: simplify by removing seemingly unneeded versions in CRDInfo
metacosm Oct 31, 2024
a0fb629
wip: add config option and initial processing
metacosm Oct 31, 2024
bbd0f88
refactor: encapsulate CRD name to info computing, rename getCRDInfosFor
metacosm Nov 4, 2024
d7ab60b
refactor: inject configuration in build step directly
metacosm Nov 4, 2024
abd9834
fix: sort owned and required CRDs in CSV
metacosm Nov 4, 2024
3e7a46a
feat: allow loading external CRDs from specified locations
metacosm Nov 4, 2024
d3b146e
feat: load external CRDs in parallel
metacosm Nov 5, 2024
9421498
chore(tests): check warnings are properly logged
metacosm Nov 5, 2024
c5b9820
fix: format messages before checking content
metacosm Nov 5, 2024
50f3c00
refactor: minor improvements
metacosm Nov 5, 2024
3519efd
fix: make properly recordable
metacosm Nov 5, 2024
b1a4289
refactor: move external CRD configuration to main CRD configuration
metacosm Nov 7, 2024
476d5a2
refactor: load external CRDs from CRD generation step
metacosm Nov 7, 2024
7fde0a1
refactor: simplify add method
metacosm Nov 7, 2024
ec03349
feat: only process CRs that are not excluded
metacosm Nov 7, 2024
10bc9cc
fix: clarify when id or full resource name is needed
metacosm Nov 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ defaults:
jobs:
release-snapshot:
uses: ./.github/workflows/release-snapshot.yml
secrets: inherit
secrets: inherit
with:
branch: "${{github.ref}}"
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
import io.quarkiverse.operatorsdk.bundle.runtime.CSVMetadataHolder;
import io.quarkiverse.operatorsdk.common.ReconcilerAugmentedClassInfo;
import io.quarkiverse.operatorsdk.runtime.BuildTimeOperatorConfiguration;
import io.quarkiverse.operatorsdk.runtime.CRDGenerationInfo;
import io.quarkiverse.operatorsdk.runtime.CRDInfo;
import io.quarkiverse.operatorsdk.runtime.CRDInfos;
import io.quarkiverse.operatorsdk.runtime.Version;
import io.quarkus.container.util.PathsUtil;

Expand Down Expand Up @@ -48,31 +50,37 @@ private BundleGenerator() {

public static List<ManifestsBuilder> prepareGeneration(BundleGenerationConfiguration bundleConfiguration,
BuildTimeOperatorConfiguration operatorConfiguration, Version version,
Map<CSVMetadataHolder, List<ReconcilerAugmentedClassInfo>> csvGroups, Map<String, CRDInfo> crds,
Path outputDirectory, String deploymentName) {
Map<CSVMetadataHolder, List<ReconcilerAugmentedClassInfo>> csvGroups, CRDGenerationInfo crds,
CRDInfos unownedCRDs, Path outputDirectory, String deploymentName) {
List<ManifestsBuilder> builders = new ArrayList<>();
final var mainSourcesRoot = PathsUtil.findMainSourcesRoot(outputDirectory);
final var crdNameToInfoMappings = crds.getCrds().getCRDNameToInfoMappings();

for (Map.Entry<CSVMetadataHolder, List<ReconcilerAugmentedClassInfo>> entry : csvGroups.entrySet()) {
final var csvMetadata = entry.getKey();
final var labels = generateBundleLabels(csvMetadata, bundleConfiguration, version);

final var mainSourcesRoot = PathsUtil.findMainSourcesRoot(outputDirectory);
final var csvBuilder = new CsvManifestsBuilder(csvMetadata, operatorConfiguration, entry.getValue(),
mainSourcesRoot != null ? mainSourcesRoot.getKey() : null, deploymentName);
builders.add(csvBuilder);
builders.add(new AnnotationsManifestsBuilder(csvMetadata, labels));
builders.add(new BundleDockerfileManifestsBuilder(csvMetadata, labels));

// output owned CRDs in the manifest, fail if we're missing some
var missing = addCRDManifestBuilder(crds, builders, csvMetadata, csvBuilder.getOwnedCRs());
var missing = addCRDManifestBuilder(crdNameToInfoMappings, builders, csvMetadata, csvBuilder.getOwnedCRs());
if (!missing.isEmpty()) {
throw new IllegalStateException(
"Missing owned CRD data for resources: " + missing + " for bundle: " + csvMetadata.bundleName);
}
// output required CRDs in the manifest, output a warning in case we're missing some
missing = addCRDManifestBuilder(crds, builders, csvMetadata, csvBuilder.getRequiredCRs());
missing = addCRDManifestBuilder(crdNameToInfoMappings, builders, csvMetadata, csvBuilder.getRequiredCRs());
if (!missing.isEmpty()) {
log.warnv("Missing required CRD data for resources: {0} for bundle: {1}", missing, csvMetadata.bundleName);
}

// output non-generated CRDs
unownedCRDs.getCRDNameToInfoMappings().values()
.forEach(info -> builders.add(new CustomResourceManifestsBuilder(csvMetadata, info)));
}

return builders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
Expand All @@ -32,11 +30,15 @@
import io.quarkiverse.operatorsdk.bundle.runtime.BundleConfiguration;
import io.quarkiverse.operatorsdk.bundle.runtime.BundleGenerationConfiguration;
import io.quarkiverse.operatorsdk.bundle.runtime.CSVMetadataHolder;
import io.quarkiverse.operatorsdk.common.*;
import io.quarkiverse.operatorsdk.common.ClassUtils;
import io.quarkiverse.operatorsdk.common.ConfigurationUtils;
import io.quarkiverse.operatorsdk.common.DeserializedKubernetesResourcesBuildItem;
import io.quarkiverse.operatorsdk.common.ReconciledAugmentedClassInfo;
import io.quarkiverse.operatorsdk.common.ReconcilerAugmentedClassInfo;
import io.quarkiverse.operatorsdk.deployment.GeneratedCRDInfoBuildItem;
import io.quarkiverse.operatorsdk.deployment.UnownedCRDInfoBuildItem;
import io.quarkiverse.operatorsdk.deployment.VersionBuildItem;
import io.quarkiverse.operatorsdk.runtime.BuildTimeOperatorConfiguration;
import io.quarkiverse.operatorsdk.runtime.CRDInfo;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.ApplicationInfoBuildItem;
Expand All @@ -49,21 +51,60 @@

public class BundleProcessor {

public static final String CRD_DISPLAY_NAME = "CRD_DISPLAY_NAME";
public static final String CRD_DESCRIPTION = "CRD_DESCRIPTION";
private static final Logger log = Logger.getLogger(BundleProcessor.class);
private static final DotName SHARED_CSV_METADATA = DotName.createSimple(SharedCSVMetadata.class.getName());
private static final DotName CSV_METADATA = DotName.createSimple(CSVMetadata.class.getName());
private static final String BUNDLE = "bundle";
private static final String DEFAULT_PROVIDER_NAME = System.getProperty("user.name");
public static final String CRD_DISPLAY_NAME = "CRD_DISPLAY_NAME";
public static final String CRD_DESCRIPTION = "CRD_DESCRIPTION";

private static class IsGenerationEnabled implements BooleanSupplier {
private static ReconcilerAugmentedClassInfo augmentReconcilerInfo(
ReconcilerAugmentedClassInfo reconcilerInfo) {
// if primary resource is a CR, check if it is annotated with CSVMetadata and augment it if it is
final ReconciledAugmentedClassInfo<?> primaryCI = reconcilerInfo.associatedResourceInfo();
augmentResourceInfoIfCR(primaryCI);

private BundleGenerationConfiguration config;
reconcilerInfo.getDependentResourceInfos().forEach(draci -> {
// if the dependent is a CR, check if it is annotated with CSVMetadata and augment it if it is
final ReconciledAugmentedClassInfo<?> reconciledAugmentedClassInfo = draci.associatedResourceInfo();
augmentResourceInfoIfCR(reconciledAugmentedClassInfo);
});
return reconcilerInfo;
}

@Override
public boolean getAsBoolean() {
return config.enabled();
private static void augmentResourceInfoIfCR(ReconciledAugmentedClassInfo<?> reconciledAugmentedClassInfo) {
if (reconciledAugmentedClassInfo.isCR()) {
final var csvMetadata = reconciledAugmentedClassInfo.classInfo().annotation(CSV_METADATA);
if (csvMetadata != null) {
// extract display name and description
final var displayName = ConfigurationUtils.annotationValueOrDefault(csvMetadata,
"displayName", AnnotationValue::asString,
() -> reconciledAugmentedClassInfo.asResourceTargeting().kind());
reconciledAugmentedClassInfo.setExtendedInfo(CRD_DISPLAY_NAME, displayName);
final var description = ConfigurationUtils.annotationValueOrDefault(
csvMetadata,
"description", AnnotationValue::asString,
() -> null);
if (description != null) {
reconciledAugmentedClassInfo.setExtendedInfo(CRD_DESCRIPTION, description);
}
}
}
}

private static String getBundleName(AnnotationInstance csvMetadata, String defaultName) {
if (csvMetadata == null) {
return defaultName;
} else {
final var bundleName = csvMetadata.value("bundleName");
if (bundleName != null) {
return bundleName.asString();
} else {
return Optional.ofNullable(csvMetadata.value("name"))
.map(AnnotationValue::asString)
.orElse(defaultName);
}
}
}

Expand Down Expand Up @@ -150,40 +191,6 @@ CSVMetadataBuildItem gatherCSVMetadata(KubernetesConfig kubernetesConfig,
return new CSVMetadataBuildItem(csvGroups);
}

private static ReconcilerAugmentedClassInfo augmentReconcilerInfo(
ReconcilerAugmentedClassInfo reconcilerInfo) {
// if primary resource is a CR, check if it is annotated with CSVMetadata and augment it if it is
final ReconciledAugmentedClassInfo<?> primaryCI = reconcilerInfo.associatedResourceInfo();
augmentResourceInfoIfCR(primaryCI);

reconcilerInfo.getDependentResourceInfos().forEach(draci -> {
// if the dependent is a CR, check if it is annotated with CSVMetadata and augment it if it is
final ReconciledAugmentedClassInfo<?> reconciledAugmentedClassInfo = draci.associatedResourceInfo();
augmentResourceInfoIfCR(reconciledAugmentedClassInfo);
});
return reconcilerInfo;
}

private static void augmentResourceInfoIfCR(ReconciledAugmentedClassInfo<?> reconciledAugmentedClassInfo) {
if (reconciledAugmentedClassInfo.isCR()) {
final var csvMetadata = reconciledAugmentedClassInfo.classInfo().annotation(CSV_METADATA);
if (csvMetadata != null) {
// extract display name and description
final var displayName = ConfigurationUtils.annotationValueOrDefault(csvMetadata,
"displayName", AnnotationValue::asString,
() -> reconciledAugmentedClassInfo.asResourceTargeting().kind());
reconciledAugmentedClassInfo.setExtendedInfo(CRD_DISPLAY_NAME, displayName);
final var description = ConfigurationUtils.annotationValueOrDefault(
csvMetadata,
"description", AnnotationValue::asString,
() -> null);
if (description != null) {
reconciledAugmentedClassInfo.setExtendedInfo(CRD_DESCRIPTION, description);
}
}
}
}

private String getMetadataOriginInformation(AnnotationInstance csvMetadataAnnotation, boolean isNameInferred,
CSVMetadataHolder metadataHolder) {
final var isDefault = csvMetadataAnnotation == null;
Expand All @@ -204,15 +211,12 @@ void generateBundle(ApplicationInfoBuildItem configuration,
BuildTimeOperatorConfiguration operatorConfiguration,
OutputTargetBuildItem outputTarget,
CSVMetadataBuildItem csvMetadata,
UnownedCRDInfoBuildItem unownedCRDs,
VersionBuildItem versionBuildItem,
BuildProducer<GeneratedBundleBuildItem> doneGeneratingCSV,
GeneratedCRDInfoBuildItem generatedCustomResourcesDefinitions,
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<DeserializedKubernetesResourcesBuildItem> maybeGeneratedKubeResources,
BuildProducer<GeneratedFileSystemResourceBuildItem> generatedCSVs) {
final var crds = generatedCustomResourcesDefinitions.getCRDGenerationInfo().getCrds()
.values().stream()
.flatMap(entry -> entry.values().stream())
.collect(Collectors.toMap(CRDInfo::getCrdName, Function.identity()));
final var outputDir = outputTarget.getOutputDirectory().resolve(BUNDLE);
final var serviceAccounts = new LinkedList<ServiceAccount>();
final var clusterRoleBindings = new LinkedList<ClusterRoleBinding>();
Expand Down Expand Up @@ -258,22 +262,25 @@ void generateBundle(ApplicationInfoBuildItem configuration,
final var deploymentName = ResourceNameUtil.getResourceName(kubernetesConfig, configuration);
final var generated = BundleGenerator.prepareGeneration(bundleConfiguration, operatorConfiguration,
versionBuildItem.getVersion(),
csvMetadata.getCsvGroups(), crds, outputTarget.getOutputDirectory(), deploymentName);
csvMetadata.getCsvGroups(), generatedCustomResourcesDefinitions.getCRDGenerationInfo(),
unownedCRDs.getCRDs(),
outputTarget.getOutputDirectory(), deploymentName);
generated.forEach(manifestBuilder -> {
final var fileName = manifestBuilder.getFileName();
final var name = manifestBuilder.getName();
try {
generatedCSVs.produce(
new GeneratedFileSystemResourceBuildItem(
Path.of(BUNDLE).resolve(manifestBuilder.getName()).resolve(fileName).toString(),
Path.of(BUNDLE).resolve(name).resolve(fileName).toString(),
manifestBuilder.getManifestData(serviceAccounts, clusterRoleBindings, clusterRoles,
roleBindings, roles, deployments)));
log.infov("Generating {0} for ''{1}'' controller -> {2}",
log.infov("Processing {0} for ''{1}'' controller -> {2}",
manifestBuilder.getManifestType(),
manifestBuilder.getName(),
outputDir.resolve(manifestBuilder.getName()).resolve(fileName));
name,
outputDir.resolve(name).resolve(fileName));
} catch (IOException e) {
log.errorv("Cannot generate {0} for ''{1}'' controller: {2}",
manifestBuilder.getManifestType(), manifestBuilder.getName(), e.getMessage());
log.errorv("Cannot process {0} for ''{1}'' controller: {2}",
manifestBuilder.getManifestType(), name, e.getMessage());
}
});
doneGeneratingCSV.produce(new GeneratedBundleBuildItem());
Expand Down Expand Up @@ -302,21 +309,6 @@ private Map<String, CSVMetadataHolder> getSharedMetadataHolders(String name, Str
return result;
}

private static String getBundleName(AnnotationInstance csvMetadata, String defaultName) {
if (csvMetadata == null) {
return defaultName;
} else {
final var bundleName = csvMetadata.value("bundleName");
if (bundleName != null) {
return bundleName.asString();
} else {
return Optional.ofNullable(csvMetadata.value("name"))
.map(AnnotationValue::asString)
.orElse(defaultName);
}
}
}

private CSVMetadataHolder createMetadataHolder(AnnotationInstance csvMetadata, CSVMetadataHolder mh,
BundleConfiguration bundleConfig, String origin) {
if (csvMetadata == null) {
Expand Down Expand Up @@ -503,4 +495,14 @@ private CSVMetadataHolder createMetadataHolder(AnnotationInstance csvMetadata, C
requiredCRDs,
origin);
}

private static class IsGenerationEnabled implements BooleanSupplier {

private BundleGenerationConfiguration config;

@Override
public boolean getAsBoolean() {
return config.enabled();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public class CsvManifestsBuilder extends ManifestsBuilder {
private static final Logger LOGGER = Logger.getLogger(CsvManifestsBuilder.class.getName());
private static final String IMAGE_PNG = "image/png";
public static final String OLM_TARGET_NAMESPACES = "metadata.annotations['olm.targetNamespaces']";
private static final Comparator<String> nullsFirst = Comparator.nullsFirst(String::compareTo);
private static final Comparator<GroupVersionKind> gvkComparator = comparing(GroupVersionKind::getGroup, nullsFirst)
.thenComparing(GroupVersionKind::getKind, nullsFirst)
.thenComparing(GroupVersionKind::getVersion, nullsFirst);
private static final Comparator<CRDDescription> crdDescriptionComparator = comparing(CRDDescription::getName, nullsFirst);
private ClusterServiceVersionBuilder csvBuilder;
private final Set<CRDDescription> ownedCRs = new HashSet<>();
private final Set<CRDDescription> requiredCRs = new HashSet<>();
Expand Down Expand Up @@ -225,17 +230,14 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, BuildTimeOperatorConfigur
}

// add sorted native APIs
final var nullsFirst = Comparator.nullsFirst(String::compareTo);
csvSpecBuilder.addAllToNativeAPIs(nativeApis.stream()
.distinct()
.sorted(comparing(GroupVersionKind::getGroup, nullsFirst)
.thenComparing(comparing(GroupVersionKind::getKind, nullsFirst))
.thenComparing(comparing(GroupVersionKind::getVersion, nullsFirst)))
.sorted(gvkComparator)
.toList());

csvSpecBuilder.editOrNewCustomresourcedefinitions()
.addAllToOwned(ownedCRs)
.addAllToRequired(requiredCRs)
.addAllToOwned(ownedCRs.stream().sorted(crdDescriptionComparator).toList())
.addAllToRequired(requiredCRs.stream().sorted(crdDescriptionComparator).toList())
.endCustomresourcedefinitions()
.endSpec();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: externals.halkyon.io
spec:
conversion:
strategy: None
group: halkyon.io
names:
kind: External
listKind: ExternalList
plural: externals
singular: external
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
properties:
spec:
type: object
status:
type: object
type: object
served: true
storage: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Fabric8 CRDGenerator, manual edits might get overwritten!
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: v1beta1s.test.com
spec:
group: test.com
names:
kind: V1Beta1
plural: v1beta1s
singular: v1beta1
scope: Namespaced
subresources:
status: { }
validation:
openAPIV3Schema:
properties:
spec:
properties:
value:
type: string
type: object
type: object
versions:
- name: v1
served: true
storage: true
Loading