From ad37d817e749107420c31f987b8545d354e5a1d5 Mon Sep 17 00:00:00 2001 From: Les Vogel Date: Fri, 21 Jul 2017 18:21:44 -0700 Subject: [PATCH 1/2] Add Metadata 1. Use Metadata server 2. Fix a bunch of check style issues 3. Switch to using StringBuilder --- appengine-java8/gaeinfo/pom.xml | 21 +- .../appengine/standard/GAEInfoServlet.java | 204 +++++++++++++----- .../src/main/webapp/WEB-INF/appengine-web.xml | 1 + 3 files changed, 165 insertions(+), 61 deletions(-) diff --git a/appengine-java8/gaeinfo/pom.xml b/appengine-java8/gaeinfo/pom.xml index a0bb6f78bba..a348dee0f0b 100644 --- a/appengine-java8/gaeinfo/pom.xml +++ b/appengine-java8/gaeinfo/pom.xml @@ -33,10 +33,10 @@ Copyright 2017 Google Inc. 1.8 1.8 - + - + com.google.appengine appengine-api-1.0-sdk ${appengine.sdk.version} @@ -50,11 +50,24 @@ Copyright 2017 Google Inc. provided + + com.squareup.okhttp3 + okhttp + 3.8.1 + + + + com.google.code.gson + gson + 2.8.1 + + - ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + org.apache.maven.plugins @@ -85,4 +98,4 @@ Copyright 2017 Google Inc. - + 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 7ebf994989e..dc2bc1c2d2a 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 @@ -1,17 +1,15 @@ /** * 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 + * 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. + * 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; @@ -20,114 +18,206 @@ 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 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.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; + // [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") -//CHECKSTYLE:OFF -public class GAEInfoServlet extends HttpServlet { - - public void table(PrintWriter p, String title, String c) { - p.print("

" + title + "

"); - p.print(""); - p.print(c); - p.print("
"); +public class GaeInfoServlet extends HttpServlet { + + final String[] v1 = { + "/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", + "/computeMetadata/v1/instance/service-accounts/default/token", + }; + + final String[] v1Acct = { + "/computeMetadata/v1/instance/service-accounts/{account}/aliases", + "/computeMetadata/v1/instance/service-accounts/{account}/email", + "/computeMetadata/v1/instance/service-accounts/{account}/scopes", + "/computeMetadata/v1/instance/service-accounts/{account}/token" + }; + + final String metadata = "http://metadata.google.internal"; + + public final OkHttpClient ok = new OkHttpClient.Builder() + .readTimeout(500, TimeUnit.MILLISECONDS) // Don't dawdle + .writeTimeout(500, TimeUnit.MILLISECONDS) + .build(); + + public 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; } - public String tr(String c) { + String tr(String c) { return "" + c + ""; } - public String td(String s) { + String td(String s) { return "" + s + ""; } + 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 recursMetadata(String prefix) throws IOException { + Request request = new Request.Builder() + .url(metadata + prefix + "?recursive=true") + .addHeader("Metadata-Flavor", "Google") + .get() + .build(); + + Response response = ok.newCall(request).execute(); + + 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); p.print(""); final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService(); - table(p, "AppIdentity", - tr(td("ServiceAccountName") + td(appIdentity.getServiceAccountName()) ) + - tr(td("GCS Bucket") + td( appIdentity.getDefaultGcsBucketName())) - ); - table(p, "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()) ) - ); + sb.append(table("AppIdentity", + tr(td("ServiceAccountName") + td(appIdentity.getServiceAccountName())) + + tr(td("GCS Bucket") + td(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())) + )); // Environment Atributes ApiProxy.Environment env = ApiProxy.getCurrentEnvironment(); - Map attr = env.getAttributes(); + Map attr = env.getAttributes(); - String c = ""; - for(String key : attr.keySet()) { + StringBuilder c = new StringBuilder(1024); + for (String key : attr.keySet()) { Object o = attr.get(key); - if(o.getClass().getCanonicalName().equals("java.lang.String")) { - c += tr(td(key) + td((String) o)); - } else - c += tr(td(key) + td(o.getClass().getCanonicalName())); + if (o.getClass().getCanonicalName().equals("java.lang.String")) { + c.append(tr(td(key) + td((String) o))); + } else { + c.append(tr(td(key) + td(o.getClass().getCanonicalName()))); + } } - table(p, "Environment Attributes", c); + sb.append(table("Environment Attributes", c.toString())); - c = ""; - for (Enumeration e = req.getHeaderNames(); e.hasMoreElements();) { + c = new StringBuilder(1024); + for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) { String key = e.nextElement(); String val = req.getHeader(key); - c += tr(td(key) + td(val) );; + c.append(tr(td(key) + td(val))); } - table(p, "Headers", c); - + sb.append(table("Headers", c.toString())); Cookie[] cookies = req.getCookies(); - if(cookies != null && cookies.length != 0) { - c = ""; + if (cookies != null && cookies.length != 0) { + c = new StringBuilder(); for (Cookie co : cookies) { - c += tr( td(co.getName()) + td(co.getValue()) + td(co.getComment()) + - td(co.getPath()) + td(Integer.toString(co.getMaxAge())) ); + c.append(tr(td(co.getName()) + td(co.getValue()) + td(co.getComment()) + + td(co.getPath()) + td(Integer.toString(co.getMaxAge())))); } - table(p, "Cookies", c); + sb.append(table("Cookies", c.toString())); } Properties properties = System.getProperties(); - c = ""; - for(Enumeration e = properties.propertyNames(); e.hasMoreElements();) { + c = new StringBuilder(1024); + for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) { String key = (String) e.nextElement(); - c += tr( td(key) + td((String)properties.get(key))); + c.append(tr(td(key) + td((String) properties.get(key)))); } - table(p, "Java SystemProperties", c); + sb.append(table("Java SystemProperties", c.toString())); Map envVar = System.getenv(); - c = ""; - for(String key : envVar.keySet()) { - c += tr(td(key)+td(envVar.get(key))); + c = new StringBuilder(1024); + for (String key : envVar.keySet()) { + c.append(tr(td(key) + td(envVar.get(key)))); } - table(p, "Envirionment Variables", c); - p.print(""); + sb.append(table("Envirionment Variables", c.toString())); + + 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))); + } + } + 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))); + } + } + sb.append(table("ServiceAccount Metadata", c.toString())); + + sb.append("

Recursive service-accounts

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

Recursive all metadata

"
+          + recursMetadata("/")
+          + "
"); + } + + sb.append(""); + p.append(sb); p.close(); } diff --git a/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml b/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml index dd2cb3e09be..87d254db02b 100644 --- a/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine-java8/gaeinfo/src/main/webapp/WEB-INF/appengine-web.xml @@ -19,5 +19,6 @@ true true java8 + From fda88a419d5c748c390fc4f1f6085b1eb931a728 Mon Sep 17 00:00:00 2001 From: Les Vogel Date: Fri, 21 Jul 2017 18:38:40 -0700 Subject: [PATCH 2/2] rename file again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Well, Intellij didn’t pickup that this was tracked by git :( --- .../standard/{GAEInfoServlet.java => GaeInfoServlet.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/{GAEInfoServlet.java => GaeInfoServlet.java} (100%) 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 similarity index 100% rename from appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GAEInfoServlet.java rename to appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GaeInfoServlet.java