diff --git a/memorystore/redis/README.md b/memorystore/redis/README.md new file mode 100644 index 00000000000..e2de0f60232 --- /dev/null +++ b/memorystore/redis/README.md @@ -0,0 +1,17 @@ +# Getting started with Googe Cloud Memorystore +Simple HTTP server example to demonstrate connecting to [Google Cloud Memorystore](https://cloud.google.com/memorystore/docs/redis) +This sample uses the [Jedis client](https://mvnrepository.com/artifact/redis.clients/jedis). +Please see other client library options [here](https://redis.io/clients#java). + +## Running on GCE + +Follow the instructions in [this guide](https://cloud.google.com/memorystore/docs/redis/connect-redis-instance-gce) to deploy the sample application on a GCE VM. + +## Running on GKE + +Follow the instructions in [this guide](https://cloud.google.com/memorystore/docs/redis/connect-redis-instance-gke) to deploy the sample application on GKE. + +## Running on Google App Engine Flex + +Follow the instructions in [this guide](https://cloud.google.com/memorystore/docs/redis/connect-redis-instance-flex) to deploy the sample application on GAE Flex. + diff --git a/memorystore/redis/flex_deployment/app.yaml b/memorystore/redis/flex_deployment/app.yaml new file mode 100644 index 00000000000..c49b943bf36 --- /dev/null +++ b/memorystore/redis/flex_deployment/app.yaml @@ -0,0 +1,17 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# [START memorystore_app_yaml] +runtime: java +env: flex +# [END memorystore_app_yaml] diff --git a/memorystore/redis/gce_deployment/deploy.sh b/memorystore/redis/gce_deployment/deploy.sh new file mode 100755 index 00000000000..06f8e5ec21b --- /dev/null +++ b/memorystore/redis/gce_deployment/deploy.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# [START memorystore_deploy_sh] +if [ -z "$GCS_APP_LOCATION" ]; then + if [ -z "$BUCKET"]; then + echo "Must set \$BUCKET. For example: BUCKET=my-bucket-name" + exit 1 + fi + GCS_APP_LOCATION="gs://$BUCKET/gce/" + echo $GCS_APP_LOCATION +fi + +if [ -z "$ZONE" ]; then + ZONE=$(gcloud config get-value compute/zone -q) + echo $ZONE +fi + +if [ -z "$WAR" ]; then + WAR=visitcounter-1.0-SNAPSHOT.war +fi + +#Build the WAR package +cd .. +mvn clean package + +#Copy the WAR artifact to the GCS bucket location +gsutil cp -r target/${WAR} ${GCS_APP_LOCATION} + +cd gce_deployment + +# Create an instance +gcloud compute instances create my-instance \ + --image-family=debian-9 \ + --image-project=debian-cloud \ + --machine-type=g1-small \ + --scopes cloud-platform \ + --metadata-from-file startup-script=startup-script.sh \ + --metadata app-location=${GCS_APP_LOCATION},app-war=$WAR \ + --zone $ZONE \ + --tags http-server + +gcloud compute firewall-rules create allow-http-server-8080 \ + --allow tcp:8080 \ + --source-ranges 0.0.0.0/0 \ + --target-tags http-server \ + --description "Allow port 8080 access to http-server" +# [END memorystore_deploy_sh] diff --git a/memorystore/redis/gce_deployment/startup-script.sh b/memorystore/redis/gce_deployment/startup-script.sh new file mode 100644 index 00000000000..5bd5ab72bbe --- /dev/null +++ b/memorystore/redis/gce_deployment/startup-script.sh @@ -0,0 +1,77 @@ +#! /bin/bash + +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# [START memorystore_startup_script_sh] +set -ex + +# Talk to the metadata server to get the project id and location of application binary. +PROJECTID=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google") +GCS_APP_LOCATION=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/app-location" -H "Metadata-Flavor: Google") +WAR=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/app-war" -H "Metadata-Flavor: Google") + +gsutil cp "$GCS_APP_LOCATION"** . + +# Install dependencies from apt +apt-get update +apt-get install -qq openjdk-8-jdk-headless + +# Make Java8 the default +update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java + +# Jetty Setup +mkdir -p /opt/jetty/temp +mkdir -p /var/log/jetty + +# Get Jetty +curl -L https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.10.v20180503/jetty-distribution-9.4.10.v20180503.tar.gz -o jetty9.tgz +tar xf jetty9.tgz --strip-components=1 -C /opt/jetty + +# Add a Jetty User +useradd --user-group --shell /bin/false --home-dir /opt/jetty/temp jetty + +cd /opt/jetty +# Add running as "jetty" +java -jar /opt/jetty/start.jar --add-to-startd=setuid +cd / + +# very important - by renaming the war to root.war, it will run as the root servlet. +mv $WAR /opt/jetty/webapps/root.war + +# Make sure "jetty" owns everything. +chown --recursive jetty /opt/jetty + +# Configure the default paths for the Jetty service +cp /opt/jetty/bin/jetty.sh /etc/init.d/jetty +echo "JETTY_HOME=/opt/jetty" > /etc/default/jetty +{ + echo "JETTY_BASE=/opt/jetty" + echo "TMPDIR=/opt/jetty/temp" + echo "JAVA_OPTIONS=-Djetty.http.port=8080" + echo "JETTY_LOGS=/var/log/jetty" +} >> /etc/default/jetty + + +# Reload daemon to pick up new service +systemctl daemon-reload + +# Install logging monitor. The monitor will automatically pickup logs sent to syslog. +curl -s "https://storage.googleapis.com/signals-agents/logging/google-fluentd-install.sh" | bash +service google-fluentd restart & + +service jetty start +service jetty check + +echo "Startup Complete" +# [END memorystore_startup_script_sh] diff --git a/memorystore/redis/gce_deployment/teardown.sh b/memorystore/redis/gce_deployment/teardown.sh new file mode 100755 index 00000000000..8277a5ce712 --- /dev/null +++ b/memorystore/redis/gce_deployment/teardown.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# [START memorystore_teardown_sh] +gcloud compute instances delete my-instance + +gcloud compute firewall-rules delete allow-http-server-8080 +# [END memorystore_teardown_sh] diff --git a/memorystore/redis/gke_deployment/Dockerfile b/memorystore/redis/gke_deployment/Dockerfile new file mode 100644 index 00000000000..2026f71135e --- /dev/null +++ b/memorystore/redis/gke_deployment/Dockerfile @@ -0,0 +1,17 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM launcher.gcr.io/google/jetty + +ADD target/visitcounter-1.0-SNAPSHOT.war $JETTY_BASE/webapps/root.war diff --git a/memorystore/redis/gke_deployment/visit-counter.yaml b/memorystore/redis/gke_deployment/visit-counter.yaml new file mode 100644 index 00000000000..a1fa7516158 --- /dev/null +++ b/memorystore/redis/gke_deployment/visit-counter.yaml @@ -0,0 +1,52 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: visit-counter + labels: + app: visit-counter +spec: + replicas: 1 + template: + metadata: + labels: + app: visit-counter + spec: + containers: + - name: visit-counter + image: "gcr.io//visit-counter:v1" + env: + - name: REDISHOST + valueFrom: + configMapKeyRef: + name: redishost + key: REDISHOST + ports: + - name: http + containerPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: visit-counter +spec: + type: LoadBalancer + selector: + app: visit-counter + ports: + - port: 80 + targetPort: 8080 + protocol: TCP diff --git a/memorystore/redis/pom.xml b/memorystore/redis/pom.xml new file mode 100644 index 00000000000..dc94e11472b --- /dev/null +++ b/memorystore/redis/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + war + 1.0-SNAPSHOT + com.example.redis + visitcounter + + + + com.google.cloud.samples + shared-configuration + 1.0.10 + + + + 1.8 + 1.8 + 9.4.10.v20180503 + false + + + + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + redis.clients + jedis + 2.9.0 + + + + + + + servlet/target/visitcounter-1.0-SNAPSHOT/WEB-INF/classes + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty} + + + + + com.google.cloud.tools + appengine-maven-plugin + 1.3.2 + + + + + diff --git a/memorystore/redis/src/main/java/com/example/redis/AppServletContextListener.java b/memorystore/redis/src/main/java/com/example/redis/AppServletContextListener.java new file mode 100644 index 00000000000..513ff8c331f --- /dev/null +++ b/memorystore/redis/src/main/java/com/example/redis/AppServletContextListener.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [START web_listener] + +package com.example.redis; + +import java.io.IOException; +import java.util.Properties; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; + +@WebListener +public class AppServletContextListener implements ServletContextListener { + + private Properties config = new Properties(); + + private JedisPool createJedisPool() throws IOException { + String host; + Integer port; + config.load( + Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream("application.properties")); + host = config.getProperty("redis.host"); + port = Integer.valueOf(config.getProperty("redis.port", "6379")); + + JedisPoolConfig poolConfig = new JedisPoolConfig(); + // Default : 8, consider how many concurrent connections into Redis you will need under load + poolConfig.setMaxTotal(128); + + return new JedisPool(poolConfig, host, port); + } + + @Override + public void contextDestroyed(ServletContextEvent event) { + JedisPool jedisPool = (JedisPool) event.getServletContext().getAttribute("jedisPool"); + if (jedisPool != null) { + jedisPool.destroy(); + event.getServletContext().setAttribute("jedisPool", null); + } + } + + // Run this before web application is started + @Override + public void contextInitialized(ServletContextEvent event) { + JedisPool jedisPool = (JedisPool) event.getServletContext().getAttribute("jedisPool"); + if (jedisPool == null) { + try { + jedisPool = createJedisPool(); + event.getServletContext().setAttribute("jedisPool", jedisPool); + } catch (IOException e) { + // handle exception + } + } + } +} +// [END web_listener] diff --git a/memorystore/redis/src/main/java/com/example/redis/VisitCounterServlet.java b/memorystore/redis/src/main/java/com/example/redis/VisitCounterServlet.java new file mode 100644 index 00000000000..5f66e69ad3b --- /dev/null +++ b/memorystore/redis/src/main/java/com/example/redis/VisitCounterServlet.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [START visit_servlet] + +package com.example.redis; + +import java.io.IOException; +import java.net.SocketException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +@WebServlet(name = "Track visits", value = "") +public class VisitCounterServlet extends HttpServlet { + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + JedisPool jedisPool = (JedisPool) req.getServletContext().getAttribute("jedisPool"); + + if (jedisPool == null) { + throw new SocketException("Error connecting to Jedis pool"); + } + Long visits; + + try (Jedis jedis = jedisPool.getResource()) { + visits = jedis.incr("visits"); + } + + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().println("Visitor counter: " + String.valueOf(visits)); + } catch (Exception e) { + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + } +} +// [END visit_servlet] diff --git a/memorystore/redis/src/main/resources/application.properties b/memorystore/redis/src/main/resources/application.properties new file mode 100644 index 00000000000..fc1a1a3ef54 --- /dev/null +++ b/memorystore/redis/src/main/resources/application.properties @@ -0,0 +1,16 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +redis.host=REDIS_HOST_IP +redis.port=6379 diff --git a/pom.xml b/pom.xml index deee7c101ea..b9d971b1e89 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,8 @@ monitoring/cloud-client monitoring/v3 + memorystore/redis + pubsub/cloud-client spanner/cloud-client