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.device.TestDeviceOptions;
19 import com.android.tradefed.device.cloud.GceRemoteCmdFormatter.ScpMode;
20 import com.android.tradefed.log.LogUtil.CLog;
21 import com.android.tradefed.util.CommandResult;
22 import com.android.tradefed.util.CommandStatus;
23 import com.android.tradefed.util.FileUtil;
24 import com.android.tradefed.util.IRunUtil;
25 
26 import java.io.File;
27 import java.io.IOException;
28 import java.util.Arrays;
29 import java.util.List;
30 
31 /** Utility class to handle file from a remote instance */
32 public class RemoteFileUtil {
33 
34     /**
35      * Fetch a remote file in the container instance.
36      *
37      * @param remoteInstance The {@link GceAvdInfo} that describe the device.
38      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
39      *     GCE device.
40      * @param runUtil a {@link IRunUtil} to execute commands.
41      * @param timeout in millisecond for the fetch to complete
42      * @param remoteFilePath The remote path where to find the file.
43      * @return The pulled filed if successful, null otherwise
44      */
fetchRemoteFile( GceAvdInfo remoteInstance, TestDeviceOptions options, IRunUtil runUtil, long timeout, String remoteFilePath)45     public static File fetchRemoteFile(
46             GceAvdInfo remoteInstance,
47             TestDeviceOptions options,
48             IRunUtil runUtil,
49             long timeout,
50             String remoteFilePath) {
51         String fileName = new File(remoteFilePath).getName();
52         File localFile = null;
53         try {
54             localFile =
55                     FileUtil.createTempFile(
56                             FileUtil.getBaseName(fileName) + "_", FileUtil.getExtension(fileName));
57             if (fetchRemoteFile(
58                     remoteInstance, options, runUtil, timeout, remoteFilePath, localFile)) {
59                 return localFile;
60             }
61         } catch (IOException e) {
62             CLog.e(e);
63         }
64         FileUtil.deleteFile(localFile);
65         return null;
66     }
67 
68     /**
69      * Fetch a remote file in the device or container instance.
70      *
71      * @param remoteInstance The {@link GceAvdInfo} that describe the device.
72      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
73      *     GCE device.
74      * @param runUtil a {@link IRunUtil} to execute commands.
75      * @param timeout in millisecond for the fetch to complete
76      * @param remoteFilePath The remote path where to find the file.
77      * @param localFile The local {@link File} where the remote file will be pulled
78      * @return True if successful, False otherwise
79      */
fetchRemoteFile( GceAvdInfo remoteInstance, TestDeviceOptions options, IRunUtil runUtil, long timeout, String remoteFilePath, File localFile)80     public static boolean fetchRemoteFile(
81             GceAvdInfo remoteInstance,
82             TestDeviceOptions options,
83             IRunUtil runUtil,
84             long timeout,
85             String remoteFilePath,
86             File localFile) {
87         return internalScpExec(
88                 remoteInstance,
89                 options,
90                 null,
91                 runUtil,
92                 timeout,
93                 remoteFilePath,
94                 localFile,
95                 ScpMode.PULL);
96     }
97 
98     /**
99      * Fetch a remote directory from the remote host.
100      *
101      * @param remoteInstance The {@link GceAvdInfo} that describe the device.
102      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
103      *     GCE device.
104      * @param runUtil a {@link IRunUtil} to execute commands.
105      * @param timeout in millisecond for the fetch to complete
106      * @param remoteDirPath The remote path where to find the directory.
107      * @param localDir The local directory where to put the pulled files.
108      * @return True if successful, False otherwise
109      */
fetchRemoteDir( GceAvdInfo remoteInstance, TestDeviceOptions options, IRunUtil runUtil, long timeout, String remoteDirPath, File localDir)110     public static boolean fetchRemoteDir(
111             GceAvdInfo remoteInstance,
112             TestDeviceOptions options,
113             IRunUtil runUtil,
114             long timeout,
115             String remoteDirPath,
116             File localDir) {
117         return internalScpExec(
118                 remoteInstance,
119                 options,
120                 Arrays.asList("-r"),
121                 runUtil,
122                 timeout,
123                 remoteDirPath,
124                 localDir,
125                 ScpMode.PULL);
126     }
127 
128     /**
129      * Fetch a remote directory from the remote host.
130      *
131      * @param remoteInstance The {@link GceAvdInfo} that describe the device.
132      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
133      *     GCE device.
134      * @param runUtil a {@link IRunUtil} to execute commands.
135      * @param timeout in millisecond for the fetch to complete
136      * @param remoteDirPath The remote path where to find the directory.
137      * @return The pulled directory {@link File} if successful, null otherwise
138      */
fetchRemoteDir( GceAvdInfo remoteInstance, TestDeviceOptions options, IRunUtil runUtil, long timeout, String remoteDirPath)139     public static File fetchRemoteDir(
140             GceAvdInfo remoteInstance,
141             TestDeviceOptions options,
142             IRunUtil runUtil,
143             long timeout,
144             String remoteDirPath) {
145         String dirName = new File(remoteDirPath).getName();
146         File localFile = null;
147         try {
148             localFile = FileUtil.createTempDir(dirName);
149             if (internalScpExec(
150                     remoteInstance,
151                     options,
152                     Arrays.asList("-r"),
153                     runUtil,
154                     timeout,
155                     remoteDirPath,
156                     localFile,
157                     ScpMode.PULL)) {
158                 return localFile;
159             }
160         } catch (IOException e) {
161             CLog.e(e);
162         }
163         FileUtil.deleteFile(localFile);
164         return null;
165     }
166 
167     /**
168      * Push a {@link File} from the local host to the remote instance
169      *
170      * @param remoteInstance The {@link GceAvdInfo} that describe the device.
171      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
172      *     GCE device.
173      * @param scpArgs extra args to be passed to the scp command
174      * @param runUtil a {@link IRunUtil} to execute commands.
175      * @param timeout in millisecond for the fetch to complete
176      * @param remoteFilePath The remote path where to find the file.
177      * @param localFile The local {@link File} where the remote file will be pulled
178      * @return True if successful, False otherwise
179      */
pushFileToRemote( GceAvdInfo remoteInstance, TestDeviceOptions options, List<String> scpArgs, IRunUtil runUtil, long timeout, String remoteFilePath, File localFile)180     public static boolean pushFileToRemote(
181             GceAvdInfo remoteInstance,
182             TestDeviceOptions options,
183             List<String> scpArgs,
184             IRunUtil runUtil,
185             long timeout,
186             String remoteFilePath,
187             File localFile) {
188         return internalScpExec(
189                 remoteInstance,
190                 options,
191                 scpArgs,
192                 runUtil,
193                 timeout,
194                 remoteFilePath,
195                 localFile,
196                 ScpMode.PUSH);
197     }
198 
internalScpExec( GceAvdInfo remoteInstance, TestDeviceOptions options, List<String> scpArgs, IRunUtil runUtil, long timeout, String remoteFilePath, File localFile, ScpMode mode)199     private static boolean internalScpExec(
200             GceAvdInfo remoteInstance,
201             TestDeviceOptions options,
202             List<String> scpArgs,
203             IRunUtil runUtil,
204             long timeout,
205             String remoteFilePath,
206             File localFile,
207             ScpMode mode) {
208         List<String> scpCmd =
209                 GceRemoteCmdFormatter.getScpCommand(
210                         options.getSshPrivateKeyPath(),
211                         scpArgs,
212                         options.getInstanceUser(),
213                         remoteInstance.hostAndPort().getHost(),
214                         remoteFilePath,
215                         localFile.getAbsolutePath(),
216                         mode);
217         CommandResult resScp = runUtil.runTimedCmd(timeout, scpCmd.toArray(new String[0]));
218         if (!CommandStatus.SUCCESS.equals(resScp.getStatus())) {
219             StringBuilder builder = new StringBuilder();
220             builder.append("Issue when ");
221             if (ScpMode.PULL.equals(mode)) {
222                 builder.append("pulling ");
223             } else {
224                 builder.append("pushing ");
225             }
226             builder.append(String.format("file, status: %s", resScp.getStatus()));
227             CLog.e(builder.toString());
228             CLog.e("%s", resScp.getStderr());
229             return false;
230         } else {
231             return true;
232         }
233     }
234 }
235