• 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 
17 package com.android.tradefed.config.gcs;
18 
19 import com.android.tradefed.config.ConfigurationDef;
20 import com.android.tradefed.config.ConfigurationException;
21 import com.android.tradefed.config.ConfigurationFactory;
22 import com.android.tradefed.config.IConfigurationFactory;
23 import com.android.tradefed.config.IConfigurationServer;
24 import com.android.tradefed.util.FileUtil;
25 
26 import java.io.BufferedInputStream;
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.Map;
33 
34 /** A {@link ConfigurationFactory} loads configs from Google Cloud Storage. */
35 public class GCSConfigurationFactory extends ConfigurationFactory {
36     private static IConfigurationFactory sInstance = null;
37     private IConfigurationServer mConfigServer;
38     /** Keep track of the latest downloaded config file so we can use it */
39     private File mConfigDownloaded = null;
40 
GCSConfigurationFactory(IConfigurationServer configServer)41     GCSConfigurationFactory(IConfigurationServer configServer) {
42         mConfigServer = configServer;
43     }
44 
45     /** Get the singleton {@link IConfigurationFactory} instance. */
getInstance(IConfigurationServer configServer)46     public static IConfigurationFactory getInstance(IConfigurationServer configServer) {
47         if (sInstance == null) {
48             sInstance = new GCSConfigurationFactory(configServer);
49         }
50         return sInstance;
51     }
52 
53     /**
54      * Loads an InputStream for given config name from Google Cloud Storage(GCS).
55      *
56      * @param name the configuration name to load
57      * @return a {@link BufferedInputStream} for reading config contents
58      * @throws ConfigurationException if config could not be found
59      */
60     @Override
getConfigStream(String name)61     protected BufferedInputStream getConfigStream(String name) throws ConfigurationException {
62         InputStream configStream = getBundledConfigStream(name);
63         if (configStream == null) {
64             // now try to load from GCS
65             configStream = mConfigServer.getConfig(name);
66             if (configStream == null) {
67                 throw new ConfigurationException(
68                         String.format("Could not find configuration '%s'", name));
69             }
70             // Create a local copy of the configuration
71             try {
72                 // If available, store the downloaded global config within the Tradefed directory
73                 File tfDir = null;
74                 String tfPath = System.getProperty("TF_JAR_DIR");
75                 if (tfPath != null) {
76                     // In some cases, a '.' for current is given, handle it.
77                     if (tfPath.equals(".")) {
78                         tfDir = new File("").getAbsoluteFile();
79                     } else {
80                         tfDir = new File(tfPath).getAbsoluteFile();
81                     }
82                 }
83                 mConfigDownloaded =
84                         FileUtil.createTempFile("gcs-downloaded-global-config", ".xml", tfDir);
85                 mConfigDownloaded.deleteOnExit();
86                 FileUtil.writeToFile(configStream, mConfigDownloaded);
87                 // Reset the stream to be available from the start again.
88                 configStream.reset();
89             } catch (IOException e) {
90                 throw new ConfigurationException(e.getMessage());
91             }
92         }
93         // buffer input for performance - just in case config file is large
94         return new BufferedInputStream(configStream);
95     }
96 
getLatestDownloadedFile()97     public File getLatestDownloadedFile() {
98         return mConfigDownloaded;
99     }
100 
101     /** {@inheritDoc} */
102     @Override
getConfigurationDef( String name, boolean isGlobal, Map<String, String> templateMap)103     protected ConfigurationDef getConfigurationDef(
104             String name, boolean isGlobal, Map<String, String> templateMap)
105             throws ConfigurationException {
106         return new GCSConfigLoader(isGlobal).getConfigurationDef(name, templateMap);
107     }
108 
109     /**
110      * Extension of {@link com.android.tradefed.config.ConfigurationFactory.ConfigLoader} that loads
111      * config from GCS, tracks the included configurations from one root config, and throws an
112      * exception on circular includes.
113      */
114     protected class GCSConfigLoader extends ConfigLoader {
115 
GCSConfigLoader(boolean isGlobalConfig)116         public GCSConfigLoader(boolean isGlobalConfig) {
117             super(isGlobalConfig);
118         }
119 
120         @Override
findConfigName(String name, String parentName)121         protected String findConfigName(String name, String parentName)
122                 throws ConfigurationException {
123             if (isBundledConfig(name)) {
124                 return name;
125             }
126             if (parentName == null || isBundledConfig(parentName)) {
127                 return name;
128             }
129 
130             return getPath(parentName, name);
131         }
132 
133         /**
134          * Help method to get file's path from its parent and filename. This is mainly for normalize
135          * path like path/to/../file to path/file
136          *
137          * @param parent parent name
138          * @param filename file name
139          * @return normalized path
140          */
getPath(String parent, String filename)141         String getPath(String parent, String filename) {
142             Path parentPath = Paths.get(parent).getParent();
143             if (parentPath == null) {
144                 return filename;
145             }
146             return parentPath.resolve(filename).normalize().toString();
147         }
148 
149         /** {@inheritDoc} */
150         @Override
trackConfig(String name, ConfigurationDef def)151         protected void trackConfig(String name, ConfigurationDef def) {
152             // FIXME: Track remote config source files' life cycle.
153             return;
154         }
155     }
156 }
157