Skip to content

Commit e273856

Browse files
authored
chore: refactor retrieving resource metadata (#716)
host logic for getting metadata values for monitored resource in MetadataLoader refactor MonitoredResourceUitl to use MetadataLoader
1 parent 116e577 commit e273856

File tree

2 files changed

+218
-153
lines changed

2 files changed

+218
-153
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.logging;
18+
19+
import com.google.cloud.logging.MonitoredResourceUtil.Label;
20+
import com.google.common.collect.ImmutableMap;
21+
import java.io.IOException;
22+
import java.nio.charset.StandardCharsets;
23+
import java.nio.file.Files;
24+
import java.nio.file.Paths;
25+
import java.util.function.Supplier;
26+
27+
public final class MetadataLoader {
28+
public static final String ENV_FLEXIBLE = "flex";
29+
public static final String ENV_STANDARD = "standard";
30+
31+
private ResourceTypeEnvironmentGetter getter;
32+
33+
private final ImmutableMap<Label, Supplier<String>> labelResolvers =
34+
ImmutableMap.<Label, Supplier<String>>builder()
35+
.put(Label.ClusterName, () -> getClusterName())
36+
.put(Label.ConfigurationName, () -> getConfigName())
37+
.put(Label.ContainerName, () -> getContainerName())
38+
.put(Label.Env, () -> getEnv())
39+
.put(Label.FunctionName, () -> getFunctionName())
40+
.put(Label.InstanceId, () -> getInstanceId())
41+
.put(Label.InstanceName, () -> getInstanceName())
42+
.put(Label.CloudRunLocation, () -> getCloudRunLocation())
43+
.put(Label.GKELocation, () -> getGKELocation())
44+
.put(Label.ModuleId, () -> getModuleId())
45+
.put(Label.NamespaceName, () -> getNamespaceName())
46+
.put(Label.PodName, () -> getPodName())
47+
.put(Label.ProjectId, () -> getProjectId())
48+
.put(Label.Region, () -> getRegion())
49+
.put(Label.RevisionName, () -> getRevisionName())
50+
.put(Label.ServiceName, () -> getServiceName())
51+
.put(Label.VersionId, () -> getVersionId())
52+
.put(Label.Zone, () -> getZone())
53+
.build();
54+
55+
public MetadataLoader(ResourceTypeEnvironmentGetter getter) {
56+
this.getter = getter;
57+
}
58+
59+
/**
60+
* Loads metadata value for the {@link label} argument.
61+
*
62+
* @param label A resource metadata label of type {@see MonitoredResourceUtil.Label}
63+
* @return A string with metadata value or {@code null} if the label is not supported.
64+
*/
65+
public String getValue(MonitoredResourceUtil.Label label) {
66+
Supplier<String> lambda = labelResolvers.get(label);
67+
if (lambda != null) {
68+
return lambda.get();
69+
}
70+
return null;
71+
}
72+
73+
private String getClusterName() {
74+
return getter.getAttribute("instance/attributes/cluster-name");
75+
}
76+
77+
private String getConfigName() {
78+
return getter.getEnv("K_CONFIGURATION");
79+
}
80+
81+
// due to lack of options to discover container name from within process
82+
// allow users to provide the container name via environment variable
83+
private String getContainerName() {
84+
return getter.getEnv("CONTAINER_NAME");
85+
}
86+
/**
87+
* Distinguish between Standard and Flexible GAE environments. There is no indicator of the
88+
* environment. The path to the startup-script in the metadata attribute was selected as one of
89+
* the new values that explitly mentioning "flex" and cannot be altered by user (e.g. environment
90+
* variable). The method assumes that the resource type is already identified as {@link
91+
* Resource.AppEngine}.
92+
*
93+
* @return {@link MetadataLoader.ENV_FLEXIBLE} for the Flexible environment and {@link
94+
* MetadataLoader.ENV_STANDARD} for the Standard environment.
95+
*/
96+
private String getEnv() {
97+
String value = getter.getAttribute("instance/attributes/startup-script");
98+
if (value == "/var/lib/flex/startup_script.sh") {
99+
return ENV_FLEXIBLE;
100+
}
101+
return ENV_STANDARD;
102+
}
103+
104+
private String getFunctionName() {
105+
String value = getter.getEnv("K_SERVICE");
106+
if (value == null) {
107+
// keep supporting custom function name if is not provided by default
108+
// for backward compatability only; reconsider removing it after Gen2
109+
// environment is enrolled for Cloud Function
110+
value = getter.getEnv("FUNCTION_NAME");
111+
}
112+
return value;
113+
}
114+
115+
private String getInstanceId() {
116+
return getter.getAttribute("instance/id");
117+
}
118+
119+
private String getInstanceName() {
120+
return getter.getAttribute("instance/name");
121+
}
122+
123+
private String getCloudRunLocation() {
124+
return getRegion();
125+
}
126+
127+
private String getGKELocation() {
128+
return getZone();
129+
}
130+
131+
private String getModuleId() {
132+
return getter.getEnv("GAE_SERVICE");
133+
}
134+
/**
135+
* Heuristic to discover the namespace name of the current environment. There is no determenistic
136+
* way to discover the namespace name of the process. The name is read from the {@link
137+
* K8S_POD_NAMESPACE_PATH} when available or read from a user defined environment variable
138+
* "NAMESPACE_NAME"
139+
*
140+
* @return Namespace name or empty string if the name could not be discovered
141+
*/
142+
private String getNamespaceName() {
143+
String value = "";
144+
try {
145+
value =
146+
new String(
147+
Files.readAllBytes(
148+
Paths.get("/var/run/secrets/kubernetes.io/serviceaccount/namespace")),
149+
StandardCharsets.UTF_8);
150+
} catch (IOException e) {
151+
// if SA token is not shared the info about namespace is unavailable
152+
// allow users to define the namespace name explicitly
153+
value = getter.getEnv("NAMESPACE_NAME");
154+
if (value == null) {
155+
value = "";
156+
}
157+
}
158+
return value;
159+
}
160+
// Kubernetes set hostname of the pod to the pod name by default, however hostname can be override
161+
// in manifest
162+
// allow users to provide the container name via environment variable
163+
private String getPodName() {
164+
String value = getter.getEnv("POD_NAME");
165+
if (value != null) {
166+
return value;
167+
}
168+
return getter.getEnv("HOSTNAME");
169+
}
170+
171+
private String getProjectId() {
172+
return getter.getAttribute("project/project-id");
173+
}
174+
/**
175+
* Retrieves a region from the qualified region of 'projects/[PROJECT_NUMBER]/regions/[REGION]'
176+
*
177+
* @return region string id
178+
*/
179+
private String getRegion() {
180+
String loc = getter.getAttribute("instance/region");
181+
return loc.substring(loc.lastIndexOf('/') + 1);
182+
}
183+
184+
private String getRevisionName() {
185+
return getter.getEnv("K_REVISION");
186+
}
187+
188+
private String getServiceName() {
189+
return getter.getEnv("K_SERVICE");
190+
}
191+
192+
private String getVersionId() {
193+
return getter.getEnv("GAE_VERSION");
194+
}
195+
/**
196+
* Retrieves a zone from the qualified zone of 'projects/[PROJECT_NUMBER]/zones/[ZONE]'
197+
*
198+
* @return zone string id
199+
*/
200+
private String getZone() {
201+
String loc = getter.getAttribute("instance/zone");
202+
return loc.substring(loc.lastIndexOf('/') + 1);
203+
}
204+
}

0 commit comments

Comments
 (0)