| #!/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 |