From 70940e11fae555e19441743dfdf33ff89278e705 Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 19:37:28 -0500 Subject: [PATCH 01/10] First pass --- Jenkinsfile | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..ff15e27 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,75 @@ +pipeline { + agent { + kubernetes { + cloud 'kubernetes' + inheritFrom 'default' + yaml ''' + apiVersion: v1 + kind: Pod + metadata: + labels: + some-label: some-label-value + spec: + containers: + - name: java + image: openjdk:11 + command: + - cat + tty: true + - name: node + image: node:20.1.0-alpine3.17 + command: + - cat + tty: true + ''' + } + } + + environment { + PROD = "${env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'master'}" + APPLICATION_VERSION="1.0.${BUILD_NUMBER}" + } + + stages { + stage('build') { + steps { + container('node') { + sh "npm install" + sh "npm run compile" + sh "npm run bundle" + } + container('java') { + sh "./gradlew clean build --no-daemon" + } + } + } +// stage('release') { +// steps { +//// if(env.PROD == "true") { +// container('java') { +// withCredentials([usernamePassword(credentialsId: 'docker-hub', passwordVariable: 'REGISTRY_PASSWORD', usernameVariable: 'REGISTRY_USERNAME')]) { +// sh "./gradlew clean jib --no-daemon -Papplication.version=${APPLICATION_VERSION}" +// } +//// } +// } +// } +// } +// stage('deploy') { +// steps { +// sh "sed 's/DOCKER_IMAGE/nstream\\/demo-ripple:${APPLICATION_VERSION}/g' k8s.yml > k8s.apply.yml" +// archiveArtifacts artifacts: 'k8s.apply.yml', followSymlinks: false +// +// withCredentials([string(credentialsId: 'demo-deployer-k8s-cluster-ca', variable: 'CLUSTER_CA'), string(credentialsId: 'demo-deployer-k8s-cluster-endpoint', variable: 'ENDPOINT')]) { +// withKubeConfig(caCertificate: CLUSTER_CA, credentialsId: 'demo-deployer-k8s-cluster-token', serverUrl: ENDPOINT) { +// container('java'){ +// // TODO Figure out a container we can use that already has kubectl so we don't download it each time +// sh "curl --no-progress-meter -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.25.7/2023-03-17/bin/linux/amd64/kubectl" +// sh "chmod +x ./kubectl" +// sh "./kubectl apply -f k8s.apply.yml" +// } +// } +// } +// } +// } + } +} \ No newline at end of file From 4f89e77441703231fbc4bd9af598d74bddcd18a5 Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 19:40:09 -0500 Subject: [PATCH 02/10] Run in the proper folders --- Jenkinsfile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ff15e27..3dbcff2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -34,12 +34,16 @@ pipeline { stage('build') { steps { container('node') { - sh "npm install" - sh "npm run compile" - sh "npm run bundle" + dir('ui') { + sh "npm install" + sh "npm run compile" + sh "npm run bundle" + } } container('java') { - sh "./gradlew clean build --no-daemon" + dir('server') { + sh "./gradlew clean build --no-daemon" + } } } } From 67ea9cad49686a811286ccdcac39eb51ca86de77 Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 20:12:37 -0500 Subject: [PATCH 03/10] Moved to shared jenkins pipeline. Added UiRouter --- Jenkinsfile | 80 +------------- run.sh | 3 +- server/build.gradle | 33 ++++++ server/src/main/java/module-info.java | 1 + .../main/java/swim/ripple/RippleUiRouter.java | 101 ++++++++++++++++++ server/src/main/resources/server.recon | 2 +- 6 files changed, 140 insertions(+), 80 deletions(-) create mode 100644 server/src/main/java/swim/ripple/RippleUiRouter.java diff --git a/Jenkinsfile b/Jenkinsfile index 3dbcff2..751eba3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,79 +1,3 @@ -pipeline { - agent { - kubernetes { - cloud 'kubernetes' - inheritFrom 'default' - yaml ''' - apiVersion: v1 - kind: Pod - metadata: - labels: - some-label: some-label-value - spec: - containers: - - name: java - image: openjdk:11 - command: - - cat - tty: true - - name: node - image: node:20.1.0-alpine3.17 - command: - - cat - tty: true - ''' - } - } +library('jenkins-pipeline@pr-2') - environment { - PROD = "${env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'master'}" - APPLICATION_VERSION="1.0.${BUILD_NUMBER}" - } - - stages { - stage('build') { - steps { - container('node') { - dir('ui') { - sh "npm install" - sh "npm run compile" - sh "npm run bundle" - } - } - container('java') { - dir('server') { - sh "./gradlew clean build --no-daemon" - } - } - } - } -// stage('release') { -// steps { -//// if(env.PROD == "true") { -// container('java') { -// withCredentials([usernamePassword(credentialsId: 'docker-hub', passwordVariable: 'REGISTRY_PASSWORD', usernameVariable: 'REGISTRY_USERNAME')]) { -// sh "./gradlew clean jib --no-daemon -Papplication.version=${APPLICATION_VERSION}" -// } -//// } -// } -// } -// } -// stage('deploy') { -// steps { -// sh "sed 's/DOCKER_IMAGE/nstream\\/demo-ripple:${APPLICATION_VERSION}/g' k8s.yml > k8s.apply.yml" -// archiveArtifacts artifacts: 'k8s.apply.yml', followSymlinks: false -// -// withCredentials([string(credentialsId: 'demo-deployer-k8s-cluster-ca', variable: 'CLUSTER_CA'), string(credentialsId: 'demo-deployer-k8s-cluster-endpoint', variable: 'ENDPOINT')]) { -// withKubeConfig(caCertificate: CLUSTER_CA, credentialsId: 'demo-deployer-k8s-cluster-token', serverUrl: ENDPOINT) { -// container('java'){ -// // TODO Figure out a container we can use that already has kubectl so we don't download it each time -// sh "curl --no-progress-meter -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.25.7/2023-03-17/bin/linux/amd64/kubectl" -// sh "chmod +x ./kubectl" -// sh "./kubectl apply -f k8s.apply.yml" -// } -// } -// } -// } -// } - } -} \ No newline at end of file +demoServerUiPipeline("ripple") \ No newline at end of file diff --git a/run.sh b/run.sh index ad47efc..4839ca0 100755 --- a/run.sh +++ b/run.sh @@ -1,8 +1,9 @@ cd ui npm install npm run compile && npm run bundle -mkdir -p ../server/ui +mkdir -p ../server/ui ../server/src/main/resources/ui/ cp -rf index.html dist ../server/ui/ +cp -rf index.html dist ../server/src/main/resources/ui/ cd ../server ./gradlew clean run diff --git a/server/build.gradle b/server/build.gradle index a62a342..51bdba4 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -9,6 +9,11 @@ buildscript { } } +plugins { + id 'com.google.cloud.tools.jib' version '3.3.1' +} + + apply plugin: 'java-library' apply plugin: 'application' apply plugin: 'nebula.ospackage-application' @@ -93,6 +98,34 @@ afterEvaluate { } } + jib { + from { + image = "openjdk:11" + } + to { + image = "nstream/demo-ripple:${version}" + auth { + username = "$System.env.REGISTRY_USERNAME" + password = "$System.env.REGISTRY_PASSWORD" + } + } + container { + mainClass = mainClassName + ports = ['9001/tcp'] + jvmFlags = ['-Dswim.config=/config/server.recon'] + } + extraDirectories { + paths { + path { + // copies a single-file.xml + from = 'src/main/resources' + into = '/config' + includes = ['*.recon'] + } + } + } + } + run { dependsOn jar if (useModules) { diff --git a/server/src/main/java/module-info.java b/server/src/main/java/module-info.java index e706cc4..b5abb85 100644 --- a/server/src/main/java/module-info.java +++ b/server/src/main/java/module-info.java @@ -20,4 +20,5 @@ exports swim.ripple; provides swim.api.plane.Plane with swim.ripple.RipplePlane; + provides swim.kernel.Kernel with swim.ripple.RippleUiRouter; } diff --git a/server/src/main/java/swim/ripple/RippleUiRouter.java b/server/src/main/java/swim/ripple/RippleUiRouter.java new file mode 100644 index 0000000..9a6287a --- /dev/null +++ b/server/src/main/java/swim/ripple/RippleUiRouter.java @@ -0,0 +1,101 @@ +// Copyright 2015-2022 Swim.inc +// +// 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 swim.ripple; + +import swim.kernel.KernelProxy; +import swim.structure.Value; +import swim.uri.UriPath; +import swim.web.WebRequest; +import swim.web.WebResponse; +import swim.web.WebRoute; +import swim.web.route.ResourceDirectoryRoute; + +/** + * SwimOS kernel module for routing HTTP requests for the bundled UI. + */ +public class RippleUiRouter extends KernelProxy { + final double kernelPriority; + final WebRoute uiRoute; + + public RippleUiRouter(double kernelPriority) { + this.kernelPriority = kernelPriority; + this.uiRoute = new ResourceDirectoryRoute(getClass().getClassLoader(), UriPath.parse("ui/"), "index.html"); + } + + public RippleUiRouter() { + this(KERNEL_PRIORITY); + } + + @Override + public final double kernelPriority() { + return this.kernelPriority; + } + + @Override + public WebResponse routeRequest(WebRequest request) { + final WebResponse response = this.uiRoute.routeRequest(request); + if (response.isAccepted()) { + return response; + } else { + return super.routeRequest(request); + } + } + + @Override + public void trace(Object message) { + // Use this hook to intercept and forward trace log messages + } + + @Override + public void debug(Object message) { + // Use this hook to intercept and forward debug log messages + } + + @Override + public void info(Object message) { + super.info(message); + // Use this hook to intercept and forward info log messages + } + + @Override + public void warn(Object message) { + super.warn(message); + // Use this hook to intercept and forward warning log messages + } + + @Override + public void error(Object message) { + super.error(message); + // Use this hook to intercept and forward error log messages + } + + @Override + public void fail(Object message) { + super.fail(message); + // Use this hook to intercept and forward failure log messages + } + + private static final double KERNEL_PRIORITY = 100.0; + + public static RippleUiRouter fromValue(Value moduleConfig) { + final Value header = moduleConfig.getAttr("kernel"); + final String kernelClassName = header.get("class").stringValue(null); + if (kernelClassName == null || RippleUiRouter.class.getName().equals(kernelClassName)) { + final double kernelPriority = header.get("priority").doubleValue(KERNEL_PRIORITY); + return new RippleUiRouter(kernelPriority); + } + return null; + } +} diff --git a/server/src/main/resources/server.recon b/server/src/main/resources/server.recon index bf009b4..da53d03 100644 --- a/server/src/main/resources/server.recon +++ b/server/src/main/resources/server.recon @@ -1,5 +1,6 @@ @kernel(class: 'swim.store.db.DbStoreKernel', optional: true) @kernel(class: 'swim.reflect.ReflectKernel', optional: true) +@kernel(class: "swim.ripple.RippleUiRouter") ripple: @fabric { @plane(class: "swim.ripple.RipplePlane") @@ -14,7 +15,6 @@ ripple: @fabric { @web(port: 9001) { space: "ripple" - documentRoot: "../ui/" @websocket { serverCompressionLevel: 0# -1 = default; 0 = off; 1-9 = deflate level clientCompressionLevel: 0# -1 = default; 0 = off; 1-9 = deflate level From f3ed020b4fc0a935720fb8c4b2291f9392538e5c Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 20:22:33 -0500 Subject: [PATCH 04/10] Point to different repo for library. --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 751eba3..239924c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ -library('jenkins-pipeline@pr-2') +library('jcustenborder-jenkins-pipeline@server-ui') demoServerUiPipeline("ripple") \ No newline at end of file From ef21bcc9d0b346c5f7296b50525f4576e0f31b03 Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 20:26:49 -0500 Subject: [PATCH 05/10] Added k8s for deployment. --- k8s.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 k8s.yml diff --git a/k8s.yml b/k8s.yml new file mode 100644 index 0000000..82d87a3 --- /dev/null +++ b/k8s.yml @@ -0,0 +1,31 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: demo-ripple + namespace: demo-ripple +spec: + replicas: 1 + selector: + matchLabels: + demo: ripple + serviceName: demo + template: + metadata: + labels: + demo: ripple + spec: + containers: + - image: DOCKER_IMAGE + imagePullPolicy: Always + name: demo + ports: + - containerPort: 9001 + protocol: TCP + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: "1" + memory: 1Gi \ No newline at end of file From 2e5d02655485de541d0a9778a42b442e34860c58 Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 20:36:51 -0500 Subject: [PATCH 06/10] Refactored to use swimVersion and applicationVersion --- server/build.gradle | 7 ++++--- server/gradle.properties | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/build.gradle b/server/build.gradle index 51bdba4..517cbdf 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -24,6 +24,7 @@ version = project.property('application.version') mainClassName = 'swim.ripple.RipplePlane' ext.moduleName = 'swim.ripple' ext.compilerArgs = ['-Xlint:all'] +ext.swimVersion = project.property('swim.version') // Build with `gradle -Pno-modules` to force compatibility with legacy JVMs. def javaVersion = System.getProperty('java.version').split('\\.') @@ -36,9 +37,9 @@ repositories { } dependencies { - implementation group: 'org.swimos', name: 'swim-recon', version: version - api group: 'org.swimos', name: 'swim-api', version: version - implementation group: 'org.swimos', name: 'swim-server', version: version + implementation group: 'org.swimos', name: 'swim-recon', version: swimVersion + api group: 'org.swimos', name: 'swim-api', version: swimVersion + implementation group: 'org.swimos', name: 'swim-server', version: swimVersion } afterEvaluate { diff --git a/server/gradle.properties b/server/gradle.properties index 7bea8ad..645e15c 100644 --- a/server/gradle.properties +++ b/server/gradle.properties @@ -1 +1,2 @@ -application.version=4.0.1 +application.version=1.0.0 +swim.version=4.0.1 From 586a891f9227f35c9fcd4698ba8dff165be1bf4b Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 20:49:44 -0500 Subject: [PATCH 07/10] Refactored logic to determine url for services. --- ui/index.html | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index 0c284fc..52afa44 100644 --- a/ui/index.html +++ b/ui/index.html @@ -22,7 +22,30 @@ var host = documentUri.query().get("host"); var room = documentUri.fragmentIdentifier() || "wall"; -var hostUri = host || "warp://localhost:9001"; +const baseUri = swim.Uri.parse(document.location.href); +const hostParam = baseUri.host().toString(); +const schemeParam = baseUri.scheme().toString(); +const portParam = baseUri.port(); +const warpScheme = schemeParam === "https" ? "warps":"warp" + +let warpHost; + +if(hostParam.endsWith("swim.services")) { + warpHost = "ripple.swim.services" +} else if(hostParam.endsWith("nstream-demo.io")) { + warpHost = "ripple.services.nstream-demo.io" +} else { + warpHost = hostParam; +} + +let hostUri; + +if (portParam === undefined) { + hostUri = `${warpScheme}://${warpHost}` +} else { + hostUri = `${warpScheme}://${warpHost}:${portParam.toString()}` +} + var nodeUri = swim.UriPath.from("mirror", room).toString(); var nodeRef = swim.client.nodeRef(hostUri, nodeUri); var mirrorController = new swim.SwimMirrorViewController(nodeRef); From f1dcc533b87d5146bb8d86cabbcc4c5cd26c662a Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 21:35:28 -0500 Subject: [PATCH 08/10] Ignore resources/ui --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b9f6532..7ede5c8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ build out server/ui +server/src/main/resources/ui From d7384ab7d379c11c9beb6d3b45b469cc0788f958 Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 21:42:23 -0500 Subject: [PATCH 09/10] Added GA. --- ui/index.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui/index.html b/ui/index.html index 52afa44..a44cd00 100644 --- a/ui/index.html +++ b/ui/index.html @@ -55,5 +55,13 @@ canvas.append(mirror); + + From df46c7bce69dc8e8f30b7adf9cda0ab156d8b4cf Mon Sep 17 00:00:00 2001 From: Jeremy Custenborder Date: Wed, 10 May 2023 21:51:13 -0500 Subject: [PATCH 10/10] Move to main jenkins-pipeline. --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 239924c..2f9ffd7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ -library('jcustenborder-jenkins-pipeline@server-ui') +library('jenkins-pipeline') demoServerUiPipeline("ripple") \ No newline at end of file