blob: b68c9c15b1ef98af606eecf4aa4ffa4f09d1c39d [file] [log] [blame]
Di Qian38c02a72019-11-18 19:14:07 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
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 */
16package com.android.tradefed.cluster;
17
18import com.android.tradefed.command.remote.DeviceDescriptor;
19import com.android.tradefed.config.GlobalConfiguration;
20import com.android.tradefed.device.DeviceManager;
21import com.android.tradefed.device.DeviceManager.FastbootDevice;
22import com.android.tradefed.log.LogUtil.CLog;
23import com.android.tradefed.util.VersionParser;
24
25import com.google.common.base.Strings;
26import com.google.common.net.HostAndPort;
27import com.google.common.net.InetAddresses;
28import com.google.common.primitives.Longs;
29
30import java.net.InetAddress;
31import java.net.UnknownHostException;
32import java.security.InvalidParameterException;
33import java.util.Map;
34import java.util.regex.Matcher;
35import java.util.regex.Pattern;
36
37/** Static util functions for TF Cluster to get global config instances, host information, etc. */
38public class ClusterHostUtil {
39
40 private static String sHostName = null;
41
42 static final String DEFAULT_TF_VERSION = "(unknown)";
43
44 private static long sTfStartTime = getCurrentTimeMillis();
45
46 /**
47 * Gets the hostname.
48 *
49 * @return the hostname or null if we were unable to fetch it
50 */
51 public static String getHostName() {
52 if (sHostName == null) {
53 try {
54 sHostName = InetAddress.getLocalHost().getHostName();
55 } catch (UnknownHostException e) {
56 CLog.w("failed to get hostname: %s", e);
57 }
58 }
59 return sHostName;
60 }
61
62 /**
63 * Gets the TF version running on this host.
64 *
65 * @return this host's TF version.
66 */
67 public static String getTfVersion() {
68 final String version = VersionParser.fetchVersion();
69 return toValidTfVersion(version);
70 }
71
72 /**
73 * Validates a TF version and returns it if it is OK.
74 *
75 * @param version The string for a TF version provided by {@link VersionParser}
76 * @return the version if valid or a default if not.
77 */
78 protected static String toValidTfVersion(String version) {
79 if (Strings.isNullOrEmpty(version) || Longs.tryParse(version) == null) {
80 // Making sure the version is valid. It should be a build number
81 return DEFAULT_TF_VERSION;
82 }
83 return version;
84 }
85
86 /**
87 * Returns the run target for a given device descriptor.
88 *
89 * @param device {@link DeviceDescriptor} to get run target for.
90 * @return run target.
91 */
92 public static String getRunTarget(
93 DeviceDescriptor device, String runTargetFormat, Map<String, String> deviceTags) {
94 if (runTargetFormat != null) {
95 // Make sure the pattern is non-greedy.
96 Pattern p = Pattern.compile("\\{([^:\\}]+)(:.*)?\\}");
97 Matcher m = p.matcher(runTargetFormat);
98 StringBuffer sb = new StringBuffer();
99 while (m.find()) {
100 String pattern = m.group(1);
101 String key = null;
102 String txt = null;
103 switch (pattern) {
104 case "PRODUCT":
105 txt = device.getProduct();
106 break;
107 case "PRODUCT_OR_DEVICE_CLASS":
108 // TODO: Refactor the logic to handle more flexible combinations.
109 txt = device.getProduct();
110 if (device.isStubDevice()) {
111 String deviceClass = device.getDeviceClass();
112 // If it's a fastboot device we report it as the product
113 if (!FastbootDevice.class.getSimpleName().equals(deviceClass)) {
114 txt = deviceClass;
115 }
116 }
117 break;
118 case "PRODUCT_VARIANT":
119 txt = device.getProductVariant();
120 break;
121 case "API_LEVEL":
122 txt = device.getSdkVersion();
123 break;
124 case "DEVICE_CLASS":
125 txt = device.getDeviceClass();
126 break;
127 case "SERIAL":
128 txt = device.getSerial();
129 break;
130 case "TAG":
131 if (deviceTags == null || deviceTags.isEmpty()) {
132 // simply delete the placeholder if there's nothing to match
133 txt = "";
134 } else {
135 txt = deviceTags.get(device.getSerial());
136 if (txt == null) {
137 txt = ""; // simply delete it if a tag does not exist
138 }
139 }
140 break;
141 case "DEVICE_PROP":
142 key = m.group(2).substring(1);
143 txt = device.getProperty(key);
144 break;
145 default:
146 throw new InvalidParameterException(
147 String.format(
148 "Unsupported pattern '%s' found for run target '%s'",
149 pattern, runTargetFormat));
150 }
151 if (txt == null || DeviceManager.UNKNOWN_DISPLAY_STRING.equals(txt)) {
Di Qian38c02a72019-11-18 19:14:07 -0800152 return DeviceManager.UNKNOWN_DISPLAY_STRING;
153 }
154 m.appendReplacement(sb, Matcher.quoteReplacement(txt));
155 }
156 m.appendTail(sb);
157 return sb.toString();
158 }
159 // Default behavior.
160 // TODO: Remove this when we cluster default run target is changed.
161 String runTarget = device.getProduct();
162 if (!runTarget.equals(device.getProductVariant())) {
163 runTarget += ":" + device.getProductVariant();
164 }
165 return runTarget;
166 }
167
168 /**
169 * Checks if a given input is a valid IP:PORT string.
170 *
171 * @param input a string to check
172 * @return true if the given input is an IP:PORT string
173 */
174 public static boolean isIpPort(String input) {
175 try {
176 HostAndPort hostAndPort = HostAndPort.fromString(input);
177 return InetAddresses.isInetAddress(hostAndPort.getHost());
178 } catch (IllegalArgumentException e) {
179 return false;
180 }
181 }
182
183 /**
184 * Returns the current system time.
185 *
186 * @return time in millis.
187 */
188 public static long getCurrentTimeMillis() {
189 return System.currentTimeMillis();
190 }
191
192 public static long getTfStartTimeMillis() {
193 return sTfStartTime;
194 }
195
196 /** Get the {@link IClusterOptions} instance used to store cluster-related settings. */
197 public static IClusterOptions getClusterOptions() {
198 IClusterOptions clusterOptions =
199 (IClusterOptions)
200 GlobalConfiguration.getInstance()
201 .getConfigurationObject(ClusterOptions.TYPE_NAME);
202 if (clusterOptions == null) {
203 throw new IllegalStateException(
204 "cluster_options not defined. You must add this "
205 + "object to your global config. See google/atp/cluster.xml.");
206 }
207
208 return clusterOptions;
209 }
210
211 /** Get the {@link IClusterClient} instance used to interact with the TFC backend. */
212 public static IClusterClient getClusterClient() {
213 IClusterClient ClusterClient =
214 (IClusterClient)
215 GlobalConfiguration.getInstance()
216 .getConfigurationObject(IClusterClient.TYPE_NAME);
217 if (ClusterClient == null) {
218 throw new IllegalStateException(
219 "cluster_client not defined. You must add this "
220 + "object to your global config. See google/atp/cluster.xml.");
221 }
222
223 return ClusterClient;
224 }
225}