diff --git a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddHostToRouteDecorator.java b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddHostToRouteDecorator.java new file mode 100644 index 000000000..fbec1371c --- /dev/null +++ b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddHostToRouteDecorator.java @@ -0,0 +1,66 @@ +/** + * 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.openshift.decorator; + +import static io.dekorate.openshift.decorator.AddRouteDecorator.KIND_ROUTE; + +import java.util.Arrays; +import java.util.List; + +import io.dekorate.ConfigReference; +import io.dekorate.WithConfigReferences; +import io.dekorate.doc.Description; +import io.dekorate.kubernetes.decorator.Decorator; +import io.dekorate.kubernetes.decorator.NamedResourceDecorator; +import io.dekorate.openshift.config.OpenshiftConfig; +import io.dekorate.utils.Strings; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.openshift.api.model.RouteSpecFluent; + +@Description("Add the host to the Route resource.") +public class AddHostToRouteDecorator extends NamedResourceDecorator> implements WithConfigReferences { + + private final OpenshiftConfig config; + + public AddHostToRouteDecorator(OpenshiftConfig config) { + super(KIND_ROUTE, config.getName()); + this.config = config; + } + + @Override + public void andThenVisit(RouteSpecFluent spec, ObjectMeta resourceMeta) { + if (!spec.hasHost() && config.getRoute() != null && Strings.isNotNullOrEmpty(config.getRoute().getHost())) { + spec.withHost(config.getRoute().getHost()); + } + } + + @Override + public Class[] after() { + return new Class[] { AddRouteDecorator.class }; + } + + @Override + public List getConfigReferences() { + return Arrays.asList(buildConfigReferenceHost()); + } + + private ConfigReference buildConfigReferenceHost() { + String property = "host"; + String path = "(kind == Route && metadata.name == " + getName() + ").spec.host"; + return new ConfigReference(property, path); + } +} diff --git a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddPortToRouteDecorator.java b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddPortToRouteDecorator.java new file mode 100644 index 000000000..80afef543 --- /dev/null +++ b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddPortToRouteDecorator.java @@ -0,0 +1,94 @@ +/** + * 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.openshift.decorator; + +import static io.dekorate.utils.Ports.getHttpPort; +import static io.dekorate.utils.Ports.getPortByFilter; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import io.dekorate.ConfigReference; +import io.dekorate.WithConfigReferences; +import io.dekorate.doc.Description; +import io.dekorate.kubernetes.config.Port; +import io.dekorate.kubernetes.decorator.Decorator; +import io.dekorate.kubernetes.decorator.NamedResourceDecorator; +import io.dekorate.openshift.config.OpenshiftConfig; +import io.dekorate.utils.Strings; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.openshift.api.model.RouteSpecFluent; + +@Description("Add the port to the Route resource.") +public class AddPortToRouteDecorator extends NamedResourceDecorator> implements WithConfigReferences { + + private final OpenshiftConfig config; + + public AddPortToRouteDecorator(OpenshiftConfig config) { + this.config = config; + } + + @Override + public void andThenVisit(RouteSpecFluent spec, ObjectMeta resourceMeta) { + Optional port = getNamedHttpPort(config); + if (!port.isPresent()) { + return; + } + + if (!spec.hasPath()) { + spec.withPath(port.get().getPath()); + } + + if (!spec.hasPort()) { + spec.editOrNewPort() + .withNewTargetPort(port.get().getName()) + .endPort(); + } + } + + private Optional getNamedHttpPort(OpenshiftConfig config) { + String namedPortName = config.getRoute().getTargetPort(); + if (Strings.isNotNullOrEmpty(namedPortName)) { + Optional port = getPortByFilter(p -> Strings.equals(p.getName(), namedPortName), config); + if (port.isPresent()) { + return port; + } + + // Set the named port to the one provided by the user even though it was not found in the configured ports. + return Optional.of(Port.newBuilder().withName(namedPortName).build()); + } + + return getHttpPort(config); + } + + @Override + public Class[] after() { + return new Class[] { AddRouteDecorator.class }; + } + + @Override + public List getConfigReferences() { + return Arrays.asList(buildConfigReferencePath()); + } + + private ConfigReference buildConfigReferencePath() { + String property = "path"; + String path = "(kind == Route && metadata.name == " + getName() + ").spec.path"; + return new ConfigReference(property, path); + } +} diff --git a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddRouteDecorator.java b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddRouteDecorator.java index 5075dbce8..4d6112bf9 100644 --- a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddRouteDecorator.java +++ b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddRouteDecorator.java @@ -16,25 +16,20 @@ package io.dekorate.openshift.decorator; -import static io.dekorate.utils.Ports.getHttpPort; -import static io.dekorate.utils.Ports.getPortByFilter; - -import java.util.Optional; - import io.dekorate.doc.Description; -import io.dekorate.kubernetes.config.Port; import io.dekorate.kubernetes.decorator.AddServiceResourceDecorator; import io.dekorate.kubernetes.decorator.Decorator; import io.dekorate.kubernetes.decorator.ResourceProvidingDecorator; import io.dekorate.openshift.config.OpenshiftConfig; import io.dekorate.utils.Labels; -import io.dekorate.utils.Strings; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.openshift.api.model.RouteBuilder; @Description("Add a route to the list.") public class AddRouteDecorator extends ResourceProvidingDecorator { + public static final String KIND_ROUTE = "Route"; + private final OpenshiftConfig config; public AddRouteDecorator(OpenshiftConfig config) { @@ -46,49 +41,20 @@ public void visit(KubernetesListBuilder list) { return; } - Optional port = getNamedHttpPort(config); - if (!port.isPresent()) { - return; - } - - if (contains(list, "route.openshift.io/v1", "Route", config.getName())) { + if (contains(list, "route.openshift.io/v1", KIND_ROUTE, config.getName())) { return; } list.addToItems(new RouteBuilder() .withNewMetadata() .withName(config.getName()) - .withLabels(Labels.createLabelsAsMap(config, "Route")) + .withLabels(Labels.createLabelsAsMap(config, KIND_ROUTE)) .endMetadata() .withNewSpec() - .withHost(config.getRoute().getHost()) - .withPath(port.get().getPath()) - .withNewTo() - .withKind("Service") - .withName(config.getName()) - .endTo() - .withNewPort() - .withNewTargetPort(port.get().getName()) - .endPort() .endSpec() .build()); } - private Optional getNamedHttpPort(OpenshiftConfig config) { - String namedPortName = config.getRoute().getTargetPort(); - if (Strings.isNotNullOrEmpty(namedPortName)) { - Optional port = getPortByFilter(p -> Strings.equals(p.getName(), namedPortName), config); - if (port.isPresent()) { - return port; - } - - // Set the named port to the one provided by the user even though it was not found in the configured ports. - return Optional.of(Port.newBuilder().withName(namedPortName).build()); - } - - return getHttpPort(config); - } - @Override public Class[] after() { return new Class[] { AddServiceResourceDecorator.class }; diff --git a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddServiceToRouteDecorator.java b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddServiceToRouteDecorator.java new file mode 100644 index 000000000..45da2f6e7 --- /dev/null +++ b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/decorator/AddServiceToRouteDecorator.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.openshift.decorator; + +import static io.dekorate.openshift.decorator.AddRouteDecorator.KIND_ROUTE; + +import io.dekorate.doc.Description; +import io.dekorate.kubernetes.decorator.Decorator; +import io.dekorate.kubernetes.decorator.NamedResourceDecorator; +import io.dekorate.openshift.config.OpenshiftConfig; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.openshift.api.model.RouteSpecFluent; + +@Description("Add the service to the Route resource.") +public class AddServiceToRouteDecorator extends NamedResourceDecorator> { + + private final OpenshiftConfig config; + + public AddServiceToRouteDecorator(OpenshiftConfig config) { + super(KIND_ROUTE, config.getName()); + this.config = config; + } + + @Override + public void andThenVisit(RouteSpecFluent spec, ObjectMeta resourceMeta) { + if (!spec.hasTo()) { + spec.withNewTo() + .withKind("Service") + .withName(config.getName()) + .endTo(); + } + } + + @Override + public Class[] after() { + return new Class[] { AddRouteDecorator.class }; + } +} diff --git a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/manifest/OpenshiftManifestGenerator.java b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/manifest/OpenshiftManifestGenerator.java index e55ed0997..94438edd6 100644 --- a/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/manifest/OpenshiftManifestGenerator.java +++ b/annotations/openshift-annotations/src/main/java/io/dekorate/openshift/manifest/OpenshiftManifestGenerator.java @@ -45,7 +45,10 @@ import io.dekorate.openshift.config.EditableOpenshiftConfig; import io.dekorate.openshift.config.OpenshiftConfig; import io.dekorate.openshift.config.OpenshiftConfigBuilder; +import io.dekorate.openshift.decorator.AddHostToRouteDecorator; +import io.dekorate.openshift.decorator.AddPortToRouteDecorator; import io.dekorate.openshift.decorator.AddRouteDecorator; +import io.dekorate.openshift.decorator.AddServiceToRouteDecorator; import io.dekorate.openshift.decorator.ApplyDeploymentTriggerDecorator; import io.dekorate.openshift.decorator.ApplyReplicasToDeploymentConfigDecorator; import io.dekorate.option.config.VcsConfig; @@ -122,6 +125,9 @@ protected void addDecorators(String group, OpenshiftConfig config) { resourceRegistry.decorate(group, new ApplyDeploymentTriggerDecorator(config.getName(), imageConfig.getName() + ":" + imageConfig.getVersion())); resourceRegistry.decorate(group, new AddRouteDecorator(config)); + resourceRegistry.decorate(group, new AddHostToRouteDecorator(config)); + resourceRegistry.decorate(group, new AddPortToRouteDecorator(config)); + resourceRegistry.decorate(group, new AddServiceToRouteDecorator(config)); if (config.hasAttribute(RUNTIME_TYPE)) { resourceRegistry.decorate(group, new AddLabelDecorator(config.getName(), diff --git a/docs/documentation/helm.md b/docs/documentation/helm.md index 1c0aab1ef..c429c5fc6 100644 --- a/docs/documentation/helm.md +++ b/docs/documentation/helm.md @@ -69,7 +69,8 @@ By default, Dekorate will generate the Helm values file (`values.yaml`) by mappi - The Kubernetes/OpenShift health checks for Readiness, Liveness and Startup probes - The Kubernetes/OpenShift service type - The Kubernetes ingress host -- The Openshift S2i builder image +- The OpenShift S2i builder image +- The OpenShift route host/path For example, if you set 3 replicas for your deployment: diff --git a/tests/issue-existing-route-resource/pom.xml b/tests/issue-existing-route-resource/pom.xml new file mode 100644 index 000000000..c17a5fc94 --- /dev/null +++ b/tests/issue-existing-route-resource/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + + dekorate-tests + io.dekorate + 3.1-SNAPSHOT + ../ + + + io.dekorate + issue-existitng-route-resource + Dekorate :: Tests :: Annotations :: Existing route resources + + + + io.dekorate + openshift-annotations + ${project.version} + + + io.dekorate + dekorate-spring-boot + ${project.version} + + + org.springframework.boot + spring-boot-starter-web + ${version.spring-boot} + + + + + org.junit.jupiter + junit-jupiter-api + ${version.junit-jupiter} + test + + + org.junit.jupiter + junit-jupiter-engine + ${version.junit-jupiter} + test + + + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + true + + false + + + + org.springframework.boot + spring-boot-maven-plugin + ${version.spring-boot} + + + + diff --git a/tests/issue-existing-route-resource/src/main/java/io/dekorate/annotationless/DemoApplication.java b/tests/issue-existing-route-resource/src/main/java/io/dekorate/annotationless/DemoApplication.java new file mode 100644 index 000000000..8bd220c62 --- /dev/null +++ b/tests/issue-existing-route-resource/src/main/java/io/dekorate/annotationless/DemoApplication.java @@ -0,0 +1,28 @@ +/** + * 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.annotationless; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/tests/issue-existing-route-resource/src/main/java/io/dekorate/annotationless/HelloController.java b/tests/issue-existing-route-resource/src/main/java/io/dekorate/annotationless/HelloController.java new file mode 100644 index 000000000..1d952335a --- /dev/null +++ b/tests/issue-existing-route-resource/src/main/java/io/dekorate/annotationless/HelloController.java @@ -0,0 +1,32 @@ +/** + * 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.annotationless; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + + private static final String HELLO = "hello world!"; + + @RequestMapping("/") + public String hello() { + return HELLO; + } +} diff --git a/tests/issue-existing-route-resource/src/main/resources/application.properties b/tests/issue-existing-route-resource/src/main/resources/application.properties new file mode 100644 index 000000000..a435b5b3a --- /dev/null +++ b/tests/issue-existing-route-resource/src/main/resources/application.properties @@ -0,0 +1,2 @@ +dekorate.options.input-path=kubernetes +dekorate.openshift.route.host=host.com diff --git a/tests/issue-existing-route-resource/src/main/resources/kubernetes/common.yml b/tests/issue-existing-route-resource/src/main/resources/kubernetes/common.yml new file mode 100644 index 000000000..8dc15038d --- /dev/null +++ b/tests/issue-existing-route-resource/src/main/resources/kubernetes/common.yml @@ -0,0 +1,8 @@ +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: issue-existitng-route-resource +spec: + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect diff --git a/tests/issue-existing-route-resource/src/test/java/io/dekorate/example/IssueExistingRouteResourceTest.java b/tests/issue-existing-route-resource/src/test/java/io/dekorate/example/IssueExistingRouteResourceTest.java new file mode 100644 index 000000000..21b842235 --- /dev/null +++ b/tests/issue-existing-route-resource/src/test/java/io/dekorate/example/IssueExistingRouteResourceTest.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.utils.Serialization; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.KubernetesList; +import io.fabric8.openshift.api.model.Route; + +public class IssueExistingRouteResourceTest { + + @Test + public void shouldUpdateCustomRoute() { + KubernetesList list = Serialization + .unmarshalAsList(getClass().getClassLoader().getResourceAsStream("META-INF/dekorate/openshift.yml")); + assertNotNull(list); + Route r = findFirst(list, Route.class).orElseThrow(() -> new IllegalStateException()); + assertEquals("issue-existitng-route-resource", r.getMetadata().getName()); + assertEquals("http", r.getSpec().getPort().getTargetPort().getStrVal()); + assertEquals("host.com", r.getSpec().getHost()); + assertEquals("Service", r.getSpec().getTo().getKind()); + assertEquals("issue-existitng-route-resource", r.getSpec().getTo().getName()); + } + + Optional findFirst(KubernetesList list, Class t) { + return (Optional) list.getItems().stream() + .filter(i -> t.isInstance(i)) + .findFirst(); + } +} diff --git a/tests/pom.xml b/tests/pom.xml index b38ed1bf7..2e7e29505 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -86,6 +86,7 @@ issue-spring-boot-openshift-named-port issue-fetch-helm-dependencies feat-1083-ingress-rules + issue-existing-route-resource