Accessing Instance Metadata
Stay organized with collections
Save and categorize content based on your preferences.
Google Cloud Platform provides a metadata server that knows details about your App Engine instance, such as its containing project ID, service accounts, and tokens used by the service accounts. You can access this data using simple HTTP requests: no client libraries are required.
This page shows how to access instance metadata from your deployed Java 8 runtime application by making HTTP calls to the appropriate metadata server endpoints.
One useful way to use this API is to get the service account token and supply it as a bearer token in the Authorization header of one of the Google Cloud APIs, to authenticate your application to that particular API service. See the Google Cloud Translation API documentation for an example of how these bearer tokens are used.
Identifying which metadata endpoint to use
The following table lists the endpoints where you can make HTTP requests for
specific metadata. The metadata server is accessible at
http://metadata.google.internal.
| Metadata endpoint | Description |
|---|---|
/computeMetadata/v1/project/numeric-project-id |
The project number assigned to your project. |
/computeMetadata/v1/project/project-id |
The project ID assigned to your project. |
/computeMetadata/v1/instance/zone |
The zone the instance is running in. |
/computeMetadata/v1/instance/service-accounts/default/aliases |
|
/computeMetadata/v1/instance/service-accounts/default/email |
The default service account email assigned to your project. |
/computeMetadata/v1/instance/service-accounts/default/ |
Lists all the default service accounts for your project. |
/computeMetadata/v1/instance/service-accounts/default/scopes |
Lists all the supported scopes for the default service accounts. |
/computeMetadata/v1/instance/service-accounts/default/token |
Returns the auth token that can be used to authenticate your application to other Google Cloud APIs. |
For example, to retrieve your project ID, send a request to
http://metadata.google.internal/computeMetadata/v1/project/project-id.
Making metadata requests
The following sample code gets all of the metadata available for the instance and displays it, except for the service account token.
@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")
publicclass MetadataServletextendsHttpServlet{
privatefinalString[]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/email",
"/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"
};
finalString[]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"
};
privatefinalStringmetadata="http://metadata.google.internal";
privateTemplateEnginetemplateEngine;
// Use OkHttp from Square as it's quite easy to use for simple fetches.
privatefinalOkHttpClientok=newOkHttpClient.Builder()
.readTimeout(500,TimeUnit.MILLISECONDS)// Don't dawdle
.writeTimeout(500,TimeUnit.MILLISECONDS)
.build();
// Setup to pretty print returned json
privatefinalGsongson=newGsonBuilder()
.setPrettyPrinting()
.create();
privatefinalJsonParserjp=newJsonParser();
// Fetch Metadata
StringfetchMetadata(Stringkey)throwsIOException{
Requestrequest=newRequest.Builder()
.url(metadata+key)
.addHeader("Metadata-Flavor","Google")
.get()
.build();
Responseresponse=ok.newCall(request).execute();
returnresponse.body().string();
}
StringfetchJsonMetadata(Stringprefix)throwsIOException{
Requestrequest=newRequest.Builder()
.url(metadata+prefix)
.addHeader("Metadata-Flavor","Google")
.get()
.build();
Responseresponse=ok.newCall(request).execute();
// Convert json to prety json
returngson.toJson(jp.parse(response.body().string()));
}
@Override
publicvoidinit(){
// Setup ThymeLeaf
ServletContextTemplateResolvertemplateResolver=
newServletContextTemplateResolver(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=newTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
}
@Override
publicvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsIOException{
StringdefaultServiceAccount="";
WebContextctx=newWebContext(req,resp,getServletContext(),req.getLocale());
resp.setContentType("text/html");
Stringenvironment=
(String)System.getProperties().get("com.google.appengine.runtime.environment");
ctx.setVariable("production",environment);
// The metadata server is only on a production system
if(environment.equals("Production")){
TreeMap<String,String>m=newTreeMap<>();
for(Stringkey:metaPath){
m.put(key,fetchMetadata(key));
if(key.contains("default/email")){
defaultServiceAccount=m.get(key);
}
}
ctx.setVariable("Metadata",m.descendingMap());
m=newTreeMap<>();
for(Stringkey:metaServiceAcct){
// substitute a service account for {account}
key=key.replace("{account}",defaultServiceAccount);
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());
}
}In the sample code, notice the check to make sure the app is running in production. If the app is running locally, no metadata will be returned from the requests.
Also, notice the use of the Google Gson JSON serializer / deserializer, the OkHttp HTTP and HTTP2 client, and the Thymeleaf templating system. These are not required, but they are useful libraries for your own projects.
Running locally
The metadata server is available for deployed applications: running locally on the development server is not supported. You can add an environment check to your code to expect metadata results only if the app is running in production, as shown in the sample code provided above:
Stringenvironment=
(String)System.getProperties().get("com.google.appengine.runtime.environment");
ctx.setVariable("production",environment);
// The metadata server is only on a production system
if(environment.equals("Production")){
...//show metadata results
}