# Deploy avail-api-app service [bamboo@localhost solar-travel-availability]$ gradle :avail-api:deployContainer -PimageVersion=0.0.1-DEMO -PocProjectName=fet-nfv-poc ~~~ > Configure project :avail-api Working directory: /home/bamboo/projects/solar-travel-availability > Task :avail-api:createNewProject Executing command: oc new-project fet-nfv-poc Executing command: oc project fet-nfv-poc Already on project "fet-nfv-poc" on server "https://c100-e.eu-de.containers.cloud.ibm.com:32553". > Task :avail-api:createImageSecret Skip creating Image Secret. Repository is public on quay.io, private is not free. > Task :avail-api:deleteApp Executing command: oc delete all -l app=avail-api-app No resources found > Task :avail-api:installRedisDatabase Executing command: oc new-app --docker-image redis --name redis-solar-travel-availability Executing command: oc new-app --docker-image redis --name redis-solar-travel-pubsub > Task :avail-api:createNewApp Executing command: oc project fet-nfv-poc Already on project "fet-nfv-poc" on server "https://c100-e.eu-de.containers.cloud.ibm.com:32553". Executing command: oc new-app --docker-image quay.io/solar-travel/avail-api-app:0.0.1-DEMO -e DEVELOPMENT_ENV=true -e REDIS_HOST=redis-solar-travel-availability -e IBM_S3_LOCATION=null -e IBM_S3_API_KEY=null -e IBM_S3_IAM_SERVICE_ID=null -e IBM_S3_PUBLIC_ENDPOINT=null -e RES_DATA_BUCKET_NAME=null -e RES_DATA_OBJECT_KEY=null -e REDIS_CONNECTION_STRING=redis://redis-solar-travel-availability -e REDIS_PUBSUB_CONNECTION_STRING=redis://redis-solar-travel-pubsub -e REDIS_API_KEY=null -e REDIS_PASSWORD='' -e REDIS_DEPLOYMENT_ID='' --> Found Docker image e426479 (9 days old) from quay.io for "quay.io/solar-travel/avail-api-app:0.0.1-DEMO" * An image stream tag will be created as "avail-api-app:0.0.1-DEMO" that will track this image * This image will be deployed in deployment config "avail-api-app" * Ports 9080/tcp, 9443/tcp will be load balanced by service "avail-api-app" * Other containers can access this service through the hostname "avail-api-app" --> Creating resources ... imagestream.image.openshift.io "avail-api-app" created deploymentconfig.apps.openshift.io "avail-api-app" created service "avail-api-app" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/avail-api-app' Run 'oc status' to view your app. > Task :avail-api:checkPodStatus Executing command: oc get dc avail-api-app | grep avail-api-app | cut -d' ' -f1,4,14,23 avail-api-app 1 1 0 Retry pods status checking: 0 Executing command: oc get dc avail-api-app | grep avail-api-app | cut -d' ' -f1,4,14,23 avail-api-app 1 1 1 Executing command: oc get dc avail-api-app | grep avail-api-app | cut -d' ' -f1,4,14,23 avail-api-app 1 1 1 > Task :avail-api:exposeService Executing command: oc expose service avail-api-app route.route.openshift.io/avail-api-app exposed Executing command: oc patch route/avail-api-app --patch '{"spec":{"tls":{"termination":"edge"}}}' route.route.openshift.io/avail-api-app patched > Task :avail-api:testDeployedService Executing command: oc get route | grep avail-api-app | grep -P 'avail-api-app-fet-nfv-poc.*\.(com|cloud)' -o avail-api-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud Executing command: curl -sX GET https://avail-api-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/hello Executing command: curl -sX GET https://avail-api-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/hello Hello, world Test success ---------------------------------------------------------------------------------------- > Task :avail-api:deployContainer The container has been successfully deployed. ~~~ # Deploy avail-mgnt-app service [bamboo@localhost solar-travel-availability]$ gradle :avail-mgnt:deployContainer -PimageVersion=0.0.1-DEMO -PocProjectName=fet-nfv-poc ~~~ > Configure project :avail-api Working directory: /home/bamboo/projects/solar-travel-availability > Task :avail-mgnt:createNewProject Executing command: oc new-project fet-nfv-poc > Task :avail-mgnt:createImageSecret Skip creating Image Secret. Repository is public on quay.io, private is not free. > Task :avail-mgnt:deleteApp Executing command: oc delete all -l app=avail-mgnt-app No resources found > Task :avail-mgnt:installRedisDatabase Executing command: oc new-app --docker-image redis --name redis-solar-travel-availability Executing command: oc new-app --docker-image redis --name redis-solar-travel-pubsub > Task :avail-mgnt:createNewApp Executing command: oc project fet-nfv-poc Already on project "fet-nfv-poc" on server "https://c100-e.eu-de.containers.cloud.ibm.com:32553". Executing command: oc new-app --docker-image quay.io/solar-travel/avail-mgnt-app:0.0.1-DEMO -e DEVELOPMENT_ENV=true -e REDIS_HOST=redis-solar-travel-availability -e IBM_S3_LOCATION=null -e IBM_S3_API_KEY=null -e IBM_S3_IAM_SERVICE_ID=null -e IBM_S3_PUBLIC_ENDPOINT=null -e RES_DATA_BUCKET_NAME=null -e RES_DATA_OBJECT_KEY=null -e REDIS_CONNECTION_STRING=redis://redis-solar-travel-availability -e REDIS_PUBSUB_CONNECTION_STRING=redis://redis-solar-travel-pubsub -e REDIS_API_KEY=null -e REDIS_PASSWORD='' -e REDIS_DEPLOYMENT_ID='' --> Found Docker image fde1105 (8 days old) from quay.io for "quay.io/solar-travel/avail-mgnt-app:0.0.1-DEMO" * An image stream tag will be created as "avail-mgnt-app:0.0.1-DEMO" that will track this image * This image will be deployed in deployment config "avail-mgnt-app" * Ports 9080/tcp, 9443/tcp will be load balanced by service "avail-mgnt-app" * Other containers can access this service through the hostname "avail-mgnt-app" --> Creating resources ... imagestream.image.openshift.io "avail-mgnt-app" created deploymentconfig.apps.openshift.io "avail-mgnt-app" created service "avail-mgnt-app" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/avail-mgnt-app' Run 'oc status' to view your app. > Task :avail-mgnt:checkPodStatus Executing command: oc get dc avail-mgnt-app | grep avail-mgnt-app | cut -d' ' -f1,4,14,23 avail-mgnt-app 1 1 0 Retry pods status checking: 0 Executing command: oc get dc avail-mgnt-app | grep avail-mgnt-app | cut -d' ' -f1,4,14,23 avail-mgnt-app 1 1 1 Executing command: oc get dc avail-mgnt-app | grep avail-mgnt-app | cut -d' ' -f1,4,14,23 avail-mgnt-app 1 1 1 > Task :avail-mgnt:exposeService Executing command: oc expose service avail-mgnt-app route.route.openshift.io/avail-mgnt-app exposed Executing command: oc patch route/avail-mgnt-app --patch '{"spec":{"tls":{"termination":"edge"}}}' route.route.openshift.io/avail-mgnt-app patched > Task :avail-mgnt:testDeployedService Executing command: oc get route | grep avail-mgnt-app | grep -P 'avail-mgnt-app-fet-nfv-poc.*\.(com|cloud)' -o avail-mgnt-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud Executing command: curl -sX GET https://avail-mgnt-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/hello Hello, world Test success ---------------------------------------------------------------------------------------- > Task :avail-mgnt:deployContainer The container has been successfully deployed. BUILD SUCCESSFUL in 1m 1s 9 actionable tasks: 9 executed ~~~ # Running CLI command to reload data into in-memory database [bamboo@localhost demo-scripts]$ ./reload.sh ~~~ 1d5ac0d8-0cbc-4c06-bca0-c498348d497e ~~~ [bamboo@localhost demo-scripts]$ ./wait.sh 1d5ac0d8-0cbc-4c06-bca0-c498348d497e ~~~ wait response: id=1d5ac0d8-0cbc-4c06-bca0-c498348d497e receivedTime=2020-02-17T04:19:42.597+0000 status=COMPLETE ~~~ # Calling api /trains/{trainDate}/{trainTime}/{origin}/{dest}/ai [bamboo@localhost demo-scripts]$ curl -sX GET 'https://avail-api-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/trains/20190131/2200/SUN/EAR/ai' ~~~ [{ "destinationStation": { "locationCode": "EAR" }, "originStation": { "locationCode": "SUN" }, "trainDate": "20190131", "trainTime": "2205", "train": { "trainNumber": "0295" }, "classCodes": [{ "code": "Y", "quantity": 0 }, { "code": "YF", "quantity": 0 }, { "code": "YV", "quantity": 0 }, { "code": "YW;", "quantity": 0 }] }, { "destinationStation": { "locationCode": "EAR" }, "originStation": { "locationCode": "SUN" }, "trainDate": "20190131", "trainTime": "2215", "train": { "trainNumber": "0565" }, "classCodes": [{ "code": "Y", "quantity": 0 }, { "code": "YF", "quantity": 0 }, { "code": "YV", "quantity": 0 }, { "code": "YW;", "quantity": 0 }] }, { "destinationStation": { "locationCode": "EAR" }, "originStation": { "locationCode": "SUN" }, "trainDate": "20190131", "trainTime": "2250", "train": { "trainNumber": "0567" }, "classCodes": [{ "code": "Y", "quantity": 0 }, { "code": "YF", "quantity": 0 }, { "code": "YV", "quantity": 0 }, { "code": "YW;", "quantity": 0 }] }] ~~~ # Deploy api-gateway-app [bamboo@localhost solar-travel-integration]$ gradle :api-gateway:deployContainer -PimageVersion=0.0.4-DEMO -PocProjectName=fet-nfv-poc ~~~ > Task :api-gateway:createNewProject Executing command: oc new-project fet-nfv-poc > Task :api-gateway:createImageSecret Skip creating Image Secret. Repository is public on quay.io, private is not free. > Task :api-gateway:deleteApp Executing command: oc delete all -l app=api-gateway-app pod "api-gateway-app-67bf5787f-kjh9z" deleted service "api-gateway-app" deleted replicaset.apps "api-gateway-app-67bf5787f" deleted route.route.openshift.io "api-gateway-app" deleted Executing command: oc delete serviceaccounts api-gateway-app serviceaccount "api-gateway-app" deleted Executing command: oc delete deployment api-gateway-app deployment.extensions "api-gateway-app" deleted Executing command: oc delete clusterrolebindings api-gateway-cluster-reader clusterrolebinding.authorization.openshift.io "api-gateway-cluster-reader" deleted > Task :api-gateway:createNewApp Executing command: cat api-gateway/create-api-gateway-template.yaml|sed "s/{{ ocProjectName }}/fet-nfv-poc/g;s/{{ imageVersion }}/0.0.4-DEMO/g" > api-gateway/create-api-gateway.yaml Executing command: oc create -f api-gateway/create-api-gateway.yaml serviceaccount/api-gateway-app created clusterrolebinding.authorization.openshift.io/api-gateway-cluster-reader created route.route.openshift.io/api-gateway-app created service/api-gateway-app created deployment.apps/api-gateway-app created > Task :api-gateway:checkPodStatus Executing command: oc get deployment api-gateway-app | grep api-gateway-app | cut -d' ' -f1,4,14,23 api-gateway-app 1 > Task :api-gateway:exposeService Skip exposing service, already did in the deployment yaml file > Task :api-gateway:testDeployedService Executing command: oc get route | grep api-gateway-app | grep -P 'api-gateway-app-fet-nfv-poc.*\.(com|cloud)' -o api-gateway-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud Executing command: (masked): oc serviceaccounts get-token api-gateway-app ****** Executing command: (masked): curl -H "Authorization: bearer <token>" -sX Get https://api-gateway-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/hello ****** Executing command: (masked): curl -H "Authorization: bearer <token>" -sX Get https://api-gateway-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/hello ****** Test success ---------------------------------------------------------------------------------------- > Task :api-gateway:deployContainer The container has been successfully deployed. BUILD SUCCESSFUL in 55s 8 actionable tasks: 8 executed ~~~ # Access API gateway url /hello via a web browser https://api-gateway-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/hello # Access API gateway url /management/trains/reload using Authorization Header ## Getting the token [bamboo@localhost solar-travel-integration]$ TOKEN=$(oc serviceaccounts get-token api-gateway-app) ## Use the token [bamboo@localhost solar-travel-integration]$ curl -H "Authorization: bearer $TOKEN" -sX Get https://api-gateway-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/management/trains/reload ~~~ {"id":"76afc0bf-1308-41af-9489-39b12cd3a1fe","receivedTime":"2020-02-17T04:42:41.049+0000","status":"ACCEPTED"} ~~~ # Lookup Train schedule via API gateway [bamboo@localhost solar-travel-integration]$ curl -H "Authorization: bearer $TOKEN" -sX Get 'https://api-gateway-app-fet-nfv-poc.fetnet-1579251008816-f72ef11f3ab089a8c677044eb28292cd-0001.eu-de.containers.appdomain.cloud/customers/trains?trainDate=20190131&trainTime=2200&origin=EAR&dest=SUN' ~~~ [{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2202","train":{"trainNumber":"0684"},"classCodes":[{"code":"Y","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2232","train":{"trainNumber":"0160"},"classCodes":[{"code":"Y","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2242","train":{"trainNumber":"0858"},"classCodes":[{"code":"YA","quantity":0},{"code":"Y","quantity":0},{"code":"YB","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2307","train":{"trainNumber":"0690"},"classCodes":[{"code":"Y","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2347","train":{"trainNumber":"0862"},"classCodes":[{"code":"YA","quantity":0},{"code":"Y","quantity":0},{"code":"YB","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2352","train":{"trainNumber":"0294"},"classCodes":[{"code":"YA","quantity":0},{"code":"Y","quantity":0},{"code":"YB","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]}] ~~~ # oauth-proxy sidecar deployment [bamboo@localhost solar-travel-integration]$ oc get deployments api-gateway-app -o yaml ~~~ apiVersion: extensions/v1beta1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: 2020-02-17T04:32:41Z generation: 1 name: api-gateway-app namespace: fet-nfv-poc resourceVersion: "10787232" selfLink: /apis/extensions/v1beta1/namespaces/fet-nfv-poc/deployments/api-gateway-app uid: 890ea3a3-513e-11ea-8fd4-8a83bb8e45db spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: api-gateway-app strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: app: api-gateway-app spec: containers: - args: - --https-address=:8443 - --provider=openshift - --openshift-service-account=api-gateway-app - --upstream=http://localhost:9080 - --tls-cert=/etc/tls/private/tls.crt - --tls-key=/etc/tls/private/tls.key - --cookie-secret=SECRET - --openshift-delegate-urls={"/":{"resource":"services","verb":"get","project":"fet-nfv-poc","name":"api-gateway-app"}} image: openshift/oauth-proxy:latest imagePullPolicy: IfNotPresent name: oauth-proxy ports: - containerPort: 8443 name: public protocol: TCP resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /etc/tls/private name: api-gateway-proxy-tls - env: - name: AVAILABILITY_SERVICE_NAME value: avail-api-app:9080 - name: AVAILABILITY_MGNT_SERVICE_NAME value: avail-mgnt-app:9080 - name: DEVELOPMENT_ENV value: "true" - name: IBM_S3_API_KEY value: "null" - name: IBM_S3_IAM_SERVICE_ID value: "null" - name: IBM_S3_LOCATION value: "null" - name: IBM_S3_PUBLIC_ENDPOINT value: "null" - name: RES_DATA_BUCKET_NAME value: "null" - name: RES_DATA_OBJECT_KEY value: "null" image: quay.io/solar-travel/api-gateway-app:0.0.4-DEMO imagePullPolicy: Always name: api-gateway-app-upstream resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: api-gateway-app serviceAccountName: api-gateway-app terminationGracePeriodSeconds: 30 volumes: - name: api-gateway-proxy-tls secret: defaultMode: 420 secretName: api-gateway-proxy-tls status: availableReplicas: 1 conditions: - lastTransitionTime: 2020-02-17T04:32:46Z lastUpdateTime: 2020-02-17T04:32:46Z message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type: Available - lastTransitionTime: 2020-02-17T04:32:41Z lastUpdateTime: 2020-02-17T04:32:46Z message: ReplicaSet "api-gateway-app-69fdbcf798" has successfully progressed. reason: NewReplicaSetAvailable status: "True" type: Progressing observedGeneration: 1 readyReplicas: 1 replicas: 1 updatedReplicas: 1 ~~~ # Integration Testing with Gradle docker-compose-plugin [bamboo@localhost solar-travel-integration]$ gradle api-gateway:tasks --all ~~~ > Task :api-gateway:tasks ------------------------------------------------------------ Tasks runnable from project :api-gateway ------------------------------------------------------------ Application tasks ----------------- bootRun - Runs this project as a Spring Boot application. Build tasks ----------- assemble - Assembles the outputs of this project. bootJar - Assembles an executable jar archive containing the main classes and their dependencies. build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. classes - Assembles main classes. clean - Deletes the build directory. jar - Assembles a jar archive containing the main classes. testClasses - Assembles test classes. Docker tasks ------------ composeBuild - Builds images for services of docker-compose project composeDown - Stops and removes containers of docker-compose project (only if stopContainers is set to true) composeDownForced - Stops and removes containers of docker-compose project composeLogs - Stores log output from services in containers of docker-compose project composePull - Builds and pulls images of docker-compose project composePush - Pushes images for services of docker-compose project composeUp - Builds and starts containers of docker-compose project Documentation tasks ------------------- javadoc - Generates Javadoc API documentation for the main source code. Help tasks ---------- buildEnvironment - Displays all buildscript dependencies declared in project ':api-gateway'. components - Displays the components produced by project ':api-gateway'. [incubating] dependencies - Displays all dependencies declared in project ':api-gateway'. dependencyInsight - Displays the insight into a specific dependency in project ':api-gateway'. dependencyManagement - Displays the dependency management declared in project ':api-gateway'. dependentComponents - Displays the dependent components of components in project ':api-gateway'. [incubating] help - Displays a help message. model - Displays the configuration model of project ':api-gateway'. [incubating] projects - Displays the sub-projects of project ':api-gateway'. properties - Displays the properties of project ':api-gateway'. tasks - Displays the tasks runnable from project ':api-gateway'. Verification tasks ------------------ check - Runs all checks. test - Runs the unit tests. Other tasks ----------- buildDockerImage - Build the docker image of Websphere Liberty Developer version that run the springboot app. checkPodStatus - Check the deployed pods status. compileJava - Compiles main Java source. compileTestJava - Compiles test Java source. createImageSecret - Create a secret for pulling image from the image registry. createNewApp createNewProject - Create a new Openshift project using the optional value of -PocProjectName if provided, otherwise, it is default to the parent project name. deleteApp - Delete the openshift application. deployContainer enableSpringApp - Let Liberty recognizes the Springboot app. exposeService - Make the app accessible outside the cluster by creating a service route. initConfigParameters installIBMCloudPlugin - Install IBM Cloud cr and cs plugins. integrationTest - Perform integration test with other containers. loginCloud - Login to IBM Cloud. loginOpenshift - Loging to openshift with parameter <openshiftUrl>. processResources - Processes main resources. processTestResources - Processes test resources. pushDockerImage - Push the spring boot application docker image to a Container Registry. removeDockerContainer - Remove any running api-gateway container. removeDockerImage - Remove any api-gateway-app image. testDeployedService - Test the deployed service. testDockerImage - Test the docker image created by the buildDockerImage task. validateContainer Rules ----- Pattern: clean<TaskName>: Cleans the output files of a task. Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration. Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration. BUILD SUCCESSFUL in 1s 1 actionable task: 1 executed <-------------> 0% WAITING > IDLE ~~~ ## docker-compose-plugins settings ~~~ dockerCompose { useComposeFiles = ['api-gateway-integration.yaml'] removeImages = "Local" environment.put 'AVAIL_API_VERSION', '0.0.1-SNAPSHOT' environment.put 'AVAIL_MGNT_VERSION', '0.0.1-SNAPSHOT' } dockerCompose.isRequiredBy(integrationTest) ~~~ [bamboo@localhost solar-travel-integration]$ ls api-gateway/api-gateway-integration.yaml -ls ~~~ 4 -rw-rw-r--. 1 bamboo bamboo 1384 Feb 7 12:20 api-gateway/api-gateway-integration.yaml ~~~ [bamboo@localhost solar-travel-integration]$ vi api-gateway/api-gateway-integration.yaml -R ~~~ 1 version: "3.3" 2 3 services: 4 api-gateway: 5 build: . 6 links: 7 - avail-api-app 8 - avail-mgnt-app 9 ports: 10 - "39083:9080" 11 environment: 12 - AVAILABILITY_SERVICE_NAME=avail-api-app:9080 13 - AVAILABILITY_MGNT_SERVICE_NAME=avail-mgnt-app:9080 14 15 avail-api-app: 16 image: "quay.io/solar-travel/avail-api-app:${AVAIL_API_VERSION}" 17 links: 18 - redis-solar-travel-availability 19 ports: 20 - "39081:9080" 21 environment: 22 - REDIS_CONNECTION_STRING=redis://redis-solar-travel-availability 23 - IBM_S3_LOCATION="" 24 - IBM_S3_API_KEY="" 25 - IBM_S3_IAM_SERVICE_ID="" 26 - IBM_S3_PUBLIC_ENDPOINT="" 27 - RES_DATA_BUCKET_NAME="" 28 - RES_DATA_OBJECT_KEY="" 29 30 avail-mgnt-app: 31 image: "quay.io/solar-travel/avail-mgnt-app:${AVAIL_MGNT_VERSION}" 32 links: 33 - redis-solar-travel-availability 34 - redis-solar-travel-pubsub 35 ports: 36 - "39082:9080" 37 environment: 38 - REDIS_CONNECTION_STRING=redis://redis-solar-travel-availability 39 - REDIS_PUBSUB_CONNECTION_STRING=redis://redis-solar-travel-pubsub 40 - IBM_S3_LOCATION="" 41 - IBM_S3_API_KEY="" 42 - IBM_S3_IAM_SERVICE_ID="" 43 - IBM_S3_PUBLIC_ENDPOINT="" 44 - RES_DATA_BUCKET_NAME="" 45 - RES_DATA_OBJECT_KEY="" 46 47 redis-solar-travel-availability: 48 image: redis 49 50 redis-solar-travel-pubsub: 51 image: redis ~~~ ## Grdle integrationTest task implementation ~~~ 669 task integrationTest(dependsOn: build) { 670 description = "Perform integration test with other containers." 671 672 doLast { 673 String[] ports = ["39081", "39082", "39083"] 674 for (String port : ports) { 675 sendRetry("http://localhost:$port/hello") 676 println "Connected to endpoint http://localhost:$port/hello" 677 println "----------------------------------------------------------------------------------------" 678 } 679 String result = executeCmd("curl -sX GET 'http://localhost:39083/management/trains/reload'") 680 def jsonSlurper = new groovy.json.JsonSlurper() 681 def reloadResult = jsonSlurper.parseText(result) 682 683 executeCmd("curl -sX GET 'http://localhost:39083/management/trains/waitfor/${reloadResult.id}'") 684 result = executeCmd("curl -sX GET 'http://localhost:39083/customers/trains?trainDate=20190131&trainTime=2200&origin=EAR&dest=SUN'") 685 def trains = jsonSlurper.parseText(result) 686 assert 6 == trains.size() 687 println "Total number of trains return: ${trains.size()}" 688 } 689 } ~~~ ## Running the integration Test [bamboo@rhel-7-server solar-travel-integration]$ gradle :api-gateway:integrationTest ~~~ Starting a Gradle Daemon (subsequent builds will be faster) > Task :api-gateway:composeUp redis-solar-travel-availability uses an image, skipping avail-api-app uses an image, skipping redis-solar-travel-pubsub uses an image, skipping avail-mgnt-app uses an image, skipping Building api-gateway aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-availability_1 is up-to-date aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-pubsub_1 is up-to-date aa06e167b60ece271c3dc97464aed27fapigateway_avail-api-app_1 is up-to-date aa06e167b60ece271c3dc97464aed27fapigateway_avail-mgnt-app_1 is up-to-date aa06e167b60ece271c3dc97464aed27fapigateway_api-gateway_1 is up-to-date Will use 172.20.0.1 (network aa06e167b60ece271c3dc97464aed27fapigateway_default) as host of redis-solar-travel-availability Will use 172.20.0.1 (network aa06e167b60ece271c3dc97464aed27fapigateway_default) as host of avail-api-app Will use 172.20.0.1 (network aa06e167b60ece271c3dc97464aed27fapigateway_default) as host of redis-solar-travel-pubsub Will use 172.20.0.1 (network aa06e167b60ece271c3dc97464aed27fapigateway_default) as host of avail-mgnt-app Will use 172.20.0.1 (network aa06e167b60ece271c3dc97464aed27fapigateway_default) as host of api-gateway Probing TCP socket on 172.20.0.1:39081 of service 'avail-api-app_1' TCP socket on 172.20.0.1:39081 of service 'avail-api-app_1' is ready Probing TCP socket on 172.20.0.1:39082 of service 'avail-mgnt-app_1' TCP socket on 172.20.0.1:39082 of service 'avail-mgnt-app_1' is ready Probing TCP socket on 172.20.0.1:39083 of service 'api-gateway_1' TCP socket on 172.20.0.1:39083 of service 'api-gateway_1' is ready > Task :api-gateway:integrationTest Executing command: curl -sX GET http://localhost:39081/hello Hello, world Connected to endpoint http://localhost:39081/hello ---------------------------------------------------------------------------------------- Executing command: curl -sX GET http://localhost:39082/hello Hello, world Connected to endpoint http://localhost:39082/hello ---------------------------------------------------------------------------------------- Executing command: curl -sX GET http://localhost:39083/hello Hello, world Connected to endpoint http://localhost:39083/hello ---------------------------------------------------------------------------------------- Executing command: curl -sX GET 'http://localhost:39083/management/trains/reload' {"id":"9f8b3775-1db9-4b05-9f89-7903d85f853b","receivedTime":"2020-02-17T08:18:12.400+0000","status":"ACCEPTED"} Executing command: curl -sX GET 'http://localhost:39083/management/trains/waitfor/9f8b3775-1db9-4b05-9f89-7903d85f853b' {"id":"9f8b3775-1db9-4b05-9f89-7903d85f853b","receivedTime":"2020-02-17T08:18:42.660+0000","status":"COMPLETE"} Executing command: curl -sX GET 'http://localhost:39083/customers/trains?trainDate=20190131&trainTime=2200&origin=EAR&dest=SUN' [{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2202","train":{"trainNumber":"0684"},"classCodes":[{"code":"Y","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2232","train":{"trainNumber":"0160"},"classCodes":[{"code":"Y","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2242","train":{"trainNumber":"0858"},"classCodes":[{"code":"YA","quantity":0},{"code":"Y","quantity":0},{"code":"YB","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2307","train":{"trainNumber":"0690"},"classCodes":[{"code":"Y","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2347","train":{"trainNumber":"0862"},"classCodes":[{"code":"YA","quantity":0},{"code":"Y","quantity":0},{"code":"YB","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]},{"destinationStation":{"locationCode":"SUN"},"originStation":{"locationCode":"EAR"},"trainDate":"20190131","trainTime":"2352","train":{"trainNumber":"0294"},"classCodes":[{"code":"YA","quantity":0},{"code":"Y","quantity":0},{"code":"YB","quantity":0},{"code":"YF","quantity":0},{"code":"YV","quantity":0},{"code":"YW;","quantity":0}]}] Total number of trains return: 6 > Task :api-gateway:composeDown Stopping aa06e167b60ece271c3dc97464aed27fapigateway_api-gateway_1 ... Stopping aa06e167b60ece271c3dc97464aed27fapigateway_avail-mgnt-app_1 ... Stopping aa06e167b60ece271c3dc97464aed27fapigateway_avail-api-app_1 ... Stopping aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-pubsub_1 ... Stopping aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-availability_1 ... Stopping aa06e167b60ece271c3dc97464aed27fapigateway_api-gateway_1 ... done Stopping aa06e167b60ece271c3dc97464aed27fapigateway_avail-api-app_1 ... done Stopping aa06e167b60ece271c3dc97464aed27fapigateway_avail-mgnt-app_1 ... done Stopping aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-pubsub_1 ... done Stopping aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-availability_1 ... done Removing aa06e167b60ece271c3dc97464aed27fapigateway_api-gateway_1 ... Removing aa06e167b60ece271c3dc97464aed27fapigateway_avail-mgnt-app_1 ... Removing aa06e167b60ece271c3dc97464aed27fapigateway_avail-api-app_1 ... Removing aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-pubsub_1 ... Removing aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-availability_1 ... Removing aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-availability_1 ... done Removing aa06e167b60ece271c3dc97464aed27fapigateway_avail-api-app_1 ... done Removing aa06e167b60ece271c3dc97464aed27fapigateway_api-gateway_1 ... done Removing aa06e167b60ece271c3dc97464aed27fapigateway_redis-solar-travel-pubsub_1 ... done Removing aa06e167b60ece271c3dc97464aed27fapigateway_avail-mgnt-app_1 ... done Removing network aa06e167b60ece271c3dc97464aed27fapigateway_default Removing image aa06e167b60ece271c3dc97464aed27fapigateway_api-gateway BUILD SUCCESSFUL in 1m 20s 6 actionable tasks: 3 executed, 3 up-to-date ~~~ # Jenkins Pipeline ~~~ def executeCmd(def cmd) { def output = new StringBuffer(); println "Executing command: " + cmd def process = ['bash', '-c', cmd].execute() process.waitForProcessOutput(output, output) if (process.exitValue() != 0) throw new Exception(output.toString()) println output.toString() return output.toString() } "${BUILD_NUMBER}" node { stage('Clone sources') { executeCmd "rm -r -f ${workspace}/${serviceName}" executeCmd "git config --global user.name 'George Tsang'" executeCmd "git config --global user.emai 'tsangcc@tw.ibm.com'" withCredentials([string(credentialsId: 'jenkins-ibm-git-repo-key', variable: 'IBM_GIT_REPO_KEY')]) { executeCmd "git clone --single-branch --branch $branch https://${IBM_GIT_REPO_KEY}@github.ibm.com/tsangcc/solar-travel-integration.git ${workspace}/${serviceName}" } //executeCmd "sudo chown -R jenkins:jenkins ${workspace}/avail-api-app" } stage('Compile and Test service application') { dir("${WORKSPACE}/${serviceName}") { def statusCode = sh label: '', returnStatus: true, script: './gradlew clean && ./gradlew ${serviceName}:build' if (statusCode != 0) throw new Exception("Failed to build container image.") } } stage('Build Container Image') { dir("${WORKSPACE}/${serviceName}") { def statusCode = sh label: '', returnStatus: true, script: './gradlew -PimageVersion=${imageVersion}.${BUILD_NUMBER}-${imageTagName} :${serviceName}:buildDockerImage' if (statusCode != 0) throw new Exception("Failed to build container image.") } } stage('Test Container Image') { dir("${WORKSPACE}/${serviceName}") { def statusCode = sh label: '', returnStatus: true, script: './gradlew -PimageVersion=${imageVersion}.${BUILD_NUMBER}-${imageTagName} :${serviceName}:testDockerImage' if (statusCode != 0) throw new Exception("Failed to test container image.") } } stage('Validate and Push Container Image') { dir("${WORKSPACE}/${serviceName}") { withCredentials([string(credentialsId: 'jenkins-docker-password', variable: 'dockerPassword')]) { def statusCode = sh label: '', returnStatus: true, script: './gradlew -PimageVersion=${imageVersion}.${BUILD_NUMBER}-${imageTagName} -PdockerUser=gtsang -PdockerPassword=$dockerPassword -PdockerImageRegistryUrl=$DOCKER_IMAGE_REGISTRY_URL -PdockerImageNamespace=$DOCKER_IMAGE_NAMESPACE :${serviceName}:validateContainer' if (statusCode != 0) throw new Exception("Failed to validate container image.") } } } stage('Deploy Container to OpenShift') { dir("${WORKSPACE}/${serviceName}") { withCredentials([string(credentialsId: 'jenkins-openshift-login-token', variable: 'token')]) { executeCmd "oc login $ocHost --token=$token --insecure-skip-tls-verify" } def statusCode = sh label: '', returnStatus: true, script: './gradlew -PimageVersion=${imageVersion}.${BUILD_NUMBER}-${imageTagName} -Ptls-termination=edge -PocProjectName=$ocProjectName -PdockerImageRegistryUrl=$DOCKER_IMAGE_REGISTRY_URL -PdockerImageNamespace=$DOCKER_IMAGE_NAMESPACE :${serviceName}:deployContainer' executeCmd "oc logout" if (statusCode != 0) throw new Exception("Failed to deploy container") } } } ~~~ ## Jenkins Build with Parameters setting example ![](jenkins1.png) ## Jenkins Build result ![](jenkins2.png)