blob: 8aa863c42959ab58ad66d084548e9d5e951d8697 [file] [log] [blame]
#!/usr/bin/env bash
###
# ============LICENSE_START=======================================================
# ONAP POLICY
# ================================================================================
# Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
# ================================================================================
# 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.
# ============LICENSE_END=========================================================
##
# #############################################################
# Features Directory Layout:
#
# POLICY_HOME/
# L─ features/
# L─ <feature-name>*/
#     L─ [config]/
#     |   L─ <config-file>+
#     L─ [bin]/
#     |   L─ <bin-file>+
#     L─ lib/
#     |  L─ [dependencies]/
#     |  | L─ <dependent-jar>+
#     │  L─ feature/
#     │  L─ <feature-jar>
#     L─ [db]/
#     │   L─ <db-name>/+
#     │  L─ sql/
#     │ L─ <sql-scripts>*
#     L─ [artifacts]/
#      L─ <artifact>+
#     L─ [install]
#      L─ [enable]
#      L─ [disable]
#      L─ [other-directories-or-files]
#
# notes: [] = optional , * = 0 or more , + = 1 or more
# <feature-name> directory without "feature-" prefix.
# [config] feature configuration directory that contains all configuration
# needed for this features
# [config]/<config-file> preferable named with "feature-<feature-name>" prefix to
# precisely match it against the exact features, source code, and
# associated wiki page for configuration details.
# [bin] feature bin directory that contains helper scripts for this feature
# [bin]/<executable-file> preferable named with "feature-<feature-name>" prefix.
# lib jar libraries needed by this features
# lib/[dependencies] 3rd party jar dependencies not provided by base installation
# of pdp-d that are necessary for <feature-name> to operate
# correctly.
# lib/feature the single feature jar that implements the feature.
# [db] database directory, if the feature contains sql.
# [db]/<db-name> database to which underlying sql scripts should be applied against.
# ideally, <db-name> = <feature-name> so it is easily to associate
# the db data with a feature itself. Ideally, since a feature is
# a somewhat independent isolated unit of functionality,the <db-name>
# database ideally isolates all its data.
# [db]/<db-name>/sql directory with all the sql scripts.
# [db]/<db-name>/sql/<sql-scripts> for this feature sql scripts
# upgrade scripts should be suffixed with ".upgrade.sql"
# downgrade scripts should be suffixed with ".downgrade.sql"
# [artifacts] maven artifacts to be deployed in a maven repository.
# [artifacts]/<artifact> maven artifact with identifiable maven coordinates embedded
# in the artifact.
# [install] custom installation directory where custom enable or disable scripts
# and other free form data is included to be used for the enable and
# and disable scripts.
# [install]/[enable] enable script executed when the enable operation is invoked in
# the feature.
# [install]/[disable] disable script executed when the disable operation is invoked in
# the feature.
# [install]/[other-directories-or-files] other executables, or data that can be used
# by the feature for any of its operations. The content is determined
# by the feature designer.
#
# Operations:
# install: installs a feature
# uninstall: uninstalls a feature
# enable : enables 1) dependencies, 2) configuration, 3) binaries 4) database, 5) artifacts,
# 6) feature, 7) customization.
# disable: disables 1) dependencies, 2) configuration, 3) binaries, 4) database, 5) feature,
# 6) customization
# status : status of a feature
#
# 'enable' operation details:
# 0. Validates current state before the operation is committed
# 1. sets the symbolic link to the actual feature jar in pdp-d classpath ($POLICY_HOME/lib)
# 2. sets symbolic links to feature dependencies in pdp-d classpath ($POLICY_HOME/lib)
# 3. sets symbolic links to feature configuration in pdp-d configuration directory ($POLICY_HOME/config)
# 4. sets symbolic links to feature executables in pdp-d bin directory ($POLICY_HOME/bin)
# 5. sets symbolic links to feature upgrade scripts and removes links to downgrade scripts (if any)
# in the pdp-d migration directory ($POLICY_HOME/etc/db/migration).
# 6. deploys any maven artifacts in the maven repositories in use (if any)
# 7. cd to the feature 'install' directory an executes (if exists) the 'enable' script to allow for specific
# customizations for this feature.
#
# 'disable' operation details:
# 0. Validates current state before the operation is committed
# 1. removes the symbolic link to the actual feature jar in pdp-d classpath ($POLICY_HOME/lib)
# 2. removes symbolic links to feature dependencies in pdp-d classpath ($POLICY_HOME/lib)
# 3. removes symbolic links to feature configuration in pdp-d configuration directory ($POLICY_HOME/config)
# 4. removes symbolic links to feature executables in pdp-d bin directory ($POLICY_HOME/bin)
# 5. removes symbolic links to feature upgrade scripts and sets links to downgrade scripts (if any)
# in the pdp-d migration directory ($POLICY_HOME/etc/db/migration).
# 6. cd to the feature 'install' directory an executes (if exists) the 'disable' script to allow for specific
# customizations for this feature.
#
# Notes for DB enabled features:
# A. Upgrade/Downgrade SQL File Name Format:
# <VERSION>-<pdp|feature-name>[-description](.upgrade|.downgrade).sql
# B. See related tooling: db-migrator, deploy-artifact, and policy
#
# Example:
#
# POLICY_HOME/
# L─ features/
# L── eelf/
# │   L── config/
# │   │   L── logback-eelf.xml
# │   L─ lib/
# │   │ L─ dependencies/
# │   │ │ L─ ONAP-Logging-1.1.0-SNAPSHOT.jar
# │   │ │ L─ eelf-core-1.0.0.jar
# │   │ L─ feature/
# │   │ L─ feature-eelf-1.1.0-SNAPSHOT.jar
# │   L─ install/
# │   L─ enable
# │   L─ disable
# L─ healthcheck/
# L── config/
# │   L─ feature-healthcheck.properties
# L─ lib/
# L─ feature/
# L─ feature-healthcheck-1.1.0-SNAPSHOT.jar
# #############################################################
if [[ ${DEBUG} == y ]]; then
echo "-- MAIN --"
set -x
fi
# The directories at play
LIB=${POLICY_HOME}/lib
CONFIG=${POLICY_HOME}/config
BIN=${POLICY_HOME}/bin
DB=${POLICY_HOME}/etc/db/migration
FEATURES=${POLICY_HOME}/features
if [[ ! ( -d "${LIB}" && -x "${LIB}" ) ]]; then
echo "error: no ${LIB} directory"
exit 1
fi
if [[ ! ( -d "${CONFIG}" && -x "${CONFIG}" ) ]]; then
echo "error: no ${CONFIG} directory"
exit 2
fi
# ensure that the directory exists
mkdir -p "${FEATURES}" 2> /dev/null
if [[ ! -d "${DB}" ]]; then
mkdir -p "${DB}"
fi
# relative per Feature Directory Paths
FEATURE_DEPS="lib/dependencies"
FEATURE_LIB="lib/feature"
FEATURE_CONFIG="config"
FEATURE_BIN="bin"
FEATURE_INSTALL="install"
FEATURE_ARTIFACTS="artifacts"
FEATURE_DB="db"
FEATURE_SQL="sql"
UPGRADE_SQL_SUFFIX=".upgrade.sql"
DOWNGRADE_SQL_SUFFIX=".downgrade.sql"
featureJars=$(find "${FEATURES}" -name "feature-*.jar" -type f -exec basename {} \; 2> /dev/null)
# default field lengths
nameLength=20
versionLength=15
# update field lengths, if needed
for jar in ${featureJars} ; do
# get file name without 'jar' suffix
tmp="${jar%\.jar}"
# remove feature prefix
tmp="${tmp#feature-}"
# get feature name by removing the version portion
name="${tmp%%-[0-9]*}"
# extract version portion of name
version="${tmp#${name}-}"
# grow the size of the name/version field, if needed
if (( "${#name}" > nameLength )) ; then
nameLength="${#name}"
fi
if (( "${#version}" > versionLength )) ; then
versionLength="${#version}"
fi
done
# ##########################################################
# usage: usage information
# ##########################################################
function usage
{
# print out usage information
cat >&2 <<-'EOF'
Usage: features status
Get enabled/disabled status on all features
features enable <feature> ...
Enable the specified feature
features disable <feature> ...
Disable the specified feature
features install [ <feature> | <file-name> ] ...
Install the specified feature
features uninstall <feature> ...
Uninstall the specified feature
EOF
}
# ##########################################################
# status: dump out status information
# ##########################################################
function status
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} --"
set -x
fi
local tmp name version status
local format="%-${nameLength}s %-${versionLength}s %s\n"
printf "${format}" "name" "version" "status"
printf "${format}" "----" "-------" "------"
for jar in ${featureJars} ; do
# get file name without 'jar' suffix
tmp="${jar%\.jar}"
# remove feature prefix
tmp="${tmp#feature-}"
# get feature name by removing the version portion
name="${tmp%%-[0-9]*}"
# extract version portion of name
version="${tmp#${name}-}"
# determine status
status=disabled
if [[ -e "${LIB}/${jar}" ]] ; then
status=enabled
fi
printf "${format}" "${name}" "${version}" "${status}"
done
echo
}
# ##########################################################
# enableDepAnalysis (featureName):
# reports on potential dependency conflicts
# featureName: name of the feature
# ##########################################################
function enableDepAnalysis ()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureDepJars featureDepJarPath depJarName multiVersionJars
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureDepJars=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_DEPS}"/*.jar 2> /dev/null)
for featureDepJarPath in ${featureDepJars}; do
depJarName=$(basename "${featureDepJarPath}")
# it could be a base jar
if [[ -f "${LIB}"/"${depJarName}" ]]; then
echo "warning: dependency ${depJarName} already in use"
continue
fi
# it could be a link from another feature
if [[ -L "${LIB}"/"${depJarName}" ]]; then
continue
fi
# unadvisable if multiple versions exist but the base or
# installed one wins.
multiVersionJars=$(ls "${LIB}"/"${depJarName%%-[0-9]*.jar}"-*.jar 2> /dev/null)
if [[ -n "${multiVersionJars}" ]]; then
echo "warning: other version of library ${depJarName} present: ${multiVersionJars}"
continue
fi
done
}
# ##########################################################
# enableConfigAnalysis (featureName):
# reports on potential dependency conflicts
# featureName: name of the feature
# ##########################################################
function enableConfigAnalysis ()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureConfigs configPath configFileName
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureConfigs=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_CONFIG}"/ 2> /dev/null)
for configPath in ${featureConfigs}; do
configFileName=$(basename "${configPath}")
if [[ -e "${CONFIG}"/"${configFileName}" ]]; then
echo "error: a config file of the same name is already in the base installation: ${configFileName}"
return 2
fi
done
}
# ##########################################################
# enableBinAnalysis (featureName):
# reports on potential dependency conflicts
# featureName: name of the feature
# ##########################################################
function enableBinAnalysis ()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureBins binPath binFileName
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureBins=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_BIN}"/ 2> /dev/null)
for binPath in ${featureBins}; do
binFileName=$(basename "${binPath}")
if [[ -e "${CONFIG}"/"${binFileName}" ]]; then
echo "error: a bin file of the same name is already in the base installation: ${binFileName}"
return 2
fi
done
}
# ##########################################################
# enableDbAnalysis (featureName):
# reports on potential db access problems
# featureName: name of the feature
# ##########################################################
function enableDbAnalysis()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureSqls
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureSqls=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/${FEATURE_SQL}/*${UPGRADE_SQL_SUFFIX} 2> /dev/null)
if [[ -z ${featureSqls} ]]; then
return 0
fi
source "${POLICY_HOME}"/etc/profile.d/env.sh
if [[ -z ${SQL_HOST} ]] || [[ -z ${SQL_USER} ]] || [[ -z ${SQL_PASSWORD} ]]; then
echo "warning: DB server is not configured"
fi
return 0
}
# ##########################################################
# enableFeatureDeps(featureName):
# enables feature dependencies
# featureName: name of the feature
# ##########################################################
function enableFeatureDeps()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureDeps featureDepPath depJarName
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureDeps=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_DEPS}"/*.jar 2> /dev/null)
for featureDepPath in ${featureDeps}; do
depJarName=$(basename "${featureDepPath}")
if [[ ! -f "${LIB}"/"${depJarName}" ]]; then
ln -s -f "${featureDepPath}" "${LIB}/"
fi
done
}
# ##########################################################
# enableFeatureConfig(featureName):
# enables feature configuration
# featureName: name of the feature
# ##########################################################
function enableFeatureConfig()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureConfigs featureConfigPath
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureConfigs=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_CONFIG}"/ -type f -maxdepth 1 2> /dev/null)
for featureConfigPath in ${featureConfigs}; do
ln -s -f "${featureConfigPath}" "${CONFIG}/"
done
}
# ##########################################################
# enableFeatureBin(featureName):
# enables feature binaries
# featureName: name of the feature
# ##########################################################
function enableFeatureBin()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureBins featureBinPath
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureBins=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_BIN}"/ -type f -maxdepth 1 2> /dev/null)
for featureBinPath in ${featureBins}; do
chmod u+x "${featureBinPath}"
ln -s -f "${featureBinPath}" "${BIN}/"
done
}
# ##########################################################
# enableFeatureDbSchema(featureName):
# enables feature DB Schema configuration
# featureName: name of the feature
# ##########################################################
function enableFeatureDbSchema()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureDbPath="$2"
local schemaName="$3"
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
if [[ -z ${featureDbPath} ]]; then
echo "warning: ${featureName} contains no DB path"
return 2
fi
if [[ -z ${schemaName} ]]; then
echo "warning: feature ${featureName} contains no schema name"
return 3
fi
rc=0
sqlUpgradeScripts=$(ls "${featureDbPath%/}"/${FEATURE_SQL}/*${UPGRADE_SQL_SUFFIX} 2> /dev/null)
for sqlUpgradeScript in ${sqlUpgradeScripts}; do
if [[ ! -d "${DB}"/"${schemaName}"/${FEATURE_SQL} ]]; then
mkdir -p "${DB}"/"${schemaName}"/${FEATURE_SQL} 2> /dev/null
fi
ln -s -f "${sqlUpgradeScript}" "${DB}"/"${schemaName}"/${FEATURE_SQL}/
done
sqlDowngradeScripts=$(ls "${featureDbPath%/}"/${FEATURE_SQL}/*${DOWNGRADE_SQL_SUFFIX} 2> /dev/null)
for sqlDowngradeScript in ${sqlDowngradeScripts}; do
if [[ -d "${DB}"/"${schemaName}"/${FEATURE_SQL} ]]; then
sqlName=$(basename "${sqlDowngradeScript}")
rm -f "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/"${sqlName}" 2> /dev/null
else
echo "warning: feature ${featureName} only contains downgrade scripts"
rc=4
break
fi
done
if [[ -n ${sqlUpgradeScripts} || -n ${sqlDowngradeScripts} ]]; then
DEBUG=${DEBUG} db-migrator -s "${schemaName}" -o ok
fi
return ${rc}
}
# ##########################################################
# enableFeatureDb(featureName):
# enables DB feature configuration
# featureName: name of the feature
# ##########################################################
function enableFeatureDb()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureDbs featureDbPath schemaName sqls
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureDbs=$(ls -d "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/ 2> /dev/null)
for featureDbPath in ${featureDbs}; do
sqls=$(ls "${featureDbPath%/}"/"${FEATURE_SQL}"/*.sql 2> /dev/null)
if [[ -z ${sqls} ]]; then
continue
fi
schemaName=$(basename "${featureDbPath%/}")
enableFeatureDbSchema "${featureName}" "${featureDbPath%/}" "${schemaName}"
done
}
# ##########################################################
# enableFeatureArtifacts(featureName):
# deploys maven artifacts
# featureName: name of the feature
# ##########################################################
function enableFeatureArtifacts()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local artifacts
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
artifacts=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_ARTIFACTS}"/* 2> /dev/null)
for artifactPath in ${artifacts}; do
deploy-artifact -f -a "${artifactPath}"
done
}
# ##########################################################
# customize(featureName):
# executes customized script for an operation.
#
# featureName - feature name
# operation - operation, ie.
# 'enable', 'disable', 'install', or 'uninstall'
# ##########################################################
function customOpScript()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local operation="$2"
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
if [[ -z ${operation} ]]; then
echo "warning: ${featureName} : a custom operation script must be provided"
return 1
fi
local customScript="${FEATURES}"/"${featureName}"/"${FEATURE_INSTALL}"/"${operation}"
if [[ -f ${customScript} ]]; then
(
cd "${FEATURES}"/"${featureName}"/"${FEATURE_INSTALL}"
chmod u+x "${customScript}"
./"$(basename "${customScript}")"
)
fi
}
# ##########################################################
# enableFeature(featureName, featureJar): enables a feature
# featureName: name of the feature
# featureJar: path to feature jar implementation
# ##########################################################
function enableFeature()
{
if [[ $DEBUG == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureJar="$2"
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
if [[ -z ${featureJar} ]]; then
echo "warning: no feature jar"
return 2
fi
if ! enableDepAnalysis "${featureName}"; then
return "$?"
fi
if ! enableConfigAnalysis "${featureName}"; then
return "$?"
fi
if ! enableBinAnalysis "${featureName}"; then
return "$?"
fi
if ! enableDbAnalysis "${featureName}"; then
return "$?"
fi
# enable feature itself
ln -s -f "${featureJar}" "${LIB}/"
# enable dependent libraries if any
enableFeatureDeps "${featureName}"
# enable configuration
enableFeatureConfig "${featureName}"
# enable binaries
enableFeatureBin "${featureName}"
# enable db
enableFeatureDb "${featureName}"
# enable feature artifacts
enableFeatureArtifacts "${featureName}"
# run custom enable if any
customOpScript "${featureName}" "enable"
}
# ##########################################################
# disableFeatureDeps(featureName):
# disables feature dependencies
# ##########################################################
function disableFeatureDeps()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local xDepsEnabledMap featureBaseDirs aFeatureDir aFeatureName
local featureDeps aFeatureDep
local depJarPath depJarName depJarRealPath
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
declare -A xDepsEnabledMap
featureBaseDirs=$(ls -d "${FEATURES}"/*/ 2> /dev/null)
for aFeatureDir in ${featureBaseDirs}; do
aFeatureName=$(basename "${aFeatureDir}")
if [[ "${aFeatureName}" == "${featureName}" ]]; then
continue
fi
depJarPaths=$(ls "${aFeatureDir}"/"${FEATURE_DEPS}"/*.jar 2> /dev/null)
for depJarPath in ${depJarPaths}; do
if [[ "$?" == 0 ]] ; then
depJarName=$(basename "${depJarPath}")
xDepsEnabledMap[${depJarName}]="${depJarPath}"
fi
done
done
if [[ ${DEBUG} == y ]]; then
echo "${!xDepsEnabledMap[@]}"
echo "${xDepsEnabledMap[@]}"
fi
featureDeps=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_DEPS}"/*.jar 2> /dev/null)
for aFeatureDep in ${featureDeps}; do
depJarName=$(basename "${aFeatureDep}")
if [[ -L "${LIB}"/"${depJarName}" ]]; then
depJarRealPath=$(readlink -f "${LIB}"/"${depJarName}")
if [[ "${depJarRealPath}" == "${aFeatureDep}" ]]; then
rm -f "${LIB}"/"${depJarName}"
# case there were multiple features using this library
# re-enable link fron an enabled feature
if [[ -n ${xDepsEnabledMap[${depJarName}]} ]]; then
ln -s -f "${xDepsEnabledMap[${depJarName}]}" "${LIB}/"
fi
fi
fi
done
}
# ##########################################################
# disableFeatureConfig(featureName):
# disables feature configuration
# featureName: name of the feature
# ##########################################################
function disableFeatureConfig()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureConfigs featureConfigPath
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureConfigs=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_CONFIG}"/ -type f -maxdepth 1 2> /dev/null)
for featureConfigPath in ${featureConfigs}; do
configFileName=$(basename "${featureConfigPath}")
rm -f "${CONFIG}"/"${configFileName}" 2> /dev/null
done
}
# ##########################################################
# disableFeatureBin(featureName):
# disables feature binaries
# featureName: name of the feature
# ##########################################################
function disableFeatureBin()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureBins featureBinPath
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureBins=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_BIN}"/ -type f -maxdepth 1 2> /dev/null)
for featureBinPath in ${featureBins}; do
binFileName=$(basename "${featureBinPath}")
rm -f "${BIN}"/"${binFileName}" 2> /dev/null
done
}
# ##########################################################
# disableFeatureDbSchema(featureName, featureDbPath, schemaName):
# disables feature db configuration for a schema
# featureName: name of the feature
# ##########################################################
function disableFeatureDbSchema()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1" featureDbPath="$2" schemaName="$3"
local upgradeFeatureSqls downgradeFeatureSqls featureSql sqlDir sqlName schemaDir schemaName
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
if [[ -z ${featureDbPath} ]]; then
echo "warning: ${featureName} contains no DB path"
return 2
fi
if [[ -z ${schemaName} ]]; then
echo "warning: feature ${featureName} contains no schema name"
return 3
fi
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
upgradeFeatureSqls=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/"${schemaName}"/"${FEATURE_SQL}"/*"${UPGRADE_SQL_SUFFIX}" -type f -maxdepth 1 2> /dev/null)
for featureSql in ${upgradeFeatureSqls}; do
sqlName=$(basename "${featureSql}")
sqlDir=$(dirname "${featureSql}")
schemaDir=$(dirname "${sqlDir}")
schemaName=$(basename "${schemaDir}")
rm -f "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/"${sqlName}" 2> /dev/null
done
downgradeFeatureSqls=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/"${schemaName}"/"${FEATURE_SQL}"/*"${DOWNGRADE_SQL_SUFFIX}" -type f -maxdepth 1 2> /dev/null)
for featureSql in ${downgradeFeatureSqls}; do
sqlName=$(basename "${featureSql}")
sqlDir=$(dirname "${featureSql}")
schemaDir=$(dirname "${sqlDir}")
schemaName=$(basename "${schemaDir}")
if [[ ! -d "${DB}"/"${schemaName}"/${FEATURE_SQL} ]]; then
mkdir -p "${DB}"/"${schemaName}"/${FEATURE_SQL} 2> /dev/null
fi
ln -s -f "${featureSql}" "${DB}"/"${schemaName}"/${FEATURE_SQL}/
done
if [[ -n ${sqlUpgradeScripts} || -n ${sqlDowngradeScripts} ]]; then
DEBUG=${DEBUG} db-migrator -s "${schemaName}" -o ok
fi
}
# ##########################################################
# disableFeatureDb(featureName):
# disables feature db configuration
# featureName: name of the feature
# ##########################################################
function disableFeatureDb()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureDbPath featureDbs schemaName
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureDbs=$(ls -d "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/ 2> /dev/null)
for featureDbPath in ${featureDbs}; do
if [[ -z "$(ls "${featureDbPath%/}"/"${FEATURE_SQL}"/*${UPGRADE_SQL_SUFFIX} 2> /dev/null)" ]]; then
continue
fi
schemaName=$(basename "${featureDbPath%/}")
disableFeatureDbSchema "${featureName}" "${featureDbPath%/}" "${schemaName}"
done
}
# ##########################################################
# disableFeature(featureName): disables a feature
# featureName: name of the feature
# ##########################################################
function disableFeature()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return
fi
# disable feature itself
(
cd "${LIB}"
rm -f feature-"${featureName}"-[0-9]*.jar 2> /dev/null
)
# disable dependencies if any
disableFeatureDeps "${featureName}"
# disable configuration if any
disableFeatureConfig "${featureName}"
# disable binaries if any
disableFeatureBin "${featureName}"
# disable DB SQL scripts if any
disableFeatureDb "${featureName}"
# run custom disable if any
customOpScript "${featureName}" "disable"
}
############################################################
# configureFeature <config-file> <features-root-directory>
#
# This was copied from 'policy-drools/docker-install.sh'
# in the 'docker' repository, and modified where needed.
############################################################
function configureFeature()
{
if [[ $DEBUG == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local envConfig=$1 featureRoot=$2
local sedLine="sed -i"
local sedFiles="" nonBinaryFiles sedFile name value
while read line || [ -n "${line}" ]; do
if [[ -n ${line} ]] && [[ ${line:0:1} != \# ]]; then
name="${line%%=*}"
value="${line#*=}"
value=$(echo "${value}" | sed -e 's/[\/&]/\\&/g')
if [[ -z ${name} ]] || [[ -z ${value} ]]; then
echo "warning: ${line} missing name or value"
fi
sedLine+=" -e 's/\${{${name}}}/${value}/g' "
fi
done < "${envConfig}"
nonBinaryFiles=$(find "${featureRoot}" -type f -exec grep -Iq . {} \; -print 2> /dev/null)
for sedFile in ${nonBinaryFiles}; do
if fgrep -l '${{' ${sedFile} > /dev/null 2>&1; then
sedFiles+="${sedFile} "
fi
done
if [[ -n ${sedFiles} ]]; then
sedLine+=${sedFiles}
eval "${sedLine}"
fi
}
############################################################
# installFeatures <feature-name-or-zip-file> ...
#
# This was copied from 'policy-drools/docker-install.sh'
# in the 'docker' repository, and modified where needed.
############################################################
function installFeatures
{
if [[ $DEBUG == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local name featureConf feature dir conf
if [[ -d "${FEATURES}" && -x "${FEATURES}" ]]; then
SOURCE_DIR=$PWD
for feature in "$@" ; do
dir=
if [[ "${feature}" == feature-*.zip ||
"${feature}" == */feature-*.zip ]] ; then
# the ZIP file is specified -- find the name
name="${feature##*/}"
name="${name#feature-}"
name="${name%%-[0-9]*\.zip}"
# if the ZIP file has a directory name component,
# set 'dir' accordingly
if [[ "${feature}" =~ / ]] ; then
dir="${feature%/*}"
fi
else
# Doesn't match the ZIP file name convention -- interpret
# this as a feature name, and try to locate a matching ZIP
# file. If there is more than one, choose the one with the
# highest version number.
name="${feature}"
feature=$(ls -v feature-"${name}"-[0-9]*.zip 2>/dev/null|tail -1)
fi
if [[ ! -f "${feature}" ]] ; then
# include the file name in the error message, unless we don't
# have one -- in this case, use the feature name
echo "error: feature file ${feature:-for ${name}} not found"
continue
fi
if [[ -d "${FEATURES}/${name}" ]] ; then
echo "error: feature ${name} has already been installed"
continue
fi
# extract contents of ZIP file in to feature directory
mkdir -p "${FEATURES}/${name}" > /dev/null 2>&1
(cd "${FEATURES}/${name}"; jar xf "${SOURCE_DIR}"/"${feature}")
# if there is a configuration file available,
# use it to configure the feature
featureConf="${dir:+$dir/}feature-${name}.conf"
if [[ -r "${featureConf}" ]]; then
configureFeature "${featureConf}" "${FEATURES}"/"${name}"
cp "${featureConf}" "${POLICY_HOME}"/etc/profile.d
echo "feature ${name} has been installed (configuration present)"
else
echo "feature ${name} has been installed (no configuration present)"
fi
customOpScript "${name}" "install"
done
# check the current directory and the 'config' directory for a
# 'base.conf' file -- use the first one that is found
for conf in base.conf ${POLICY_HOME}/config/base.conf ${POLICY_HOME}/etc/profile.d/base.conf; do
if [[ -f "${conf}" ]] ; then
echo "applying base configuration '${conf}' to features"
configureFeature "${conf}" "${FEATURES}"
break
fi
done
else
echo "error: aborting -- ${FEATURES} is not accessible"
exit 1
fi
}
# ##########################################################
# uninstallFeatureDb(featureName):
# uninstalls the feature db configuration
# featureName: name of the feature
# ##########################################################
function uninstallFeatureDb()
{
if [[ ${DEBUG} == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
local featureSqls sqlDir sqlName schemaDir schemaName schemaNames leftSqls
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return 1
fi
featureSqls=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/${FEATURE_SQL}/*.sql -type f -maxdepth 1 2> /dev/null)
for featureSql in ${featureSqls}; do
sqlName=$(basename "${featureSql}")
sqlDir=$(dirname "${featureSql}")
schemaDir=$(dirname "${sqlDir}")
schemaName=$(basename "${schemaDir}")
schemaNames+=${schemaName}
rm -f "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/"${sqlName}" 2> /dev/null
done
for schemaName in ${schemaNames};
do
leftSqls=$(ls "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/*.sql 2> /dev/null)
if [[ -z ${leftSqls} ]]; then
if ! DEBUG=${DEBUG} db-migrator -s "${schemaName}" -o ok; then
echo -n "warning: ${featureName}: ${schemaName}: database data is leftover. "
echo -n "Consider cleaning left over data with 'db-migrator'."
fi
fi
done
}
############################################################
# uninstallFeature <feature-name> ...
############################################################
function uninstallFeature
{
if [[ $DEBUG == y ]]; then
echo "-- ${FUNCNAME[0]} $* --"
set -x
fi
local featureName="$1"
if [[ -z ${featureName} ]]; then
echo "warning: no feature name"
return
fi
disableFeature "${featureName}"
uninstallFeatureDb "${featureName}"
customOpScript "${featureName}" "uninstall"
if [[ -n ${FEATURES} && -n ${featureName} ]]; then
rm -rf "${FEATURES:-???}/${featureName}"
fi
}
############################################################
# uninstallFeatures <feature-name> ...
############################################################
function uninstallFeatures
{
if [[ $DEBUG == y ]]; then
echo "-- ${FUNCNAME[0]} --"
set -x
fi
local name
local allFeatures=$'\n'$(cd ${FEATURES};ls)$'\n'
for name in "$@" ; do
# the following check takes care of potentially troublesome names
# like '.', '..', and names containing '/'
if [[ "${allFeatures}" =~ $'\n'${name}$'\n' ]] ; then
uninstallFeature "${name}"
else
echo "feature ${name} not found"
fi
done
}
case "$1" in
status)
{
# dump out status information
status
};;
enable)
{
if [[ -f "${POLICY_HOME}"/PID ]]; then
echo "error: enable: not allowed when policy is running .."
echo
status
exit 10
fi
# enable the specified options
shift
match=
for name in "$@" ; do
# look for matches - 'file' has the full path name
file=$(ls "${FEATURES}"/"${name}"/"${FEATURE_LIB}"/feature-"${name}"-[0-9]*.jar 2> /dev/null)
if [[ "$?" != 0 ]] ; then
# no matching file
echo "${name}: no such option"
else
# make sure there is only one feature jar
countFeatureJars=$(echo "${file}" | wc -w)
if [[ ${countFeatureJars} != 1 ]]; then
echo "warning: skipping ${name}, ${countFeatureJars} feature libraries found"
continue
fi
# found a match (handle multiple matches, just in case)
match=true
enableFeature "${name}" "${file}"
fi
done
if [[ "${match}" ]] ; then
echo
status
fi
};;
disable)
{
if [[ -f "${POLICY_HOME}"/PID ]]; then
echo "error: disable: not allowed when policy is running .."
echo
status
exit 11
fi
# disable the specified options
shift
match=
for name in "$@" ; do
# look for matches -- 'file' has the last segment of the path name
file=$(ls "${FEATURES}"/"${name}"/"${FEATURE_LIB}"/feature-"${name}"-[0-9]*.jar 2> /dev/null)
if [[ "$?" != 0 ]] ; then
echo "${name}: no such option"
else
# found a match (handle multiple matches, just in case)
match=true
disableFeature "${name}"
fi
done
if [[ "${match}" ]] ; then
echo
status
fi
};;
install)
{
shift
installFeatures "$@"
};;
uninstall)
{
if [[ -f "${POLICY_HOME}"/PID ]]; then
echo "error: uninstall: not allowed when policy is running .."
echo
status
exit 12
fi
shift
uninstallFeatures "$@"
};;
*)
{
usage
};;
esac
exit