Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy configurations #3751

Merged
merged 18 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,21 @@ public String getMessageString() {
public void setMessageFlowTracingState(int tracingState){
}

@Override
public Object getVariable(String s) {
return null;
}

@Override
public void setVariable(String s, Object o) {
//
}

@Override
public Set getVariableKeySet() {
return null;
}

public int getMessageFlowTracingState(){
return SynapseConstants.TRACING_OFF;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.wso2.micro.integrator.initializer.StartupFinalizer;
import org.wso2.micro.integrator.initializer.dashboard.HeartBeatComponent;
import org.wso2.micro.integrator.initializer.deployment.application.deployer.CappDeployer;
import org.wso2.micro.integrator.initializer.deployment.config.deployer.ConfigDeployer;
import org.wso2.micro.integrator.initializer.deployment.synapse.deployer.FileRegistryResourceDeployer;
import org.wso2.micro.integrator.initializer.deployment.synapse.deployer.SynapseAppDeployer;
import org.wso2.micro.integrator.initializer.deployment.user.store.deployer.UserStoreDeployer;
Expand Down Expand Up @@ -169,6 +170,7 @@ private void addCAppDeployer(DeploymentEngine deploymentEngine) {
cappDeployer.init(configCtx);

// Register application deployment handlers
cappDeployer.registerDeploymentHandler(new ConfigDeployer());
cappDeployer.registerDeploymentHandler(new FileRegistryResourceDeployer(
synapseEnvironmentService.getSynapseEnvironment().getSynapseConfiguration().getRegistry()));
cappDeployer.registerDeploymentHandler(new DataSourceCappDeployer());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
/*
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. 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.wso2.micro.integrator.initializer.deployment.config.deployer;

import org.apache.axis2.deployment.DeploymentException;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.commons.property.PropertyHolder;
import org.apache.synapse.commons.resolvers.ResolverFactory;
import org.apache.synapse.transport.nhttp.config.SslSenderTrustStoreHolder;
import org.wso2.micro.application.deployer.CarbonApplication;
import org.wso2.micro.application.deployer.config.ApplicationConfiguration;
import org.wso2.micro.application.deployer.config.Artifact;
import org.wso2.micro.application.deployer.config.CappFile;
import org.wso2.micro.application.deployer.handler.AppDeploymentHandler;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

public class ConfigDeployer implements AppDeploymentHandler {

private static final Log log = LogFactory.getLog(ConfigDeployer.class);

private static final String PROPERTY_TYPE = "config/property";

private static final String LOCAL_CONFIG_FILE_NAME = "config.properties";
private static final String GLOBAL_CONFIG_FILE_NAME = "file.properties";
private static final String IS_CERT_DEPLOYMENT_ENABLED = "isCertDeploymentEnabled";
private Properties globalProperties;

public static final char URL_SEPARATOR_CHAR = '/';

public ConfigDeployer() {
}

@Override
public void deployArtifacts(CarbonApplication carbonApp, AxisConfiguration axisConfig) throws DeploymentException {
if (log.isDebugEnabled()) {
log.debug("Deploying properties - " + carbonApp.getAppName());
}
ApplicationConfiguration appConfig = carbonApp.getAppConfig();
List<Artifact.Dependency> deps = appConfig.getApplicationArtifact().getDependencies();

List<Artifact> artifacts = new ArrayList<Artifact>();
for (Artifact.Dependency dep : deps) {
if (dep.getArtifact() != null) {
artifacts.add(dep.getArtifact());
}
}
deployConfigArtifacts(artifacts, carbonApp.getAppNameWithVersion());
}

@Override
public void undeployArtifacts(CarbonApplication carbonApp, AxisConfiguration axisConfig) throws DeploymentException {

}

private void deployConfigArtifacts(List<Artifact> artifacts, String parentAppName) {
artifacts.stream().filter(artifact -> PROPERTY_TYPE.equals(artifact.getType())).forEach(artifact -> {
if (log.isDebugEnabled()) {
log.debug("Deploying config artifact: " + artifact.getName());
}
writePropertyToMap(artifact);
});
}

private void writePropertyToMap(Artifact artifact) {
// get the file path of the registry config file
List<CappFile> files = artifact.getFiles();
if (files.size() == 1) {
Path confFolder = Paths.get(getHome(), "conf");
Path globalPropertiesFilePath = confFolder.resolve(GLOBAL_CONFIG_FILE_NAME) ;
Path serverConfPropertyPath = confFolder.resolve(LOCAL_CONFIG_FILE_NAME);
String configFilePath = artifact.getExtractedPath() + File.separator + LOCAL_CONFIG_FILE_NAME;
processConfFile(configFilePath, globalPropertiesFilePath.toString(), serverConfPropertyPath.toString());
} else {
log.error("config/property type must have a single file which declares " +
"config. But " + files.size() + " files found.");
}
}

public void processConfFile(String configFilePath, String globalPropertiesFilePath, String serverConfPropertyPath) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
File configFile = new File(configFilePath);
// Load capp conf property file
Properties configProperties = loadPropertiesFromFile(configFile);
// Load global conf property file
this.globalProperties = loadPropertiesFromFile(new File(globalPropertiesFilePath));
// Load sever conf property file
Properties serverConfigProperties = loadPropertiesFromFile(new File(serverConfPropertyPath));

Properties newServerConfigProperties = new Properties();
String isCertDeploymentEnabled = getValueOfKey(IS_CERT_DEPLOYMENT_ENABLED);
if (isCertDeploymentEnabled == null) {
isCertDeploymentEnabled = "true";
}
PropertyHolder.getInstance().setProperty(IS_CERT_DEPLOYMENT_ENABLED, isCertDeploymentEnabled);
if (serverConfigProperties.size() == 0 && configProperties.size() == 0 ) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
log.info("No configuration is used in the integration");
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
} else {
if (serverConfigProperties.size() > 0) {
for (Map.Entry<Object, Object> entry : serverConfigProperties.entrySet()) {
String key = entry.getKey().toString();
String type = entry.getValue().toString();
if (configProperties.containsKey(key)) {
type = configProperties.getProperty(key);
configProperties.remove(key);
}
newServerConfigProperties.setProperty(key, type);
processConfigProperties(key, type);
}
}
if (configProperties.size() > 0) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
for (Map.Entry<Object, Object> entry : configProperties.entrySet()) {
String key = entry.getKey().toString();
String type = entry.getValue().toString();
newServerConfigProperties.setProperty(key, type);
processConfigProperties(key, type);
}
}
writeServerConfFile(serverConfPropertyPath, newServerConfigProperties);
}
}

public void processConfigProperties(String key, String type) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
String value = getValueOfKey(key);
if (value != null) {
if (Objects.equals(type, "cert")) {
deployCert(key, value);
}
if (PropertyHolder.getInstance().hasKey(key)) {
String oldValue = PropertyHolder.getInstance().getPropertyValue(key);
if (!Objects.equals(oldValue, value)) {
log.error(String.format("The value:[%s] of the key:[%s] has been " +
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
"replaced with the new value:[%s].", oldValue, key, value));
}
}
PropertyHolder.getInstance().setProperty(key, value);
} else {
log.error(String.format("The value of the key:[%s] is not found.", key));
}
}

public void deployCert(String key, String path) {
if (ResolverFactory.getInstance().getResolver("$config:" + IS_CERT_DEPLOYMENT_ENABLED).resolve().
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
equals("true")) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
// Load the truststore properties
char[] password = SslSenderTrustStoreHolder.getInstance().getPassword().toCharArray();
String type = SslSenderTrustStoreHolder.getInstance().getType();
Path trustStorePath = Paths.get(getHome(), SslSenderTrustStoreHolder.getInstance().getLocation());
try (FileInputStream trustStoreStream = new FileInputStream(trustStorePath.toFile())) {
KeyStore trustStore = KeyStore.getInstance(type);
trustStore.load(trustStoreStream, password);
if (!trustStore.containsAlias(key)) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
// Load the certificate file
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
try (FileInputStream certStream = new FileInputStream(path)) {
Certificate cert = certFactory.generateCertificate(certStream);
// Add the certificate to the truststore
trustStore.setCertificateEntry(key, cert);
log.info("Certificate added with alias: " + key);
}
// Save the truststore with the new certificate
try (FileOutputStream outputStream = new FileOutputStream(trustStorePath.toFile())) {
trustStore.store(outputStream, password);
log.info("Truststore updated successfully at: " + trustStorePath);
}
}
} catch (Exception e) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
e.printStackTrace();
System.err.println("Failed to import certificate: " + e.getMessage());
}
}
}

public void writeServerConfFile(String file, Properties newServerConfigProperties) {
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
try (FileWriter writer = new FileWriter(file)) {
Enumeration<?> propertyNames = newServerConfigProperties.propertyNames();
while (propertyNames.hasMoreElements()) {
String key = (String) propertyNames.nextElement();
String value = newServerConfigProperties.getProperty(key);
writer.write(key + ":" + value + "\n");
}
} catch (IOException e) {
System.err.println("Failed to add the config.properties file to the server conf folder: " + e.getMessage());
kalaiyarasiganeshalingam marked this conversation as resolved.
Show resolved Hide resolved
}
}

public Properties loadPropertiesFromFile(File file) {
Properties properties = new Properties();
if (file.exists()) {
try (FileInputStream serverConfigFileReader = new FileInputStream(file)) {
properties.load(serverConfigFileReader);
} catch (IOException e) {
log.debug("Error occurred while loading properties from file:" + e.getMessage());
}
}
return properties;
}

private String getValueOfKey(String key) {
String value = System.getenv(key);
if (value == null) {
value = System.getProperty(key);
if (value == null) {
value = this.globalProperties.getProperty(key);
}
}
return value;
}

public String getHome() {
String carbonHome = System.getProperty("carbon.home");
if (carbonHome == null || "".equals(carbonHome) || ".".equals(carbonHome)) {
carbonHome = getSystemDependentPath(new File(".").getAbsolutePath());
}
return carbonHome;
}

public String getSystemDependentPath(String path) {
return path.replace(URL_SEPARATOR_CHAR, File.separatorChar);
}
}
40 changes: 40 additions & 0 deletions distribution/src/scripts/micro-integrator.bat
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ if ""%1""==""car"" goto setCar
if ""%1""==""-car"" goto setCar
if ""%1""==""--car"" goto setCar

@REM Check if the argument starts with --env-file=
set "envfile=%~1"
if "!envfile:~0,11!"=="--env-file=" (
set "file_path=!envfile:~11!"
call :export_env_file "!file_path!"
)
shift
goto setupArgs

Expand Down Expand Up @@ -133,6 +139,40 @@ echo Stopping the Micro Integrator Server
taskkill /F /PID %processId%
goto end

:export_env_file
setlocal EnableDelayedExpansion

set "file_path=%~1"

REM Check if the file exists
if not exist "!file_path!" (
echo Error: File '!file_path!' not found.
exit /b 1
)

REM Read each line in the file
for /f "usebackq tokens=1,* delims==" %%A in ("!file_path!") do (
set "line=%%A"

REM Ignore lines that start with '#' (comments) or are empty
if not "!line!"=="" (
if "!line:~0,1!" neq "#" (
set "key=%%A"
set "value=%%B"

REM Trim surrounding whitespace from key and value
for /f "tokens=* delims= " %%i in ("!key!") do set "key=%%i"
for /f "tokens=* delims= " %%i in ("!value!") do set "value=%%i"

REM Set the environment variable
setx "!key!" "!value!" >nul
set "!key!=!value!"
)
)
)
echo Environment variables loaded from !file_path!.
exit /b 0

rem ----- commandLifecycle -----------------------------------------------------
:commandLifecycle
goto findJdk
Expand Down
32 changes: 32 additions & 0 deletions distribution/src/scripts/micro-integrator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,32 @@ if [ -e "$CARBON_HOME/wso2carbon.pid" ]; then
fi

# ----- Process the input command ----------------------------------------------

# Function to export variables from the given .env file
export_env_file() {
local file_path="$1"

# Check if the file exists
if [ ! -f "$file_path" ]; then
echo "Error: File '$file_path' not found."
return 1 # Return with an error status
fi

# Read the .env file and export each variable to the environment
while IFS='=' read -r key value; do
# Ignore lines starting with '#' (comments) or empty lines
if [[ ! "$key" =~ ^# ]] && [[ "$key" != "" ]]; then
# Trim surrounding whitespace from key and value
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
# Export the key-value pair to the environment
export "$key=$value"
fi
done < "$file_path"

echo "Environment variables loaded from $file_path."
}

args=""
for c in $*
do
Expand All @@ -142,6 +168,12 @@ do
else
args="$args $c"
fi
# Check if the argument starts with --env-file=
if [[ "$c" == --env-file=* ]]; then
# Extract the file path from the argument
file_path="${c#--env-file=}"
export_env_file "$file_path"
fi
done

if [ "$ARGUMENT" = "car" ]; then
Expand Down
Loading
Loading