From c89f874025e8f00d03971ecf37c36b8de7844f25 Mon Sep 17 00:00:00 2001 From: Les Vogel Date: Mon, 7 Aug 2017 16:38:28 -0700 Subject: [PATCH 1/2] Add Templating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. App Engine Sockets (moved from GoogleArchive) 2. J8 GAE Info now uses ThymeLeaf templating 3. Flex GAE Info for combat (WL’d only) sample 4. J8 Metadata - Only uses the Metadata server --- appengine-java8/gaeinfo/pom.xml | 6 + .../appengine/standard/GaeInfoServlet.java | 189 ++++++++------- .../main/webapp/WEB-INF/templates/index.html | 99 ++++++++ appengine-java8/metadata/README.md | 51 ++++ appengine-java8/metadata/pom.xml | 107 +++++++++ .../appengine/standard/MetadataServlet.java | 161 +++++++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 24 ++ .../main/webapp/WEB-INF/templates/index.html | 49 ++++ .../metadata/src/main/webapp/WEB-INF/web.xml | 27 +++ appengine/sockets/README.md | 56 +++++ appengine/sockets/README_LIBS.md | 41 ++++ appengine/sockets/pom.xml | 99 ++++++++ .../appengine/sockets/WhoIsClientServlet.java | 101 ++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 10 + .../main/webapp/WEB-INF/logging.properties | 1 + .../sockets/src/main/webapp/WEB-INF/web.xml | 19 ++ appengine/sockets/src/main/webapp/favicon.ico | Bin 0 -> 8348 bytes .../sockets/src/main/webapp/redirect.jsp | 3 + flexible/gaeinfo/README.md | 52 +++++ flexible/gaeinfo/pom.xml | 107 +++++++++ .../appengine/flex_compat/GaeInfoServlet.java | 218 ++++++++++++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 27 +++ .../main/webapp/WEB-INF/templates/index.html | 99 ++++++++ .../gaeinfo/src/main/webapp/WEB-INF/web.xml | 27 +++ flexible/pom.xml | 1 + 25 files changed, 1475 insertions(+), 99 deletions(-) create mode 100644 appengine-java8/gaeinfo/src/main/webapp/WEB-INF/templates/index.html create mode 100644 appengine-java8/metadata/README.md create mode 100644 appengine-java8/metadata/pom.xml create mode 100644 appengine-java8/metadata/src/main/java/com/example/appengine/standard/MetadataServlet.java create mode 100644 appengine-java8/metadata/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine-java8/metadata/src/main/webapp/WEB-INF/templates/index.html create mode 100644 appengine-java8/metadata/src/main/webapp/WEB-INF/web.xml create mode 100644 appengine/sockets/README.md create mode 100644 appengine/sockets/README_LIBS.md create mode 100755 appengine/sockets/pom.xml create mode 100644 appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java create mode 100644 appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine/sockets/src/main/webapp/WEB-INF/logging.properties create mode 100644 appengine/sockets/src/main/webapp/WEB-INF/web.xml create mode 100644 appengine/sockets/src/main/webapp/favicon.ico create mode 100644 appengine/sockets/src/main/webapp/redirect.jsp create mode 100644 flexible/gaeinfo/README.md create mode 100644 flexible/gaeinfo/pom.xml create mode 100644 flexible/gaeinfo/src/main/java/com/example/appengine/flex_compat/GaeInfoServlet.java create mode 100644 flexible/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 flexible/gaeinfo/src/main/webapp/WEB-INF/templates/index.html create mode 100644 flexible/gaeinfo/src/main/webapp/WEB-INF/web.xml diff --git a/appengine-java8/gaeinfo/pom.xml b/appengine-java8/gaeinfo/pom.xml index a348dee0f0b..5a1bf510998 100644 --- a/appengine-java8/gaeinfo/pom.xml +++ b/appengine-java8/gaeinfo/pom.xml @@ -62,6 +62,12 @@ Copyright 2017 Google Inc. 2.8.1 + + org.thymeleaf + thymeleaf + 3.0.7.RELEASE + + diff --git a/appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GaeInfoServlet.java b/appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GaeInfoServlet.java index 1d1a76e689a..be190c197c2 100644 --- a/appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GaeInfoServlet.java +++ b/appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GaeInfoServlet.java @@ -21,22 +21,23 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - import java.io.IOException; -import java.io.PrintWriter; import java.util.Enumeration; import java.util.Map; import java.util.Properties; +import java.util.TreeMap; import java.util.concurrent.TimeUnit; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.WebContext; +import org.thymeleaf.templateresolver.ServletContextTemplateResolver; // [START example] @@ -46,7 +47,7 @@ urlPatterns = "/gaeinfo") public class GaeInfoServlet extends HttpServlet { - final String[] v1 = { + private final String[] metaPath = { "/computeMetadata/v1/project/numeric-project-id", // (pending) "/computeMetadata/v1/project/project-id", "/computeMetadata/v1/instance/zone", @@ -57,7 +58,7 @@ public class GaeInfoServlet extends HttpServlet { // "/computeMetadata/v1/instance/service-accounts/default/token" }; - final String[] v1Acct = { + final String[] metaServiceAcct = { "/computeMetadata/v1/instance/service-accounts/{account}/aliases", "/computeMetadata/v1/instance/service-accounts/{account}/email", "/computeMetadata/v1/instance/service-accounts/{account}/scopes", @@ -65,36 +66,22 @@ public class GaeInfoServlet extends HttpServlet { // "/computeMetadata/v1/instance/service-accounts/{account}/token" }; - final String metadata = "http://metadata.google.internal"; + private final String metadata = "http://metadata.google.internal"; + private TemplateEngine templateEngine; - public final OkHttpClient ok = new OkHttpClient.Builder() + // Use OkHttp from Square as it's quite easy to use for simple fetches. + private final OkHttpClient ok = new OkHttpClient.Builder() .readTimeout(500, TimeUnit.MILLISECONDS) // Don't dawdle .writeTimeout(500, TimeUnit.MILLISECONDS) .build(); - public Gson gson = new GsonBuilder() + // Setup to pretty print returned json + private final Gson gson = new GsonBuilder() .setPrettyPrinting() .create(); - public JsonParser jp = new JsonParser(); - - StringBuilder table(String title, String c) { - StringBuilder sb = new StringBuilder(); - sb.append("

"); - sb.append(title); - sb.append("

"); - sb.append(c); - sb.append("
"); - return sb; - } - - String tr(String c) { - return "" + c + ""; - } - - String td(String s) { - return "" + s + ""; - } + private final JsonParser jp = new JsonParser(); + // Fetch Metadata String fetchMetadata(String key) throws IOException { Request request = new Request.Builder() .url(metadata + key) @@ -106,122 +93,126 @@ String fetchMetadata(String key) throws IOException { return response.body().string(); } - String recursMetadata(String prefix) throws IOException { + String fetchJsonMetadata(String prefix) throws IOException { Request request = new Request.Builder() - .url(metadata + prefix + "?recursive=true") + .url(metadata + prefix ) .addHeader("Metadata-Flavor", "Google") .get() .build(); Response response = ok.newCall(request).execute(); + // Convert json to prety json return gson.toJson(jp.parse(response.body().string())); } - @Override - public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - resp.setContentType("text/html"); - PrintWriter p = resp.getWriter(); - StringBuilder sb = new StringBuilder(4096); + public void init() { + // Setup ThymeLeaf + ServletContextTemplateResolver templateResolver = + new ServletContextTemplateResolver(this.getServletContext()); + + templateResolver.setPrefix("/WEB-INF/templates/"); + templateResolver.setSuffix(".html"); + templateResolver.setCacheTTLMs(Long.valueOf(1200000L)); // TTL=20m - p.print(""); + // Cache is set to true by default. Set to false if you want templates to + // be automatically updated when modified. + templateResolver.setCacheable(true); + + templateEngine = new TemplateEngine(); + templateEngine.setTemplateResolver(templateResolver); + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String key =""; final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService(); + WebContext ctx = new WebContext(req, resp, getServletContext(), req.getLocale()); - sb.append(table("AppIdentity", - tr(td("ServiceAccountName") + td(appIdentity.getServiceAccountName())) - + tr(td("GCS Bucket") + td(appIdentity.getDefaultGcsBucketName())) - )); + resp.setContentType("text/html"); + + ctx.setVariable("production", SystemProperty.environment.value().name()); + ctx.setVariable("ServiceAccountName", appIdentity.getServiceAccountName()); + ctx.setVariable("gcs", appIdentity.getDefaultGcsBucketName()); - sb.append(table("SystemProperties", - tr(td("appId") + td(SystemProperty.applicationId.get())) - + tr(td("appVer") + td(SystemProperty.applicationVersion.get())) - + tr(td("version") + td(SystemProperty.version.get())) - + tr(td("environment") + td(SystemProperty.environment.get())) - )); + ctx.setVariable("appId", SystemProperty.applicationId.get()); + ctx.setVariable("appVer", SystemProperty.applicationVersion.get()); + ctx.setVariable("version", SystemProperty.version.get()); + ctx.setVariable("environment", SystemProperty.environment.get()); // Environment Atributes ApiProxy.Environment env = ApiProxy.getCurrentEnvironment(); Map attr = env.getAttributes(); + TreeMap m = new TreeMap<>(); - StringBuilder c = new StringBuilder(1024); - for (String key : attr.keySet()) { - Object o = attr.get(key); + for (String k : attr.keySet()) { + Object o = attr.get(k); if (o.getClass().getCanonicalName().equals("java.lang.String")) { - c.append(tr(td(key) + td((String) o))); + m.put(k, (String) o); + } else if (o.getClass().getCanonicalName().equals("java.lang.Boolean")) { + m.put(k, ((Boolean) o).toString()); } else { - c.append(tr(td(key) + td(o.getClass().getCanonicalName()))); + m.put(k, "a " + o.getClass().getCanonicalName()); } } - sb.append(table("Environment Attributes", c.toString())); + ctx.setVariable("attribs", m); - c = new StringBuilder(1024); + m = new TreeMap<>(); for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) { - String key = e.nextElement(); - String val = req.getHeader(key); - c.append(tr(td(key) + td(val))); + key = e.nextElement(); + m.put(key, req.getHeader(key)); } - sb.append(table("Headers", c.toString())); + ctx.setVariable("headers", m); Cookie[] cookies = req.getCookies(); + m = new TreeMap<>(); if (cookies != null && cookies.length != 0) { - c = new StringBuilder(); for (Cookie co : cookies) { - c.append(tr(td(co.getName()) + td(co.getValue()) + td(co.getComment()) - + td(co.getPath()) + td(Integer.toString(co.getMaxAge())))); + m.put(co.getName(), co.getValue()); } - sb.append(table("Cookies", c.toString())); } + ctx.setVariable("cookies", m); Properties properties = System.getProperties(); - c = new StringBuilder(1024); + m = new TreeMap<>(); for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) { - String key = (String) e.nextElement(); - c.append(tr(td(key) + td((String) properties.get(key)))); + key = (String) e.nextElement(); + m.put(key, (String) properties.get(key)); } - sb.append(table("Java SystemProperties", c.toString())); + ctx.setVariable("systemprops", m); Map envVar = System.getenv(); - c = new StringBuilder(1024); - for (String key : envVar.keySet()) { - c.append(tr(td(key) + td(envVar.get(key)))); - } - sb.append(table("Envirionment Variables", c.toString())); + m = new TreeMap<>(envVar); + ctx.setVariable("envvar", m); + // The metadata server is only on a production system if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) { - c = new StringBuilder(1024); - for (String key : v1) { - String val = fetchMetadata(key); - if (val != null) { - c.append(tr(td(key) + td(val))); - } + + m = new TreeMap<>(); + for (String k : metaPath) { + m.put(k, fetchMetadata(key)); } - sb.append(table("Metadata", c.toString())); - - c = new StringBuilder(1024); - for (String key : v1Acct) { - key = key.replace("{account}", appIdentity.getServiceAccountName()); - String val = fetchMetadata(key); - if (val != null) { - c.append(tr(td(key) + td(val))); - } + ctx.setVariable("Metadata", m.descendingMap()); + + m = new TreeMap<>(); + for (String k : metaServiceAcct) { + // substitute a service account for {account} + k = k.replace("{account}", appIdentity.getServiceAccountName()); + m.put(k, fetchMetadata(k)); } - sb.append(table("ServiceAccount Metadata", c.toString())); - - sb.append("

Recursive service-accounts

"
-          + recursMetadata("/computeMetadata/v1/instance/service-accounts/")
-          + "
"); - sb.append("

Recursive all metadata

"
-          + recursMetadata("/")
-          + "
"); - } + ctx.setVariable("sam", m.descendingMap()); - sb.append(""); - p.append(sb); - p.close(); + // Recursivly get all info about service accounts -- Note tokens are leftout by default. + ctx.setVariable("rsa", + fetchJsonMetadata("/computeMetadata/v1/instance/service-accounts/?recursive=true")); + // Recursivly get all data on Metadata server. + ctx.setVariable("ram", fetchJsonMetadata("/?recursive=true")); + } + templateEngine.process("index", ctx, resp.getWriter()); } } // [END example] diff --git a/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/templates/index.html b/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/templates/index.html new file mode 100644 index 00000000000..8b4a61fcebc --- /dev/null +++ b/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/templates/index.html @@ -0,0 +1,99 @@ + + + + + GAE standard Metadata + + + +

AppIdentity

+ + + +
ServiceAccountName
GCS Bucket
+

SystemProperties

+ + + + + +
appId
appVer
version
environment
+

Environment Attributes

+ + + + + +
+

Headers

+ + + + + + +
+

Cookies

+ + + + + + +
+

Java SystemProperties

+ + + + + + +
+

Envirionment Variables

+ + + + + +
+
+
+

Metadata

+ + + + + +
+

ServiceAccount Metadata

+ + + + + +
+

Recursive service-accounts

+
+

Recursive all metadata

+
+
+
No Local Metadata Server
+
+ + diff --git a/appengine-java8/metadata/README.md b/appengine-java8/metadata/README.md new file mode 100644 index 00000000000..cce04b74c42 --- /dev/null +++ b/appengine-java8/metadata/README.md @@ -0,0 +1,51 @@ +# Google App Engine - Metadata Inspection + +This sample displays what's going on in your app. It dumps the environment and lots more. + +See the [Google App Engine standard environment documentation][ae-docs] for more +detailed instructions. + +[ae-docs]: https://cloud.google.com/appengine/docs/java/ + +## Setup + +Use either: + +* `gcloud init` +* `gcloud auth application-default login` +* `gcloud components update` + +## Maven +### Running locally + + $ mvn appengine:run + +### Deploying + + $ mvn appengine:deploy + + diff --git a/appengine-java8/metadata/pom.xml b/appengine-java8/metadata/pom.xml new file mode 100644 index 00000000000..a3bde4ceec1 --- /dev/null +++ b/appengine-java8/metadata/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + war + 1.0-SNAPSHOT + com.example.appengine + metadata-j8 + + + appengine-java8-samples + com.google.cloud + 1.0.0 + .. + + + + + 1.8 + 1.8 + + + + + + com.google.appengine + appengine-api-1.0-sdk + ${appengine.sdk.version} + + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + + com.squareup.okhttp3 + okhttp + 3.8.1 + + + + com.google.code.gson + gson + 2.8.1 + + + + org.thymeleaf + thymeleaf + 3.0.7.RELEASE + + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + + + + com.google.cloud.tools + appengine-maven-plugin + 1.3.1 + + true + true + + + + + + + diff --git a/appengine-java8/metadata/src/main/java/com/example/appengine/standard/MetadataServlet.java b/appengine-java8/metadata/src/main/java/com/example/appengine/standard/MetadataServlet.java new file mode 100644 index 00000000000..b160d5e3b4e --- /dev/null +++ b/appengine-java8/metadata/src/main/java/com/example/appengine/standard/MetadataServlet.java @@ -0,0 +1,161 @@ +/** + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.example.appengine.standard; + +import com.google.appengine.api.appidentity.AppIdentityService; +import com.google.appengine.api.appidentity.AppIdentityServiceFactory; +import com.google.appengine.api.utils.SystemProperty; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParser; +import java.io.IOException; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.WebContext; +import org.thymeleaf.templateresolver.ServletContextTemplateResolver; + + +// [START example] +@SuppressWarnings({"serial"}) +// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required. +@WebServlet(name = "Metadata", description = "Metadata: Write info about GAE Standard", + urlPatterns = "/metadata") +public class MetadataServlet extends HttpServlet { + + private final String[] metaPath = { + "/computeMetadata/v1/project/numeric-project-id", // (pending) + "/computeMetadata/v1/project/project-id", + "/computeMetadata/v1/instance/zone", + "/computeMetadata/v1/instance/service-accounts/default/aliases", + "/computeMetadata/v1/instance/service-accounts/default/", + "/computeMetadata/v1/instance/service-accounts/default/scopes", +// Tokens work - but are a security risk to display +// "/computeMetadata/v1/instance/service-accounts/default/token" + }; + + final String[] metaServiceAcct = { + "/computeMetadata/v1/instance/service-accounts/{account}/aliases", + "/computeMetadata/v1/instance/service-accounts/{account}/email", + "/computeMetadata/v1/instance/service-accounts/{account}/scopes", +// Tokens work - but are a security risk to display +// "/computeMetadata/v1/instance/service-accounts/{account}/token" + }; + + private final String metadata = "http://metadata.google.internal"; + private TemplateEngine templateEngine; + + // Use OkHttp from Square as it's quite easy to use for simple fetches. + private final OkHttpClient ok = new OkHttpClient.Builder() + .readTimeout(500, TimeUnit.MILLISECONDS) // Don't dawdle + .writeTimeout(500, TimeUnit.MILLISECONDS) + .build(); + + // Setup to pretty print returned json + private final Gson gson = new GsonBuilder() + .setPrettyPrinting() + .create(); + private final JsonParser jp = new JsonParser(); + + // Fetch Metadata + String fetchMetadata(String key) throws IOException { + Request request = new Request.Builder() + .url(metadata + key) + .addHeader("Metadata-Flavor", "Google") + .get() + .build(); + + Response response = ok.newCall(request).execute(); + return response.body().string(); + } + + String fetchJsonMetadata(String prefix) throws IOException { + Request request = new Request.Builder() + .url(metadata + prefix ) + .addHeader("Metadata-Flavor", "Google") + .get() + .build(); + + Response response = ok.newCall(request).execute(); + + // Convert json to prety json + return gson.toJson(jp.parse(response.body().string())); + } + + @Override + public void init() { + // Setup ThymeLeaf + ServletContextTemplateResolver templateResolver = + new ServletContextTemplateResolver(this.getServletContext()); + + templateResolver.setPrefix("/WEB-INF/templates/"); + templateResolver.setSuffix(".html"); + templateResolver.setCacheTTLMs(Long.valueOf(1200000L)); // TTL=20m + + // Cache is set to true by default. Set to false if you want templates to + // be automatically updated when modified. + templateResolver.setCacheable(true); + + templateEngine = new TemplateEngine(); + templateEngine.setTemplateResolver(templateResolver); + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService(); + WebContext ctx = new WebContext(req, resp, getServletContext(), req.getLocale()); + + resp.setContentType("text/html"); + + ctx.setVariable("production", SystemProperty.environment.value().name()); + + // The metadata server is only on a production system + if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) { + + TreeMap m = new TreeMap<>(); + + for (String key : metaPath) { + m.put(key, fetchMetadata(key)); + } + + ctx.setVariable("Metadata", m.descendingMap()); + + m = new TreeMap<>(); + for (String key : metaServiceAcct) { + // substitute a service account for {account} + key = key.replace("{account}", appIdentity.getServiceAccountName()); + m.put(key, fetchMetadata(key)); + } + ctx.setVariable("sam", m.descendingMap()); + + // Recursivly get all info about service accounts -- Note tokens are leftout by default. + ctx.setVariable("rsa", + fetchJsonMetadata("/computeMetadata/v1/instance/service-accounts/?recursive=true")); + // Recursivly get all data on Metadata server. + ctx.setVariable("ram", fetchJsonMetadata("/?recursive=true")); + } + + templateEngine.process("index", ctx, resp.getWriter()); + + } +} +// [END example] diff --git a/appengine-java8/metadata/src/main/webapp/WEB-INF/appengine-web.xml b/appengine-java8/metadata/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..87d254db02b --- /dev/null +++ b/appengine-java8/metadata/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,24 @@ + + + + + true + true + java8 + + + diff --git a/appengine-java8/metadata/src/main/webapp/WEB-INF/templates/index.html b/appengine-java8/metadata/src/main/webapp/WEB-INF/templates/index.html new file mode 100644 index 00000000000..0f4e99cbde3 --- /dev/null +++ b/appengine-java8/metadata/src/main/webapp/WEB-INF/templates/index.html @@ -0,0 +1,49 @@ + + + + + GAE standard Metadata + + + +
+
+

Metadata

+ + + + + +
+

ServiceAccount Metadata

+ + + + + +
+

Recursive service-accounts

+
+

Recursive all metadata

+
+
+
No Local Metadata Server
+
+ + \ No newline at end of file diff --git a/appengine-java8/metadata/src/main/webapp/WEB-INF/web.xml b/appengine-java8/metadata/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..82253902cbc --- /dev/null +++ b/appengine-java8/metadata/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,27 @@ + + + + + metadata + + diff --git a/appengine/sockets/README.md b/appengine/sockets/README.md new file mode 100644 index 00000000000..2643cff3e9c --- /dev/null +++ b/appengine/sockets/README.md @@ -0,0 +1,56 @@ + +# Java Socket API Example App: Whois Client + +This sample displays what's going on in your app. It dumps the environment and lots more. + +See the [Google App Engine standard environment documentation][ae-docs] for more +detailed instructions. + +[ae-docs]: https://cloud.google.com/appengine/docs/java/ + +## Setup + +Use either: + +* `gcloud init` +* `gcloud auth application-default login` + +## Maven +### Running locally + + $ mvn appengine:run + +### Deploying + + $ mvn appengine:deploy + + + +This small example application demonstrates the use of the App Engine Socket API to query a Whois server. + +To build, install [maven](http://maven.apache.org/), then run `mvn package`. +You can run the local dev app server via `mvn appengine:devserver` and deploy via `mvnappengine:update`. diff --git a/appengine/sockets/README_LIBS.md b/appengine/sockets/README_LIBS.md new file mode 100644 index 00000000000..8e0c5139636 --- /dev/null +++ b/appengine/sockets/README_LIBS.md @@ -0,0 +1,41 @@ + +# Using the Socket API with Some Common Third-Party Libraries + +## Using the Socket API with JavaPNS + +**Note:** JavaPNS +is an open source library for Apple Push Notifications. With socket support for +App Engine, many applications can now use JavaPNS on App Engine directly. + +App Engine does not officially support JavaPNS, although it may work +with these caveats: + +- **JavaPNS** uses + Security.getProperty, + which was not permitted in versions of App Engine earlier than 1.7.3. However, + if you need this to work in 1.7.2, you may change the `javapns` + source to not use `Security.getProperty`, and simply set + **ALGORITHM** to ``sunx509`. (Future versions are expected to fix this by replacing the use of + `Security.getProperty` with `KeyManagerFactory.getDefaultAlgorithm()`, which will work correctly + with older versions of App Engine. + +- App Engine does not support signed JAR files; accordingly the "Bouncy Castle" jar provided with the javapns distribution fails to load. To fix this, +remove the META-INF/MANIFEST.MF file from ``bcprov-jdk15-146.jar`` using the following command line: + + zip -d bcprov-jdk15-146.jar META-INF/MANIFEST.MF + + +## Using JavaMail with the Socket API + +App Engine does not officially support JavaMail, although it may work +with these caveats: + +JavaMail + 1.4.5 is compatible with App Engine but requires a work-around to + resolve the issue of + class loader + ordering. Currently, there are JavaMail classes in the `appengine-api.jar`, which is scanned + before all other JAR files. This causes the wrong `javax.mail` classes to be loaded. The work-around is to unzip the JavaMail 1.4.5 + `mailapi.jar` file (excluding the `META-INF/MANIFEST.MF` file) into the `WEB-INF/classes` directory. This causes the correct + classes to be loaded before those in `appengine-api.jar`. + diff --git a/appengine/sockets/pom.xml b/appengine/sockets/pom.xml new file mode 100755 index 00000000000..ada36c8e6ee --- /dev/null +++ b/appengine/sockets/pom.xml @@ -0,0 +1,99 @@ + + + + + + 4.0.0 + war + 1.0-SNAPSHOT + + com.example.appengine + sockets + + + + appengine-doc-samples + com.google.cloud + 1.0.0 + .. + + + + + 1.7 + 1.7 + + + + + + com.google.appengine + appengine-api-1.0-sdk + ${appengine.sdk.version} + + + + javax.servlet + servlet-api + 2.5 + provided + + + + + org.jsoup + jsoup + 1.10.3 + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + + + + com.google.cloud.tools + appengine-maven-plugin + 1.3.1 + + true + true + + + + + + diff --git a/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java b/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java new file mode 100644 index 00000000000..53ea0d2acc1 --- /dev/null +++ b/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java @@ -0,0 +1,101 @@ +package com.example.appengine.sockets; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.Socket; +import java.util.logging.Logger; + +import javax.servlet.http.*; + +import org.jsoup.Jsoup; +import org.jsoup.safety.Whitelist; + + + +/** + * This simple example uses the Socket API to access a WHOIS server and query + * for domains that contain the string "google.com". + **/ +@SuppressWarnings("serial") +public class WhoIsClientServlet extends HttpServlet { + + private static final Logger log = Logger.getLogger(WhoIsClientServlet.class.getName()); + + private static final int DEFAULT_PORT = 43; + private static final String DEFAULT_SERVER = "whois.internic.net"; + + void writeHeader(HttpServletResponse resp, String name) throws IOException { + resp.setContentType("text/html"); + resp.setCharacterEncoding("UTF-8"); + String header = "App Engine Whois example result for " + name + "" + + "\n"; + resp.getWriter().print(header); + } + + void writeFooter(HttpServletResponse resp) throws IOException { + resp.getWriter().println(""); + } + + static String getParam(HttpServletRequest req, String attributeName, String defaultValue) { + String value = req.getParameter(attributeName); + if (value == null) { + value = defaultValue; + } + return value; + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + + String name = getParam(req, "name", "google.com"); + // use jsoup to sanitize the name, since it will be output + name = Jsoup.clean(name, Whitelist.basic()); + String server = getParam(req, "server", DEFAULT_SERVER); + int port = Integer.parseInt(getParam(req, "port", Integer.toString(DEFAULT_PORT))); + + writeHeader(resp, name); + resp.getWriter().println("

"); + resp.getWriter().println(doWhoIs(server, port, name)); + resp.getWriter().println("
"); + writeFooter(resp); + } + + /** + * Open a socket to the whois server, write out the query, and receive + * the results. + **/ + String doWhoIs(String server, int port, String name) { + Socket socket = null; + try { + socket = new Socket(server, port); + Writer out = new OutputStreamWriter(socket.getOutputStream(), "8859_1"); + + socket.setSoTimeout(10000); + Reader recv = new InputStreamReader(socket.getInputStream(), "8859_1"); + out.write("=" + name + "\r\n"); + out.flush(); + + StringBuilder builder = new StringBuilder(); + for (int c = 0; (c = recv.read()) != -1;) { + builder.append(String.valueOf((char) c)); + } + + return builder.toString(); + } catch (IOException e) { + String message = "whois server failed: " + server + " exception:" + e.toString(); + log.warning(message); + return message; + } finally { + try { + if (socket != null) { + socket.close(); + } + } catch (IOException e) { + // don't care. + } + } + } +} diff --git a/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..a84e5a45539 --- /dev/null +++ b/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,10 @@ + + + true + true + + + + + + diff --git a/appengine/sockets/src/main/webapp/WEB-INF/logging.properties b/appengine/sockets/src/main/webapp/WEB-INF/logging.properties new file mode 100644 index 00000000000..a7f787071a5 --- /dev/null +++ b/appengine/sockets/src/main/webapp/WEB-INF/logging.properties @@ -0,0 +1 @@ +.level = INFO diff --git a/appengine/sockets/src/main/webapp/WEB-INF/web.xml b/appengine/sockets/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..4dc4827f924 --- /dev/null +++ b/appengine/sockets/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,19 @@ + + + + + + whois + com.example.appengine.sockets.WhoIsClientServlet + + + whois + /whois + + + redirect.jsp + + + diff --git a/appengine/sockets/src/main/webapp/favicon.ico b/appengine/sockets/src/main/webapp/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..23c553a2966ca4cecf146093f33d8114b4f1e368 GIT binary patch literal 8348 zcmeI0du&tJ8Ng3Vwv|ewX4Hu@my&|vCD%DN@CLnxyptBT_%HjatoYr7%N3zGPed#@ckvA><;HWecDU4&2}*2(h%gm&WgCftWj zkQfW;&mXr@0S&(csd+cjaImbXSy=NC<10}z(efGwgi=;B$dt=HkKYCvp-#3KX+qIu zxx$>zcwk+N=c%1^J9)sO44lmS0##~wzU(43f>wW-p_YXwj>s>3{gHI*^oo1lmJ!X*bw{3UBAKRut zUh5Uy4_94IIkdxC^v{_g%FjuEI+f&;9KQ3i+nK7pU_RivFjP_DTl-&gP_qr$nD=M{ z@z;C3#y5Jsh77svGQ4u$ZX)t}=e52{#Xvk;4qIxNh86kR$OhCAie%&e`U{r{ACQZ@ z-)1#sItef{2L za&U;nm+_lo@lbR7vat&^EcECsH)uSnhlht@etsV4LE5B`j#GW*iur~}xpYlTtc;FC{nl|LK^miZ0y3WU>MIM zmc}94VzEFx9?#&?4l+h;ggzvOeCI$ob=`tBp*&EtirH2xU z4a#KB)IMa{_YdYrnxq>-DrrQ>rfpYe8@|Nc-oHnG*L(HR$}d4Eo2&X@o1~9l@%@W) zU{%rv$`tBAOHJH+?zcv7`!T~x;=<#7@4R5T^5$-%Pz-NAYt+5{d;>R+9W24y&`;ZkZqFGQ6_)<35Z_$5V#ga#=N9985-M0KR*fl@h4M0BxWvbYQr6t zULtYBAMJ%iU>x|?U8z_Zyv1jg_VcZ^kO)pd_)jk`_~2MHZmybbloW?l)lnMrb~TAX zV&%#e+VLvM4!%js+%B6}N!=udFlN5Jv;yQm0sdW({6ny+{{$_b`%pI&q3%#p3R?q( z%3@zpafPo4-GA}ErIfU@j?gpfdgeyI);;S-otz(GefQbXvG3J6hbwD_0*YOuqb1V8 zpQm{(oT|g$!tcw;Ck6l>=mo$z0J@0f0^U0{x?+mD8}QB{9yV7qQ;&$5^%*fb@qUB& zX(O<{D-aZ493K;1xH%!}9+}vt8Sshs4os9)d132glTa=lIJv}MJyU_Y!ZFl62j9@l zggg2y{y~c&Vm0cMa@}r@bbn?HR4Sa|66p;nlMl_6D%_%EjCNRq)NBvx!R!t`@zUoW zKV#O#EhZy4>~?VU+rfg@_W_4Kt~zS<|3JjVMcZ#exy;pDUypq|xjpD&0#H{BHgrvM zI=z9nnTN~NCX?mf@DOU;!82-#gXGsw5CSSf22lJ>u8duE&igGuZq4lVZf*LH2%QqOqkv@O{w`Y}q~yWm0EP zeSP~Hau49ZBU@&hWwH5YG0dnGVN1^iztQFh>rIvj5$iQ;q^nyuSuXo`U~{E8DpuIS zA{kR5oC9o=_>jhfRX@QTs1KRm{@F31 zFKP1!w?51@R^I~kA%H*B0W^sKnyVIsv`_2;=zbUGR9pOTqUhV{{^UH=RQ2@S?`uaQ zEy`)Gsd}1IEedW&4lAe0Sg5h`nQXqaZ}RyEzX{FT?hmF3>0_QQT1V~jI$wc&1@aZh ZS0G=3d706zJ{{SaIO|Jj| literal 0 HcmV?d00001 diff --git a/appengine/sockets/src/main/webapp/redirect.jsp b/appengine/sockets/src/main/webapp/redirect.jsp new file mode 100644 index 00000000000..dbf58efa009 --- /dev/null +++ b/appengine/sockets/src/main/webapp/redirect.jsp @@ -0,0 +1,3 @@ +<% + request.getRequestDispatcher("/whois").forward(request, response); +%> diff --git a/flexible/gaeinfo/README.md b/flexible/gaeinfo/README.md new file mode 100644 index 00000000000..bbc44092165 --- /dev/null +++ b/flexible/gaeinfo/README.md @@ -0,0 +1,52 @@ +# Google App Engine Information + +## WARNING - this version runs on App Engine Flexible using the deprecated COMPAT runtime. +## Most users will prefer to use the Metadata example for flex (in progress) +This sample displays what's going on in your app. It dumps the environment and lots more. + +See the [Google App Engine standard environment documentation][ae-docs] for more +detailed instructions. + +[ae-docs]: https://cloud.google.com/appengine/docs/java/ + +## Setup + +Use either: + +* `gcloud init` +* `gcloud auth application-default login` + +## Maven +### Running locally + + $ mvn appengine:run + +### Deploying + + $ mvn appengine:deploy + + diff --git a/flexible/gaeinfo/pom.xml b/flexible/gaeinfo/pom.xml new file mode 100644 index 00000000000..0991cbf0ad3 --- /dev/null +++ b/flexible/gaeinfo/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + war + 1.0-SNAPSHOT + com.example.appengine + gaeinfo-flex-compat + + + appengine-flexible + com.google.cloud + 1.0.0 + .. + + + + + 1.8 + 1.8 + + + + + + com.google.appengine + appengine-api-1.0-sdk + 1.9.52 + + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + + com.squareup.okhttp3 + okhttp + 3.8.1 + + + + com.google.code.gson + gson + 2.8.1 + + + + org.thymeleaf + thymeleaf + 3.0.7.RELEASE + + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + + + + com.google.cloud.tools + appengine-maven-plugin + 1.3.1 + + true + true + + + + + + + diff --git a/flexible/gaeinfo/src/main/java/com/example/appengine/flex_compat/GaeInfoServlet.java b/flexible/gaeinfo/src/main/java/com/example/appengine/flex_compat/GaeInfoServlet.java new file mode 100644 index 00000000000..a0bebe998f2 --- /dev/null +++ b/flexible/gaeinfo/src/main/java/com/example/appengine/flex_compat/GaeInfoServlet.java @@ -0,0 +1,218 @@ +/** + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.example.appengine.flex_compat; + +import com.google.appengine.api.appidentity.AppIdentityService; +import com.google.appengine.api.appidentity.AppIdentityServiceFactory; +import com.google.appengine.api.utils.SystemProperty; +import com.google.apphosting.api.ApiProxy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParser; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.WebContext; +import org.thymeleaf.templateresolver.ServletContextTemplateResolver; + + +// [START example] +@SuppressWarnings({"serial"}) +// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required. +@WebServlet(name = "GAEInfo", description = "GAEInfo: Write info about GAE Standard", + urlPatterns = "/gaeinfo") +public class GaeInfoServlet extends HttpServlet { + + private final String[] metaPath = { + "/computeMetadata/v1/project/numeric-project-id", // (pending) + "/computeMetadata/v1/project/project-id", + "/computeMetadata/v1/instance/zone", + "/computeMetadata/v1/instance/service-accounts/default/aliases", + "/computeMetadata/v1/instance/service-accounts/default/", + "/computeMetadata/v1/instance/service-accounts/default/scopes", +// Tokens work - but are a security risk to display +// "/computeMetadata/v1/instance/service-accounts/default/token" + }; + + final String[] metaServiceAcct = { + "/computeMetadata/v1/instance/service-accounts/{account}/aliases", + "/computeMetadata/v1/instance/service-accounts/{account}/email", + "/computeMetadata/v1/instance/service-accounts/{account}/scopes", +// Tokens work - but are a security risk to display +// "/computeMetadata/v1/instance/service-accounts/{account}/token" + }; + + private final String metadata = "http://metadata.google.internal"; + private TemplateEngine templateEngine; + + // Use OkHttp from Square as it's quite easy to use for simple fetches. + private final OkHttpClient ok = new OkHttpClient.Builder() + .readTimeout(500, TimeUnit.MILLISECONDS) // Don't dawdle + .writeTimeout(500, TimeUnit.MILLISECONDS) + .build(); + + // Setup to pretty print returned json + private final Gson gson = new GsonBuilder() + .setPrettyPrinting() + .create(); + private final JsonParser jp = new JsonParser(); + + // Fetch Metadata + String fetchMetadata(String key) throws IOException { + Request request = new Request.Builder() + .url(metadata + key) + .addHeader("Metadata-Flavor", "Google") + .get() + .build(); + + Response response = ok.newCall(request).execute(); + return response.body().string(); + } + + String fetchJsonMetadata(String prefix) throws IOException { + Request request = new Request.Builder() + .url(metadata + prefix ) + .addHeader("Metadata-Flavor", "Google") + .get() + .build(); + + Response response = ok.newCall(request).execute(); + + // Convert json to prety json + return gson.toJson(jp.parse(response.body().string())); + } + + @Override + public void init() { + // Setup ThymeLeaf + ServletContextTemplateResolver templateResolver = + new ServletContextTemplateResolver(this.getServletContext()); + + templateResolver.setPrefix("/WEB-INF/templates/"); + templateResolver.setSuffix(".html"); + templateResolver.setCacheTTLMs(Long.valueOf(1200000L)); // TTL=20m + + // Cache is set to true by default. Set to false if you want templates to + // be automatically updated when modified. + templateResolver.setCacheable(true); + + templateEngine = new TemplateEngine(); + templateEngine.setTemplateResolver(templateResolver); + } + + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String key =""; + final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService(); + WebContext ctx = new WebContext(req, resp, getServletContext(), req.getLocale()); + + resp.setContentType("text/html"); + + ctx.setVariable("production", SystemProperty.environment.value().name()); + ctx.setVariable("ServiceAccountName", appIdentity.getServiceAccountName()); + ctx.setVariable("gcs", appIdentity.getDefaultGcsBucketName()); + + ctx.setVariable("appId", SystemProperty.applicationId.get()); + ctx.setVariable("appVer", SystemProperty.applicationVersion.get()); + ctx.setVariable("version", SystemProperty.version.get()); + ctx.setVariable("environment", SystemProperty.environment.get()); + + // Environment Atributes + ApiProxy.Environment env = ApiProxy.getCurrentEnvironment(); + Map attr = env.getAttributes(); + TreeMap m = new TreeMap<>(); + + for (String k : attr.keySet()) { + Object o = attr.get(k); + + if (o.getClass().getCanonicalName().equals("java.lang.String")) { + m.put(k, (String) o); + } else if (o.getClass().getCanonicalName().equals("java.lang.Boolean")) { + m.put(k, ((Boolean) o).toString()); + } else { + m.put(k, "a " + o.getClass().getCanonicalName()); + } + } + ctx.setVariable("attribs", m); + + m = new TreeMap<>(); + for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) { + key = e.nextElement(); + m.put(key, req.getHeader(key)); + } + ctx.setVariable("headers", m); + + Cookie[] cookies = req.getCookies(); + m = new TreeMap<>(); + if (cookies != null && cookies.length != 0) { + for (Cookie co : cookies) { + m.put(co.getName(), co.getValue()); + } + } + ctx.setVariable("cookies", m); + + Properties properties = System.getProperties(); + m = new TreeMap<>(); + for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) { + key = (String) e.nextElement(); + m.put(key, (String) properties.get(key)); + } + ctx.setVariable("systemprops", m); + + Map envVar = System.getenv(); + m = new TreeMap<>(envVar); + ctx.setVariable("envvar", m); + + // The metadata server is only on a production system + if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) { + + m = new TreeMap<>(); + for (String k : metaPath) { + m.put(k, fetchMetadata(key)); + } + ctx.setVariable("Metadata", m.descendingMap()); + + m = new TreeMap<>(); + for (String k : metaServiceAcct) { + // substitute a service account for {account} + k = k.replace("{account}", appIdentity.getServiceAccountName()); + m.put(k, fetchMetadata(k)); + } + ctx.setVariable("sam", m.descendingMap()); + + // Recursivly get all info about service accounts -- Note tokens are leftout by default. + ctx.setVariable("rsa", + fetchJsonMetadata("/computeMetadata/v1/instance/service-accounts/?recursive=true")); + // Recursivly get all data on Metadata server. + ctx.setVariable("ram", fetchJsonMetadata("/?recursive=true")); + } + + templateEngine.process("index", ctx, resp.getWriter()); + } +} +// [END example] diff --git a/flexible/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml b/flexible/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..4a50e55a042 --- /dev/null +++ b/flexible/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,27 @@ + + + + + true + true + flex + + + + + + diff --git a/flexible/gaeinfo/src/main/webapp/WEB-INF/templates/index.html b/flexible/gaeinfo/src/main/webapp/WEB-INF/templates/index.html new file mode 100644 index 00000000000..8b4a61fcebc --- /dev/null +++ b/flexible/gaeinfo/src/main/webapp/WEB-INF/templates/index.html @@ -0,0 +1,99 @@ + + + + + GAE standard Metadata + + + +

AppIdentity

+ + + +
ServiceAccountName
GCS Bucket
+

SystemProperties

+ + + + + +
appId
appVer
version
environment
+

Environment Attributes

+ + + + + +
+

Headers

+ + + + + + +
+

Cookies

+ + + + + + +
+

Java SystemProperties

+ + + + + + +
+

Envirionment Variables

+ + + + + +
+
+
+

Metadata

+ + + + + +
+

ServiceAccount Metadata

+ + + + + +
+

Recursive service-accounts

+
+

Recursive all metadata

+
+
+
No Local Metadata Server
+
+ + diff --git a/flexible/gaeinfo/src/main/webapp/WEB-INF/web.xml b/flexible/gaeinfo/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..e31839a606f --- /dev/null +++ b/flexible/gaeinfo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,27 @@ + + + + + gaeinfo + + diff --git a/flexible/pom.xml b/flexible/pom.xml index f68b4abc72d..4777e659429 100644 --- a/flexible/pom.xml +++ b/flexible/pom.xml @@ -40,6 +40,7 @@ disk errorreporting extending-runtime + gaeinfo helloworld mailgun mailjet From 380cc7036b83c845b1eefab22d50a5d33b44cb55 Mon Sep 17 00:00:00 2001 From: Les Vogel Date: Tue, 8 Aug 2017 09:58:30 -0700 Subject: [PATCH 2/2] add to parent 1. add a few things to the parent pom.xml (both app engine & appengine-java8) 2. Fix some copyrights. --- appengine-java8/pom.xml | 6 ++++++ appengine/pom.xml | 7 +++++++ .../appengine/sockets/WhoIsClientServlet.java | 15 +++++++++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 15 +++++++++++++++ appengine/sockets/src/main/webapp/WEB-INF/web.xml | 15 +++++++++++++++ appengine/sockets/src/main/webapp/redirect.jsp | 15 +++++++++++++++ 6 files changed, 73 insertions(+) diff --git a/appengine-java8/pom.xml b/appengine-java8/pom.xml index e4880272fe8..9c203faf31c 100644 --- a/appengine-java8/pom.xml +++ b/appengine-java8/pom.xml @@ -61,9 +61,15 @@ mailgun mailjet memcache + + metadata + multitenancy + oauth2 + postgres + requests remote-client diff --git a/appengine/pom.xml b/appengine/pom.xml index e07b0e4806f..4a7b7e11161 100644 --- a/appengine/pom.xml +++ b/appengine/pom.xml @@ -58,6 +58,9 @@ endpoints-frameworks-v2/migration-example firebase-event-proxy/gae-firebase-event-proxy firebase-tictactoe + + gaeinfo + guestbook-objectify helloworld helloworld-new-plugins @@ -74,7 +77,11 @@ sendgrid remote/remote-client remote/remote-server + + sockets + static-files + taskqueue-push twilio urlfetch diff --git a/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java b/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java index 53ea0d2acc1..39bfc397392 100644 --- a/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java +++ b/appengine/sockets/src/main/java/com/example/appengine/sockets/WhoIsClientServlet.java @@ -1,3 +1,18 @@ +/** + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.example.appengine.sockets; import java.io.IOException; diff --git a/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml index a84e5a45539..a6a25f304a7 100644 --- a/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine/sockets/src/main/webapp/WEB-INF/appengine-web.xml @@ -1,4 +1,19 @@ + true true diff --git a/appengine/sockets/src/main/webapp/WEB-INF/web.xml b/appengine/sockets/src/main/webapp/WEB-INF/web.xml index 4dc4827f924..22ae85a79a0 100644 --- a/appengine/sockets/src/main/webapp/WEB-INF/web.xml +++ b/appengine/sockets/src/main/webapp/WEB-INF/web.xml @@ -1,4 +1,19 @@ + diff --git a/appengine/sockets/src/main/webapp/redirect.jsp b/appengine/sockets/src/main/webapp/redirect.jsp index dbf58efa009..6965fdb55d2 100644 --- a/appengine/sockets/src/main/webapp/redirect.jsp +++ b/appengine/sockets/src/main/webapp/redirect.jsp @@ -1,3 +1,18 @@ + <% request.getRequestDispatcher("/whois").forward(request, response); %>