├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── DEVELOPING.md ├── Dockerfile.builder ├── LICENSE ├── README.md ├── checkstyle └── checkstyle-suppressions.xml ├── cloudbuild.yaml ├── java-runtimes-common ├── README.md ├── mvn-gcloud-image │ └── Dockerfile └── test-spring-application │ ├── README.md │ ├── pom.xml │ └── src │ └── main │ ├── appengine │ └── app.yaml │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── google │ │ └── cloud │ │ └── runtimes │ │ ├── Application.java │ │ ├── DeploymentTokenController.java │ │ ├── ExceptionController.java │ │ ├── HelloController.java │ │ ├── LoggingTestController.java │ │ ├── MonitoringTestController.java │ │ ├── config │ │ └── GcpConfiguration.java │ │ └── stackdriver │ │ └── StackDriverMonitoringService.java │ ├── kubernetes │ └── openjdk-spring-boot.yaml.in │ └── resources │ └── application.properties ├── openjdk-common ├── pom.xml └── src │ └── main │ ├── assembly │ └── assembly.xml │ └── docker │ ├── docker-entrypoint.bash │ ├── setup-env.d │ ├── 05-utils.bash │ ├── 10-platform-env.bash │ ├── 25-profiler-env.bash │ └── 30-java-env.bash │ ├── shutdown │ ├── shutdown-env.bash │ └── shutdown-wrapper.bash │ └── sid.list ├── openjdk-test-common ├── pom.xml └── src │ ├── main │ └── assembly │ │ └── assembly.xml │ └── test │ └── resources │ ├── structure.yaml │ └── workspace │ ├── entrypoint-args-only.bash │ ├── entrypoint-default.bash │ ├── entrypoint-setup.bash │ ├── setup-java.bash │ ├── setup-platform.bash │ ├── setup-profiler.bash │ ├── shutdown-env.bash │ └── test-denylisted-pkgs.bash ├── openjdk11 ├── pom.xml └── src │ ├── main │ └── docker │ │ └── Dockerfile │ └── test │ └── resources │ ├── jdk11-compilation-test │ ├── .gitignore │ ├── com.google.greetings │ │ ├── com │ │ │ └── google │ │ │ │ └── greetings │ │ │ │ └── Main.java │ │ └── module-info.java │ ├── com.google.world │ │ ├── com │ │ │ └── google │ │ │ │ └── world │ │ │ │ └── World.java │ │ └── module-info.java │ └── compile-and-run.sh │ └── openjdk11-structure.yaml ├── openjdk8 ├── pom.xml └── src │ ├── main │ └── docker │ │ └── Dockerfile │ └── test │ └── resources │ └── openjdk8-structure.yaml ├── pom.xml └── scripts ├── ae_integration_test.sh ├── build.sh ├── ci-build.sh ├── deploy-check-openjdk8.sh ├── gcloud-init.sh ├── gke_cluster_cleanup.yaml ├── gke_integration_test.sh ├── integration_test.sh ├── integration_test.yaml ├── integration_test_cleanup.yaml ├── local_runtimes_common_integration_test.sh ├── local_shutdown_test.sh ├── release-openjdk.sh └── structure_test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # docker specific 2 | docker/lib/ 3 | docker/jetty/ 4 | 5 | # maven 6 | target 7 | *.versionsBackup 8 | *.releaseBackup 9 | 10 | # common junk 11 | *.log 12 | *.diff 13 | *.patch 14 | *.sw[a-z0-9] 15 | *.bak 16 | *.backup 17 | *.debug 18 | *.dump 19 | *~ 20 | ~* 21 | 22 | # eclipse 23 | .project 24 | .settings 25 | .classpath 26 | 27 | # intellij / idea 28 | *.iml 29 | *.ipr 30 | *.iws 31 | .idea 32 | 33 | # netbeans 34 | /nbproject 35 | 36 | # Mac filesystem dust 37 | .DS_Store 38 | 39 | # merge tooling 40 | *.orig 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | sudo: required 16 | 17 | language: java 18 | 19 | services: 20 | - docker 21 | 22 | jdk: 23 | - oraclejdk8 24 | 25 | # skip the install step 26 | install: true 27 | script: mvn --batch-mode clean verify 28 | 29 | branches: 30 | only: 31 | - master 32 | 33 | dist: trusty 34 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to become a contributor and submit your own code 2 | 3 | ## Contributor License Agreements 4 | 5 | We'd love to accept your patches! Before we can take them, we have to jump a couple of legal hurdles. 6 | 7 | Please fill out either the individual or corporate Contributor License Agreement (CLA). 8 | 9 | * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). 10 | * If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). 11 | 12 | Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to accept your pull requests. 13 | 14 | ## Contributing A Patch 15 | 16 | 1. Submit an issue describing your proposed change to the repo in question. 17 | 1. The repo owner will respond to your issue promptly. 18 | 1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above). 19 | 1. Fork the desired repo, develop and test your code changes. 20 | 1. Submit a pull request. 21 | -------------------------------------------------------------------------------- /DEVELOPING.md: -------------------------------------------------------------------------------- 1 | # Developing 2 | 3 | This document contains instructions on how to build and test this image. 4 | 5 | # Building the image 6 | 7 | ### Local build 8 | To build the image you need git, docker (your user needs to be part of the ``docker`` group to run docker without sudo) and maven installed: 9 | ``` 10 | $ git clone https://github.com/GoogleCloudPlatform/openjdk-runtime.git 11 | $ cd openjdk-runtime 12 | 13 | # build all images 14 | $ mvn clean install 15 | 16 | # only build the openjdk:8 image 17 | $ mvn clean install --also-make --projects openjdk8 18 | 19 | # only build the openjdk:11 image 20 | $ mvn clean install --also-make --projects openjdk11 21 | ``` 22 | These commands build the `openjdk` image with tags for each JDK version (`openjdk:8` and `openjdk:11`). 23 | 24 | ### Cloud build 25 | To build using the [Google Cloud Container Builder](https://cloud.google.com/container-builder/docs/overview), 26 | you need to have the [Google Cloud SDK](https://cloud.google.com/sdk/) installed locally. We provide a script to make this more convenient. 27 | ``` 28 | # the following commands will build and push an image named "gcr.io/my-project/openjdk:8" 29 | $ PROJECT_ID=my-project 30 | $ MODULE_TO_BUILD=openjdk8 # only builds the openjdk:8 image 31 | $ ./scripts/build.sh -p $PROJECT_ID -m $MODULE_TO_BUILD 32 | ``` 33 | 34 | If you would like to simulate the cloud build locally, pass in the `--local` argument. 35 | ``` 36 | $ PROJECT_ID=my-project 37 | $ MODULE_TO_BUILD=openjdk8 # only builds the openjdk:8 image 38 | $ ./scripts/build.sh -p $PROJECT_ID -m $MODULE_TO_BUILD --local 39 | ``` 40 | 41 | The configured Cloud Build execution will build the OpenJDK docker container, then create and teardown various GCP resources for integration testing. 42 | Before running, make sure you have done all of the following: 43 | 44 | * enabled the Cloud Container Builder API 45 | * initialized App Engine for your GCP project (run `gcloud app create`), and successfully deployed at least once 46 | * provided the Container Builder Service account (cloudbuild.gserviceaccount.com) with the appropriate permissions needed to deploy App Engine applications and create GKE clusters. 47 | * This includes at least the "App Engine Admin" and "Cloud Container Builder" roles, but simply adding the "Project Editor" role works fine as well. 48 | 49 | # Running Tests 50 | Integration tests can be run via [Google Cloud Container Builder](https://cloud.google.com/container-builder/docs/overview). 51 | These tests deploy a sample test application to App Engine and to Google Kubernetes Engine using the provided runtime image, and 52 | exercise various integrations with other GCP services. Note that the image under test must be pushed 53 | to a gcr.io repository before the integration tests can run. 54 | 55 | ```bash 56 | $ RUNTIME_IMAGE=gcr.io/my-project-id/openjdk:my-tag 57 | $ gcloud docker -- push $RUNTIME_IMAGE 58 | ``` 59 | 60 | **Run ALL integration tests (Local Docker, App Engine, Google Kubernetes Engine):** 61 | ```bash 62 | $ ./scripts/integration_test.sh $RUNTIME_IMAGE 63 | ``` 64 | 65 | **Run ONLY Local Docker integration tests:** 66 | ```bash 67 | $ ./scripts/local_runtimes_common_integration_test.sh $RUNTIME_IMAGE 68 | ``` 69 | 70 | **Run ONLY Local shutdown tests:** 71 | ```bash 72 | $ ./scripts/local_shutdown_test.sh $RUNTIME_IMAGE 73 | ``` 74 | 75 | 76 | **Run ONLY App Engine flexible environment integration tests:** 77 | ```bash 78 | $ ./scripts/ae_integration_test.sh $RUNTIME_IMAGE 79 | ``` 80 | 81 | **Run ONLY Kubernetes Engine (GKE) integration tests:** 82 | ```bash 83 | $ ./scripts/gke_integration_test.sh $RUNTIME_IMAGE 84 | ``` 85 | -------------------------------------------------------------------------------- /Dockerfile.builder: -------------------------------------------------------------------------------- 1 | FROM gcr.io/cloud-builders/javac 2 | ARG MAVEN_VERSION=3.5.0 3 | ARG USER_HOME_DIR="/root" 4 | ARG SHA=beb91419245395bd69a4a6edad5ca3ec1a8b64e41457672dc687c173a495f034 5 | ARG BASE_URL=https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries 6 | 7 | RUN apt-get update -qqy && apt-get install -qqy curl \ 8 | && mkdir -p /usr/share/maven /usr/share/maven/ref \ 9 | && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-$MAVEN_VERSION-bin.tar.gz \ 10 | && echo "${SHA} /tmp/apache-maven.tar.gz" | sha256sum -c - \ 11 | && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \ 12 | && rm -f /tmp/apache-maven.tar.gz \ 13 | && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn \ 14 | # clean up build packages 15 | && apt-get remove -qqy --purge curl \ 16 | && rm /var/lib/apt/lists/*_* 17 | 18 | ENV M2_HOME /usr/share/maven 19 | 20 | ENTRYPOINT ["mvn"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Google Cloud Platform OpenJDK Docker Image 3 | 4 | This repository contains the source for the Google-maintained OpenJDK [docker](https://docker.com) image. This image can be used as the base image for running Java applications on [Google App Engine Flexible Environment](https://cloud.google.com/appengine/docs/flexible/java/) and [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine). 5 | 6 | ## Repository/Tag Details 7 | Supported images/tags include: 8 | * `gcr.io/google-appengine/openjdk:8` 9 | 10 | ## App Engine Flexible Environment 11 | When using App Engine Flexible, you can use the runtime without worrying about Docker by specifying `runtime: java` in your `app.yaml`: 12 | ```yaml 13 | runtime: java 14 | env: flex 15 | ``` 16 | The runtime image `gcr.io/google-appenine/openjdk:8` will be automatically selected if you are attempting to deploy a JAR (`*.jar` file). 17 | 18 | To select a jdk version, use the `runtime_config.jdk` field in app.yaml. Supported JDK versions include `openjdk8` and `openjdk11`. 19 | ```yaml 20 | runtime: java 21 | env: flex 22 | runtime_config: 23 | jdk: openjdk8 24 | ``` 25 | 26 | If you want to use the image as a base for a custom runtime, you can specify `runtime: custom` in your `app.yaml` and then 27 | write the Dockerfile like this: 28 | 29 | ```dockerfile 30 | FROM gcr.io/google-appengine/openjdk 31 | COPY your-application.jar $APP_DESTINATION 32 | ``` 33 | 34 | That will add the JAR in the correct location for the Docker container. 35 | 36 | Once you have this configuration, you can use the Google Cloud SDK to deploy this directory containing the 2 configuration files and the JAR using: 37 | ``` 38 | gcloud app deploy app.yaml 39 | ``` 40 | 41 | ## Kubernetes Engine & other Docker hosts 42 | For other Docker hosts, you'll need to create a Dockerfile based on this image that copies your application code and installs dependencies. For example: 43 | 44 | ```dockerfile 45 | FROM gcr.io/google-appengine/openjdk 46 | COPY your-application.jar $APP_DESTINATION 47 | ``` 48 | You can then build the docker container using `docker build` or [Google Cloud Container Builder](https://cloud.google.com/container-builder/docs/). 49 | By default, the CMD is set to run the application JAR. You can change this by specifying your own `CMD` or `ENTRYPOINT`. 50 | 51 | ### Container Memory Limits 52 | The runtime will try to detect the container memory limit by looking at the `/sys/fs/cgroup/memory/memory.limit_in_bytes` file, which is automatically mounted by Docker. However, this may not work with other container runtimes. In those cases, to help the runtime compute accurate JVM memory defaults when running on Kubernetes, you can indicate memory limit through the [Downward API](https://kubernetes.io/docs/tasks/configure-pod-container/environment-variable-expose-pod-information). 53 | 54 | To do so add an environment variable named `KUBERNETES_MEMORY_LIMIT` *(This name is subject to change)* with the value `limits.memory` and the name of your container. 55 | For example: 56 | 57 | ```yaml 58 | apiVersion: v1 59 | kind: Pod 60 | metadata: 61 | name: dapi-envars-resourcefieldref 62 | spec: 63 | containers: 64 | - name: java-kubernetes-container 65 | image: gcr.io/google-appengine/openjdk 66 | resources: 67 | requests: 68 | memory: "32Mi" 69 | limits: 70 | memory: "64Mi" 71 | env: 72 | - name: KUBERNETES_MEMORY_LIMIT 73 | valueFrom: 74 | resourceFieldRef: 75 | containerName: java-kubernetes-container 76 | resource: limits.memory 77 | ``` 78 | 79 | ## The Default Entry Point 80 | Any arguments passed to the entry point that are not executable are treated as arguments to the java command: 81 | ``` 82 | $ docker run openjdk -jar /usr/share/someapplication.jar 83 | ``` 84 | 85 | Any arguments passed to the entry point that are executable replace the default command, thus a shell could 86 | be run with: 87 | ``` 88 | > docker run -it --rm openjdk bash 89 | root@c7b35e88ff93:/# 90 | ``` 91 | 92 | ## Entry Point Features 93 | The entry point for the openjdk8 image is [docker-entrypoint.bash](https://github.com/GoogleCloudPlatform/openjdk-runtime/blob/master/openjdk-common/src/main/docker/docker-entrypoint.bash), which does the processing of the passed command line arguments to look for an executable alternative or arguments to the default command (java). 94 | 95 | If the default command (java) is used, then the entry point sources the [setup-env.d/](https://github.com/GoogleCloudPlatform/openjdk-runtime/tree/master/openjdk-common/src/main/docker/setup-env.d), which looks for supported features to be enabled and/or configured. The following table indicates the environment variables that may be used to enable/disable/configure features, any default values if they are not set: 96 | 97 | |Env Var | Description | Type | Default | 98 | |------------------------------------|---------------------|----------|---------------------------------------------| 99 | |`PROFILER_ENABLE` | Stackdriver Profiler| boolean | `false` | 100 | |`TMPDIR` | Temporary Directory | dirname | | 101 | |`JAVA_TMP_OPTS` | JVM tmpdir args | JVM args | `-Djava.io.tmpdir=${TMPDIR}` | 102 | |`GAE_MEMORY_MB` | Available memory | size | Set by GAE or `/proc/meminfo`-400M | 103 | |`HEAP_SIZE_RATIO` | Memory for the heap | percent | 80 | 104 | |`HEAP_SIZE_MB` | Available heap | size | `${HEAP_SIZE_RATIO}`% of `${GAE_MEMORY_MB}` | 105 | |`JAVA_HEAP_OPTS` | JVM heap args | JVM args | `-Xms${HEAP_SIZE_MB}M -Xmx${HEAP_SIZE_MB}M` | 106 | |`JAVA_GC_OPTS` | JVM GC args | JVM args | `-XX:+UseG1GC` plus configuration | 107 | |`JAVA_USER_OPTS` | JVM other args | JVM args | | 108 | |`JAVA_OPTS` | JVM args | JVM args | See below | 109 | |`SHUTDOWN_LOGGING_THREAD_DUMP` | Shutdown thread dump| boolean | `false` | 110 | |`SHUTDOWN_LOGGING_HEAP_INFO` | Shutdown heap info | boolean | `false` | 111 | |`SHUTDOWN_LOGGING_SAMPLE_THRESHOLD` | Shutdown sampling | percent | 100 | 112 | 113 | If not explicitly set, `JAVA_OPTS` is defaulted to 114 | ``` 115 | JAVA_OPTS:=-showversion \ 116 | ${JAVA_TMP_OPTS} \ 117 | ${PROFILER_AGENT} \ 118 | ${JAVA_HEAP_OPTS} \ 119 | ${JAVA_GC_OPTS} \ 120 | ${JAVA_USER_OPTS} 121 | ``` 122 | 123 | The command line executed is effectively (where $@ are the args passed into the docker entry point): 124 | ``` 125 | java $JAVA_OPTS "$@" 126 | ``` 127 | 128 | ### JVM Shutdown Diagnostics 129 | 130 | This feature is not enabled by default. 131 | 132 | Sometimes it's necessary to obtain diagnostic information when the JVM is stopped using `SIGTERM` or `docker stop`. 133 | This may happen on App Engine flexible environment, when the autohealer decides to kill unhealthy VMs that have 134 | an app that is unresponsive due to a deadlock or high load and stopped returning requests, including health checks. 135 | 136 | To help diagnose such situations the runtime provides support for outputting a thread dump and/or 137 | heap info upon JVM shutdown forced by the `TERM` signal. 138 | 139 | The following environment variables should be used to enable app container shutdown reporting (must be set to `true` or `false`): 140 | 141 | `SHUTDOWN_LOGGING_THREAD_DUMP` - output thread dump 142 | 143 | `SHUTDOWN_LOGGING_HEAP_INFO` - output heap information 144 | 145 | If enabled, the runtime provides a wrapper for the JVM that traps `SIGTERM`, and runs debugging tools on the JVM 146 | to emit the thread dump and heap information to stdout. 147 | 148 | If you're running many VMs, sampling is supported by using the environment variable `SHUTDOWN_LOGGING_SAMPLE_THRESHOLD` 149 | which is an integer between 0 and 100. 0 means no VMs report logs, 100 means all VMs report logs. 150 | (If this env var is not set, we default to reporting for all VMs). 151 | 152 | ## The Default Command 153 | The default command will attempt to run `app.jar` in the current working directory. 154 | It's equivalent to: 155 | ``` 156 | $ docker run openjdk java -jar app.jar 157 | Error: Unable to access jarfile app.jar 158 | ``` 159 | The error is normal because the default command is designed for child containers that have a Dockerfile definition like this: 160 | ``` 161 | FROM openjdk 162 | ADD my_app_0.0.1.jar app.jar 163 | ``` 164 | # Development Guide 165 | 166 | * See [instructions](DEVELOPING.md) on how to build and test this image. 167 | 168 | # Contributing changes 169 | 170 | * See [CONTRIBUTING.md](CONTRIBUTING.md) 171 | 172 | ## Licensing 173 | 174 | * See [LICENSE.md](LICENSE) 175 | -------------------------------------------------------------------------------- /checkstyle/checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | # Cloud Builder pipeline 2 | # https://cloud.google.com/container-builder/docs/overview 3 | 4 | steps: 5 | # Build the openjdk image 6 | - name: gcr.io/cloud-builders/docker 7 | args: ['build', '.', '-f', 'Dockerfile.builder', '-t', 'builder'] 8 | - name: 'builder' 9 | args: 10 | - 'clean' 11 | - 'install' 12 | - '--batch-mode' 13 | - '-Ddocker.image.name=${_IMAGE}' 14 | # only build the specified module 15 | - '--projects=${_MODULE}' 16 | - '--also-make' 17 | id: 'MVN_PACKAGE' 18 | 19 | # temporarily this test is turned off while we restructure the testing infrastructure, to enable 20 | # quicker release process 21 | 22 | ## Tag and push the openjdk image to a staging repository for integration testing 23 | #- name: 'gcr.io/cloud-builders/docker' 24 | # args: ['tag', '${_IMAGE}', '${_STAGING_IMAGE}'] 25 | # id: 'TAG_STAGING_IMG' 26 | #- name: 'gcr.io/cloud-builders/docker' 27 | # args: ['push', '${_STAGING_IMAGE}'] 28 | # id: 'PUSH_STAGING_IMG' 29 | # 30 | ## Build a 'builder' image for running integration tests 31 | #- name: 'gcr.io/cloud-builders/docker' 32 | # args: ['build', '--tag=mvn-gcloud', 'java-runtimes-common/mvn-gcloud-image'] 33 | # waitFor: ['-'] 34 | # id: 'BUILD_MVN_GCLOUD' 35 | # 36 | ## Execute integration tests 37 | #- name: 'mvn-gcloud' 38 | # entrypoint: 'scripts/integration_test.sh' 39 | # args: ['${_STAGING_IMAGE}'] 40 | # id: 'INTEGRATION_TEST' 41 | 42 | images: ['${_IMAGE}'] 43 | -------------------------------------------------------------------------------- /java-runtimes-common/README.md: -------------------------------------------------------------------------------- 1 | # Java Runtimes Common 2 | 3 | This module contains code that is common across multiple java runtimes. -------------------------------------------------------------------------------- /java-runtimes-common/mvn-gcloud-image/Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile for building a test container that includes java, maven, and the Google Cloud SDK. 2 | # This is intended to be used as part of a Google Cloud Container Builder build. 3 | 4 | FROM gcr.io/cloud-builders/mvn:3.3.9-jdk-8 5 | 6 | ARG CLOUD_SDK_VERSION=172.0.0 7 | 8 | RUN apt-get -y update && \ 9 | apt-get -y install gcc python2.7 python-dev python-setuptools curl wget ca-certificates gettext-base && \ 10 | 11 | # Setup Google Cloud SDK (latest) 12 | mkdir -p /builder && \ 13 | wget -qO- "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz" | tar zxv -C /builder && \ 14 | CLOUDSDK_PYTHON="python2.7" /builder/google-cloud-sdk/install.sh \ 15 | --usage-reporting=false \ 16 | --bash-completion=false \ 17 | --disable-installation-options && \ 18 | 19 | /builder/google-cloud-sdk/bin/gcloud config set component_manager/disable_update_check 1 && \ 20 | 21 | # Kubernetes configuration 22 | /builder/google-cloud-sdk/bin/gcloud config set compute/zone us-east1-b && \ 23 | /builder/google-cloud-sdk/bin/gcloud components install kubectl -q 24 | 25 | ENV PATH=/builder/google-cloud-sdk/bin/:$PATH 26 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/README.md: -------------------------------------------------------------------------------- 1 | # Test Application 2 | 3 | This is a test application to be used in testing the Java Runtimes containers. It implements a set 4 | of http endpoints which exercise integrations with various Stackdriver APIs, in line with the 5 | [Runtimes-common integration test framework](https://github.com/GoogleCloudPlatform/runtimes-common/tree/master/integration_tests#tests). 6 | 7 | The test application is a simple [Spring Boot](https://projects.spring.io/spring-boot/) application, 8 | which can be built in several different ways. 9 | 10 | ## Supported profiles 11 | ### Runtime staging profiles 12 | Runtime staging profiles can be mixed & matched with deployment profiles. 13 | 14 | **Java runtime profile (default)** - prepares files in the `target/deploy` directory for deployment to the default Java runtime on App Engine Flexible: 15 | ```bash 16 | mvn install -Pruntime.java 17 | ``` 18 | **Custom runtime profile** - prepares files in the `target/deploy` directory for deployment to a custom runtime on App Engine Flexible: 19 | - When using this profile, the `app.deploy.image` property must be specified as well. 20 | ```bash 21 | mvn install -Pruntime.custom -Dapp.deploy.image=gcr.io/google-appengine/openjdk 22 | ``` 23 | 24 | ### Deployment profiles 25 | Deployment profiles can be mixed & matched with runtime staging profiles. 26 | 27 | **JAR deployment profile (default)** - packages the application as an executable JAR that embeds a web server. 28 | ```bash 29 | mvn install -Pdeploy.jar 30 | ``` 31 | **WAR deployment profile** - packages the application as a WAR file that can be deployed to a web server instance. 32 | ```bash 33 | mvn install -Pdeploy.war 34 | ``` 35 | 36 | 37 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.google.cloud.runtimes 8 | test-spring-application 9 | 1.0.0 10 | ${packaging.type} 11 | 12 | Test Spring application for java runtimes 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.1.RELEASE 18 | 19 | 20 | 21 | UTF-8 22 | UTF-8 23 | 1.8 24 | ${java.version} 25 | ${java.version} 26 | default_deployment_token 27 | jar 28 | java 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-web 35 | 36 | 37 | com.google.cloud 38 | google-cloud-monitoring 39 | 0.22.0-alpha 40 | 41 | 42 | com.google.cloud 43 | google-cloud-logging 44 | 1.4.0 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | app 55 | ${project.build.directory}/deploy 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-resources-plugin 61 | 3.0.2 62 | 63 | 64 | copy-app-yaml 65 | prepare-package 66 | 67 | copy-resources 68 | 69 | 70 | ${project.build.directory}/deploy 71 | 72 | 73 | ${basedir}/src/main/appengine 74 | true 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | deploy.jar 87 | 88 | true 89 | 90 | 91 | jar 92 | 93 | 94 | 95 | deploy.war 96 | 97 | war 98 | 99 | 100 | 101 | org.springframework.boot 102 | spring-boot-starter-tomcat 103 | provided 104 | 105 | 106 | 107 | 108 | 109 | runtime.custom 110 | 111 | true 112 | 113 | 114 | custom 115 | 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-resources-plugin 121 | 3.0.2 122 | 123 | 124 | copy-resources 125 | prepare-package 126 | 127 | copy-resources 128 | 129 | 130 | ${project.build.directory}/deploy 131 | 132 | 133 | ${basedir}/src/main/docker 134 | true 135 | 136 | 137 | ${basedir}/src/main/kubernetes 138 | false 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | runtime.java 151 | 152 | java 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/appengine/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: @app.deploy.runtime@ 2 | env: flex 3 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM @app.deploy.image@ 2 | ADD app.jar app.jar 3 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/Application.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.support.SpringBootServletInitializer; 7 | 8 | @SpringBootApplication 9 | public class Application extends SpringBootServletInitializer { 10 | public static void main(String[] args) { 11 | SpringApplication.run(Application.class, args); 12 | } 13 | 14 | @Override 15 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 16 | return application.sources(Application.class); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/DeploymentTokenController.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import static org.springframework.web.bind.annotation.RequestMethod.GET; 8 | 9 | @RestController 10 | public class DeploymentTokenController { 11 | 12 | @Value("${deployment.token}") 13 | private String deploymentToken; 14 | 15 | @RequestMapping(path = "/deployment.token", method = GET) 16 | public String deploymentToken() { 17 | return deploymentToken; 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/ExceptionController.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes; 2 | 3 | import org.springframework.web.bind.annotation.RequestBody; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import static org.springframework.web.bind.annotation.RequestMethod.POST; 8 | 9 | @RestController 10 | public class ExceptionController { 11 | 12 | static class ExceptionRequest { 13 | public String token; 14 | } 15 | 16 | @RequestMapping(path = "/exception", method = POST) 17 | public void exception(@RequestBody ExceptionRequest request) { 18 | // Print a stack trace to stdout. This should be automatically registered to stackdriver error 19 | // reporting. 20 | new RuntimeException("Sample runtime exception for testing. Token from test driver request: " 21 | + request.token).printStackTrace(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | import static org.springframework.web.bind.annotation.RequestMethod.GET; 7 | 8 | @RestController 9 | public class HelloController { 10 | 11 | @RequestMapping(path = "/", method = GET) 12 | public String hello() { 13 | return "Hello World!"; 14 | } 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/LoggingTestController.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes; 2 | 3 | import com.google.cloud.MonitoredResource; 4 | import com.google.cloud.logging.LogEntry; 5 | import com.google.cloud.logging.Logging; 6 | import com.google.cloud.logging.Payload; 7 | import com.google.cloud.logging.Severity; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Lazy; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.logging.Logger; 18 | 19 | import static org.springframework.web.bind.annotation.RequestMethod.POST; 20 | 21 | @RestController 22 | public class LoggingTestController { 23 | 24 | @Autowired 25 | @Lazy 26 | private Logging logging; 27 | 28 | private static Logger LOG = Logger.getLogger(LoggingTestController.class.getName()); 29 | 30 | public static class LoggingTestRequest { 31 | private String level; 32 | private String log_name; 33 | private String token; 34 | 35 | public void setLevel(String level) { 36 | this.level = level; 37 | } 38 | 39 | public void setLog_name(String log_name) { 40 | this.log_name = log_name; 41 | } 42 | 43 | public void setToken(String token) { 44 | this.token = token; 45 | } 46 | 47 | 48 | @Override 49 | public String toString() { 50 | return "LoggingTestRequest{" + 51 | "level='" + level + '\'' + 52 | ", log_name='" + log_name + '\'' + 53 | ", token='" + token + '\'' + 54 | '}'; 55 | } 56 | } 57 | 58 | @RequestMapping(path = "/logging_custom", method = POST) 59 | public String handleLoggingTestRequest(@RequestBody LoggingTestRequest loggingTestRequest) throws IOException, InterruptedException { 60 | LOG.info(String.valueOf(loggingTestRequest)); 61 | 62 | List entries = new ArrayList<>(); 63 | Payload.StringPayload payload = Payload.StringPayload.of(loggingTestRequest.token); 64 | Severity severity = Severity.valueOf(loggingTestRequest.level); 65 | LogEntry entry = LogEntry.newBuilder(payload) 66 | .setSeverity(severity) 67 | .setLogName(loggingTestRequest.log_name) 68 | .setResource(MonitoredResource.newBuilder("global").build()) 69 | .build(); 70 | entries.add(entry); 71 | logging.write(entries); 72 | LOG.info("Log written to StackDriver: " + entries); 73 | return "OK"; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/MonitoringTestController.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes; 2 | 3 | import com.google.cloud.runtimes.stackdriver.StackDriverMonitoringService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.context.annotation.Lazy; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import java.io.IOException; 12 | import java.util.logging.Logger; 13 | 14 | import static org.springframework.web.bind.annotation.RequestMethod.POST; 15 | 16 | @RestController 17 | public class MonitoringTestController { 18 | 19 | @Autowired 20 | @Lazy 21 | private StackDriverMonitoringService stackDriverMonitoringService; 22 | 23 | @Autowired 24 | @Qualifier("projectId") 25 | private String projectId; 26 | 27 | private static Logger LOG = Logger.getLogger(MonitoringTestController.class.getName()); 28 | 29 | public static class MonitoringTestRequest { 30 | private String name; 31 | private Long token; 32 | 33 | public void setToken(Long token) { 34 | this.token = token; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "MonitoringTestRequest{" + 44 | "name='" + name + '\'' + 45 | ", token=" + token + 46 | '}'; 47 | } 48 | } 49 | 50 | @RequestMapping(path = "/monitoring", method = POST) 51 | public String handleMonitoringRequest(@RequestBody MonitoringTestRequest monitoringTestRequest) throws IOException, InterruptedException { 52 | LOG.info(String.valueOf(monitoringTestRequest)); 53 | 54 | stackDriverMonitoringService.createMetricAndInsertTestToken(projectId, 55 | monitoringTestRequest.name, 56 | monitoringTestRequest.token); 57 | 58 | return "OK"; 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/config/GcpConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes.config; 2 | 3 | import com.google.cloud.logging.Logging; 4 | import com.google.cloud.logging.LoggingOptions; 5 | import com.google.cloud.monitoring.v3.MetricServiceClient; 6 | import com.google.cloud.monitoring.v3.MetricServiceSettings; 7 | import com.google.cloud.monitoring.v3.stub.MetricServiceStub; 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Lazy; 12 | 13 | import java.io.IOException; 14 | 15 | import static com.google.cloud.ServiceOptions.getDefaultProjectId; 16 | 17 | @Configuration 18 | public class GcpConfiguration { 19 | 20 | @Bean 21 | @Lazy 22 | public Logging getLogging() { 23 | LoggingOptions options = LoggingOptions.getDefaultInstance(); 24 | return options.getService(); 25 | } 26 | 27 | @Bean(name = "metricServiceClient") 28 | @Lazy 29 | public MetricServiceClient getMetricServiceClient() throws IOException { 30 | return MetricServiceClient.create(); 31 | } 32 | 33 | @Qualifier("projectId") 34 | @Bean 35 | public String getProjectId() { 36 | return getDefaultProjectId(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/java/com/google/cloud/runtimes/stackdriver/StackDriverMonitoringService.java: -------------------------------------------------------------------------------- 1 | package com.google.cloud.runtimes.stackdriver; 2 | 3 | import com.google.api.Metric; 4 | import com.google.api.MetricDescriptor; 5 | import com.google.api.MonitoredResource; 6 | import com.google.cloud.monitoring.v3.MetricServiceClient; 7 | import com.google.cloud.monitoring.v3.stub.MetricServiceStub; 8 | import com.google.cloud.runtimes.config.GcpConfiguration; 9 | import com.google.monitoring.v3.*; 10 | import com.google.protobuf.util.Timestamps; 11 | import org.springframework.beans.BeansException; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.beans.factory.annotation.Value; 14 | import org.springframework.context.ApplicationContext; 15 | import org.springframework.context.ApplicationContextAware; 16 | import org.springframework.context.annotation.Lazy; 17 | import org.springframework.stereotype.Service; 18 | 19 | import java.io.IOException; 20 | import java.util.logging.Logger; 21 | 22 | @Service 23 | public class StackDriverMonitoringService { 24 | 25 | @Autowired 26 | private ApplicationContext applicationContext; 27 | 28 | @Value("${monitoring.write.retries}") 29 | private int maxRetries; 30 | private static Logger LOG = Logger.getLogger(StackDriverMonitoringService.class.getName()); 31 | 32 | 33 | public void createMetricAndInsertTestToken(String projectId, String metricType, long metricValue) throws IOException { 34 | int retries = maxRetries; 35 | while (retries > 0) { 36 | try { 37 | CreateTimeSeriesRequest timeSeriesRequest = createTimeSeriesRequest(projectId, metricType, metricValue); 38 | getClient().createTimeSeries(timeSeriesRequest); 39 | LOG.info("Metric created with timeseries."); 40 | return; 41 | } catch (Exception e) { 42 | LOG.warning("error creating timeseries request, retrying..." + e.getClass() + ": " + e.getMessage()); 43 | retries--; 44 | if (retries == 0) { 45 | throw new IllegalStateException("Failed to store timeseries after " + maxRetries + " attempts! Last error:", e); 46 | } 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * This pairs up with the @Lazy annotation on {@link GcpConfiguration#getMetricServiceClient()}. 53 | * As MetricServiceClient methods are all `final` and that breaks the "@Autowire @Lazy" combination, 54 | * this is the only way to wire this bean lazily. 55 | */ 56 | private MetricServiceClient getClient() { 57 | return (MetricServiceClient) applicationContext.getBean("metricServiceClient"); 58 | } 59 | 60 | private CreateTimeSeriesRequest createTimeSeriesRequest(String projectId, String metricType, Long metricValue) { 61 | LOG.info("Creating time series to insert token: " + metricValue); 62 | ProjectName projectName = ProjectName.create(projectId); 63 | Metric metric = Metric.newBuilder() 64 | .setType(metricType) 65 | .build(); 66 | TimeInterval interval = TimeInterval.newBuilder() 67 | .setEndTime(Timestamps.fromMillis(System.currentTimeMillis())) 68 | .build(); 69 | TypedValue pointValue = TypedValue.newBuilder() 70 | .setInt64Value(metricValue) 71 | .build(); 72 | Point point = Point.newBuilder() 73 | .setInterval(interval) 74 | .setValue(pointValue) 75 | .build(); 76 | TimeSeries timeSeries = TimeSeries.newBuilder() 77 | .setMetric(metric) 78 | .setMetricKind(MetricDescriptor.MetricKind.GAUGE) 79 | .setResource(MonitoredResource.newBuilder().setType("global").build()) 80 | .addPoints(point) 81 | .build(); 82 | return CreateTimeSeriesRequest.newBuilder() 83 | .setNameWithProjectName(projectName) 84 | .addTimeSeries(timeSeries) 85 | .build(); 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/kubernetes/openjdk-spring-boot.yaml.in: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: openjdk-spring-boot 5 | spec: 6 | type: LoadBalancer 7 | ports: 8 | - port: 80 9 | targetPort: 8080 10 | selector: 11 | app: openjdk-spring-boot-app 12 | --- 13 | apiVersion: extensions/v1beta1 14 | kind: Deployment 15 | metadata: 16 | name: openjdk-spring-boot 17 | spec: 18 | replicas: 1 19 | template: 20 | metadata: 21 | name: openjdk-spring-boot 22 | labels: 23 | app: openjdk-spring-boot-app 24 | spec: 25 | containers: 26 | - name: openjdk-spring-boot 27 | image: ${TESTED_IMAGE} 28 | resources: 29 | requests: 30 | cpu: 100m 31 | memory: "512Mi" 32 | limits: 33 | cpu: 200m 34 | memory: "1024Mi" 35 | env: 36 | - name: HEAP_SIZE_RATIO 37 | value: "50" 38 | ports: 39 | - containerPort: 8080 40 | -------------------------------------------------------------------------------- /java-runtimes-common/test-spring-application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | monitoring.write.retries=3 2 | deployment.token=@deployment.token@ -------------------------------------------------------------------------------- /openjdk-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 4.0.0 21 | 22 | com.google.cloud.runtimes 23 | openjdk-parent 24 | 0.1.0-SNAPSHOT 25 | ../pom.xml 26 | 27 | 28 | Openjdk Common Docker Configuration 29 | openjdk-common 30 | pom 31 | 32 | 33 | 34 | 35 | maven-enforcer-plugin 36 | 37 | 38 | 39 | enforce 40 | 41 | validate 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-assembly-plugin 48 | 49 | 50 | package 51 | 52 | single 53 | 54 | 55 | 56 | 57 | 58 | src/main/assembly/assembly.xml 59 | 60 | gnu 61 | false 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /openjdk-common/src/main/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | assembly 21 | 22 | tar.gz 23 | 24 | src/main/docker 25 | false 26 | 27 | 28 | false 29 | src/main/docker 30 | 31 | 32 | ** 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/docker-entrypoint.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | is_java_cmd() { 4 | [ "$(which java)" = "$1" -o "$(readlink -f $(which java))" = "$1" ] 5 | } 6 | 7 | # Normalize invocations of "java" so that other scripts can more easily detect it 8 | if is_java_cmd "$1"; then 9 | shift 10 | set -- java "$@" 11 | # else if the first argument is not executable assume java 12 | elif ! type "$1" &>/dev/null; then 13 | set -- java "$@" 14 | fi 15 | 16 | # scan the setup-env.d directory for scripts to source for additional setup 17 | if [ -d "${SETUP_ENV:=/setup-env.d}" ]; then 18 | for SCRIPT in $( ls "${SETUP_ENV}/"[0-9]*.bash | sort ) ; do 19 | source ${SCRIPT} 20 | done 21 | fi 22 | 23 | # Normalize invocations of "java" again in case other scripts have modified it 24 | if is_java_cmd "$1"; then 25 | shift 26 | set -- java "$@" 27 | fi 28 | 29 | # Do we have JAVA_OPTS for a java command? 30 | if [ "$1" = "java" -a -n "$JAVA_OPTS" ]; then 31 | shift 32 | set -- java $JAVA_OPTS "$@" 33 | fi 34 | 35 | # configure shutdown wrapper for diagnostics if enabled 36 | source /shutdown/shutdown-env.bash 37 | 38 | # exec the entry point arguments as a command 39 | echo "Start command: $*" 40 | exec "$@" 41 | -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/setup-env.d/05-utils.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | is_true() { 4 | # case insensitive check for "true" 5 | if [[ ${1,,} = "true" ]]; then 6 | true 7 | else 8 | false 9 | fi 10 | } 11 | -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/setup-env.d/10-platform-env.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$PLATFORM" ]; then 4 | if [ -n "$GAE_INSTANCE" ]; then 5 | PLATFORM=gae 6 | else 7 | PLATFORM=unknown 8 | fi 9 | fi 10 | export PLATFORM 11 | 12 | -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/setup-env.d/25-profiler-env.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # configure Stackdriver Profiler 4 | 5 | export PROFILER_AGENT_COMMAND=${PROFILER_AGENT_COMMAND:-"-agentpath:/opt/cprof/profiler_java_agent.so=--logtostderr"} 6 | 7 | export PROFILER_AGENT= 8 | 9 | if is_true "$PROFILER_ENABLE"; then 10 | PROFILER_AGENT=${PROFILER_AGENT_COMMAND} 11 | fi 12 | 13 | # Avoid adding Profiler twice for Alpha users 14 | if [[ $JAVA_USER_OPTS = *"profiler_java_agent.so"* ]]; then 15 | echo "WARNING: Stackdriver Profiler seems to be enabled already using JAVA_USER_OPTS." 16 | PROFILER_AGENT= 17 | fi -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/setup-env.d/30-java-env.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GetAvailableMemory () { 4 | local default_memory="$(awk '/MemTotal/{ print int($2/1024-400) }' /proc/meminfo)" 5 | local memory="" 6 | 7 | # Search for a memory limit set by kubernetes 8 | if [ -n "$KUBERNETES_MEMORY_LIMIT" ]; then 9 | memory=$((KUBERNETES_MEMORY_LIMIT / (1024 * 1024))) 10 | fi 11 | 12 | # Search for a memory limit set by cgroup 13 | local cgroup_mem_file="/sys/fs/cgroup/memory/memory.limit_in_bytes" 14 | if [ -z $memory ] && [ -r "$cgroup_mem_file" ]; then 15 | local cgroup_memory="$(cat ${cgroup_mem_file})" 16 | cgroup_memory=$((cgroup_memory / (1024 * 1024))) 17 | # Cgroup memory can be 0 or unbound, in which case we use the default limit 18 | if [ ${cgroup_memory} -gt 0 ] && [ ${cgroup_memory} -lt ${default_memory} ]; then 19 | memory=$cgroup_memory 20 | fi 21 | fi 22 | 23 | # Fallback to default memory limit 24 | if [ -z $memory ]; then 25 | memory=$default_memory 26 | fi 27 | 28 | echo $memory 29 | } 30 | 31 | # Setup default Java Options 32 | export JAVA_TMP_OPTS=${JAVA_TMP_OPTS:-$( if [[ -z ${TMPDIR} ]]; then echo ""; else echo "-Djava.io.tmpdir=$TMPDIR"; fi)} 33 | export GAE_MEMORY_MB=${GAE_MEMORY_MB:-$(GetAvailableMemory)} 34 | export HEAP_SIZE_RATIO=${HEAP_SIZE_RATIO:-"80"} 35 | export HEAP_SIZE_MB=${HEAP_SIZE_MB:-$(expr ${GAE_MEMORY_MB} \* ${HEAP_SIZE_RATIO} / 100)} 36 | export JAVA_HEAP_OPTS=${JAVA_HEAP_OPTS:-"-Xms${HEAP_SIZE_MB}M -Xmx${HEAP_SIZE_MB}M"} 37 | export JAVA_GC_OPTS=${JAVA_GC_OPTS:-"-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:+PrintCommandLineFlags"} 38 | export JAVA_OPTS=${JAVA_OPTS:--showversion ${JAVA_TMP_OPTS} ${PROFILER_AGENT} ${JAVA_HEAP_OPTS} ${JAVA_GC_OPTS} ${JAVA_USER_OPTS}} 39 | -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/shutdown/shutdown-env.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /setup-env.d/05-utils.bash 4 | 5 | # If configured, output a thread dump and/or heap info on shutdown by wrapping the java process 6 | if is_true "${SHUTDOWN_LOGGING_THREAD_DUMP}" || is_true "${SHUTDOWN_LOGGING_HEAP_INFO}"; then 7 | # default shutdown logging sample threshold is 100 (100%) 8 | export SHUTDOWN_LOGGING_SAMPLE_THRESHOLD=${SHUTDOWN_LOGGING_SAMPLE_THRESHOLD:-100} 9 | random_sample=$(( RANDOM % 100 )) 10 | if (( random_sample < SHUTDOWN_LOGGING_SAMPLE_THRESHOLD)); then 11 | echo "Shutdown logging threshold of ${SHUTDOWN_LOGGING_SAMPLE_THRESHOLD}% satisfied with sample ${random_sample}." 12 | set -- /shutdown/shutdown-wrapper.bash "$@" 13 | else 14 | echo "Shutdown logging threshold of ${SHUTDOWN_LOGGING_SAMPLE_THRESHOLD}% NOT satisfied with sample ${random_sample}." 15 | fi 16 | fi -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/shutdown/shutdown-wrapper.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /setup-env.d/05-utils.bash 4 | 5 | function java_shutdown_hook { 6 | JAVA_PID=`ps -C java -o pid --no-headers` 7 | PUSER=`ps -o ruser --no-headers -p $JAVA_PID` 8 | 9 | # send thread dump to a file 10 | if is_true "${SHUTDOWN_LOGGING_THREAD_DUMP}"; then 11 | export THREAD_DUMP_FILE=${THREAD_DUMP_FILE:-/app.shutdown.threads} 12 | # run jcmd under JVM process owner and skip first 3 lines of output 13 | su $PUSER -c "jcmd $JAVA_PID Thread.print" | tail -n +3 &> $THREAD_DUMP_FILE 14 | fi 15 | 16 | # send heap info to a file 17 | if is_true "${SHUTDOWN_LOGGING_HEAP_INFO}"; then 18 | export HEAP_INFO_FILE=${HEAP_INFO_FILE:-/app.shutdown.heap} 19 | # run jcmd under JVM process owner and skip first 3 lines of output 20 | su $PUSER -c "jcmd $JAVA_PID GC.class_histogram" | tail -n +3 &> $HEAP_INFO_FILE 21 | fi 22 | } 23 | 24 | # capture the TERM signal and first generate the thread dump and/or heap info 25 | trap 'java_shutdown_hook; kill -TERM $PID' TERM 26 | "$@" & 27 | PID=$! 28 | wait $PID 29 | wait $PID 30 | if is_true "${SHUTDOWN_LOGGING_THREAD_DUMP}"; then 31 | # output thread dump to stdout 32 | echo '~~~~~~~~~~~~~~~~~~~~~~ THREAD DUMP ~~~~~~~~~~~~~~~~~~~~~~' 33 | cat $THREAD_DUMP_FILE 34 | fi 35 | if is_true "${SHUTDOWN_LOGGING_HEAP_INFO}"; then 36 | # output abbreviated heap info to stdout 37 | echo '~~~~~~~~~~~~~~~~~~~~~~~ HEAP INFO ~~~~~~~~~~~~~~~~~~~~~~~' 38 | heap_total_lines=`wc -l < "$HEAP_INFO_FILE"` 39 | HEAP_SHOW_LINES_COUNT=${HEAP_SHOW_LINES_COUNT:-54} 40 | head -"$HEAP_SHOW_LINES_COUNT" $HEAP_INFO_FILE 41 | echo "[$(( heap_total_lines - HEAP_SHOW_LINES_COUNT - 1 )) lines omitted]" 42 | tail -1 $HEAP_INFO_FILE 43 | fi 44 | exit $? 45 | -------------------------------------------------------------------------------- /openjdk-common/src/main/docker/sid.list: -------------------------------------------------------------------------------- 1 | deb http://ftp.us.debian.org/debian sid main 2 | -------------------------------------------------------------------------------- /openjdk-test-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 4.0.0 21 | 22 | com.google.cloud.runtimes 23 | openjdk-parent 24 | 0.1.0-SNAPSHOT 25 | ../pom.xml 26 | 27 | 28 | Openjdk Common Test resources 29 | openjdk-test-common 30 | pom 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-assembly-plugin 37 | 38 | 39 | package 40 | 41 | single 42 | 43 | 44 | 45 | 46 | 47 | src/main/assembly/assembly.xml 48 | 49 | gnu 50 | false 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /openjdk-test-common/src/main/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | assembly 21 | 22 | tar.gz 23 | 24 | src/test/resources 25 | false 26 | 27 | 28 | false 29 | src/test/resources 30 | 31 | 32 | ** 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/structure.yaml: -------------------------------------------------------------------------------- 1 | # Test spec for the Cloud Runtimes container structure testing framework. 2 | # 3 | # See https://github.com/GoogleCloudPlatform/runtimes-common/tree/master/functional_tests/README.md for more detail. 4 | # 5 | schemaVersion: 1.0.0 6 | 7 | commandTests: 8 | - name: 'OPENJDK_VERSION env variable is set correctly' 9 | command: ['env'] 10 | expectedOutput: ['OPENJDK_VERSION=${openjdk.version}'] 11 | - name: 'GAE_IMAGE_LABEL env variable is set correctly' 12 | command: ['env'] 13 | expectedOutput: ['GAE_IMAGE_LABEL=${docker.tag.long}'] 14 | - name: 'check entrypoint default' 15 | setup: [[ 'chmod', '+x', '/workspace/entrypoint-default.bash' ]] 16 | command: [ '/workspace/entrypoint-default.bash' ] 17 | expectedOutput: ['OK'] 18 | exitCode: 0 19 | - name: 'check entrypoint args only' 20 | setup: [[ 'chmod', '+x', '/workspace/entrypoint-args-only.bash' ]] 21 | command: [ '/workspace/entrypoint-args-only.bash' ] 22 | expectedOutput: ['OK'] 23 | exitCode: 0 24 | - name: 'check entrypoint setup' 25 | setup: [[ 'chmod', '+x', '/workspace/entrypoint-setup.bash' ]] 26 | command: [ '/workspace/entrypoint-setup.bash' ] 27 | expectedOutput: ['OK'] 28 | exitCode: 0 29 | - name: 'check setup platform' 30 | setup: [[ 'chmod', '+x', '/workspace/setup-platform.bash' ]] 31 | command: [ '/workspace/setup-platform.bash' ] 32 | expectedOutput: ['OK'] 33 | exitCode: 0 34 | - name: 'check setup java' 35 | setup: [[ 'chmod', '+x', '/workspace/setup-java.bash' ]] 36 | command: [ '/workspace/setup-java.bash' ] 37 | expectedOutput: ['OK'] 38 | exitCode: 0 39 | - name: 'check setup Stackdriver Profiler' 40 | setup: [[ 'chmod', '+x', '/workspace/setup-profiler.bash' ]] 41 | command: [ '/workspace/setup-profiler.bash' ] 42 | expectedOutput: ['OK'] 43 | exitCode: 0 44 | - name: 'check setup Stackdriver Profiler' 45 | setup: [[ 'chmod', '+x', '/workspace/setup-profiler.bash' ]] 46 | command: [ '/workspace/setup-profiler.bash' ] 47 | expectedOutput: ['OK'] 48 | exitCode: 0 49 | - name: 'APP_DESTINATION env variable is set' 50 | command: ['env'] 51 | expectedOutput: ['APP_DESTINATION=app.jar'] 52 | - name: 'check shutdown logging wrapper setup' 53 | setup: [[ 'chmod', '+x', '/workspace/shutdown-env.bash' ]] 54 | command: [ '/workspace/shutdown-env.bash' ] 55 | expectedOutput: ['OK'] 56 | exitCode: 0 57 | - name: 'ensure blacklisted packages are not installed as a dependency accidentally' 58 | setup: [[ 'chmod', '+x', '/workspace/test-denylisted-pkgs.bash' ]] 59 | command: [ '/workspace/test-denylisted-pkgs.bash' ] 60 | excludedOutput: ['NOT OK.* is installed'] 61 | - name: 'Debian 9' 62 | command: [ 'cat', '/etc/debian_version' ] 63 | expectedOutput: ['9.*'] 64 | 65 | 66 | fileExistenceTests: 67 | - name: 'ssl certificates are present' 68 | path: '/etc/ssl/certs/java/cacerts' 69 | isDirectory: false 70 | shouldExist: true 71 | - name: 'App Engine logs directory exists' 72 | path: '/var/log/app_engine' 73 | isDirectory: true 74 | shouldExist: true 75 | - name: 'Stackdriver Profiler agent is installed' 76 | path: '/opt/cprof/profiler_java_agent.so' 77 | isDirectory: false 78 | shouldExist: true 79 | - name: 'Docker entrypoint exists' 80 | path: '/docker-entrypoint.bash' 81 | isDirectory: false 82 | shouldExist: true 83 | - name: 'Env setup script dir exists' 84 | path: '/setup-env.d' 85 | isDirectory: true 86 | shouldExist: true 87 | - name: 'Utils script exists' 88 | path: '/setup-env.d/05-utils.bash' 89 | isDirectory: false 90 | shouldExist: true 91 | - name: 'Platform setup script exists' 92 | path: '/setup-env.d/10-platform-env.bash' 93 | isDirectory: false 94 | shouldExist: true 95 | - name: 'Profiler setup script exists' 96 | path: '/setup-env.d/25-profiler-env.bash' 97 | isDirectory: false 98 | shouldExist: true 99 | - name: 'Java setup script exists' 100 | path: '/setup-env.d/30-java-env.bash' 101 | isDirectory: false 102 | shouldExist: true 103 | 104 | licenseTests: 105 | - debian: true 106 | files: [] 107 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/entrypoint-args-only.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set - one two three 3 | JAVA_OPTS="-java -options" 4 | sed 's/exec /# /' /docker-entrypoint.bash > /tmp/entrypoint.bash 5 | source /tmp/entrypoint.bash 6 | if [ "$(echo "$@" | xargs)" != "java -java -options one two three" ]; then 7 | echo "@='$(echo "$@" | xargs)'" 8 | else 9 | echo OK 10 | fi 11 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/entrypoint-default.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set - java one two three 3 | JAVA_OPTS="-java -options" 4 | sed 's/exec /# /' /docker-entrypoint.bash > /tmp/entrypoint.bash 5 | source /tmp/entrypoint.bash 6 | if [ "$(echo "$@" | xargs)" != "java -java -options one two three" ]; then 7 | echo "@='$(echo "$@" | xargs)'" 8 | else 9 | echo OK 10 | fi 11 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/entrypoint-setup.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -- java one two three 3 | JAVA_OPTS="-java -options" 4 | 5 | trap "rm -f /setup-env.d/01-one.bash /setup-env.d/02-two.bash /setup-env.d/03-three.bash" EXIT 6 | 7 | cat << 'EOF' > /setup-env.d/01-one.bash 8 | export ONE=OK 9 | set -- $(echo $@ | sed 's/one/1/') 10 | EOF 11 | 12 | cat << 'EOF' > /setup-env.d/02-two.bash 13 | export TWO=$ONE 14 | set -- $(echo $@ | sed 's/two/2/') 15 | EOF 16 | 17 | cat << 'EOF' > /setup-env.d/03-three.bash 18 | export THREE=$TWO 19 | set -- $(echo $@ | sed 's/three/3/') 20 | EOF 21 | 22 | sed -e 's/exec /# /' -e 's/set - /set -- /' /docker-entrypoint.bash > /tmp/entrypoint.bash 23 | 24 | source /tmp/entrypoint.bash 25 | if [ "$(echo "$@" | xargs)" != "java -java -options 1 2 3" ]; then 26 | echo "@='$(echo "$@" | xargs)'" 27 | elif [ "$THREE" != "OK" ]; then 28 | echo setup out of order $ONE, $TWO, $THREE 29 | else 30 | echo OK 31 | fi 32 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/setup-java.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function cleanEnv() { 4 | unset JAVA_OPTS TMPDIR GAE_MEMORY_MB HEAP_SIZE_MB JAVA_HEAP_OPTS JAVA_GC_OPTS JAVA_OPTS DBG_AGENT PROFILER_AGENT 5 | } 6 | 7 | cleanEnv 8 | 9 | #test default 10 | source /setup-env.d/30-java-env.bash 11 | 12 | 13 | TEST=$(echo $JAVA_OPTS | sed 's/^-showversion.*/OK/') 14 | if [ "$TEST" != "OK" ]; then 15 | echo "Show version JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 16 | exit 1 17 | fi 18 | 19 | TEST=$(echo $JAVA_OPTS | sed 's/.*-Xms.*/OK/') 20 | if [ "$TEST" != "OK" ]; then 21 | echo "No Xms JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 22 | exit 1 23 | fi 24 | 25 | TEST=$(echo $JAVA_OPTS | sed 's/.*-XX:+ParallelRefProcEnabled.*/OK/') 26 | if [ "$TEST" != "OK" ]; then 27 | echo "No XX:ParallelRefProc JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 28 | exit 1 29 | fi 30 | 31 | TEST=$(echo $JAVA_OPTS | sed 's/.*-XX:.UseG1GC.*/OK/') 32 | if [ "$TEST" != "OK" ]; then 33 | echo "No XX:UseG1GC JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 34 | exit 1 35 | fi 36 | 37 | 38 | # test base values 39 | cleanEnv 40 | TMPDIR=/var/tmp 41 | GAE_MEMORY_MB=1000 42 | source /setup-env.d/30-java-env.bash 43 | if [ "$(echo $JAVA_OPTS | xargs)" != "-showversion -Djava.io.tmpdir=/var/tmp -Xms800M -Xmx800M -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:+PrintCommandLineFlags" ]; then 44 | echo "Bad values JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 45 | exit 1 46 | fi 47 | 48 | cleanEnv 49 | TMPDIR=/var/tmp 50 | GAE_MEMORY_MB=1000 51 | HEAP_SIZE_MB=500 52 | source /setup-env.d/30-java-env.bash 53 | if [ "$(echo $JAVA_OPTS | xargs)" != "-showversion -Djava.io.tmpdir=/var/tmp -Xms500M -Xmx500M -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:+PrintCommandLineFlags" ]; then 54 | echo "Bad values JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 55 | exit 1 56 | fi 57 | 58 | 59 | # test direct OPTS 60 | cleanEnv 61 | TMPDIR=/var/tmp 62 | GAE_MEMORY_MB=1000 63 | HEAP_SIZE_MB=500 64 | JAVA_TMP_OPTS=-XX:Temp 65 | JAVA_HEAP_OPTS=-XX:Heap 66 | JAVA_GC_OPTS=-XX:GC 67 | PROFILER_AGENT=profiler 68 | JAVA_USER_OPTS=user 69 | 70 | source /setup-env.d/30-java-env.bash 71 | if [ "$(echo $JAVA_OPTS | xargs)" != "-showversion -XX:Temp profiler -XX:Heap -XX:GC user" ]; then 72 | echo "Bad opts JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 73 | exit 1 74 | fi 75 | 76 | #test override 77 | cleanEnv 78 | TMPDIR=/var/tmp 79 | GAE_MEMORY_MB=1000 80 | HEAP_SIZE_MB=500 81 | JAVA_TMP_OPTS=-XX:Temp 82 | JAVA_HEAP_OPTS=-XX:Heap 83 | JAVA_GC_OPTS=-XX:GC 84 | JAVA_USER_OPTS=user 85 | JAVA_OPTS=-XX:options 86 | 87 | source /setup-env.d/30-java-env.bash 88 | if [ "$(echo $JAVA_OPTS | xargs)" != "-XX:options" ]; then 89 | echo "Bad opts JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 90 | exit 1 91 | fi 92 | 93 | 94 | # test heap size ratio 95 | cleanEnv 96 | GAE_MEMORY_MB=1000 97 | HEAP_SIZE_RATIO=50 98 | source /setup-env.d/30-java-env.bash 99 | 100 | TEST_MIN_HEAP=$(echo $JAVA_OPTS | sed 's/.*-Xms500M .*/OK/') 101 | TEST_MAX_HEAP=$(echo $JAVA_OPTS | sed 's/.*-Xmx500M .*/OK/') 102 | 103 | if [ "$TEST_MIN_HEAP" != "OK" -o "$TEST_MAX_HEAP" != "OK" ]; then 104 | echo "Bad values JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 105 | exit 1 106 | fi 107 | 108 | 109 | #test GKE environment 110 | cleanEnv 111 | TMPDIR=/var/tmp 112 | KUBERNETES_MEMORY_LIMIT=20000000 113 | HEAP_SIZE_RATIO=30 114 | source /setup-env.d/30-java-env.bash 115 | 116 | TEST_MIN_HEAP=$(echo $JAVA_OPTS | sed 's/.*-Xms5M .*/OK/') 117 | TEST_MAX_HEAP=$(echo $JAVA_OPTS | sed 's/.*-Xmx5M .*/OK/') 118 | 119 | if [ "$TEST_MIN_HEAP" != "OK" -o "$TEST_MAX_HEAP" != "OK" ]; then 120 | echo "Memory limit set by kubernetes is not considered in JAVA_OPTS='$(echo $JAVA_OPTS | xargs)'" 121 | exit 1 122 | fi 123 | 124 | echo OK 125 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/setup-platform.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #test default 4 | unset PLATFORM GAE_INSTANCE 5 | source /setup-env.d/10-platform-env.bash 6 | if [ "$PLATFORM" != "unknown" ]; then 7 | echo "Bad default PLATFORM='$PLATFORM'" 8 | exit 1 9 | fi 10 | 11 | #test GAE 12 | unset PLATFORM GAE_INSTANCE 13 | GAE_INSTANCE=12345 14 | source /setup-env.d/10-platform-env.bash 15 | if [ "$PLATFORM" != "gae" ]; then 16 | echo "Bad gae PLATFORM='$PLATFORM'" 17 | exit 1 18 | fi 19 | 20 | #test forced 21 | unset PLATFORM GAE_INSTANCE 22 | GAE_INSTANCE=12345 23 | PLATFORM=special 24 | source /setup-env.d/10-platform-env.bash 25 | if [ "$PLATFORM" != "special" ]; then 26 | echo "Bad forced PLATFORM='$PLATFORM'" 27 | exit 1 28 | fi 29 | 30 | 31 | echo OK 32 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/setup-profiler.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /setup-env.d/05-utils.bash 4 | 5 | function testProfilerOn() { 6 | source /setup-env.d/25-profiler-env.bash 7 | if [ "$PROFILER_AGENT" != "-agentpath:/opt/cprof/profiler_java_agent.so=--logtostderr" ]; then 8 | echo "Profiler should be ON because $1" 9 | exit 1 10 | fi 11 | } 12 | 13 | function testProfilerOff() { 14 | source /setup-env.d/25-profiler-env.bash 15 | if [ "$PROFILER_AGENT" != "" ]; then 16 | echo "Profiler should be OFF because $1" 17 | exit 1 18 | fi 19 | } 20 | 21 | function cleanEnv() { 22 | unset PROFILER_AGENT 23 | unset PROFILER_ENABLE 24 | unset PLATFORM 25 | unset JAVA_USER_OPTS 26 | } 27 | 28 | # test default - profiler OFF 29 | cleanEnv 30 | testProfilerOff "that's the default" 31 | 32 | # test GAE default - profiler OFF 33 | cleanEnv 34 | PLATFORM=gae 35 | testProfilerOff "that's the default on GAE" 36 | 37 | # test GKE default - profiler OFF 38 | cleanEnv 39 | PLATFORM=gke 40 | testProfilerOff "that's the default on GKE" 41 | 42 | # test PROFILER_ENABLE = true 43 | cleanEnv 44 | PROFILER_ENABLE=true 45 | testProfilerOn "PROFILER_ENABLE=$PROFILER_ENABLE" 46 | 47 | # test PROFILER_ENABLE = True 48 | cleanEnv 49 | PROFILER_ENABLE=True 50 | testProfilerOn "PROFILER_ENABLE=$PROFILER_ENABLE" 51 | 52 | # test PROFILER_ENABLE = false 53 | cleanEnv 54 | PROFILER_ENABLE=false 55 | testProfilerOff "PROFILER_ENABLE=$PROFILER_ENABLE" 56 | 57 | # test PROFILER_ENABLE = False 58 | cleanEnv 59 | PROFILER_ENABLE=False 60 | testProfilerOff "PROFILER_ENABLE=$PROFILER_ENABLE" 61 | 62 | # test JAVA_USER_OPTS = -agentpath:/opt/cprof/profiler_java_agent.so=--logtostderr 63 | cleanEnv 64 | JAVA_USER_OPTS=-agentpath:/opt/cprof/profiler_java_agent.so=--logtostderr 65 | PROFILER_ENABLE=True 66 | testProfilerOff "JAVA_USER_OPTS=$JAVA_USER_OPTS" 67 | 68 | echo OK 69 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/shutdown-env.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | wrapper="/shutdown/shutdown-wrapper.bash" 4 | 5 | function doTest() { 6 | test_setup="testing SHUTDOWN_LOGGING_THREAD_DUMP=$SHUTDOWN_LOGGING_THREAD_DUMP, " \ 7 | "SHUTDOWN_LOGGING_HEAP_INFO=$SHUTDOWN_LOGGING_HEAP_INFO, " \ 8 | "SHUTDOWN_LOGGING_SAMPLE_THRESHOLD=$SHUTDOWN_LOGGING_SAMPLE_THRESHOLD." 9 | expected=$1 10 | set - java 11 | JAVA_OPTS=" " 12 | source /shutdown/shutdown-env.bash > /dev/null 13 | if [ "$(echo "$@" | xargs)" != "$expected" ]; then 14 | echo $test_setup 15 | echo "command='$(echo "$@" | xargs)' rather than expected '$expected'" 16 | echo FAILED 17 | exit 1 18 | fi 19 | } 20 | 21 | function cleanEnv() { 22 | unset SHUTDOWN_LOGGING_THREAD_DUMP 23 | unset SHUTDOWN_LOGGING_HEAP_INFO 24 | unset SHUTDOWN_LOGGING_SAMPLE_THRESHOLD 25 | } 26 | 27 | # default - no shutdown wrapper 28 | cleanEnv 29 | doTest "java" 30 | 31 | # thread dump on 32 | cleanEnv 33 | SHUTDOWN_LOGGING_THREAD_DUMP=True 34 | doTest "$wrapper java" 35 | 36 | # heap info on 37 | cleanEnv 38 | SHUTDOWN_LOGGING_HEAP_INFO=True 39 | doTest "$wrapper java" 40 | 41 | # thread dump and heap info off 42 | cleanEnv 43 | SHUTDOWN_LOGGING_THREAD_DUMP=False 44 | SHUTDOWN_LOGGING_HEAP_INFO=False 45 | doTest "java" 46 | 47 | # both on 48 | cleanEnv 49 | SHUTDOWN_LOGGING_THREAD_DUMP=True 50 | SHUTDOWN_LOGGING_HEAP_INFO=True 51 | doTest "$wrapper java" 52 | 53 | # both on but threshold 0 54 | cleanEnv 55 | SHUTDOWN_LOGGING_THREAD_DUMP=True 56 | SHUTDOWN_LOGGING_HEAP_INFO=True 57 | SHUTDOWN_LOGGING_SAMPLE_THRESHOLD=0 58 | doTest "java" 59 | 60 | # both on but threshold 100 61 | cleanEnv 62 | SHUTDOWN_LOGGING_THREAD_DUMP=True 63 | SHUTDOWN_LOGGING_HEAP_INFO=True 64 | SHUTDOWN_LOGGING_SAMPLE_THRESHOLD=100 65 | doTest "$wrapper java" 66 | 67 | echo OK 68 | -------------------------------------------------------------------------------- /openjdk-test-common/src/test/resources/workspace/test-denylisted-pkgs.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DENYLIST="\ 4 | jvm-7-avian-jre \ 5 | java7-runtime-headless \ 6 | python2.7-pyjavaproperties \ 7 | libjsr107cache-java \ 8 | libbiojava1.7-java \ 9 | oracle-java7-installer \ 10 | oracle-java7-jdk \ 11 | openjdk-7-jre-zero \ 12 | sun-java7-jre \ 13 | java7-sdk \ 14 | libdb4.7-java-dev \ 15 | openjdk-7-jdk \ 16 | java7-sdk-headless \ 17 | openjdk-7-jre-headless \ 18 | java7-runtime \ 19 | libtomcat7-java \ 20 | openjdk-7-dbg \ 21 | openjdk-7-jre-dcevm \ 22 | openjdk-7-jre-lib \ 23 | uwsgi-plugin-jvm-openjdk-7 \ 24 | openjdk-7-jre \ 25 | openjdk-7-source \ 26 | icedtea-7-jre-jamvm \ 27 | openjdk-7-demo \ 28 | openjdk-7-doc \ 29 | libnb-platform7-devel-java \ 30 | uwsgi-plugin-jwsgi-openjdk-7" 31 | 32 | 33 | for PKG in $DENYLIST; 34 | do 35 | dpkg -l | grep '^.i' | grep $PKG > /dev/null && echo "NOT OK. $PKG is installed" || echo "OK. $PKG is not installed" 36 | done 37 | -------------------------------------------------------------------------------- /openjdk11/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 4.0.0 21 | 22 | com.google.cloud.runtimes 23 | openjdk-parent 24 | 0.1.0-SNAPSHOT 25 | ../pom.xml 26 | 27 | Google App Engine Image for OpenJDK (openjdk11) 28 | openjdk11 29 | pom 30 | 31 | 32 | 11 33 | 34 | ${openjdk.version.major}${openjdk.version.minor} 35 | gcr.io/google-appengine/debian9 36 | ${docker.image.baseName}:${docker.tag.long} 37 | 38 | 39 | 40 | 41 | com.google.cloud.runtimes 42 | openjdk-common 43 | ${project.version} 44 | tar.gz 45 | 46 | 47 | com.google.cloud.runtimes 48 | openjdk-test-common 49 | ${project.version} 50 | tar.gz 51 | 52 | 53 | com.google.cloud.runtimes 54 | test-spring-application 55 | 1.0.0 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-dependency-plugin 64 | 65 | 66 | unpack-openjdk-common 67 | generate-resources 68 | 69 | 70 | unpack-openjdk-test-common 71 | generate-test-resources 72 | 73 | 74 | 75 | 76 | 77 | io.fabric8 78 | docker-maven-plugin 79 | 80 | 81 | docker-build 82 | package 83 | 84 | 85 | 86 | 87 | 88 | org.codehaus.mojo 89 | exec-maven-plugin 90 | 91 | 92 | common-structure-test 93 | integration-test 94 | 95 | 96 | local-shutdown-test 97 | integration-test 98 | 99 | 100 | 101 | openjdk11-structure-test 102 | integration-test 103 | 104 | exec 105 | 106 | 107 | ${project.parent.basedir}/scripts/structure_test.sh 108 | ${project.basedir} 109 | 110 | ${docker.image.name} 111 | ${project.build.testOutputDirectory} 112 | ${project.build.testOutputDirectory}/openjdk11-structure.yaml 113 | 114 | 115 | 116 | 117 | 118 | 119 | maven-resources-plugin 120 | 121 | 122 | generate-test-resources 123 | generate-test-resources 124 | 125 | testResources 126 | 127 | 128 | ${project.build.testOutputDirectory} 129 | 130 | 131 | ${basedir}/src/test/resources 132 | true 133 | 134 | ** 135 | 136 | 137 | 138 | 139 | 140 | 141 | copy-resources 142 | generate-resources 143 | 144 | copy-resources 145 | 146 | 147 | ${docker.staging.dir} 148 | 149 | 150 | ${basedir}/src/main/docker 151 | true 152 | 153 | ** 154 | 155 | 156 | 157 | 158 | 159 | 160 | filter-test-resources 161 | process-test-resources 162 | 163 | copy-resources 164 | 165 | 166 | ${project.build.testOutputDirectory}/openjdk-test-common-out 167 | 168 | 169 | ${project.build.testOutputDirectory}/openjdk-test-common 170 | true 171 | 172 | ** 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /openjdk11/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM ${docker.appengine.image} 16 | ENV DEBIAN_FRONTEND noninteractive 17 | 18 | # Create env vars to identify image 19 | ENV OPENJDK_VERSION ${openjdk.version} 20 | ENV GAE_IMAGE_NAME ${project.artifactId} 21 | ENV GAE_IMAGE_LABEL ${docker.tag.long} 22 | 23 | RUN \ 24 | # add debian stretch-backports repo in order to install openjdk11 25 | echo 'deb http://httpredir.debian.org/debian stretch-backports main' > /etc/apt/sources.list.d/stretch-backports.list \ 26 | 27 | && apt-get -q update \ 28 | && apt-get -y -q --no-install-recommends install \ 29 | # install the jdk and its dependencies 30 | ca-certificates-java \ 31 | openjdk-${openjdk.version.major}-jdk-headless=${openjdk.version}'*' \ 32 | # procps is used in the jvm shutdown hook 33 | procps \ 34 | # other system utilities 35 | netbase \ 36 | unzip \ 37 | wget \ 38 | 39 | # cleanup package manager caches 40 | && apt-get clean \ 41 | && rm /var/lib/apt/lists/*_* 42 | 43 | # Add the Stackdriver Profiler libraries 44 | ADD https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz /opt/cprof/ 45 | COPY docker-entrypoint.bash / 46 | COPY setup-env.d /setup-env.d/ 47 | COPY shutdown/ /shutdown/ 48 | RUN tar Cxfvz /opt/cprof /opt/cprof/profiler_java_agent.tar.gz --no-same-owner \ 49 | && rm /opt/cprof/profiler_java_agent.tar.gz \ 50 | && chmod +x /docker-entrypoint.bash /shutdown/*.bash /setup-env.d/*.bash \ 51 | && mkdir /var/log/app_engine \ 52 | && chmod go+rwx /var/log/app_engine 53 | 54 | ENV APP_DESTINATION ${docker.application.destination} 55 | 56 | ENTRYPOINT ["/docker-entrypoint.bash"] 57 | CMD ["java", "-jar", "${docker.application.destination}"] 58 | -------------------------------------------------------------------------------- /openjdk11/src/test/resources/jdk11-compilation-test/.gitignore: -------------------------------------------------------------------------------- 1 | out/ -------------------------------------------------------------------------------- /openjdk11/src/test/resources/jdk11-compilation-test/com.google.greetings/com/google/greetings/Main.java: -------------------------------------------------------------------------------- 1 | package com.google.greetings; 2 | import com.google.world.World; 3 | 4 | public class Main { 5 | public static void main(String[] args) { 6 | System.out.format("Greetings %s!%n", World.name()); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /openjdk11/src/test/resources/jdk11-compilation-test/com.google.greetings/module-info.java: -------------------------------------------------------------------------------- 1 | module com.google.greetings { 2 | exports com.google.greetings; 3 | requires com.google.world; 4 | } -------------------------------------------------------------------------------- /openjdk11/src/test/resources/jdk11-compilation-test/com.google.world/com/google/world/World.java: -------------------------------------------------------------------------------- 1 | package com.google.world; 2 | 3 | public class World { 4 | public static String name() { 5 | return "world"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /openjdk11/src/test/resources/jdk11-compilation-test/com.google.world/module-info.java: -------------------------------------------------------------------------------- 1 | module com.google.world { 2 | exports com.google.world; 3 | } -------------------------------------------------------------------------------- /openjdk11/src/test/resources/jdk11-compilation-test/compile-and-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SOURCE_DIR=$1 4 | 5 | if [ -z $SOURCE_DIR ]; then 6 | echo "USAGE: $0 " 7 | exit 1; 8 | fi 9 | 10 | # compile modules 11 | javac -d out --module-source-path $SOURCE_DIR $(find $SOURCE_DIR -name '*.java') 12 | 13 | # run main class 14 | java --module-path out -m com.google.greetings/com.google.greetings.Main 15 | -------------------------------------------------------------------------------- /openjdk11/src/test/resources/openjdk11-structure.yaml: -------------------------------------------------------------------------------- 1 | # Test spec for the Cloud Runtimes container structure testing framework. 2 | # 3 | # See https://github.com/GoogleCloudPlatform/runtimes-common/tree/master/functional_tests/README.md for more detail. 4 | # 5 | schemaVersion: 1.0.0 6 | 7 | commandTests: 8 | - name: 'correct java version is installed' 9 | command: ['java', '-version'] 10 | expectedError: ['openjdk version "${openjdk.version.major}'] 11 | - name: 'correct javac version is installed' 12 | command: ['javac', '-version'] 13 | expectedOut: ['javac ${openjdk.version.major}'] 14 | - name: 'compilation of openjdk11 code works' 15 | setup: [['chmod', '+x', '/workspace/jdk11-compilation-test/compile-and-run.sh']] 16 | command: ['/workspace/jdk11-compilation-test/compile-and-run.sh', '/workspace/jdk11-compilation-test'] 17 | expectedOut: ['Greetings World!'] 18 | -------------------------------------------------------------------------------- /openjdk8/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 4.0.0 21 | 22 | com.google.cloud.runtimes 23 | openjdk-parent 24 | 0.1.0-SNAPSHOT 25 | ../pom.xml 26 | 27 | Google App Engine Image for OpenJDK (openjdk8) 28 | openjdk8 29 | pom 30 | 31 | 32 | 8 33 | 34 | ${openjdk.version.major}${openjdk.version.minor} 35 | gcr.io/google-appengine/debian9 36 | ${docker.image.baseName}:${docker.tag.long} 37 | 38 | 39 | 40 | 41 | com.google.cloud.runtimes 42 | openjdk-common 43 | ${project.version} 44 | tar.gz 45 | 46 | 47 | com.google.cloud.runtimes 48 | openjdk-test-common 49 | ${project.version} 50 | tar.gz 51 | 52 | 53 | com.google.cloud.runtimes 54 | test-spring-application 55 | 1.0.0 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-dependency-plugin 64 | 65 | 66 | unpack-openjdk-common 67 | generate-resources 68 | 69 | 70 | unpack-openjdk-test-common 71 | generate-test-resources 72 | 73 | 74 | 75 | 76 | 77 | io.fabric8 78 | docker-maven-plugin 79 | 80 | 81 | docker-build 82 | package 83 | 84 | 85 | 86 | 87 | 88 | org.codehaus.mojo 89 | exec-maven-plugin 90 | 91 | 92 | 93 | common-structure-test 94 | integration-test 95 | 96 | 97 | local-shutdown-test 98 | integration-test 99 | 100 | 101 | 102 | openjdk8-structure-test 103 | integration-test 104 | 105 | exec 106 | 107 | 108 | ${project.parent.basedir}/scripts/structure_test.sh 109 | ${project.basedir} 110 | 111 | ${docker.image.name} 112 | ${project.build.testOutputDirectory} 113 | ${project.build.testOutputDirectory}/openjdk8-structure.yaml 114 | 115 | 116 | 117 | 118 | 119 | 120 | maven-resources-plugin 121 | 122 | 123 | generate-test-resources 124 | generate-test-resources 125 | 126 | testResources 127 | 128 | 129 | ${project.build.testOutputDirectory} 130 | 131 | 132 | ${basedir}/src/test/resources 133 | true 134 | 135 | ** 136 | 137 | 138 | 139 | 140 | 141 | 142 | copy-resources 143 | generate-resources 144 | 145 | copy-resources 146 | 147 | 148 | ${docker.staging.dir} 149 | 150 | 151 | ${basedir}/src/main/docker 152 | true 153 | 154 | ** 155 | 156 | 157 | 158 | 159 | 160 | 161 | filter-test-resources 162 | process-test-resources 163 | 164 | copy-resources 165 | 166 | 167 | ${project.build.testOutputDirectory}/openjdk-test-common-out 168 | 169 | 170 | ${project.build.testOutputDirectory}/openjdk-test-common 171 | true 172 | 173 | ** 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /openjdk8/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM ${docker.appengine.image} 16 | ENV DEBIAN_FRONTEND noninteractive 17 | 18 | # Create env vars to identify image 19 | ENV OPENJDK_VERSION ${openjdk.version} 20 | ENV GAE_IMAGE_NAME ${project.artifactId} 21 | ENV GAE_IMAGE_LABEL ${docker.tag.long} 22 | 23 | RUN echo 'deb http://archive.debian.org/debian stretch main' > /etc/apt/sources.list \ 24 | && apt-get -q update \ 25 | && apt-get -y -q --no-install-recommends install \ 26 | # install the jdk and its dependencies 27 | ca-certificates-java \ 28 | # procps is used in the jvm shutdown hook 29 | procps \ 30 | # other system utilities 31 | netbase \ 32 | wget \ 33 | unzip \ 34 | fontconfig \ 35 | locales \ 36 | 37 | # cleanup package manager caches 38 | && apt-get clean \ 39 | && rm /var/lib/apt/lists/*_* 40 | 41 | ARG OPENJDK_VER='jdk8u345-b01' 42 | ARG OPENJDK_VER_NAME='8u345b01' 43 | ARG OPENJDK_TEMP_PATH='/tmp/openjdk' 44 | ARG OPENJDK_OUT='/usr/lib/openjdk' 45 | ENV PATH $OPENJDK_OUT/bin:$PATH 46 | ENV JAVA_HOME $OPENJDK_OUT 47 | 48 | RUN mkdir -p $OPENJDK_TEMP_PATH \ 49 | && mkdir -p $OPENJDK_OUT \ 50 | && wget -O $OPENJDK_TEMP_PATH/openjdk.tar.gz https://github.com/adoptium/temurin8-binaries/releases/download/$OPENJDK_VER/OpenJDK8U-jdk_x64_linux_hotspot_$OPENJDK_VER_NAME.tar.gz \ 51 | && tar Cxfvz --file $OPENJDK_TEMP_PATH/openjdk.tar.gz --directory $OPENJDK_TEMP_PATH --no-same-owner \ 52 | && rm $OPENJDK_TEMP_PATH/openjdk.tar.gz \ 53 | && cp -r $OPENJDK_TEMP_PATH/$OPENJDK_VER/* $OPENJDK_OUT \ 54 | && rm -rf $OPENJDK_TEMP_PATH \ 55 | && ln -s $OPENJDK_OUT/bin/* /usr/local/bin/ 56 | 57 | # Add the Stackdriver Profiler libraries 58 | ADD https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz /opt/cprof/ 59 | COPY docker-entrypoint.bash / 60 | COPY setup-env.d /setup-env.d/ 61 | COPY shutdown/ /shutdown/ 62 | RUN tar Cxfvz /opt/cprof /opt/cprof/profiler_java_agent.tar.gz --no-same-owner \ 63 | && rm /opt/cprof/profiler_java_agent.tar.gz \ 64 | && chmod +x /docker-entrypoint.bash /shutdown/*.bash /setup-env.d/*.bash \ 65 | && mkdir /var/log/app_engine \ 66 | && chmod go+rwx /var/log/app_engine 67 | 68 | ENV APP_DESTINATION ${docker.application.destination} 69 | 70 | ENTRYPOINT ["/docker-entrypoint.bash"] 71 | CMD ["java", "-jar", "${docker.application.destination}"] 72 | -------------------------------------------------------------------------------- /openjdk8/src/test/resources/openjdk8-structure.yaml: -------------------------------------------------------------------------------- 1 | # Test spec for the Cloud Runtimes container structure testing framework. 2 | # 3 | # See https://github.com/GoogleCloudPlatform/runtimes-common/tree/master/functional_tests/README.md for more detail. 4 | # 5 | schemaVersion: 1.0.0 6 | 7 | commandTests: 8 | - name: 'correct java version is installed' 9 | command: ['java', '-version'] 10 | expectedError: ['openjdk version "1\.${openjdk.version.major}.*${openjdk.version.minor}"'] 11 | - name: 'correct javac version is installed' 12 | command: ['javac', '-version'] 13 | expectedError: ['javac 1\.${openjdk.version.major}.*${openjdk.version.minor}'] 14 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 4.0.0 18 | 19 | com.google.cloud.runtimes 20 | openjdk-parent 21 | 0.1.0-SNAPSHOT 22 | pom 23 | Google App Engine OpenJDK Runtime Parent 24 | 25 | 26 | UTF-8 27 | UTF-8 28 | yyyy-MM-dd-HH-mm 29 | ${openjdk.version.major} 30 | ${openjdk.version.major}-${maven.build.timestamp} 31 | openjdk 32 | app.jar 33 | ${project.build.outputDirectory}/docker 34 | 35 | 36 | 37 | 38 | Apache License 2.0 39 | http://www.apache.org/licenses/LICENSE-2.0.html 40 | repo 41 | 42 | 43 | 44 | 45 | openjdk-common 46 | openjdk-test-common 47 | openjdk8 48 | openjdk11 49 | java-runtimes-common/test-spring-application 50 | 51 | 52 | 53 | 54 | 55 | junit 56 | junit 57 | 4.12 58 | test 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-enforcer-plugin 69 | 1.4.1 70 | 71 | 72 | 73 | [3.3,) 74 | 75 | 76 | [1.8,) 77 | 78 | 79 | 80 | 81 | 82 | 83 | io.fabric8 84 | docker-maven-plugin 85 | 0.21.0 86 | 87 | true 88 | always 89 | 90 | 91 | ${docker.image.name} 92 | 93 | ${docker.staging.dir} 94 | true 95 | 96 | ${docker.tag.short} 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | docker-build 105 | none 106 | 107 | build 108 | 109 | 110 | 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-dependency-plugin 116 | 2.10 117 | 118 | 119 | 120 | unpack-openjdk-common 121 | none 122 | 123 | unpack 124 | 125 | 126 | 127 | 128 | com.google.cloud.runtimes 129 | openjdk-common 130 | ${project.version} 131 | tar.gz 132 | true 133 | ${docker.staging.dir} 134 | 135 | 136 | 137 | 138 | 139 | unpack-openjdk-test-common 140 | none 141 | 142 | unpack 143 | 144 | 145 | 146 | 147 | com.google.cloud.runtimes 148 | openjdk-test-common 149 | ${project.version} 150 | tar.gz 151 | true 152 | ${project.build.testOutputDirectory}/openjdk-test-common 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.codehaus.mojo 162 | exec-maven-plugin 163 | 1.4.0 164 | 165 | 166 | common-structure-test 167 | 169 | none 170 | 171 | exec 172 | 173 | 174 | ${project.parent.basedir}/scripts/structure_test.sh 175 | ${project.build.outputDirectory} 176 | 177 | ${docker.image.name} 178 | ${project.build.testOutputDirectory}/openjdk-test-common-out/workspace 179 | ${project.build.testOutputDirectory}/openjdk-test-common-out/structure.yaml 180 | 181 | 182 | 183 | 184 | local-shutdown-test 185 | 187 | none 188 | 189 | exec 190 | 191 | 192 | ${project.parent.basedir}/scripts/local_shutdown_test.sh 193 | ${project.build.outputDirectory} 194 | 195 | ${docker.image.name} 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | org.apache.maven.plugins 204 | maven-compiler-plugin 205 | 3.2 206 | 207 | 1.8 208 | 1.8 209 | 210 | 211 | 212 | 213 | org.apache.maven.plugins 214 | maven-resources-plugin 215 | 3.0.1 216 | 217 | 218 | 219 | org.apache.maven.plugins 220 | maven-surefire-plugin 221 | 2.18 222 | 223 | false 224 | 225 | 226 | 227 | 228 | org.apache.maven.plugins 229 | maven-install-plugin 230 | 2.5.2 231 | 232 | 233 | 234 | org.apache.maven.plugins 235 | maven-jar-plugin 236 | 2.5 237 | 238 | 239 | 240 | org.apache.maven.plugins 241 | maven-antrun-plugin 242 | 1.8 243 | 244 | 245 | 246 | org.apache.maven.plugins 247 | maven-deploy-plugin 248 | 2.8.2 249 | 250 | 251 | 252 | 253 | 254 | 255 | org.apache.maven.plugins 256 | maven-checkstyle-plugin 257 | 2.17 258 | true 259 | 260 | 261 | com.puppycrawl.tools 262 | checkstyle 263 | 8.1 264 | 265 | 266 | 267 | 268 | checkstyle 269 | validate 270 | 271 | check 272 | 273 | 274 | google_checks.xml 275 | checkstyle/checkstyle-suppressions.xml 276 | true 277 | true 278 | error 279 | true 280 | true 281 | 282 | 283 | 284 | 285 | 286 | org.apache.maven.plugins 287 | maven-failsafe-plugin 288 | 2.19.1 289 | 290 | false 291 | 292 | 293 | 294 | 295 | integration-test 296 | verify 297 | 298 | 299 | 300 | 301 | 302 | org.apache.maven.surefire 303 | surefire-junit47 304 | 2.19.1 305 | 306 | 307 | 308 | 309 | org.codehaus.mojo 310 | properties-maven-plugin 311 | 1.0.0 312 | 313 | 314 | build-properties 315 | 316 | write-project-properties 317 | 318 | 319 | 320 | ${project.build.directory}/build.properties 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | -------------------------------------------------------------------------------- /scripts/ae_integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2016 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | # Runs integration tests on a given runtime image 20 | 21 | readonly dir=`dirname $0` 22 | readonly projectRoot=$dir/.. 23 | readonly testAppDir=$projectRoot/java-runtimes-common/test-spring-application 24 | readonly deployDir=$testAppDir/target/deploy 25 | readonly DEPLOYMENT_TOKEN=$(date -u +%Y-%m-%d-%H-%M-%S-%N) 26 | 27 | readonly imageUnderTest=$1 28 | if [ -z "${imageUnderTest}" ]; then 29 | echo "Usage: ${0} [gae_deployment_version]" 30 | exit 1 31 | fi 32 | 33 | # If provided, pin to a specific version. Otherwise, generate a random new version ID to prevent 34 | # inadvertent collisions. 35 | gaeDeploymentVersion=$2 36 | if [ -z "${gaeDeploymentVersion}" ]; then 37 | gaeDeploymentVersion=$(date -u +%Y-%m-%d-%H-%M-%S-%N) 38 | readonly tearDown="true" 39 | fi 40 | DEPLOYMENT_OPTS="-v $gaeDeploymentVersion --no-promote --no-stop-previous-version" 41 | DEPLOYMENT_VERSION_URL_PREFIX="$gaeDeploymentVersion-dot-" 42 | 43 | # build the test app 44 | pushd $testAppDir 45 | mvn clean install -Pruntime.custom -Dapp.deploy.image=$imageUnderTest -Ddeployment.token="${DEPLOYMENT_TOKEN}" -DskipTests --batch-mode 46 | popd 47 | 48 | # deploy to app engine 49 | pushd $deployDir 50 | echo "Deploying to App Engine: gcloud app deploy -q ${DEPLOYMENT_OPTS}" 51 | gcloud app deploy -q ${DEPLOYMENT_OPTS} 52 | popd 53 | 54 | DEPLOYED_APP_URL="http://${DEPLOYMENT_VERSION_URL_PREFIX}$(gcloud app describe | grep defaultHostname | awk '{print $2}')" 55 | 56 | echo "App deployed to URL: $DEPLOYED_APP_URL, making sure it accepts connections..." 57 | # sometimes AppEngine deploys, returns the URL and then serves 502 errors, this was introduced to wait for that to be resolved 58 | until [[ $(curl --silent --fail "$DEPLOYED_APP_URL/deployment.token" | grep "$DEPLOYMENT_TOKEN") ]]; do 59 | sleep 2 60 | done 61 | 62 | 63 | echo "Success pinging app! Output: " 64 | echo "-----" 65 | curl -s "${DEPLOYED_APP_URL}" 66 | echo "" 67 | echo "Deployment token: $DEPLOYMENT_TOKEN" 68 | echo "-----" 69 | 70 | echo "Running integration tests on application that is deployed at $DEPLOYED_APP_URL" 71 | 72 | # run in cloud container builder 73 | gcloud builds submit \ 74 | --config $dir/integration_test.yaml \ 75 | --substitutions "_DEPLOYED_APP_URL=$DEPLOYED_APP_URL" \ 76 | $dir 77 | 78 | if [ "$tearDown" == "true" ]; then 79 | # run a cleanup build once tests have finished executing 80 | gcloud builds submit \ 81 | --config $dir/integration_test_cleanup.yaml \ 82 | --substitutions "_VERSION=$gaeDeploymentVersion" \ 83 | --async \ 84 | --no-source 85 | fi 86 | 87 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2016 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | usage() { 20 | echo "Usage: ${0} " 21 | echo " where include:" 22 | echo " -p|--publishing-project - GCP project to use for publishing. Used to generate the destination docker repository name in gcr.io" 23 | echo " -m|--module - one of {openjdk8, openjdk11}" 24 | echo " [ -t|--tag-suffix ] - suffix for the tag that is applied to the built image" 25 | echo " [ -s|--staging-project ] - GCP project to use for staging images. If not provided, the publishing project will be used." 26 | echo " [ -l|--local ] - runs the build locally" 27 | exit 1 28 | } 29 | 30 | # Parse arguments to this script 31 | while [[ $# -gt 0 ]]; do 32 | key="$1" 33 | case $key in 34 | -p|--publishing-project) 35 | PUBLISHING_PROJECT="$2" 36 | shift # past argument 37 | ;; 38 | -m|--module) 39 | MODULE="$2" 40 | shift # past argument 41 | ;; 42 | -t|--tag-suffix) 43 | TAG_SUFFIX="$2" 44 | shift # past argument 45 | ;; 46 | -s|--staging-project) 47 | STAGING_PROJECT="$2" 48 | shift # past argument 49 | ;; 50 | -l|--local) 51 | LOCAL_BUILD="true" 52 | ;; 53 | *) 54 | # unknown option 55 | usage 56 | ;; 57 | esac 58 | shift 59 | done 60 | 61 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 62 | PROJECT_ROOT=$DIR/.. 63 | RUNTIME_NAME="openjdk" 64 | 65 | if [ -z "${PUBLISHING_PROJECT}" -o -z "${MODULE}" ]; then 66 | usage 67 | fi 68 | 69 | if [ "${MODULE}" == "openjdk8" ]; then 70 | TAG_PREFIX="8" 71 | elif [ "${MODULE}" == "openjdk11" ]; then 72 | TAG_PREFIX="11" 73 | else 74 | echo "${MODULE} is not a supported module" 75 | usage 76 | fi 77 | 78 | if [ -z "$TAG_SUFFIX" ]; then 79 | TAG_SUFFIX="$(date -u +%Y-%m-%d_%H_%M)" 80 | fi 81 | 82 | if [ -z "${STAGING_PROJECT}" ]; then 83 | STAGING_PROJECT=$PUBLISHING_PROJECT 84 | fi 85 | 86 | # export TAG, IMAGE for use in downstream scripts 87 | export TAG="${TAG_PREFIX}-${TAG_SUFFIX}" 88 | export IMAGE="gcr.io/${PUBLISHING_PROJECT}/${RUNTIME_NAME}:${TAG}" 89 | echo "IMAGE: $IMAGE" 90 | 91 | STAGING_IMAGE="gcr.io/${STAGING_PROJECT}/${RUNTIME_NAME}_staging:${TAG}" 92 | 93 | # build and test the runtime image 94 | BUILD_FLAGS="--config $PROJECT_ROOT/cloudbuild.yaml" 95 | BUILD_FLAGS="$BUILD_FLAGS --substitutions _IMAGE=$IMAGE,_MODULE=$MODULE" # temporarily getting rid of this ,_STAGING_IMAGE=$STAGING_IMAGE" 96 | BUILD_FLAGS="$BUILD_FLAGS $PROJECT_ROOT" 97 | 98 | if [ "${LOCAL_BUILD}" = "true" ]; then 99 | if [ ! $(which cloud-build-local) ]; then 100 | echo "The cloud-build-local tool is required to perform a local build. To install it, run 'gcloud components install cloud-build-local'" 101 | exit 1 102 | fi 103 | cloud-build-local --dryrun=false $BUILD_FLAGS 104 | else 105 | gcloud builds submit --timeout=25m $BUILD_FLAGS 106 | fi 107 | 108 | -------------------------------------------------------------------------------- /scripts/ci-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2016 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Build script for CI-like environments. Sets up local dependencies required for performing a 18 | # continuous-integration build. 19 | set -e 20 | 21 | dir=$(dirname "$0") 22 | 23 | # downloads, unpacks, installs the cloud SDK 24 | source "$dir"/gcloud-init.sh 25 | 26 | cd github/openjdk-runtime 27 | TAG_SUFFIX=$(git rev-parse --short HEAD) 28 | 29 | echo "Invoking build.sh with GCP_PROJECT=$GCP_PROJECT, MODULE=$MODULE, TAG_SUFFIX=$TAG_SUFFIX" 30 | source ./scripts/build.sh --publishing-project "$GCP_PROJECT" --module "$MODULE" --tag-suffix "$TAG_SUFFIX" 31 | 32 | if [ -z "$IMAGE" ]; then 33 | echo "Error: \$IMAGE not defined. It should be exported by build.sh script." 34 | exit 1 35 | fi 36 | 37 | -------------------------------------------------------------------------------- /scripts/deploy-check-openjdk8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export KOKORO_GITHUB_DIR=${KOKORO_ROOT}/src/github 4 | source ${KOKORO_GFILE_DIR}/kokoro/common.sh 5 | 6 | mkdir -p ${KOKORO_GITHUB_DIR}/${SAMPLE_APP_DIRECTORY} 7 | 8 | cd ${KOKORO_GITHUB_DIR}/${SAMPLE_APP_SOURCE_DIRECTORY} 9 | 10 | mvn install --batch-mode -DskipTests -Pruntime.java,deploy.war 11 | 12 | cat < ${KOKORO_GITHUB_DIR}/${SAMPLE_APP_DIRECTORY}/app.yaml 13 | runtime: java 14 | env: flex 15 | runtime_config: 16 | server: jetty9 17 | resources: 18 | memory_gb: 2.5 19 | EOF 20 | 21 | cd ${KOKORO_GFILE_DIR}/appengine/integration_tests 22 | 23 | sudo /usr/local/bin/pip install --upgrade -r requirements.txt 24 | 25 | if [ -f ${KOKORO_GITHUB_DIR}/${SAMPLE_APP_SOURCE_DIRECTORY}/requirements.txt ] 26 | then 27 | sudo /usr/local/bin/pip install --upgrade -r ${KOKORO_GITHUB_DIR}/${SAMPLE_APP_SOURCE_DIRECTORY}/requirements.txt 28 | fi 29 | 30 | export DEPLOY_LATENCY_PROJECT='cloud-deploy-latency' 31 | 32 | skip_flag="" 33 | 34 | if [ "${SKIP_CUSTOM_LOGGING_TESTS}" = "true" -o "${SKIP_BUILDERS}" = "true" ]; then 35 | skip_flag="$skip_flag --skip-builders" 36 | fi 37 | 38 | if [ "${SKIP_XRT}" = "true" ]; then 39 | skip_flag="$skip_flag --skip-xrt" 40 | fi 41 | 42 | python deploy_check.py -d ${KOKORO_GITHUB_DIR}/${SAMPLE_APP_DIRECTORY} -l ${LANGUAGE} ${skip_flag} 43 | -------------------------------------------------------------------------------- /scripts/gcloud-init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2016 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # Set up gcloud and auth 19 | set -ex 20 | 21 | DIR=$(pwd) 22 | 23 | if [ -z $GCLOUD_FILE ]; then 24 | echo '$GCLOUD_FILE environment variable must be set.' 25 | exit 1 26 | fi 27 | 28 | if [ -z $KEYFILE ]; then 29 | echo '$KEYFILE environment variable must be set.' 30 | exit 1 31 | fi 32 | 33 | if [ -z $GCP_PROJECT ]; then 34 | echo '$GCP_PROJECT environment variable must be set.' 35 | exit 1 36 | fi 37 | 38 | LOCAL_GCLOUD_FILE=gcloud.tar.gz 39 | cp $GCLOUD_FILE $LOCAL_GCLOUD_FILE 40 | 41 | # Hide the output here, it's long. 42 | tar -xzf $LOCAL_GCLOUD_FILE 43 | export PATH=$DIR/google-cloud-sdk/bin:$PATH 44 | 45 | gcloud auth activate-service-account --key-file=$KEYFILE 46 | gcloud config set project $GCP_PROJECT 47 | gcloud config set compute/zone us-east1-b 48 | gcloud components install beta kubectl -q 49 | gcloud components install beta cloud-build-local 50 | -------------------------------------------------------------------------------- /scripts/gke_cluster_cleanup.yaml: -------------------------------------------------------------------------------- 1 | # Cloud Builder pipeline for tearing down integration test resources 2 | steps: 3 | - name: 'gcr.io/cloud-builders/gcloud' 4 | args: ['--quiet', 'container', 'clusters', 'delete', '$_CLUSTER_NAME', '--zone=$_ZONE'] 5 | 6 | -------------------------------------------------------------------------------- /scripts/gke_integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Setup environment for CI with GKE. 18 | # This include: 19 | # - Building a test application into a docker image 20 | # - Upload the image to Google Container Registry 21 | # - Create a Kubernetes cluster on GKE 22 | # - Deploy the application 23 | # - Run the integration test 24 | set -e 25 | 26 | readonly dir=$(dirname $0) 27 | readonly projectRoot="$dir/.." 28 | readonly testAppDir="$projectRoot/java-runtimes-common/test-spring-application" 29 | readonly deployDir="$testAppDir/target/deploy" 30 | readonly DEPLOYMENT_TOKEN=$(date -u +%Y-%m-%d-%H-%M-%S-%N) 31 | 32 | # The $TAG was introduced to be able to reuse the existing cluster but force redeployment. 33 | # Kubernetes' "kubectl apply -f" doesn't trigger a new deployment rollout unless there is a change in the yaml spec. 34 | # See https://github.com/kubernetes/kubernetes/issues/33664 for the debate around this behavior. 35 | 36 | if [ -z "${TAG}" ]; then 37 | export TAG="$(date -u +%Y-%m-%d_%H_%M)" 38 | fi 39 | 40 | readonly projectName=$(gcloud info \ 41 | | awk '/^Project: / { print $2 }' \ 42 | | sed 's/\[//' \ 43 | | sed 's/\]//') 44 | readonly imageName="openjdk-gke-integration:$TAG" 45 | readonly imageUrl="gcr.io/$projectName/$imageName" 46 | readonly defaultZone="us-east1-c" 47 | 48 | readonly imageUnderTest=$1 49 | clusterName=$2 50 | if [[ -z "$imageUnderTest" ]]; then 51 | echo "Usage: ${0} [gke_cluster_name]" 52 | exit 1 53 | fi 54 | 55 | if [[ -z "$clusterName" ]]; then 56 | # generate random alpha string 57 | clusterName=$(head /dev/urandom | tr -dc 'a-z' | fold -w 20 | head -n 1) 58 | readonly tearDown="true" 59 | fi 60 | 61 | # build the test app 62 | pushd ${testAppDir} 63 | mvn clean install -Pruntime.custom -Dapp.deploy.image=$imageUnderTest -Ddeployment.token="${DEPLOYMENT_TOKEN}" -DskipTests --batch-mode 64 | popd 65 | 66 | # deploy to Google Kubernetes Engine 67 | pushd ${deployDir} 68 | export TESTED_IMAGE=${imageUrl} 69 | envsubst < "openjdk-spring-boot.yaml.in" > "openjdk-spring-boot.yaml" 70 | 71 | echo "Deploying image to Google Container Registry..." 72 | gcloud docker -- build -t "$imageName" . 73 | gcloud docker -- tag "$imageName" "$imageUrl" 74 | gcloud docker -- push gcr.io/${projectName}/${imageName} 75 | 76 | echo "Creating or searching for a Kubernetes cluster..." 77 | TEST_CLUSTER_EXISTENCE=$(gcloud container clusters list --zone="$defaultZone" | awk "/$clusterName/") 78 | if [ -z "$TEST_CLUSTER_EXISTENCE" ]; then 79 | gcloud container clusters create "$clusterName" --num-nodes=1 --disk-size=10 --zone="$defaultZone" 80 | fi 81 | 82 | echo "Deploying application to Google Kubernetes Engine..." 83 | gcloud container clusters get-credentials ${clusterName} --zone="$defaultZone" 84 | kubectl apply -f "openjdk-spring-boot.yaml" 85 | popd 86 | 87 | echo "Waiting for the application to be accessible (expected time: ~1min)" 88 | 89 | # The load balancer service may take some time to expose the application 90 | # (~ 2 min on the cluster creation) 91 | until [[ $(curl --silent --fail "http://$DEPLOYED_APP_URL/deployment.token" | grep "$DEPLOYMENT_TOKEN") ]]; do 92 | sleep 5 93 | DEPLOYED_APP_URL=$(kubectl describe services openjdk-spring-boot \ 94 | | awk '/LoadBalancer Ingress/ { print $3 }') 95 | echo "Current URL for app: $DEPLOYED_APP_URL, deployment token: $DEPLOYMENT_TOKEN. Making sure it accepts connections..." 96 | done 97 | 98 | # run in cloud container builder 99 | echo "Running integration tests on application that is deployed at $DEPLOYED_APP_URL" 100 | gcloud builds submit \ 101 | --config ${dir}/integration_test.yaml \ 102 | --substitutions "_DEPLOYED_APP_URL=http://$DEPLOYED_APP_URL" \ 103 | ${dir} 104 | 105 | # teardown any resources we created 106 | if [ "$tearDown" == "true" ]; then 107 | # run a cleanup build once tests have finished executing 108 | gcloud builds submit \ 109 | --config $dir/gke_cluster_cleanup.yaml \ 110 | --substitutions "_CLUSTER_NAME=$clusterName,_ZONE=$defaultZone" \ 111 | --async \ 112 | --no-source 113 | fi 114 | -------------------------------------------------------------------------------- /scripts/integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Setup environment for CI. 18 | # This script exits as soon as any of the commands in the integration scripts fail 19 | # (including remote failure from Google Cloud Container Builder) 20 | set -e 21 | 22 | readonly dir=`dirname $0` 23 | 24 | imageUnderTest=$1 25 | if [ -z "${imageUnderTest}" ]; then 26 | echo "Usage: ${0} [gae_deployment_version]" 27 | exit 1 28 | fi 29 | 30 | # for local tests it makes sense sometimes to pin the deployment to an 31 | # active version as that will speed up the deployment, for CI/CD this feature 32 | # is not recommended 33 | readonly gaeDeploymentVersion=$2 34 | 35 | ${dir}/local_shutdown_test.sh ${imageUnderTest} 36 | 37 | ${dir}/ae_integration_test.sh ${imageUnderTest} ${gaeDeploymentVersion} 38 | 39 | ${dir}/gke_integration_test.sh ${imageUnderTest} 40 | -------------------------------------------------------------------------------- /scripts/integration_test.yaml: -------------------------------------------------------------------------------- 1 | # Cloud Builder pipeline for running integration tests 2 | # https://cloud.google.com/container-builder/docs/overview 3 | steps: 4 | # Runtimes-common integration tests 5 | # See https://github.com/GoogleCloudPlatform/runtimes-common/tree/master/integration_tests 6 | 7 | # temporarily we'll depend on our own version until the runtimes-common version is pushed 8 | # - name: 'gcr.io/gcp-runtimes/integration_test' 9 | - name: 'gcr.io/java-runtime-test/integration-test' 10 | args: 11 | - '--url=${_DEPLOYED_APP_URL}' 12 | - '--skip-standard-logging-tests' # blocked by b/33415496 13 | - '--skip-custom-tests' 14 | - '--skip-monitoring-tests' 15 | 16 | -------------------------------------------------------------------------------- /scripts/integration_test_cleanup.yaml: -------------------------------------------------------------------------------- 1 | # Cloud Builder pipeline for tearing down integration test resources 2 | steps: 3 | - name: 'gcr.io/cloud-builders/gcloud' 4 | args: ['--quiet', 'app', 'versions', 'delete', '$_VERSION'] 5 | 6 | -------------------------------------------------------------------------------- /scripts/local_runtimes_common_integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # exit on command failure 19 | set -e 20 | 21 | readonly dir=$(dirname $0) 22 | readonly projectRoot="$dir/.." 23 | readonly testAppDir="$projectRoot/java-runtimes-common/test-spring-application" 24 | readonly deployDir="$testAppDir/target/deploy" 25 | 26 | APP_IMAGE='openjdk-local-integration' 27 | CONTAINER=${APP_IMAGE}-container 28 | OUTPUT_FILE=${CONTAINER}-output.txt 29 | DEPLOYMENT_TOKEN=$(date -u +%Y-%m-%d-%H-%M-%S-%N) 30 | 31 | readonly imageUnderTest=$1 32 | if [[ -z "$imageUnderTest" ]]; then 33 | echo "Usage: ${0} " 34 | exit 1 35 | fi 36 | 37 | if [[ ! -f $HOME/.config/gcloud/application_default_credentials.json ]]; then 38 | # get default application credentials 39 | gcloud auth application-default login 40 | fi 41 | 42 | # build the test app 43 | pushd ${testAppDir} 44 | mvn clean package -Pruntime.custom -Ddeployment.token="${DEPLOYMENT_TOKEN}" -Dapp.deploy.image=${imageUnderTest} -DskipTests --batch-mode 45 | popd 46 | 47 | # build app container locally 48 | pushd $deployDir 49 | export STAGING_IMAGE=$imageUnderTest 50 | echo "Building app container..." 51 | docker build -t $APP_IMAGE . || docker build -t $APP_IMAGE . 52 | 53 | docker rm -f $CONTAINER || echo "Integration-test-app container is not running, ready to start a new instance." 54 | 55 | # run app container locally to test shutdown logging 56 | echo "Starting app container..." 57 | docker run --rm --name $CONTAINER -p 8080 \ 58 | -e "SHUTDOWN_LOGGING_THREAD_DUMP=true" \ 59 | -e "SHUTDOWN_LOGGING_HEAP_INFO=true" \ 60 | -v "$HOME/.config/gcloud/:/root/.config/gcloud" $APP_IMAGE &> $OUTPUT_FILE & 61 | 62 | function waitForOutput() { 63 | found_output='false' 64 | for run in {1..10} 65 | do 66 | grep "$1" $OUTPUT_FILE && found_output='true' && break 67 | sleep 1 68 | done 69 | 70 | if [ "$found_output" == "false" ]; then 71 | cat $OUTPUT_FILE 72 | echo "did not match '$1' in '$OUTPUT_FILE'" 73 | exit 1 74 | fi 75 | } 76 | 77 | waitForOutput 'Started Application' 78 | 79 | getPort() { 80 | docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}}{{(index $conf 0).HostPort}}{{end}}' ${CONTAINER} 81 | } 82 | 83 | 84 | PORT=`getPort` 85 | 86 | nslookup `hostname` | grep Address | grep -v 127.0 | awk '{print $2}' > /tmp/myip 87 | MYIP=`cat /tmp/myip` 88 | 89 | DEPLOYED_APP_URL=http://$MYIP:$PORT 90 | 91 | echo app is deployed to $DEPLOYED_APP_URL, making sure it accepts connections 92 | 93 | 94 | until [[ $(curl --silent --fail "$DEPLOYED_APP_URL/deployment.token" | grep "$DEPLOYMENT_TOKEN") ]]; do 95 | sleep 2 96 | done 97 | popd 98 | 99 | docker rm -f metadata || echo "ready to run local cloud builder" 100 | 101 | # run in cloud container builder 102 | echo "Running integration tests on application that is deployed at $DEPLOYED_APP_URL" 103 | echo `pwd` 104 | cloud-build-local \ 105 | --config ${dir}/integration_test.yaml \ 106 | --substitutions "_DEPLOYED_APP_URL=$DEPLOYED_APP_URL" \ 107 | --dryrun=false \ 108 | ${dir} 109 | -------------------------------------------------------------------------------- /scripts/local_shutdown_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # exit on command failure 19 | set -e 20 | 21 | readonly dir=$(dirname $0) 22 | readonly projectRoot="$dir/.." 23 | readonly testAppDir="$projectRoot/java-runtimes-common/test-spring-application" 24 | readonly deployDir="$testAppDir/target/deploy" 25 | 26 | APP_IMAGE='openjdk-local-integration' 27 | CONTAINER=${APP_IMAGE}-container 28 | OUTPUT_FILE=${CONTAINER}-output.txt 29 | 30 | readonly imageUnderTest=$1 31 | if [[ -z "$imageUnderTest" ]]; then 32 | echo "Usage: ${0} " 33 | exit 1 34 | fi 35 | 36 | 37 | pushd ${testAppDir} 38 | mvn clean package -Pruntime.custom -Dapp.deploy.image=$imageUnderTest -DskipTests --batch-mode 39 | popd 40 | 41 | # build app container locally 42 | pushd $deployDir 43 | echo "Building app container..." 44 | docker build -t $APP_IMAGE . || gcloud docker -- build -t $APP_IMAGE . 45 | 46 | docker rm -f $CONTAINER || echo "Integration-test-app container is not running, ready to start a new instance." 47 | 48 | # run app container locally to test shutdown logging 49 | # as ServiceOptions.getDefaultProjectId takes 2 minutes to timeout on Argo 50 | # builds, when using "sibling" containers, we use --net=host to make the call 51 | # to the metadata server faster 52 | 53 | echo "Starting app container..." 54 | docker run --rm --memory="1g" --net=host --name $CONTAINER -e "SHUTDOWN_LOGGING_THREAD_DUMP=true" -e "SHUTDOWN_LOGGING_HEAP_INFO=true" $APP_IMAGE &> $OUTPUT_FILE & 55 | 56 | function waitForOutput() { 57 | found_output='false' 58 | for run in {1..20} 59 | do 60 | grep -P "$1" $OUTPUT_FILE && found_output='true' && break 61 | sleep 1 62 | done 63 | 64 | if [ "$found_output" == "false" ]; then 65 | cat $OUTPUT_FILE 66 | echo "did not match '$1' in '$OUTPUT_FILE'" 67 | exit 1 68 | fi 69 | } 70 | 71 | waitForOutput 'Started Application' 72 | 73 | docker stop $CONTAINER 74 | 75 | docker rmi $APP_IMAGE 76 | 77 | echo 'verify thread dump' 78 | waitForOutput 'Full thread dump OpenJDK 64-Bit Server VM' 79 | 80 | echo 'verify heap info' 81 | waitForOutput '\d+:\s+\d+\s+\d+\s+java.lang.Class' 82 | 83 | popd 84 | 85 | echo 'OK' 86 | -------------------------------------------------------------------------------- /scripts/release-openjdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export KOKORO_GITHUB_DIR=${KOKORO_ROOT}/src/github 3 | source ${KOKORO_GFILE_DIR}/kokoro/common.sh 4 | 5 | cd ${KOKORO_GITHUB_DIR}/openjdk-runtime 6 | 7 | params="--publishing-project ${PUBLISHING_PROJECT} --staging-project ${GCP_TEST_PROJECT} --module ${MODULE}" 8 | if [ -n "${TAG_SUFFIX}" ]; then 9 | params="$params --tag-suffix ${TAG_SUFFIX}" 10 | fi 11 | 12 | source ./scripts/build.sh ${params} -------------------------------------------------------------------------------- /scripts/structure_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2016 Google Inc. All rights reserved. 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # 18 | # Fetch and execute the structure test framework run script. 19 | set -e 20 | 21 | dir=`dirname $0` 22 | scriptPath=https://storage.googleapis.com/container-structure-test/v1.1.0/container-structure-test 23 | destDir=$dir/../target 24 | fileName=$destDir/container-structure-test 25 | 26 | if [ ! -d $destDir ] 27 | then 28 | mkdir -p $destDir 29 | fi 30 | 31 | wget -O $fileName --no-verbose $scriptPath 32 | chmod +x $fileName 33 | 34 | IMAGE=$1 35 | WORKSPACE=$2 36 | CONFIG=$3 37 | TEST_IMAGE="${IMAGE}-struct-test" 38 | 39 | pushd `pwd` 40 | cd $WORKSPACE 41 | echo "Creating temporary image $TEST_IMAGE" 42 | cat < Dockerfile 43 | FROM $IMAGE 44 | ADD . /workspace 45 | EOF 46 | docker build -t $TEST_IMAGE . 47 | rm Dockerfile 48 | popd 49 | 50 | $fileName test --image $TEST_IMAGE --config $CONFIG 51 | 52 | --------------------------------------------------------------------------------