/*
* Copyright (c) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudera.director.google;
import com.cloudera.director.google.internal.GoogleCredentials;
import com.cloudera.director.spi.v1.common.http.HttpProxyParameters;
import com.cloudera.director.spi.v1.model.Configured;
import com.cloudera.director.spi.v1.model.LocalizationContext;
import com.cloudera.director.spi.v1.model.exception.InvalidCredentialsException;
import com.cloudera.director.spi.v1.provider.CloudProvider;
import com.cloudera.director.spi.v1.provider.CredentialsProvider;
import com.cloudera.director.spi.v1.provider.util.AbstractLauncher;
import com.google.api.services.compute.Compute;
import com.google.common.annotations.VisibleForTesting;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigParseOptions;
import com.typesafe.config.ConfigSyntax;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Locale;
public class GoogleLauncher extends AbstractLauncher {
private Config applicationProperties = null;
@VisibleForTesting
protected Config googleConfig = null;
public GoogleLauncher() {
super(Collections.singletonList(GoogleCloudProvider.METADATA), null);
}
/**
* The config is loaded from a google.conf file on the classpath. If a google.conf file also exists in the
* configuration directory, its values will override the values defined in the google.conf file on the
* classpath.
*/
@Override
public void initialize(File configurationDirectory, HttpProxyParameters httpProxyParameters) {
try {
googleConfig = parseConfigFromClasspath(Configurations.GOOGLE_CONFIG_QUALIFIED_FILENAME);
applicationProperties = parseConfigFromClasspath(Configurations.APPLICATION_PROPERTIES_FILENAME);
} catch (Exception e) {
throw new RuntimeException(e);
}
// Check if an additional google.conf file exists in the configuration directory.
File configFile = new File(configurationDirectory, Configurations.GOOGLE_CONFIG_FILENAME);
if (configFile.canRead()) {
try {
Config configFromFile = parseConfigFromFile(configFile);
// Merge the two configurations, with values in configFromFile overriding values in googleConfig.
googleConfig = configFromFile.withFallback(googleConfig);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Parses the specified configuration file from the classpath.
*
* @param configPath the path to the configuration file
* @return the parsed configuration
*/
private static Config parseConfigFromClasspath(String configPath) {
ConfigParseOptions options = ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false);
return ConfigFactory.parseResourcesAnySyntax(GoogleLauncher.class, configPath, options);
}
/**
* Parses the specified configuration file.
*
* @param configFile the configuration file
* @return the parsed configuration
*/
private static Config parseConfigFromFile(File configFile) {
ConfigParseOptions options = ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false);
return ConfigFactory.parseFileAnySyntax(configFile, options);
}
@Override
public CloudProvider createCloudProvider(String cloudProviderId, Configured configuration,
Locale locale) {
if (!GoogleCloudProvider.ID.equals(cloudProviderId)) {
throw new IllegalArgumentException("Cloud provider not found: " + cloudProviderId);
}
LocalizationContext localizationContext = getLocalizationContext(locale);
// At this point the configuration object will already contain
// the required data for authentication.
CredentialsProvider<GoogleCredentials> provider = new GoogleCredentialsProvider(applicationProperties);
GoogleCredentials credentials = provider.createCredentials(configuration, localizationContext);
Compute compute = credentials.getCompute();
if (compute == null) {
throw new InvalidCredentialsException("Invalid cloud provider credentials.");
} else {
String projectId = credentials.getProjectId();
try {
// Attempt GCP api call to verify credentials.
compute.regions().list(projectId).execute();
} catch (IOException e) {
throw new InvalidCredentialsException(
"Invalid cloud provider credentials for project '" + projectId + "'.", e);
}
}
return new GoogleCloudProvider(credentials, applicationProperties, googleConfig, localizationContext);
}
}