diff --git a/annotations/kind-annotations/pom.xml b/annotations/kind-annotations/pom.xml
index 2aa1b0213..1a1eb81d5 100644
--- a/annotations/kind-annotations/pom.xml
+++ b/annotations/kind-annotations/pom.xml
@@ -43,7 +43,12 @@ limitations under the License.
docker-annotations
${project.version}
-
+
+ io.dekorate
+ kubernetes-annotations
+ ${project.version}
+
+
io.sundr
builder-annotations
compile
@@ -60,7 +65,7 @@ limitations under the License.
sundr-codegen-velocity
compile
true
-
+
io.dekorate
dekorate-templates
@@ -115,7 +120,7 @@ limitations under the License.
-
+
org.apache.maven.plugins
maven-shade-plugin
${version.maven-shade-plugin}
@@ -138,7 +143,7 @@ limitations under the License.
*:*
- io/dekorate/kubernetes/annotation/**
+ io/dekorate/kind/annotation/**
META-INF/MANIFEST.MF
@@ -158,14 +163,14 @@ limitations under the License.
*:*
- io/dekorate/kubernetes/adapter/**
- io/dekorate/kubernetes/apt/**
- io/dekorate/kubernetes/config/**
- io/dekorate/kubernetes/configurator/**
- io/dekorate/kubernetes/decorator/**
- io/dekorate/kubernetes/manifest/**
- io/dekorate/kubernetes/hook/**
- io/dekorate/kubernetes/listener/**
+ io/dekorate/kind/adapter/**
+ io/dekorate/kind/apt/**
+ io/dekorate/kind/config/**
+ io/dekorate/kind/configurator/**
+ io/dekorate/kind/decorator/**
+ io/dekorate/kind/manifest/**
+ io/dekorate/kind/hook/**
+ io/dekorate/kind/listener/**
META-INF/services/*
META-INF/MANIFEST.MF
@@ -186,14 +191,14 @@ limitations under the License.
*:*
- io/dekorate/kubernetes/adapter/**
- io/dekorate/kubernetes/annotation/**
- io/dekorate/kubernetes/config/**
- io/dekorate/kubernetes/configurator/**
- io/dekorate/kubernetes/decorator/**
- io/dekorate/kubernetes/manifest/**
- io/dekorate/kubernetes/hook/**
- io/dekorate/kubernetes/listener/**
+ io/dekorate/kind/adapter/**
+ io/dekorate/kind/annotation/**
+ io/dekorate/kind/config/**
+ io/dekorate/kind/configurator/**
+ io/dekorate/kind/decorator/**
+ io/dekorate/kind/manifest/**
+ io/dekorate/kind/hook/**
+ io/dekorate/kind/listener/**
META-INF/services/io.dekorate.*
META-INF/MANIFEST.MF
@@ -203,6 +208,6 @@ limitations under the License.
-
+
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/annotation/Kind.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/annotation/Kind.java
index c96506e51..033464767 100644
--- a/annotations/kind-annotations/src/main/java/io/dekorate/kind/annotation/Kind.java
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/annotation/Kind.java
@@ -20,17 +20,37 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import io.dekorate.kubernetes.annotation.ImagePullPolicy;
+import io.dekorate.kubernetes.annotation.Port;
+import io.dekorate.kubernetes.annotation.ServiceType;
import io.dekorate.kubernetes.config.BaseConfig;
import io.sundr.builder.annotations.Adapter;
import io.sundr.builder.annotations.Buildable;
import io.sundr.builder.annotations.Pojo;
@Buildable(builderPackage = "io.fabric8.kubernetes.api.builder")
-@Pojo(name = "KindLoadConfig", relativePath = "../config", autobox = true, mutable = true, superClass = BaseConfig.class, withStaticBuilderMethod = true, withStaticAdapterMethod = false, adapter = @Adapter(name = "KindLoadConfigAdapter", relativePath = "../adapter", withMapAdapterMethod = true))
+@Pojo(name = "KindConfig", relativePath = "../config", autobox = true, mutable = true, superClass = BaseConfig.class, withStaticBuilderMethod = true, withStaticAdapterMethod = false, adapter = @Adapter(name = "KindConfigAdapter", relativePath = "../adapter", withMapAdapterMethod = true))
@Target({ ElementType.CONSTRUCTOR, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Kind {
boolean enabled() default true;
+ /**
+ * Image pull policy.
+ *
+ * @return The image pull policy.
+ */
+ ImagePullPolicy imagePullPolicy() default ImagePullPolicy.IfNotPresent;
+
+ /**
+ * The application ports.
+ */
+ Port[] ports() default {};
+
+ /**
+ * The type of service that will be generated for the application.
+ */
+ ServiceType serviceType() default ServiceType.NodePort;
+
}
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/apt/KindAnnotationProcessor.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/apt/KindAnnotationProcessor.java
index 400995190..b9bbcf8f5 100644
--- a/annotations/kind-annotations/src/main/java/io/dekorate/kind/apt/KindAnnotationProcessor.java
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/apt/KindAnnotationProcessor.java
@@ -15,6 +15,9 @@
*/
package io.dekorate.kind.apt;
+import static io.dekorate.kind.config.KindConfigGenerator.KIND;
+
+import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.RoundEnvironment;
@@ -22,29 +25,27 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
-import io.dekorate.Logger;
-import io.dekorate.LoggerFactory;
-import io.dekorate.doc.Description;
import io.dekorate.kind.annotation.Kind;
import io.dekorate.processor.AbstractAnnotationProcessor;
-@Description("Generates kubernetes manifests.")
@SupportedAnnotationTypes("io.dekorate.kind.annotation.Kind")
public class KindAnnotationProcessor extends AbstractAnnotationProcessor {
- private final Logger LOGGER = LoggerFactory.getLogger();
-
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
getSession().close();
return true;
}
+ Set mainClasses = new HashSet<>();
for (TypeElement typeElement : annotations) {
for (Element mainClass : roundEnv.getElementsAnnotatedWith(typeElement)) {
- LOGGER.info("Found @Kind on: " + mainClass.toString());
- process("kind", mainClass, Kind.class);
+ mainClasses.add(mainClass);
}
}
+
+ for (Element mainClass : mainClasses) {
+ process(KIND, mainClass, Kind.class);
+ }
return false;
}
}
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/DefaultKindConfigGenerator.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/DefaultKindConfigGenerator.java
index 83e6f38ef..8a9ff644c 100644
--- a/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/DefaultKindConfigGenerator.java
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/DefaultKindConfigGenerator.java
@@ -25,7 +25,7 @@ public class DefaultKindConfigGenerator implements KindConfigGenerator {
public DefaultKindConfigGenerator(ConfigurationRegistry configurationRegistry) {
this.configurationRegistry = configurationRegistry;
this.configurationRegistry.add(new ApplyKindImageAutoloadConfiguration());
- add(new DefaultConfiguration(KindLoadConfig.newKindLoadConfigBuilderFromDefaults()));
+ add(new DefaultConfiguration(KindConfig.newKindConfigBuilderFromDefaults()));
}
@Override
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/KindConfigGenerator.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/KindConfigGenerator.java
index d27051c0c..d1228590c 100644
--- a/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/KindConfigGenerator.java
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/config/KindConfigGenerator.java
@@ -22,7 +22,7 @@
import io.dekorate.config.AnnotationConfiguration;
import io.dekorate.config.ConfigurationSupplier;
import io.dekorate.config.PropertyConfiguration;
-import io.dekorate.kind.adapter.KindLoadConfigAdapter;
+import io.dekorate.kind.adapter.KindConfigAdapter;
import io.dekorate.kubernetes.config.Configuration;
public interface KindConfigGenerator extends ConfigurationGenerator, WithProject {
@@ -34,20 +34,20 @@ default String getKey() {
}
default Class extends Configuration> getConfigType() {
- return KindLoadConfig.class;
+ return KindConfig.class;
}
@Override
default void addAnnotationConfiguration(Map map) {
- add(new AnnotationConfiguration<>(KindLoadConfigAdapter.newBuilder(propertiesMap(map, KindLoadConfig.class))));
+ add(new AnnotationConfiguration<>(KindConfigAdapter.newBuilder(propertiesMap(map, KindConfig.class))));
}
@Override
default void addPropertyConfiguration(Map map) {
- add(new PropertyConfiguration<>(KindLoadConfigAdapter.newBuilder(propertiesMap(map, KindLoadConfig.class))));
+ add(new PropertyConfiguration<>(KindConfigAdapter.newBuilder(propertiesMap(map, KindConfig.class))));
}
- default void add(ConfigurationSupplier config) {
+ default void add(ConfigurationSupplier config) {
getConfigurationRegistry().add(config);
}
}
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/decorator/ApplyPortToKindServiceDecorator.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/decorator/ApplyPortToKindServiceDecorator.java
new file mode 100644
index 000000000..7dbc3ced1
--- /dev/null
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/decorator/ApplyPortToKindServiceDecorator.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2018 The original 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
+ *
+ * http://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 io.dekorate.kind.decorator;
+
+import io.dekorate.kubernetes.config.Port;
+import io.dekorate.kubernetes.decorator.NamedResourceDecorator;
+import io.dekorate.utils.Ports;
+import io.fabric8.kubernetes.api.model.ObjectMeta;
+import io.fabric8.kubernetes.api.model.ServicePortFluent;
+
+public class ApplyPortToKindServiceDecorator extends NamedResourceDecorator {
+
+ private final Port port;
+
+ public ApplyPortToKindServiceDecorator(String name, Port port) {
+ super(name);
+ this.port = port;
+ }
+
+ @Override
+ public void andThenVisit(ServicePortFluent servicePort, ObjectMeta resourceMeta) {
+ if (port.getNodePort() > 0) {
+ servicePort.withNodePort(port.getNodePort());
+ } else {
+ servicePort.withNodePort(Ports.calculateNodePort(getName(), port));
+ }
+ }
+
+}
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/decorator/ApplyServiceTypeToKindServiceDecorator.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/decorator/ApplyServiceTypeToKindServiceDecorator.java
new file mode 100644
index 000000000..2210ac9eb
--- /dev/null
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/decorator/ApplyServiceTypeToKindServiceDecorator.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2018 The original 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
+ *
+ * http://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 io.dekorate.kind.decorator;
+
+import io.dekorate.kind.config.KindConfig;
+import io.dekorate.kubernetes.decorator.NamedResourceDecorator;
+import io.fabric8.kubernetes.api.model.ObjectMeta;
+import io.fabric8.kubernetes.api.model.ServiceSpecFluent;
+
+public class ApplyServiceTypeToKindServiceDecorator extends NamedResourceDecorator {
+
+ private final KindConfig config;
+
+ public ApplyServiceTypeToKindServiceDecorator(String name, KindConfig config) {
+ super(name);
+ this.config = config;
+ }
+
+ @Override
+ public void andThenVisit(ServiceSpecFluent spec, ObjectMeta resourceMeta) {
+ spec.withType(config.getServiceType() != null ? config.getServiceType().name() : "NodePort");
+ }
+}
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/manifest/KindManifestGenerator.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/manifest/KindManifestGenerator.java
new file mode 100644
index 000000000..99cc2a626
--- /dev/null
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/manifest/KindManifestGenerator.java
@@ -0,0 +1,65 @@
+package io.dekorate.kind.manifest;
+
+import java.util.Arrays;
+
+import io.dekorate.ConfigurationRegistry;
+import io.dekorate.ResourceRegistry;
+import io.dekorate.kind.config.KindConfig;
+import io.dekorate.kind.decorator.ApplyPortToKindServiceDecorator;
+import io.dekorate.kind.decorator.ApplyServiceTypeToKindServiceDecorator;
+import io.dekorate.kubernetes.config.KubernetesConfig;
+import io.dekorate.kubernetes.decorator.AddServiceResourceDecorator;
+import io.dekorate.kubernetes.decorator.ApplyImagePullPolicyDecorator;
+import io.dekorate.kubernetes.manifest.KubernetesManifestGenerator;
+
+public class KindManifestGenerator extends KubernetesManifestGenerator {
+
+ private static final String KIND = "kind";
+
+ public KindManifestGenerator() {
+ this(new ResourceRegistry(), new ConfigurationRegistry());
+ }
+
+ public KindManifestGenerator(ResourceRegistry resourceRegistry, ConfigurationRegistry configurationRegistry) {
+ super(resourceRegistry, configurationRegistry);
+ }
+
+ @Override
+ public int order() {
+ return 400;
+ }
+
+ @Override
+ public String getKey() {
+ return KIND;
+ }
+
+ @Override
+ protected void addDecorators(String group, KubernetesConfig config) {
+ super.addDecorators(group, config);
+ if (config.getPorts().length > 0) {
+ resourceRegistry.decorate(group, new AddServiceResourceDecorator(config));
+ }
+ }
+
+ @Override
+ public void generate(KubernetesConfig kubernetesConfig) {
+ initializeRegistry(kubernetesConfig);
+ addDecorators(KIND, kubernetesConfig);
+
+ configurationRegistry.get(KindConfig.class).ifPresent(c -> {
+ resourceRegistry.decorate(KIND, new ApplyImagePullPolicyDecorator(kubernetesConfig.getName(), c.getImagePullPolicy()));
+ resourceRegistry.decorate(KIND, new ApplyServiceTypeToKindServiceDecorator(kubernetesConfig.getName(), c));
+ // Check if MinikubeConfig defines port, else fallback to KubernetesConfig
+ if (c.getPorts().length > 0) {
+ Arrays.stream(c.getPorts()).forEach(p -> {
+ resourceRegistry.decorate(KIND, new ApplyPortToKindServiceDecorator(kubernetesConfig.getName(), p));
+ });
+ } else {
+ Arrays.stream(kubernetesConfig.getPorts()).forEach(p -> {
+ resourceRegistry.decorate(KIND, new ApplyPortToKindServiceDecorator(kubernetesConfig.getName(), p));
+ });
+ }
+ });
+ }
+}
diff --git a/annotations/kind-annotations/src/main/java/io/dekorate/kind/manifest/KindManifestGeneratorFactory.java b/annotations/kind-annotations/src/main/java/io/dekorate/kind/manifest/KindManifestGeneratorFactory.java
new file mode 100644
index 000000000..7115f41f1
--- /dev/null
+++ b/annotations/kind-annotations/src/main/java/io/dekorate/kind/manifest/KindManifestGeneratorFactory.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2018 The original 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
+ *
+ * http://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 io.dekorate.kind.manifest;
+
+import io.dekorate.ConfigurationRegistry;
+import io.dekorate.ManifestGeneratorFactory;
+import io.dekorate.ResourceRegistry;
+
+public class KindManifestGeneratorFactory implements ManifestGeneratorFactory {
+
+ public KindManifestGenerator create(ResourceRegistry resourceRegistry, ConfigurationRegistry configurationRegistry) {
+ return new KindManifestGenerator(resourceRegistry, configurationRegistry);
+ }
+}
diff --git a/annotations/kind-annotations/src/main/resources/META-INF/services/io.dekorate.ManifestGeneratorFactory b/annotations/kind-annotations/src/main/resources/META-INF/services/io.dekorate.ManifestGeneratorFactory
new file mode 100644
index 000000000..4366ce715
--- /dev/null
+++ b/annotations/kind-annotations/src/main/resources/META-INF/services/io.dekorate.ManifestGeneratorFactory
@@ -0,0 +1 @@
+io.dekorate.kind.manifest.KindManifestGeneratorFactory
diff --git a/docs/_data/sidebar.yml b/docs/_data/sidebar.yml
index c61e6b53d..e2418a494 100644
--- a/docs/_data/sidebar.yml
+++ b/docs/_data/sidebar.yml
@@ -21,6 +21,8 @@
url: /docs/openshift
- title: Minikube
url: /docs/minikube
+ - title: Kind
+ url: /docs/kind
- title: Tekton
url: /docs/tekton
- title: Helm
diff --git a/docs/configuration-guide.md b/docs/configuration-guide.md
index 25f985a5a..e870a83a4 100644
--- a/docs/configuration-guide.md
+++ b/docs/configuration-guide.md
@@ -126,6 +126,13 @@ The document is structured as follows.
| dekorate.minikube.ports | Port[] | The application ports. | {} |
| dekorate.minikube.service-type | ServiceType | The type of service that will be generated for the application. | io.dekorate.kubernetes.annotation.ServiceType.NodePort |
+### Kind
+
+| Property | Type | Description | Default Value |
+|-- ----------------------------------------------- | ------------------------------- | ----------------------------------------------------------------- | ----------------------- |
+| dekorate.kind.image-pull-policy | ImagePullPolicy | Image pull policy. | IfNotPresent |
+| dekorate.kind.ports | Port[] | The application ports. | {} |
+| dekorate.kind.service-type | ServiceType | The type of service that will be generated for the application. | io.dekorate.kubernetes.annotation.ServiceType.NodePort |
### Global Types
The section below describes all the available subtypes.
diff --git a/docs/documentation/kind.md b/docs/documentation/kind.md
new file mode 100644
index 000000000..c97d26839
--- /dev/null
+++ b/docs/documentation/kind.md
@@ -0,0 +1,45 @@
+---
+title: Kind
+description: Kind
+layout: docs
+permalink: /docs/kind
+---
+
+### Kind
+
+[@Kind](https://raw.githubusercontent.com/dekorateio/dekorate/main/annotations/kind-annotations/src/main/java/io/dekorate/kind/annotation/Kind.java) is a more specialized form of [@KubernetesApplication](https://raw.githubusercontent.com/dekorateio/dekorate/main/annotations/kubernetes-annotations/src/main/java/io/dekorate/kubernetes/annotation/KubernetesApplication.java).
+It can be added to your project like:
+
+```java
+import io.dekorate.kind.annotation.Kind;
+
+@Kind
+public class Main {
+
+ public static void main(String[] args) {
+ //Your application code goes here.
+ }
+}
+```
+
+When the project gets compiled, the annotation will trigger the generation of a `Deployment` in both `kind.json` and `kind.yml` that
+will end up under 'target/classes/META-INF/dekorate'. Also, if the deployment is enabled, it will automate the process of loading images to the cluster
+when performing container image builds.
+
+#### Adding the kind annotation processor to the classpath
+
+This module can be added to the project using:
+
+```xml
+
+ io.dekorate
+ kind-annotations
+ {{site.data.project.release.current-version}}
+
+```
+
+The `@Kind` annotation can be used in combination with `@KubernetesApplication`. In that case the `@Kind` configuration will take precedence over the one specified using `@KubernetesApplication` in the generated Kind manifests.
+
+**REMINDER**: A complete reference on all the supported properties can be found in the [configuration options guide]({{site.baseurl}}/configuration-guide).
+
+Check the Kind example [here](https://github.com/dekorateio/dekorate/tree/main/examples/kind-example).
diff --git a/examples/kind-example/Dockerfile b/examples/kind-example/Dockerfile
new file mode 100644
index 000000000..b901d2ee8
--- /dev/null
+++ b/examples/kind-example/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:8u171-alpine3.7
+RUN apk --no-cache add curl
+COPY target/*.jar kind-example.jar
+CMD java ${JAVA_OPTS} -jar kind-example.jar
diff --git a/examples/kind-example/pom.xml b/examples/kind-example/pom.xml
new file mode 100644
index 000000000..d2dacd7e6
--- /dev/null
+++ b/examples/kind-example/pom.xml
@@ -0,0 +1,106 @@
+
+ 4.0.0
+
+ io.dekorate
+ kind-example
+ 3.1-SNAPSHOT
+ Dekorate :: Examples :: Kind cluster
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+ 3.8.0
+ 3.0.0-M3
+ 3.0.0-M3
+ 3.2.0
+ 2.5.12
+
+
+
+
+
+ io.dekorate
+ kubernetes-spring-starter
+ ${project.version}
+
+
+ io.dekorate
+ kind-annotations
+ ${project.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${version.spring-boot}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+ ${version.spring-boot}
+
+
+
+ io.dekorate
+ kubernetes-junit-starter
+ ${project.version}
+ test
+
+
+
+
+
+ maven-compiler-plugin
+ ${version.maven-compiler-plugin}
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${version.spring-boot}
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${version.maven-surefire-plugin}
+ true
+
+ false
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ ${version.maven-failsafe-plugin}
+
+
+
+ integration-test
+ verify
+
+ integration-test
+
+
+ **/*IT.class
+
+
+
+
+
+
+
+
diff --git a/examples/kind-example/readme.md b/examples/kind-example/readme.md
new file mode 100644
index 000000000..bf5759887
--- /dev/null
+++ b/examples/kind-example/readme.md
@@ -0,0 +1,95 @@
+# Kind example
+
+A very simple example that demonstrates the use of `@Kind` in its simplest form.
+Check the [Main.java](src/main/java/io/dekorate/example/App.java) which bears the annotation.
+To access the `@Kind` annotation you just need to have the following dependency in your
+class path:
+
+```
+
+ io.dekorate
+ kind-annotations
+ ${project.version}
+
+```
+```java
+@Kind
+public class App
+{
+
+ public static void main(String[] args) {
+ //do stuff
+ }
+}
+```
+
+Users that configure dekorate in the annotationless fashion (via application.properties or application.yaml), can:
+
+```
+dekorate.kind.ports[0].name=http
+dekorate.kind.ports[0].containerPort=8080
+```
+
+or
+
+```
+dekorate:
+ kind:
+ ports:
+ - name: http
+ containerPort: 8080
+```
+
+
+Check, if necessary, the [App.java](src/main/java/io/dekorate/example/App.java).
+
+Compile the project using:
+
+ mvn clean install
+
+
+The Kind module will calculate a few values by default:
+- ImagePullPolicy will be set to `IfNotPresent`.
+
+You can find the generated deployment under: `target/classes/META-INF/dekorate/kind.yml` that should look like:
+
+```
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app.kubernetes.io/name: kind-example
+ app.kubernetes.io/version: 2.8-SNAPSHOT
+ name: kind-example
+spec:
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+ selector:
+ app.kubernetes.io/name: kind-example
+ app.kubernetes.io/version: 2.8-SNAPSHOT
+ type: NodePort
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app.kubernetes.io/version: 2.8-SNAPSHOT
+ app.kubernetes.io/name: kind-example
+ name: kind-example
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/version: 2.8-SNAPSHOT
+ app.kubernetes.io/name: kind-example
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/version: 2.8-SNAPSHOT
+ app.kubernetes.io/name: kind-example
+ spec: {}
+```
+
+
diff --git a/examples/kind-example/src/main/java/io/dekorate/example/App.java b/examples/kind-example/src/main/java/io/dekorate/example/App.java
new file mode 100644
index 000000000..4ef5a18f4
--- /dev/null
+++ b/examples/kind-example/src/main/java/io/dekorate/example/App.java
@@ -0,0 +1,30 @@
+package io.dekorate.example;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import com.sun.net.httpserver.HttpServer;
+
+@SpringBootApplication
+public class App
+{
+ public static void main(String[] args) throws IOException {
+ int serverPort = 8080;
+ HttpServer server = HttpServer.create(new InetSocketAddress(serverPort), 0);
+ server.createContext("/api/hello", (exchange -> {
+ String respText = "Hello world from Kind!";
+ exchange.sendResponseHeaders(200, respText.getBytes().length);
+ OutputStream output = exchange.getResponseBody();
+ output.write(respText.getBytes());
+ output.flush();
+ exchange.close();
+ }));
+ server.setExecutor(null); // creates a default executor
+ System.out.println("Listening in port "+serverPort);
+ server.start();
+ }
+
+}
diff --git a/examples/kind-example/src/main/resources/application.properties b/examples/kind-example/src/main/resources/application.properties
new file mode 100644
index 000000000..523dca290
--- /dev/null
+++ b/examples/kind-example/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+dekorate.kind.imagePullPolicy=Never
+dekorate.kubernetes.imagePullPolicy=Always
diff --git a/examples/kind-example/src/test/java/io/dekorate/example/KindExampleTest.java b/examples/kind-example/src/test/java/io/dekorate/example/KindExampleTest.java
new file mode 100644
index 000000000..9f07f939c
--- /dev/null
+++ b/examples/kind-example/src/test/java/io/dekorate/example/KindExampleTest.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2018 The original 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
+ *
+ * http://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 io.dekorate.example;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+
+import io.dekorate.kubernetes.annotation.ImagePullPolicy;
+import io.dekorate.utils.Serialization;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.KubernetesList;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+
+class KindExampleTest {
+
+ @Test
+ public void shouldExpectedConfiguration() {
+ KubernetesList kindList = Serialization.unmarshalAsList(KindExampleTest.class.getClassLoader().getResourceAsStream("META-INF/dekorate/kind.yml"));
+ assertNotNull(kindList);
+ Deployment kindDeployment = findFirst(kindList, Deployment.class).orElseThrow(() -> new IllegalStateException("Deployment not found in kind.yml!"));
+ assertEquals(ImagePullPolicy.Never.name(), kindDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImagePullPolicy());
+
+ KubernetesList kubernetes = Serialization.unmarshalAsList(KindExampleTest.class.getClassLoader().getResourceAsStream("META-INF/dekorate/kubernetes.yml"));
+ assertNotNull(kubernetes);
+ Deployment kubernetesDeployment = findFirst(kubernetes, Deployment.class).orElseThrow(() -> new IllegalStateException("Deployment not found in kubernetes.yml!"));
+ assertEquals(ImagePullPolicy.Always.name(), kubernetesDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImagePullPolicy());
+ }
+
+ Optional findFirst(KubernetesList list, Class t) {
+ return (Optional) list.getItems().stream()
+ .filter(i -> t.isInstance(i))
+ .findFirst();
+ }
+}
diff --git a/examples/pom.xml b/examples/pom.xml
index f13feee94..ac239246a 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -52,6 +52,7 @@
minikube-example-with-properties
helm-on-kubernetes-example
helm-on-openshift-example
+ kind-example