diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 00000000..3e08f2fc --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,123 @@ +name: "[E2E Tests] Minikube" + +on: + push: + branches: + - e2e-testing + inputs: + theia-cloud-helm-branch: + description: "Theia Cloud Helm Branch to use" + type: string + default: "main" + workflow_dispatch: + inputs: + theia-cloud-helm-branch: + description: "Theia Cloud Helm Branch to use" + type: string + default: "main" + +permissions: + contents: read + +concurrency: + group: ci-e2e-theia-cloud-minikube-${{ github.ref }} + cancel-in-progress: true + +jobs: + runtests: + name: Run Tests on Minikube + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + kubernetes: [v1.31.0] #[v1.31.0, v1.30.4, v1.29.8, v1.28.13] + paths: [false] #[true, false] + ephemeral: [true] #[true, false] + keycloak: [false] #[true, false] + steps: + - name: Checkout Theia Cloud + uses: actions/checkout@v4 + with: + path: "./theia-cloud" + + - name: Checkout Theia Cloud Helm + uses: actions/checkout@v4 + with: + repository: "eclipsesource/theia-cloud-helm" + ref: "${{ github.event.inputs.theia-cloud-helm-branch }}" + path: "./theia-cloud-helm" + + - name: Setup Minikube + uses: manusa/actions-setup-minikube@92af4db914ab207f837251cd53eb7060e6477614 + with: + minikube version: v1.33.1 + kubernetes version: ${{ matrix.kubernetes }} + github token: ${{ secrets.GITHUB_TOKEN }} + start args: "--force" + + - name: Enable Minikube Addons + run: | + minikube addons enable dashboard + minikube addons enable default-storageclass + minikube addons enable ingress + minikube addons enable metrics-server + + - name: List Minikube Addons + run: minikube addons list + + - name: Patch Ingress to allow snippet annotations and restart + run: | + kubectl -n ingress-nginx patch cm ingress-nginx-controller --patch '{"data":{"allow-snippet-annotations":"true"}}' + kubectl -n ingress-nginx delete pod -l app.kubernetes.io/name=ingress-nginx + + -name: Build Theia Cloud Images + run: | + eval $(minikube -p minikube docker-env) + cd theia-cloud + docker build --no-cache -t theiacloud/theia-cloud-service:minikube-ci-e2e -f dockerfiles/service/Dockerfile . + docker build --no-cache -t theiacloud/theia-cloud-operator:minikube-ci-e2e -f dockerfiles/operator/Dockerfile . + docker build --no-cache -t theiacloud/theia-cloud-landing-page:minikube-ci-e2e -f dockerfiles/landing-page/Dockerfile . + docker build --no-cache -t theiacloud/theia-cloud-wondershaper:minikube-ci-e2e -f dockerfiles/wondershaper/Dockerfile . + docker build --no-cache -t theiacloud/theia-cloud-conversion-webhook:minikube-ci-e2e -f dockerfiles/conversion-webhook/Dockerfile . + + - name: Get NGINX Ingress Controller Host + id: ingress_info + run: | + INGRESS_HOST=$(kubectl get svc -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.clusterIP}') + echo "INGRESS_HOST=$INGRESS_HOST" >> $GITHUB_ENV + + - name: Run Terraform + run: | + cd theia-cloud/terraform/ci-configurations + terraform init + terraform apply \ + -var="ingress_ip=${{ env.INGRESS_HOST }}" \ + -var="use_paths=${{ matrix.paths }}" \ + -var="use_ephemeral_storage=${{ matrix.ephemeral }}" \ + -var="enable_keycloak=${{ matrix.keycloak }}" \ + -auto-approve + + - name: List All Services in All Namespaces + run: kubectl get services --all-namespaces + + - name: List All Ingresses in All Namespaces + run: kubectl get ingress --all-namespaces + + - name: List All Pods in All Namespaces + run: kubectl get pods --all-namespaces + + - name: Wait for Deployments to be Ready + run: | + kubectl wait --namespace ingress-nginx --for=condition=available deployment/ingress-nginx-controller --timeout=300s + kubectl wait --namespace theiacloud --for=condition=available deployment/conversion-webhook --timeout=300s + kubectl wait --namespace theiacloud --for=condition=available deployment/landing-page-deployment --timeout=300s + kubectl wait --namespace theiacloud --for=condition=available deployment/operator-deployment --timeout=300s + kubectl wait --namespace theiacloud --for=condition=available deployment/service-deployment --timeout=300s + + # URLs + # service: servicex + # landing: trynow + # instance: instances + - name: Access NGINX Ingress URL + run: | + curl -LkI "https://trynow.${{ env.INGRESS_HOST }}.nip.io/" diff --git a/terraform/ci-configurations/.terraform.lock.hcl b/terraform/ci-configurations/.terraform.lock.hcl new file mode 100644 index 00000000..7df1a1bb --- /dev/null +++ b/terraform/ci-configurations/.terraform.lock.hcl @@ -0,0 +1,83 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/gavinbunney/kubectl" { + version = "1.14.0" + constraints = ">= 1.14.0" + hashes = [ + "h1:gLFn+RvP37sVzp9qnFCwngRjjFV649r6apjxvJ1E/SE=", + "zh:0350f3122ff711984bbc36f6093c1fe19043173fad5a904bce27f86afe3cc858", + "zh:07ca36c7aa7533e8325b38232c77c04d6ef1081cb0bac9d56e8ccd51f12f2030", + "zh:0c351afd91d9e994a71fe64bbd1662d0024006b3493bb61d46c23ea3e42a7cf5", + "zh:39f1a0aa1d589a7e815b62b5aa11041040903b061672c4cfc7de38622866cbc4", + "zh:428d3a321043b78e23c91a8d641f2d08d6b97f74c195c654f04d2c455e017de5", + "zh:4baf5b1de2dfe9968cc0f57fd4be5a741deb5b34ee0989519267697af5f3eee5", + "zh:6131a927f9dffa014ab5ca5364ac965fe9b19830d2bbf916a5b2865b956fdfcf", + "zh:c62e0c9fd052cbf68c5c2612af4f6408c61c7e37b615dc347918d2442dd05e93", + "zh:f0beffd7ce78f49ead612e4b1aefb7cb6a461d040428f514f4f9cc4e5698ac65", + ] +} + +provider "registry.terraform.io/hashicorp/helm" { + version = "2.9.0" + constraints = ">= 2.9.0" + hashes = [ + "h1:D5BLFN82WndhQZQleXE5rO0hUDnlyqb60XeUJKDhuo4=", + "zh:1471cb45908b426104687c962007b2980cfde294fa3530fabc4798ce9fb6c20c", + "zh:1572e9cec20591ec08ece797b3630802be816a5adde36ca91a93359f2430b130", + "zh:1b10ae03cf5ab1ae21ffaac2251de99797294ae4242b156b3b0beebbdbcb7e0f", + "zh:3bd043b68de967d8d0b549d3f71485193d81167d5656f5507d743dedfe60e352", + "zh:538911921c729185900176cc22eb8edcb822bc8d22b9ebb48103a1d9bb53cc38", + "zh:69a6a2d40c0463662c3fb1621e37a3ee65024ea4479adf4d5f7f19fb0dea48c2", + "zh:94b58daa0c351a49d01f6d8f1caae46c95c2d6c3f29753e2b9ea3e3c0e7c9ab4", + "zh:9d0543331a4a32241e1ab5457f30b41df745acb235a0391205c725a5311e4809", + "zh:a6789306524ca121512a95e873e3949b4175114a6c5db32bed2df2551a79368f", + "zh:d146b94cd9502cca7f2044797a328d71c7ec2a98e2d138270d8a28c872f04289", + "zh:d14ccd14511f0446eacf43a9243f22de7c1427ceb059cf67d7bf9803be2cb15d", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "2.19.0" + hashes = [ + "h1:soxnBBEH2yLFS0xyALi7J8KQ4u7eQzEYIGvkDyyYCcU=", + "zh:028d346460de2d1d19b4c863dfc36be51c7bcd97d372b54a3a946bcb19f3f613", + "zh:391d0b38c455437d0a2ab1beb6ce6e1230aa4160bbae11c58b2810b258b44280", + "zh:40ea742f91b67f66e71d7091cfd40cc604528c4947651924bd6d8bd8d9793708", + "zh:48a99d341c8ba3cadaafa7cb99c0f11999f5e23f5cfb0f8469b4e352d9116e74", + "zh:4a5ade940eff267cbf7dcd52c1a7ac3999e7cc24996a409bd8b37bdb48a97f02", + "zh:5063742016a8249a4be057b9cc0ef24a684ec76d0ae5463d4b07e9b2d21e047e", + "zh:5d36b3a5662f840a6788f5e2a19d02139e87318feb3c5d82c7d076be1366fec4", + "zh:75edd9960cb30e54ef7de1b7df2761a274f17d4d41f54e72f86b43f41af3eb6d", + "zh:b85cadef3e6f25f1a10a617472bf5e8449decd61626733a1bc723de5edc08f64", + "zh:dc565b17b4ea6dde6bd1b92bc37e5e850fcbf9400540eec00ad3d9552a76ac2e", + "zh:deb665cc2123f2701aa3d653987b2ca35fb035a08a76a2382efb215c209f19a5", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/mrparkers/keycloak" { + version = "4.2.0" + constraints = ">= 4.2.0" + hashes = [ + "h1:0Z10wRvT3mrlm10AzTQIQy0h1QN6u8qAnePJKXxmvHw=", + "zh:0158a265b74b3e800864a78e24a822278aca250e97d5b4ac7ceb3fba9ff8d468", + "zh:1067bda8ec35e5f77de9fa6296fbb17d4f931692d624c50a6e97486982185422", + "zh:29ca6d1f647d82cf64641946b128ed90e2d3702fb7e79a432a692766d9bf66cc", + "zh:2d1fd51770fe5bc8b9b9188a1cffe34c108ca53678f77ccd369b7f0f8ea7ae28", + "zh:43e8dc93845c01b2b2b27fb245fd2de2daf391d239285201ab0ed294e7a8d104", + "zh:49f72033a1b48312c5c6e865043745e98ec11f564c80da780d5cfd02271a9dff", + "zh:4b18a3438d30553b9300d347452f81699aff2cbe8523116346da7bf51e7cc505", + "zh:613a73f6d3c196ebbdfcd451939d441afffb64bc514c94d91849231018f33df7", + "zh:6e0c20a937f1911820580fd2c3d933d19b38bdd8377ad1de5464c0e653f04f02", + "zh:87edc21042b62c7536e198354bc06843d4e10e83288db2e35a3829f719c44319", + "zh:aa9a5535c6e7e7b572bcba8a0eeaf5c0ed8cb5844eabc1aa8a96aab1cd685060", + "zh:b0d6e8f454b16d62bedd2122c4526c8f0c4c22ca78188b4e2eeaf78f3b7ec95a", + "zh:b35ab93aeffcca42574d87e77f43a6f394a64d41564d650f43f631d988b1d404", + "zh:b9f2d50549001bb801f1f99e4926e52c5de7e858c6758580a9845ca815a2606d", + "zh:da1ce72055cb7602a07bf2ecb0901292449b3b1261c8282236ac74d780c26659", + "zh:ebfe41b6b6a443482e66d08d544030e9d2c689290ff664d88839a9b80cee859c", + "zh:fb32217f92008e52ce57d6d9e5ffc8ec135a262dcac8fe47e10771e42b878178", + ] +} diff --git a/terraform/ci-configurations/e2e_tests.tf b/terraform/ci-configurations/e2e_tests.tf new file mode 100644 index 00000000..e72a0193 --- /dev/null +++ b/terraform/ci-configurations/e2e_tests.tf @@ -0,0 +1,154 @@ +variable "ingress_ip" { + description = "The IP of the running Minikube Cluster" + type = string +} + +variable "use_paths" { + description = "Whether to use Theia Cloud with paths or subdomains" + type = bool +} + +variable "use_ephemeral_storage" { + description = "Whether to use ephemeral storage" + type = bool +} + +variable "enable_keycloak" { + description = "Whether to enable keycloak" + type = bool +} + +provider "kubernetes" { + config_path = "~/.kube/config" +} + +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + } +} + +resource "kubernetes_persistent_volume" "minikube" { + metadata { + name = "minikube-volume" + } + spec { + storage_class_name = "manual" + capacity = { + storage = "16Gi" + } + access_modes = ["ReadWriteOnce"] + persistent_volume_source { + host_path { + path = "/data/theiacloud" + } + } + } +} + +module "helm" { + source = "../modules/helm" + + depends_on = [kubernetes_persistent_volume.minikube] + + install_ingress_controller = false + install_theia_cloud_base = false + install_theia_cloud_crds = false + install_theia_cloud = false + install_selfsigned_issuer = true + cert_manager_issuer_email = "jdoe@theia-cloud.io" + cert_manager_cluster_issuer = "keycloak-selfsigned-issuer" + cert_manager_common_name = "${var.ingress_ip}.nip.io" + hostname = "${var.ingress_ip}.nip.io" + service_type = "ClusterIP" + postgresql_storageClass = "manual" + postgresql_volumePermissions = true + keycloak_admin_password = "admin" + postgresql_enabled = true + postgres_postgres_password = "admin" + postgres_password = "admin" + loadBalancerIP = "" + cloudProvider = "MINIKUBE" +} + +provider "keycloak" { + client_id = "admin-cli" + username = "admin" + password = "admin" + url = "https://${var.ingress_ip}.nip.io/keycloak" + tls_insecure_skip_verify = true # only for minikube self signed + initial_login = false + client_timeout = 60 +} + +module "keycloak" { + source = "../modules/keycloak" + + depends_on = [module.helm] + + hostname = "${var.ingress_ip}.nip.io" + keycloak_test_user_foo_password = "foo" + keycloak_test_user_bar_password = "bar" + valid_redirect_uri = "*" +} + +resource "helm_release" "theia-cloud-crds" { + depends_on = [module.keycloak] + + name = "theia-cloud-crds" + chart = "../../../theia-cloud-helm/charts/theia-cloud-crds" + namespace = "theiacloud" + create_namespace = true + + set { + name = "conversion.image" + value = "theiacloud/theia-cloud-conversion-webhook:minikube-ci-e2e" + } +} + +resource "helm_release" "theia-cloud-base" { + depends_on = [module.keycloak] + + name = "theia-cloud-base" + chart = "../../../theia-cloud-helm/charts/theia-cloud-base" + namespace = "theiacloud" + create_namespace = true + + set { + name = "issuer.email" + value = "jdoe@theia-cloud.io" + } +} + +resource "helm_release" "theia-cloud" { + depends_on = [helm_release.theia-cloud-crds, helm_release.theia-cloud-base] + + name = "theia-cloud" + chart = "../../../theia-cloud-helm/charts/theia-cloud" + namespace = "theiacloud" + create_namespace = true + + values = [ + "${file("${path.module}/valuesE2ECI.yaml")}" + ] + + set { + name = "hosts.usePaths" + value = var.use_paths + } + + set { + name = "hosts.configuration.baseHost" + value = "${var.ingress_ip}.nip.io" + } + + set { + name = "landingPage.ephemeralStorage" + value = var.use_ephemeral_storage + } + + set { + name = "keycloak.enable" + value = var.enable_keycloak + } +} diff --git a/terraform/ci-configurations/outputs.tf b/terraform/ci-configurations/outputs.tf new file mode 100644 index 00000000..a3034db9 --- /dev/null +++ b/terraform/ci-configurations/outputs.tf @@ -0,0 +1,4 @@ +output "ingress_ip" { + description = "The IP of the running Minikube Cluster" + value = var.ingress_ip +} diff --git a/terraform/ci-configurations/valuesE2ECI.yaml b/terraform/ci-configurations/valuesE2ECI.yaml new file mode 100644 index 00000000..f02c5231 --- /dev/null +++ b/terraform/ci-configurations/valuesE2ECI.yaml @@ -0,0 +1,55 @@ +imagePullPolicy: IfNotPresent + +issuer: + email: jdoe@theia-cloud.io + +demoApplication: + install: false + +hosts: + usePaths: false + allWildcardInstances: ["*.webview."] + configuration: + baseHost: 192.168.39.173.nip.io + +landingPage: + image: theiacloud/theia-cloud-landing-page:minikube-ci-e2e + appDefinition: "theia-cloud-monitor-theia" + ephemeralStorage: true + additionalApps: + theia-cloud-monitor-vscode: + label: "Theia with VSCode Monitor" + +keycloak: + enable: false + authUrl: "https://keycloak.url/auth/" + +operator: + image: theiacloud/theia-cloud-operator:minikube-ci-e2e + cloudProvider: "MINIKUBE" + bandwidthLimiter: "WONDERSHAPER" + wondershaperImage: theiacloud/theia-cloud-wondershaper:minikube-ci-e2e + sessionsPerUser: "1" + storageClassName: "default" + requestedStorage: "250Mi" + replicas: 2 + +service: + image: theiacloud/theia-cloud-service:minikube-ci-e2e + +ingress: + certManagerAnnotations: true + clusterIssuer: theia-cloud-selfsigned-issuer + theiaCloudCommonName: true + tls: true + addTLSSecretName: true + +monitor: + enable: true + activityTracker: + enable: true + interval: 1 + +preloading: + enable: true + images: [] diff --git a/terraform/ci-configurations/versions.tf b/terraform/ci-configurations/versions.tf new file mode 100644 index 00000000..c5a2180e --- /dev/null +++ b/terraform/ci-configurations/versions.tf @@ -0,0 +1,18 @@ +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.18.1" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.9.0" + } + keycloak = { + source = "mrparkers/keycloak" + version = ">= 4.2.0" + } + } + + required_version = ">= 1.4.0" +}