diff --git a/src/main/java/org/openrewrite/kubernetes/KubernetesParser.java b/src/main/java/org/openrewrite/kubernetes/KubernetesParser.java
index 1269428..2dfdbb6 100644
--- a/src/main/java/org/openrewrite/kubernetes/KubernetesParser.java
+++ b/src/main/java/org/openrewrite/kubernetes/KubernetesParser.java
@@ -25,11 +25,12 @@
import java.util.regex.Pattern;
import java.util.stream.Stream;
+/**
+ * @deprecated Unused; likely better served by {@link org.openrewrite.kubernetes.trait.Traits}.
+ */
+@Deprecated
public final class KubernetesParser extends YamlParser {
- private static final Pattern METADATA_LABEL = Pattern.compile("/metadata/labels/(.+)");
- private static final Pattern METADATA_ANNOTATION = Pattern.compile("/metadata/annotations/(.+)");
-
public static Builder builder() {
return new Builder();
}
diff --git a/src/main/java/org/openrewrite/kubernetes/KubernetesVisitor.java b/src/main/java/org/openrewrite/kubernetes/KubernetesVisitor.java
index af10a9e..4274b3e 100644
--- a/src/main/java/org/openrewrite/kubernetes/KubernetesVisitor.java
+++ b/src/main/java/org/openrewrite/kubernetes/KubernetesVisitor.java
@@ -21,6 +21,10 @@
import org.openrewrite.yaml.YamlVisitor;
import org.openrewrite.yaml.tree.Yaml;
+/**
+ * @deprecated Likely better served by {@link org.openrewrite.kubernetes.trait.Traits}.
+ */
+@Deprecated
public class KubernetesVisitor
extends YamlVisitor
{
@Override
diff --git a/src/main/java/org/openrewrite/kubernetes/UpdateKubernetesModel.java b/src/main/java/org/openrewrite/kubernetes/UpdateKubernetesModel.java
index e9e71db..aa94825 100644
--- a/src/main/java/org/openrewrite/kubernetes/UpdateKubernetesModel.java
+++ b/src/main/java/org/openrewrite/kubernetes/UpdateKubernetesModel.java
@@ -33,27 +33,26 @@ public class UpdateKubernetesModel
extends YamlIsoVisitor
{
public Yaml.Document visitDocument(Yaml.Document document, P p) {
Yaml.Document d = super.visitDocument(document, p);
- KubernetesModel resource = new KubernetesModel(
- randomId(),
- getCursor().getMessage("apiVersion"),
- getCursor().getMessage("kind"),
- new KubernetesModel.Metadata(
- getCursor().getMessage("namespace"),
- getCursor().getMessage("name"),
- getCursor().getMessage("annotations"),
- getCursor().getMessage("labels")
- )
- );
- if (resource.getApiVersion() != null && resource.getKind() != null) {
- return d.withMarkers(document.getMarkers().addIfAbsent(resource));
- } else {
- return d;
+ if (getCursor().getMessage("apiVersion") != null &&
+ getCursor().getMessage("kind") != null) {
+ KubernetesModel kubernetesModel = new KubernetesModel(
+ randomId(),
+ getCursor().getMessage("apiVersion"),
+ getCursor().getMessage("kind"),
+ new KubernetesModel.Metadata(
+ getCursor().getMessage("namespace"),
+ getCursor().getMessage("name"),
+ getCursor().getMessage("annotations"),
+ getCursor().getMessage("labels")
+ ));
+ return d.withMarkers(document.getMarkers().addIfAbsent(kubernetesModel));
}
+
+ return d;
}
@Override
public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, P p) {
-
String path = getPath();
if (entry.getValue() instanceof Yaml.Scalar) {
diff --git a/src/main/java/org/openrewrite/kubernetes/search/FindResourceMissingConfiguration.java b/src/main/java/org/openrewrite/kubernetes/search/FindResourceMissingConfiguration.java
index 82649d6..8be9ab9 100644
--- a/src/main/java/org/openrewrite/kubernetes/search/FindResourceMissingConfiguration.java
+++ b/src/main/java/org/openrewrite/kubernetes/search/FindResourceMissingConfiguration.java
@@ -19,11 +19,17 @@
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
-import org.openrewrite.kubernetes.tree.K8S;
+import org.openrewrite.kubernetes.trait.KubernetesResource;
+import org.openrewrite.kubernetes.trait.Traits;
import org.openrewrite.marker.SearchResult;
+import org.openrewrite.yaml.JsonPathMatcher;
import org.openrewrite.yaml.YamlIsoVisitor;
import org.openrewrite.yaml.tree.Yaml;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.util.Objects.requireNonNull;
+
@Value
@EqualsAndHashCode(callSuper = false)
public class FindResourceMissingConfiguration extends Recipe {
@@ -57,29 +63,26 @@ public String getDescription() {
return "Find Kubernetes resources with missing configuration.";
}
-
@Override
public TreeVisitor, ExecutionContext> getVisitor() {
- YamlIsoVisitor visitor = new YamlIsoVisitor() {
- @Override
- public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) {
- Yaml.Block b = (Yaml.Block) visit(document.getBlock(), ctx, getCursor());
- boolean inKind = resourceKind == null || K8S.inKind(resourceKind, getCursor());
- if (inKind && !"true".equals(getCursor().getMessage(FindResourceMissingConfiguration.class.getSimpleName()))) {
- return SearchResult.found(document.withBlock(b));
- }
- return document;
- }
+ TreeVisitor extends Tree, ExecutionContext> kubernetesResourceVisitor = Traits.kubernetesResource(resourceKind)
+ .asVisitor((KubernetesResource resource, ExecutionContext ctx) -> {
+ AtomicBoolean pathFound = new AtomicBoolean(false);
+ new YamlIsoVisitor() {
+ @Override
+ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, AtomicBoolean bool) {
+ if (new JsonPathMatcher(configurationPath).matches(getCursor())) {
+ bool.set(true);
+ }
+ return bool.get() ? entry : super.visitMappingEntry(entry, bool);
+ }
+ }.visitNonNull(resource.getTree(), pathFound, requireNonNull(resource.getCursor().getParent()));
+ return pathFound.get() ? resource.getTree() : SearchResult.found(resource.getTree());
+ });
- @Override
- public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionContext ctx) {
- if (K8S.firstEnclosingEntryMatching(configurationPath, getCursor()).isPresent()) {
- getCursor().putMessageOnFirstEnclosing(Yaml.Document.class,
- FindResourceMissingConfiguration.class.getSimpleName(), "true");
- }
- return super.visitMappingEntry(entry, ctx);
- }
- };
- return fileMatcher != null ? Preconditions.check(new FindSourceFiles(fileMatcher), visitor) : visitor;
+ if (fileMatcher != null) {
+ return Preconditions.check(new FindSourceFiles(fileMatcher), kubernetesResourceVisitor);
+ }
+ return kubernetesResourceVisitor;
}
}
diff --git a/src/main/java/org/openrewrite/kubernetes/trait/KubernetesResource.java b/src/main/java/org/openrewrite/kubernetes/trait/KubernetesResource.java
new file mode 100644
index 0000000..7d9ab8d
--- /dev/null
+++ b/src/main/java/org/openrewrite/kubernetes/trait/KubernetesResource.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.kubernetes.trait;
+
+import lombok.EqualsAndHashCode;
+import lombok.Value;
+import org.openrewrite.Cursor;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.InMemoryExecutionContext;
+import org.openrewrite.internal.lang.Nullable;
+import org.openrewrite.kubernetes.UpdateKubernetesModel;
+import org.openrewrite.kubernetes.tree.KubernetesModel;
+import org.openrewrite.trait.SimpleTraitMatcher;
+import org.openrewrite.trait.Trait;
+import org.openrewrite.yaml.tree.Yaml;
+
+@Value
+public class KubernetesResource implements Trait {
+
+ Cursor cursor;
+ KubernetesModel model;
+
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ public static class Matcher extends SimpleTraitMatcher {
+
+ @Nullable
+ String kind;
+
+ @Override
+ protected @Nullable KubernetesResource test(Cursor cursor) {
+ Object value = cursor.getValue();
+ if (value instanceof Yaml.Document) {
+ return new UpdateKubernetesModel()
+ .visitNonNull((Yaml.Document) value, new InMemoryExecutionContext(), cursor.getParent())
+ .getMarkers()
+ .findFirst(KubernetesModel.class)
+ .filter(model -> kind == null || kind.equals(model.getKind()))
+ .map(kubernetesModel -> new KubernetesResource(cursor, kubernetesModel))
+ .orElse(null);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/org/openrewrite/kubernetes/trait/Traits.java b/src/main/java/org/openrewrite/kubernetes/trait/Traits.java
new file mode 100644
index 0000000..f31705b
--- /dev/null
+++ b/src/main/java/org/openrewrite/kubernetes/trait/Traits.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.kubernetes.trait;
+
+import org.openrewrite.internal.lang.Nullable;
+
+public class Traits {
+
+ private Traits() {
+ }
+
+ public static KubernetesResource.Matcher kubernetesResource(@Nullable String kind) {
+ return new KubernetesResource.Matcher(kind);
+ }
+}
diff --git a/src/main/java/org/openrewrite/kubernetes/tree/K8S.java b/src/main/java/org/openrewrite/kubernetes/tree/K8S.java
index dd3370d..0001b30 100644
--- a/src/main/java/org/openrewrite/kubernetes/tree/K8S.java
+++ b/src/main/java/org/openrewrite/kubernetes/tree/K8S.java
@@ -22,10 +22,8 @@
import lombok.With;
import lombok.experimental.FieldDefaults;
import org.openrewrite.Cursor;
-import org.openrewrite.Tree;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.kubernetes.resource.ResourceLimit;
-import org.openrewrite.marker.Marker;
import org.openrewrite.yaml.JsonPathMatcher;
import org.openrewrite.yaml.tree.Yaml;
@@ -35,8 +33,11 @@
import static java.util.Collections.emptySet;
import static org.openrewrite.Tree.randomId;
-public interface K8S extends Marker {
-
+/**
+ * @deprecated Likely better served by {@link org.openrewrite.kubernetes.trait.Traits}.
+ */
+@Deprecated
+public interface K8S {
static boolean inKind(String kind, Cursor cursor) {
Yaml.Document doc = cursor.firstEnclosing(Yaml.Document.class);
@@ -210,7 +211,7 @@ static Optional firstEnclosingEntryMatching(JsonPathMatcher jsonPath, @N
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Resource implements K8S {
@EqualsAndHashCode.Include
@@ -222,7 +223,7 @@ class Resource implements K8S {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Metadata implements K8S {
@EqualsAndHashCode.Include
@@ -248,7 +249,7 @@ public static boolean isMetadata(Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Annotations implements K8S {
@EqualsAndHashCode.Include
@@ -282,7 +283,7 @@ public boolean valueMatches(String name, Pattern regex, Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Labels implements K8S {
@EqualsAndHashCode.Include
@@ -312,7 +313,7 @@ public boolean valueMatches(String name, Pattern regex, Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Pod implements K8S {
@EqualsAndHashCode.Include
@@ -326,7 +327,7 @@ public static boolean inSpec(Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Containers implements K8S {
@EqualsAndHashCode.Include
@@ -343,7 +344,7 @@ public static boolean isImageName(Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class InitContainers implements K8S {
@EqualsAndHashCode.Include
@@ -356,7 +357,7 @@ public static boolean inInitContainerSpec(Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class ResourceLimits implements K8S {
@EqualsAndHashCode.Include
@@ -380,7 +381,7 @@ public static boolean inRequests(String type, Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Service implements K8S {
@EqualsAndHashCode.Include
@@ -406,7 +407,7 @@ public static boolean inExternalIPs(Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class Ingress implements K8S {
@EqualsAndHashCode.Include
@@ -434,7 +435,7 @@ public static boolean isDisallowHttpConfigured(Cursor cursor) {
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
- @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = false)
+ @EqualsAndHashCode(callSuper = false)
@Data
class RBAC implements K8S {
@EqualsAndHashCode.Include
diff --git a/src/test/java/org/openrewrite/kubernetes/search/FindResourceMissingConfigurationTest.java b/src/test/java/org/openrewrite/kubernetes/search/FindResourceMissingConfigurationTest.java
index d44a1c1..65d9061 100644
--- a/src/test/java/org/openrewrite/kubernetes/search/FindResourceMissingConfigurationTest.java
+++ b/src/test/java/org/openrewrite/kubernetes/search/FindResourceMissingConfigurationTest.java
@@ -17,6 +17,7 @@
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
+import org.openrewrite.Issue;
import org.openrewrite.config.Environment;
import org.openrewrite.kubernetes.KubernetesRecipeTest;
@@ -33,6 +34,7 @@ void podLivenessProbe() {
"$.spec.containers[*].livenessProbe",
null
)),
+ //language=yaml
yaml(
"""
apiVersion: v1
@@ -54,6 +56,31 @@ void podLivenessProbe() {
);
}
+ @Test
+ void noChangeIfPresent() {
+ rewriteRun(
+ spec -> spec.recipe(new FindResourceMissingConfiguration(
+ "Pod",
+ "$.spec.containers[*].livenessProbe",
+ null
+ )),
+ //language=yaml
+ yaml(
+ """
+ apiVersion: v1
+ kind: Pod
+ spec:
+ containers:
+ - name:
+ image:
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ """
+ )
+ );
+ }
+
@Test
void correctlyConfiguredPodLivenessProbe() {
rewriteRun(
@@ -62,6 +89,7 @@ void correctlyConfiguredPodLivenessProbe() {
"$.spec.containers[*].livenessProbe",
null
)),
+ //language=yaml
yaml(
"""
apiVersion: v1
@@ -91,6 +119,7 @@ void onlyMatchOnConfiguredResources() {
"..spec.containers[*].livenessProbe",
null
)),
+ //language=yaml
yaml(
"""
apiVersion: apps/v1
@@ -117,10 +146,8 @@ void onlyMatchOnConfiguredResources() {
@Test
void missingPodLivenessProbe() {
rewriteRun(
- spec -> spec.recipe(Environment.builder()
- .scanRuntimeClasspath()
- .build()
- .activateRecipes("org.openrewrite.kubernetes.MissingPodLivenessProbe")),
+ spec -> spec.recipeFromResources("org.openrewrite.kubernetes.MissingPodLivenessProbe"),
+ //language=yaml
yaml(
"""
apiVersion: apps/v1
@@ -147,12 +174,10 @@ void missingPodLivenessProbe() {
}
@Test
- void missingCpuLimits() {
+ void cpuLimitsMissing() {
rewriteRun(
- spec -> spec.recipe(Environment.builder()
- .scanRuntimeClasspath()
- .build()
- .activateRecipes("org.openrewrite.kubernetes.MissingCpuLimits")),
+ spec -> spec.recipeFromResources("org.openrewrite.kubernetes.MissingCpuLimits"),
+ //language=yaml
yaml(
"""
apiVersion: apps/v1
@@ -181,4 +206,45 @@ void missingCpuLimits() {
)
);
}
+
+ @Test
+ void cpuLimitsPresent() {
+ rewriteRun(
+ spec -> spec.recipeFromResources("org.openrewrite.kubernetes.MissingCpuLimits"),
+ //language=yaml
+ yaml(
+ """
+ apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+ labels:
+ app: application
+ spec:
+ template:
+ spec:
+ containers:
+ - image: nginx:latest
+ resources:
+ limits:
+ cpu: "64Mi"
+ """
+ )
+ );
+ }
+
+ @Test
+ @Issue("https://github.com/openrewrite/rewrite-kubernetes/issues/51")
+ void springApplicationProperties() {
+ rewriteRun(
+ spec -> spec.recipeFromResources("org.openrewrite.kubernetes.MissingCpuLimits"),
+ //language=yaml
+ yaml(
+ """
+ spring:
+ application:
+ foo: hello
+ """
+ )
+ );
+ }
}