blob: cbeea849808d98812dc6ae9d6ec65c261b9bbf64 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.nifi.properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
/**
* An abstract base class for an application-specific BootstrapProperties loader.
*/
public abstract class AbstractBootstrapPropertiesLoader {
private static final Logger logger = LoggerFactory.getLogger(AbstractBootstrapPropertiesLoader.class);
private static final String RELATIVE_APPLICATION_PROPERTIES_PATTERN = "conf/%s";
private static final String BOOTSTRAP_CONF = "bootstrap.conf";
/**
* Return the property prefix used in the bootstrap.conf file for this application.
* @return the property prefix
*/
protected abstract String getApplicationPrefix();
/**
* Return the name of the main application properties file (e.g., nifi.properties). This will be
* used to determine the default location of the application properties file.
* @return The name of the application properties file
*/
protected abstract String getApplicationPropertiesFilename();
/**
* Return the system property name that should specify the file path of the main
* application properties file.
* @return The system property name that should provide the file path of the main application
* properties file
*/
protected abstract String getApplicationPropertiesFilePathSystemProperty();
/**
* Returns the key (if any) used to encrypt sensitive properties, extracted from
* {@code $APPLICATION_HOME/conf/bootstrap.conf}.
*
* @return the key in hexadecimal format
* @throws IOException if the file is not readable
*/
public String extractKeyFromBootstrapFile() throws IOException {
return extractKeyFromBootstrapFile(null);
}
/**
* Loads the bootstrap.conf file into a BootstrapProperties object.
* @param bootstrapPath the path to the bootstrap file
* @return The bootstrap.conf as a BootstrapProperties object
* @throws IOException If the file is not readable
*/
public BootstrapProperties loadBootstrapProperties(final String bootstrapPath) throws IOException {
final Properties properties = new Properties();
final Path bootstrapFilePath = getBootstrapFile(bootstrapPath).toPath();
try (final InputStream bootstrapInput = Files.newInputStream(bootstrapFilePath)) {
properties.load(bootstrapInput);
return new BootstrapProperties(getApplicationPrefix(), properties, bootstrapFilePath);
} catch (final IOException e) {
logger.error("Cannot read from bootstrap.conf file at {}", bootstrapFilePath);
throw new IOException("Cannot read from bootstrap.conf", e);
}
}
/**
* Returns the key (if any) used to encrypt sensitive properties, extracted from
* {@code $APPLICATION_HOME/conf/bootstrap.conf}.
*
* @param bootstrapPath the path to the bootstrap file (if null, returns the sensitive key
* found in $APPLICATION_HOME/conf/bootstrap.conf)
* @return the key in hexadecimal format
* @throws IOException if the file is not readable
*/
public String extractKeyFromBootstrapFile(final String bootstrapPath) throws IOException {
final BootstrapProperties bootstrapProperties = loadBootstrapProperties(bootstrapPath);
return bootstrapProperties.getBootstrapSensitiveKey().orElseGet(() -> {
logger.warn("No encryption key present in the bootstrap.conf file at {}", bootstrapProperties.getConfigFilePath());
return "";
});
}
/**
* Returns the file for bootstrap.conf.
*
* @param bootstrapPath the path to the bootstrap file (defaults to $APPLICATION_HOME/conf/bootstrap.conf
* if null)
* @return the {@code $APPLICATION_HOME/conf/bootstrap.conf} file
* @throws IOException if the directory containing the file is not readable
*/
private File getBootstrapFile(final String bootstrapPath) throws IOException {
final File expectedBootstrapFile;
if (bootstrapPath == null) {
// Guess at location of bootstrap.conf file from nifi.properties file
final String defaultApplicationPropertiesFilePath = getDefaultApplicationPropertiesFilePath();
final File propertiesFile = new File(defaultApplicationPropertiesFilePath);
final File confDir = new File(propertiesFile.getParent());
if (confDir.exists() && confDir.canRead()) {
expectedBootstrapFile = new File(confDir, BOOTSTRAP_CONF);
} else {
logger.error("Cannot read from bootstrap.conf file at {} -- conf/ directory is missing or permissions are incorrect", confDir.getAbsolutePath());
throw new IOException("Cannot read from bootstrap.conf");
}
} else {
expectedBootstrapFile = new File(bootstrapPath);
}
if (expectedBootstrapFile.exists() && expectedBootstrapFile.canRead()) {
return expectedBootstrapFile;
} else {
logger.error("Cannot read from bootstrap.conf file at {} -- file is missing or permissions are incorrect", expectedBootstrapFile.getAbsolutePath());
throw new IOException("Cannot read from bootstrap.conf");
}
}
/**
* Returns the default file path to {@code $APPLICATION_HOME/conf/$APPLICATION.properties}. If the system
* property provided by {@code AbstractBootstrapPropertiesLoader#getApplicationPropertiesFilePathSystemProperty()}
* is not set, it will be set to the relative path provided by
* {@code AbstractBootstrapPropertiesLoader#getRelativeApplicationPropertiesFilePath()}.
*
* @return the path to the application properties file
*/
public String getDefaultApplicationPropertiesFilePath() {
final String systemPropertyName = getApplicationPropertiesFilePathSystemProperty();
final String defaultRelativePath = String.format(RELATIVE_APPLICATION_PROPERTIES_PATTERN, getApplicationPropertiesFilename());
String systemPath = System.getProperty(systemPropertyName);
if (systemPath == null || systemPath.trim().isEmpty()) {
logger.warn("The system property {} is not set, so it is being set to '{}'", systemPropertyName, defaultRelativePath);
System.setProperty(systemPropertyName, defaultRelativePath);
systemPath = defaultRelativePath;
}
logger.info("Determined default application properties path to be '{}'", systemPath);
return systemPath;
}
}