From 5e8e43d6b6da27af0fd3ba0384ccb0d334a3273d Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 29 Jul 2019 16:52:29 -0300 Subject: [PATCH] feat(operator): Add Quarkus Operator Based on https://www.instana.com/blog/writing-a-kubernetes-operator-in-java-part-3/ Fixes #898 --- cico_build_deploy.sh | 7 +- operator/deploy/crd.yaml | 14 +++ operator/deploy/namespace.yaml | 4 + operator/deploy/operator.yaml | 48 ++++++++ operator/deploy/role.yaml | 62 ++++++++++ operator/deploy/role_binding.yaml | 12 ++ operator/deploy/service_account.yaml | 4 + operator/example/cr_minimum.yaml | 19 +++ operator/example/cr_next.yaml | 36 ++++++ operator/example/launcher_cr.yaml | 13 ++ operator/pom.xml | 112 ++++++++++++++++++ operator/src/main/docker/Dockerfile.jvm | 22 ++++ operator/src/main/docker/Dockerfile.native | 23 ++++ .../launcher/operator/LauncherOperator.java | 86 ++++++++++++++ .../operator/cr/LauncherResource.java | 23 ++++ .../operator/cr/LauncherResourceDoneable.java | 10 ++ .../operator/cr/LauncherResourceList.java | 6 + .../operator/cr/LauncherResourceSpec.java | 111 +++++++++++++++++ .../src/main/resources/application.properties | 3 + .../operator/LauncherOperatorTest.java | 14 +++ .../operator/cr/LauncherResourceTest.java | 30 +++++ pom.xml | 6 + web/pom.xml | 1 - 23 files changed, 664 insertions(+), 2 deletions(-) create mode 100644 operator/deploy/crd.yaml create mode 100644 operator/deploy/namespace.yaml create mode 100644 operator/deploy/operator.yaml create mode 100644 operator/deploy/role.yaml create mode 100644 operator/deploy/role_binding.yaml create mode 100644 operator/deploy/service_account.yaml create mode 100644 operator/example/cr_minimum.yaml create mode 100644 operator/example/cr_next.yaml create mode 100644 operator/example/launcher_cr.yaml create mode 100644 operator/pom.xml create mode 100644 operator/src/main/docker/Dockerfile.jvm create mode 100644 operator/src/main/docker/Dockerfile.native create mode 100644 operator/src/main/java/io/fabric8/launcher/operator/LauncherOperator.java create mode 100644 operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResource.java create mode 100644 operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceDoneable.java create mode 100644 operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceList.java create mode 100644 operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceSpec.java create mode 100644 operator/src/main/resources/application.properties create mode 100644 operator/src/test/java/io/fabric8/launcher/operator/LauncherOperatorTest.java create mode 100644 operator/src/test/java/io/fabric8/launcher/operator/cr/LauncherResourceTest.java diff --git a/cico_build_deploy.sh b/cico_build_deploy.sh index e3032aa39..da455d86e 100755 --- a/cico_build_deploy.sh +++ b/cico_build_deploy.sh @@ -69,7 +69,7 @@ docker build -t ${BUILDER_IMAGE} -f Dockerfile.build . docker run --detach=true --name ${BUILDER_CONT} -t -v $(pwd)/${TARGET_DIR}:/${TARGET_DIR}:Z ${BUILDER_IMAGE} /bin/tail -f /dev/null #FIXME -docker exec ${BUILDER_CONT} ./mvnw -B clean install -Dmaven.test.skip=true -DfailIfNoTests=false -DskipTests -Ddownload.plugin.skip.cache +docker exec ${BUILDER_CONT} ./mvnw -B clean install -Dmaven.test.skip=true -DfailIfNoTests=false -DskipTests -Ddownload.plugin.skip.cache -DoperatorNative docker exec -u root ${BUILDER_CONT} cp web/target/launcher-runner.jar /${TARGET_DIR} docker exec -u root ${BUILDER_CONT} cp -r web/target/lib/ /${TARGET_DIR}/lib @@ -84,6 +84,11 @@ if [ -z $CICO_LOCAL ]; then tag_push "${REGISTRY_URL}:${TAG}" tag_push "${REGISTRY_URL}:latest" + # Push Operator + docker tag "quay.io/launcher/launcher-operator:latest" "quay.io/launcher/launcher-operator:${TAG}" + docker push "quay.io/launcher/launcher-operator:${TAG}" + docker push "quay.io/launcher/launcher-operator:latest" + if [[ "$TARGET" != "rhel" && -n "${GENERATOR_DOCKER_HUB_PASSWORD}" ]]; then docker_login "${GENERATOR_DOCKER_HUB_USERNAME}" "${GENERATOR_DOCKER_HUB_PASSWORD}" tag_push "${DOCKER_HUB_URL}:${TAG}" diff --git a/operator/deploy/crd.yaml b/operator/deploy/crd.yaml new file mode 100644 index 000000000..7c45991f1 --- /dev/null +++ b/operator/deploy/crd.yaml @@ -0,0 +1,14 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: launchers.launcher.fabric8.io + namespace: launcher +spec: + group: launcher.fabric8.io + version: v1beta1 + scope: Namespaced + names: + kind: Launcher + listKind: LauncherList + plural: launchers + singular: launcher \ No newline at end of file diff --git a/operator/deploy/namespace.yaml b/operator/deploy/namespace.yaml new file mode 100644 index 000000000..b51f0797d --- /dev/null +++ b/operator/deploy/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: launcher \ No newline at end of file diff --git a/operator/deploy/operator.yaml b/operator/deploy/operator.yaml new file mode 100644 index 000000000..ce4132658 --- /dev/null +++ b/operator/deploy/operator.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: launcher-operator +spec: + replicas: 1 + selector: + matchLabels: + name: launcher-operator + template: + metadata: + labels: + name: launcher-operator + spec: + serviceAccountName: launcher-operator + containers: + - name: launcher-operator + image: quay.io/gastaldi/launcher-operator:latest + imagePullPolicy: Always + readinessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 4 + periodSeconds: 10 + timeoutSeconds: 10 + failureThreshold: 1 + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 4 + periodSeconds: 10 + timeoutSeconds: 10 + failureThreshold: 1 + ports: + - containerPort: 8080 + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name diff --git a/operator/deploy/role.yaml b/operator/deploy/role.yaml new file mode 100644 index 000000000..7bf480983 --- /dev/null +++ b/operator/deploy/role.yaml @@ -0,0 +1,62 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: launcher-operator +rules: + - apiGroups: + - "" + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + - processedtemplates.template.openshift.io + verbs: + - '*' + - apiGroups: + - template.openshift.io + resources: + - processedtemplates + verbs: [ get, list, create, update, delete, deletecollection, watch] + - apiGroups: + - apps.openshift.io + resources: + - deploymentconfigs + - deploymentconfigs/instantiate + verbs: [ get, list, create, update, delete, deletecollection, watch] + - apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: [ get, list, create, update, delete, deletecollection, watch] + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' + - apiGroups: + - launcher.fabric8.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get \ No newline at end of file diff --git a/operator/deploy/role_binding.yaml b/operator/deploy/role_binding.yaml new file mode 100644 index 000000000..e24ae11d6 --- /dev/null +++ b/operator/deploy/role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: launcher-operator +subjects: + - kind: ServiceAccount + name: launcher-operator + namespace: launcher +roleRef: + kind: ClusterRole + name: launcher-operator + apiGroup: rbac.authorization.k8s.io diff --git a/operator/deploy/service_account.yaml b/operator/deploy/service_account.yaml new file mode 100644 index 000000000..16f3d463e --- /dev/null +++ b/operator/deploy/service_account.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: launcher-operator diff --git a/operator/example/cr_minimum.yaml b/operator/example/cr_minimum.yaml new file mode 100644 index 000000000..fde1b7b64 --- /dev/null +++ b/operator/example/cr_minimum.yaml @@ -0,0 +1,19 @@ +apiVersion: launcher.fabric8.io/v1beta1 +kind: Launcher +metadata: + name: example-launcher +spec: + openshift: + consoleUrl: consoleUrl + git: + providers: + - id: GitHub + name: "GitHub" + apiUrl: https://api.github.com + repositoryUrl: https://github.com + type: GITHUB + clientProperties: + clientId: CHANGE_TO_CLIENT_ID + serverProperties: + oauthUrl: https://github.com/login/oauth/access_token + clientSecret: CHANGE_TO_CLIENT_SECRET diff --git a/operator/example/cr_next.yaml b/operator/example/cr_next.yaml new file mode 100644 index 000000000..b47a2aedd --- /dev/null +++ b/operator/example/cr_next.yaml @@ -0,0 +1,36 @@ +apiVersion: launcher.fabric8.io/v1beta1 +kind: Launcher +metadata: + name: example-launcher +spec: + environment: production + catalog: + repositoryUrl: http://github.com/fabric8-launcher/launcher-booster-catalog + repositoryRef: master + filter: filter expression + openshift: + apiUrl: https://api.cluster.openshift.com + consoleUrl: https://console.cluster.openshift.com + username: username + password: password + token: token + impersonate: true + clientId: launcher + git: + providers: + - id: GitHub + name: "GitHub" + apiUrl: https://api.github.com + repositoryUrl: https://github.com + type: GITHUB + clientProperties: + clientId: CHANGE_TO_CLIENT_ID + serverProperties: + oauthUrl: https://github.com/login/oauth/access_token + clientSecret: CHANGE_TO_CLIENT_SECRET + username: username + token: token + keycloak: + url: https://sso.openshift.io/auth + realm: rh-developers-launch + clientId: launcher diff --git a/operator/example/launcher_cr.yaml b/operator/example/launcher_cr.yaml new file mode 100644 index 000000000..1d56278f3 --- /dev/null +++ b/operator/example/launcher_cr.yaml @@ -0,0 +1,13 @@ +apiVersion: launcher.fabric8.io/v1beta1 +kind: Launcher +metadata: + name: launcher +spec: + + ####### OpenShift Configuration + openshift: + consoleUrl: ## + + ####### OAuth Configuration + oauth: + enabled: true diff --git a/operator/pom.xml b/operator/pom.xml new file mode 100644 index 000000000..0e3522ce4 --- /dev/null +++ b/operator/pom.xml @@ -0,0 +1,112 @@ + + + + launcher-parent + io.fabric8.launcher + 1-SNAPSHOT + + 4.0.0 + launcher-operator + + + io.quarkus + quarkus-kubernetes-client + + + io.quarkus + quarkus-smallrye-health + + + + io.fabric8.launcher + launcher-base-test + test + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-test-kubernetes-client + test + + + + + launcher-operator + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + maven-surefire-plugin + + + org.jboss.logmanager.LogManager + + + + + + + + + native + + + operatorNative + + + + true + + + + + io.quarkus + quarkus-maven-plugin + + + + native-image + + + true + -H:IncludeResources=../templates/openshift/launcher-template.yaml + + + + + + maven-failsafe-plugin + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + + + + + + + + + + \ No newline at end of file diff --git a/operator/src/main/docker/Dockerfile.jvm b/operator/src/main/docker/Dockerfile.jvm new file mode 100644 index 000000000..33d88f2eb --- /dev/null +++ b/operator/src/main/docker/Dockerfile.jvm @@ -0,0 +1,22 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the docker image run: +# +# mvn package +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/operator-example-jvm . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/operator-example-jvm +# +### +FROM fabric8/java-alpine-openjdk8-jre +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV AB_ENABLED=jmx_exporter +COPY target/lib/* /deployments/lib/ +COPY target/*-runner.jar /deployments/app.jar +ENTRYPOINT [ "/deployments/run-java.sh" ] \ No newline at end of file diff --git a/operator/src/main/docker/Dockerfile.native b/operator/src/main/docker/Dockerfile.native new file mode 100644 index 000000000..4f069f430 --- /dev/null +++ b/operator/src/main/docker/Dockerfile.native @@ -0,0 +1,23 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode +# +# Before building the docker image run: +# +# mvn package -Pnative -Dnative-image.docker-build=true +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native -t fabric8/launcher-operator . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 fabric8/launcher-operator +# +### +FROM registry.access.redhat.com/ubi8/ubi-minimal +WORKDIR /work/ +COPY target/*-runner /work/application +COPY --from=quay.io/quarkus/ubi-quarkus-native-image:19.1.1 /opt/graalvm/jre/lib/amd64/libsunec.so /work/library/ +RUN chmod 775 /work +EXPOSE 8080 +CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djava.library.path=/work/library"] \ No newline at end of file diff --git a/operator/src/main/java/io/fabric8/launcher/operator/LauncherOperator.java b/operator/src/main/java/io/fabric8/launcher/operator/LauncherOperator.java new file mode 100644 index 000000000..22931f5b3 --- /dev/null +++ b/operator/src/main/java/io/fabric8/launcher/operator/LauncherOperator.java @@ -0,0 +1,86 @@ +package io.fabric8.launcher.operator; + +import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.internal.KubernetesDeserializer; +import io.fabric8.launcher.operator.cr.LauncherResource; +import io.fabric8.launcher.operator.cr.LauncherResourceDoneable; +import io.fabric8.launcher.operator.cr.LauncherResourceList; +import io.quarkus.runtime.StartupEvent; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.inject.Inject; + +/** + * An Operator listens for events and performs necessary work + */ +@ApplicationScoped +public class LauncherOperator implements Watcher { + + private static final String CRD_NAME = "launchers.launcher.fabric8.io"; + private static final String CRD_API_VERSION = "launcher.fabric8.io/v1beta1"; + private static final String CRD_KIND = "Launcher"; + + @Inject + KubernetesClient client; + + void onStartup(@Observes StartupEvent _ev) { + // Register deserializers + KubernetesDeserializer.registerCustomKind(CRD_API_VERSION, CRD_KIND, LauncherResource.class); + // Fetch installed CRD + CustomResourceDefinition crd = client.customResourceDefinitions().withName(CRD_NAME).require(); + // Watch for events + client.customResources(crd, LauncherResource.class, LauncherResourceList.class, LauncherResourceDoneable.class) + .inNamespace(client.getNamespace()) + .watch(this); + } + + @Override + public void eventReceived(Action action, LauncherResource resource) { + switch (action) { + case ADDED: + onAdded(resource); + break; + case MODIFIED: + onModified(resource); + break; + case DELETED: + onDeleted(resource); + break; + case ERROR: + onError(resource); + break; + default: + System.exit(-1); + } + } + + @Override + public void onClose(KubernetesClientException cause) { + if (cause != null) { + cause.printStackTrace(); + } + System.exit(-1); + } + + private void onAdded(LauncherResource resource) { + System.out.println("ADDED: " + resource + "->" + Thread.currentThread().getName()); + } + + private void onDeleted(LauncherResource resource) { + System.out.println("DELETED: " + resource + "->" + Thread.currentThread().getName()); + } + + private void onModified(LauncherResource resource) { + System.out.println("MODIFIED: " + resource + "->" + Thread.currentThread().getName()); + } + + private void onError(LauncherResource resource) { + System.out.println("ERROR:" + resource + "->" + Thread.currentThread().getName()); + } + + +} diff --git a/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResource.java b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResource.java new file mode 100644 index 000000000..9a622c6e1 --- /dev/null +++ b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResource.java @@ -0,0 +1,23 @@ +package io.fabric8.launcher.operator.cr; + +import io.fabric8.kubernetes.client.CustomResource; + +public class LauncherResource extends CustomResource { + private LauncherResourceSpec spec; + + public LauncherResourceSpec getSpec() { + return spec; + } + + public void setSpec(LauncherResourceSpec spec) { + this.spec = spec; + } + + @Override + public String toString() { + String name = getMetadata() != null ? getMetadata().getName() : "unknown"; + String version = getMetadata() != null ? getMetadata().getResourceVersion() : "unknown"; + return "name=" + name + " version=" + version + " value=" + spec; + } + +} diff --git a/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceDoneable.java b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceDoneable.java new file mode 100644 index 000000000..1079604a8 --- /dev/null +++ b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceDoneable.java @@ -0,0 +1,10 @@ +package io.fabric8.launcher.operator.cr; + +import io.fabric8.kubernetes.api.builder.Function; +import io.fabric8.kubernetes.client.CustomResourceDoneable; + +public class LauncherResourceDoneable extends CustomResourceDoneable { + public LauncherResourceDoneable(LauncherResource resource, Function function) { + super(resource, function); + } +} diff --git a/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceList.java b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceList.java new file mode 100644 index 000000000..bff361279 --- /dev/null +++ b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceList.java @@ -0,0 +1,6 @@ +package io.fabric8.launcher.operator.cr; + +import io.fabric8.kubernetes.client.CustomResourceList; + +public class LauncherResourceList extends CustomResourceList { +} diff --git a/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceSpec.java b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceSpec.java new file mode 100644 index 000000000..820e38bc1 --- /dev/null +++ b/operator/src/main/java/io/fabric8/launcher/operator/cr/LauncherResourceSpec.java @@ -0,0 +1,111 @@ +package io.fabric8.launcher.operator.cr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.quarkus.runtime.annotations.RegisterForReflection; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RegisterForReflection +public class LauncherResourceSpec { + + @JsonProperty + public String environment = "production"; + + @JsonProperty + public OpenShift openshift; + + @JsonProperty + public Git git; + + @JsonProperty + public BoosterCatalog catalog; + + @JsonProperty + public Keycloak keycloak; + + @RegisterForReflection + public static class OpenShift { + + public String consoleUrl; + + public String clientId = "launcher"; + + public String apiUrl = "htps://openshift.default.svc.cluster.local"; + + public boolean impersonate; + + public String username; + + public String password; + + public String token; + } + + @RegisterForReflection + public static class Git { + public List providers = new ArrayList<>(); + public String username; + public String password; + public String token; + } + + @RegisterForReflection + public static class BoosterCatalog { + public String repositoryUrl = "https://github.com/fabric8-launcher/launcher-booster-catalog"; + + public String repositoryRef = "latest"; + + public String filter; + } + + @RegisterForReflection + public static class Keycloak { + public String url; + + public String realm; + + public String clientId; + } + + @RegisterForReflection + public static class GitProvider { + + /** + * @return a unique identifier for this instance + */ + public String id; + + /** + * @return A human-friendly name for this instance + */ + public String name; + + /** + * @return The URL this instance is configured + */ + public String apiUrl; + + /** + * @return The repository URL this instance is configured + */ + public String repositoryUrl; + + /** + * @return The type this instance targets + */ + public String type; + + /** + * @return properties used only in the Git Provider implementation + */ + public Map clientProperties = new HashMap<>(); + + /** + * @return properties used only in the Git Provider implementation + */ + public Map serverProperties = new HashMap<>(); + } +} diff --git a/operator/src/main/resources/application.properties b/operator/src/main/resources/application.properties new file mode 100644 index 000000000..a4a892e4e --- /dev/null +++ b/operator/src/main/resources/application.properties @@ -0,0 +1,3 @@ +# Configuration file +# key = value +#quarkus.kubernetes-client.namespace=launcher diff --git a/operator/src/test/java/io/fabric8/launcher/operator/LauncherOperatorTest.java b/operator/src/test/java/io/fabric8/launcher/operator/LauncherOperatorTest.java new file mode 100644 index 000000000..fd2846558 --- /dev/null +++ b/operator/src/test/java/io/fabric8/launcher/operator/LauncherOperatorTest.java @@ -0,0 +1,14 @@ +package io.fabric8.launcher.operator; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +@QuarkusTest +class LauncherOperatorTest { + + @Test + void testInteractionWithAPIServer() { + } + + +} \ No newline at end of file diff --git a/operator/src/test/java/io/fabric8/launcher/operator/cr/LauncherResourceTest.java b/operator/src/test/java/io/fabric8/launcher/operator/cr/LauncherResourceTest.java new file mode 100644 index 000000000..f98bc363f --- /dev/null +++ b/operator/src/test/java/io/fabric8/launcher/operator/cr/LauncherResourceTest.java @@ -0,0 +1,30 @@ +package io.fabric8.launcher.operator.cr; + +import io.fabric8.kubernetes.client.utils.Serialization; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +class LauncherResourceTest { + + @Test + void should_deserialize_cr() throws Exception { + File contents = new File("example/cr_next.yaml"); + LauncherResource resource = Serialization.yamlMapper().readValue(contents, LauncherResource.class); + assertThat(resource).isNotNull(); + assertThat(resource.getSpec().catalog.repositoryUrl).isEqualTo("http://github.com/fabric8-launcher/launcher-booster-catalog"); + assertThat(resource.getSpec().catalog.repositoryRef).isEqualTo("master"); + } + + @Test + void should_deserialize_minimum_cr() throws Exception { + File contents = new File("example/cr_minimum.yaml"); + LauncherResource resource = Serialization.yamlMapper().readValue(contents, LauncherResource.class); + assertThat(resource).isNotNull(); + assertThat(resource.getSpec().openshift.consoleUrl).isNotNull(); + assertThat(resource.getSpec().git.providers).isNotEmpty(); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index f000fc8a0..ffb71d446 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,7 @@ frontend creator web + operator @@ -468,6 +469,11 @@ + + io.quarkus + quarkus-maven-plugin + ${version.quarkus} + org.jacoco jacoco-maven-plugin diff --git a/web/pom.xml b/web/pom.xml index a6683df18..d64134630 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -139,7 +139,6 @@ io.quarkus quarkus-maven-plugin - ${version.quarkus}