• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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  */
16 package com.android.tradefed.device.cloud;
17 
18 import com.android.tradefed.command.remote.DeviceDescriptor;
19 import com.android.tradefed.log.LogUtil.CLog;
20 import com.android.tradefed.targetprep.TargetSetupError;
21 import com.android.tradefed.util.FileUtil;
22 
23 import com.google.common.base.Strings;
24 import com.google.common.net.HostAndPort;
25 
26 import org.json.JSONArray;
27 import org.json.JSONException;
28 import org.json.JSONObject;
29 
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.List;
35 
36 /** Structure to hold relevant data for a given GCE AVD instance. */
37 public class GceAvdInfo {
38 
39     public static final List<String> BUILD_VARS =
40             Arrays.asList(
41                     "build_id",
42                     "build_target",
43                     "branch",
44                     "kernel_build_id",
45                     "kernel_build_target",
46                     "kernel_branch",
47                     "system_build_id",
48                     "system_build_target",
49                     "system_branch",
50                     "emulator_build_id",
51                     "emulator_build_target",
52                     "emulator_branch");
53 
54     private String mInstanceName;
55     private HostAndPort mHostAndPort;
56     private String mErrors;
57     private GceStatus mStatus;
58     private HashMap<String, String> mBuildVars;
59 
60     public static enum GceStatus {
61         SUCCESS,
62         FAIL,
63         BOOT_FAIL,
64         DEVICE_OFFLINE,
65     }
66 
GceAvdInfo(String instanceName, HostAndPort hostAndPort)67     public GceAvdInfo(String instanceName, HostAndPort hostAndPort) {
68         mInstanceName = instanceName;
69         mHostAndPort = hostAndPort;
70         mBuildVars = new HashMap<String, String>();
71     }
72 
GceAvdInfo( String instanceName, HostAndPort hostAndPort, String errors, GceStatus status)73     public GceAvdInfo(
74             String instanceName, HostAndPort hostAndPort, String errors, GceStatus status) {
75         mInstanceName = instanceName;
76         mHostAndPort = hostAndPort;
77         mErrors = errors;
78         mStatus = status;
79         mBuildVars = new HashMap<String, String>();
80     }
81 
82     /** {@inheritDoc} */
83     @Override
toString()84     public String toString() {
85         return "GceAvdInfo [mInstanceName="
86                 + mInstanceName
87                 + ", mHostAndPort="
88                 + mHostAndPort
89                 + ", mErrors="
90                 + mErrors
91                 + ", mStatus="
92                 + mStatus
93                 + ", mBuildVars="
94                 + mBuildVars.toString()
95                 + "]";
96     }
97 
instanceName()98     public String instanceName() {
99         return mInstanceName;
100     }
101 
hostAndPort()102     public HostAndPort hostAndPort() {
103         return mHostAndPort;
104     }
105 
getErrors()106     public String getErrors() {
107         return mErrors;
108     }
109 
getStatus()110     public GceStatus getStatus() {
111         return mStatus;
112     }
113 
setStatus(GceStatus status)114     public void setStatus(GceStatus status) {
115         mStatus = status;
116     }
117 
addBuildVar(String buildKey, String buildValue)118     private void addBuildVar(String buildKey, String buildValue) {
119         mBuildVars.put(buildKey, buildValue);
120     }
121 
122     /**
123      * Return build variable information hash of GCE AVD device.
124      *
125      * <p>Possible build variables keys are described in BUILD_VARS for example: build_id,
126      * build_target, branch, kernel_build_id, kernel_build_target, kernel_branch, system_build_id,
127      * system_build_target, system_branch, emulator_build_id, emulator_build_target,
128      * emulator_branch.
129      */
getBuildVars()130     public HashMap<String, String> getBuildVars() {
131         return new HashMap<String, String>(mBuildVars);
132     }
133 
134     /**
135      * Parse a given file to obtain the GCE AVD device info.
136      *
137      * @param f {@link File} file to read the JSON output from GCE Driver.
138      * @param descriptor the descriptor of the device that needs the info.
139      * @param remoteAdbPort the remote port that should be used for adb connection
140      * @return the {@link GceAvdInfo} of the device if found, or null if error.
141      */
parseGceInfoFromFile( File f, DeviceDescriptor descriptor, int remoteAdbPort)142     public static GceAvdInfo parseGceInfoFromFile(
143             File f, DeviceDescriptor descriptor, int remoteAdbPort) throws TargetSetupError {
144         String data;
145         try {
146             data = FileUtil.readStringFromFile(f);
147         } catch (IOException e) {
148             CLog.e("Failed to read result file from GCE driver:");
149             CLog.e(e);
150             return null;
151         }
152         return parseGceInfoFromString(data, descriptor, remoteAdbPort);
153     }
154 
155     /**
156      * Parse a given string to obtain the GCE AVD device info.
157      *
158      * @param data JSON string.
159      * @param descriptor the descriptor of the device that needs the info.
160      * @param remoteAdbPort the remote port that should be used for adb connection
161      * @return the {@link GceAvdInfo} of the device if found, or null if error.
162      */
parseGceInfoFromString( String data, DeviceDescriptor descriptor, int remoteAdbPort)163     public static GceAvdInfo parseGceInfoFromString(
164             String data, DeviceDescriptor descriptor, int remoteAdbPort) throws TargetSetupError {
165         if (Strings.isNullOrEmpty(data)) {
166             CLog.w("No data provided");
167             return null;
168         }
169         String errors = data;
170         try {
171             errors = parseErrorField(data);
172             JSONObject res = new JSONObject(data);
173             String status = res.getString("status");
174             JSONArray devices = null;
175             GceStatus gceStatus = GceStatus.valueOf(status);
176             if (GceStatus.FAIL.equals(gceStatus) || GceStatus.BOOT_FAIL.equals(gceStatus)) {
177                 // In case of failure we still look for instance name to shutdown if needed.
178                 if (res.getJSONObject("data").has("devices_failing_boot")) {
179                     devices = res.getJSONObject("data").getJSONArray("devices_failing_boot");
180                 }
181             } else {
182                 devices = res.getJSONObject("data").getJSONArray("devices");
183             }
184             if (devices != null) {
185                 if (devices.length() == 1) {
186                     JSONObject d = (JSONObject) devices.get(0);
187                     String ip = d.getString("ip");
188                     String instanceName = d.getString("instance_name");
189                     GceAvdInfo avdInfo =
190                             new GceAvdInfo(
191                                     instanceName,
192                                     HostAndPort.fromString(ip).withDefaultPort(remoteAdbPort),
193                                     errors,
194                                     gceStatus);
195                     for (String buildVar : BUILD_VARS) {
196                         if (d.has(buildVar) && !d.getString(buildVar).trim().isEmpty()) {
197                             avdInfo.addBuildVar(buildVar, d.getString(buildVar).trim());
198                         }
199                     }
200                     return avdInfo;
201                 } else {
202                     CLog.w("Expected only one device to return but found %d", devices.length());
203                 }
204             } else {
205                 CLog.w("No device information, device was not started.");
206             }
207         } catch (JSONException e) {
208             CLog.e("Failed to parse JSON %s:", data);
209             CLog.e(e);
210         }
211         // If errors are found throw an exception with the acloud message.
212         if (errors.isEmpty()) {
213             throw new TargetSetupError(String.format("acloud errors: %s", data), descriptor);
214         } else {
215             throw new TargetSetupError(String.format("acloud errors: %s", errors), descriptor);
216         }
217     }
218 
parseErrorField(String data)219     private static String parseErrorField(String data) throws JSONException {
220         String res = "";
221         JSONObject response = new JSONObject(data);
222         JSONArray errors = response.getJSONArray("errors");
223         for (int i = 0; i < errors.length(); i++) {
224             res += (errors.getString(i) + "\n");
225         }
226         return res;
227     }
228 }
229