| #! /bin/bash |
| |
| ### |
| # ============LICENSE_START======================================================= |
| # ONAP POLICY |
| # ================================================================================ |
| # Copyright (C) 2017 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/ |
| # └── features/ |
| # └── <feature-name>*/ |
| # └── [config]/ |
| # │ └── <config-file>* |
| # └── lib/ |
| # │ └── [dependencies]/ |
| # │ │ └── <dependent-jar>* |
| # │ └── feature/ |
| # │ └── <feature-jar> |
| # └── [install] |
| # └── [enable] |
| # └── [disable] |
| # └── [other-future-operations] |
| # └── [other-files] |
| # |
| # <feature-name> directory should not have the "feature-" prefix. |
| # <config-file> preferable with "feature-" prefix. |
| # |
| # Example: |
| # |
| # POLICY_HOME/ |
| # └── features/ |
| # ├── eelf/ |
| # │ ├── config/ |
| # │ │ ├── logback-eelf.xml |
| # │ └── lib/ |
| # │ │ └── dependencies/ |
| # │ │ │ └── ONAP-Logging-1.1.0-SNAPSHOT.jar |
| # │ │ │ └── eelf-core-1.0.0.jar |
| # │ │ └── feature/ |
| # │ │ └── feature-eelf-1.1.0-SNAPSHOT.jar |
| # │ └── install/ |
| # │ └── enable |
| # │ └── disable |
| # └── healthcheck/ |
| # ├── config/ |
| # │ └── feature-healthcheck.properties |
| # └── lib/ |
| # └── feature/ |
| # └── 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 |
| 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 |
| |
| if [[ ! ( -d "${FEATURES}" && -x "${FEATURES}" ) ]]; then |
| echo "ERROR: no ${FEATURES} directory" |
| exit 3 |
| fi |
| |
| # relative per Feature Directory Paths |
| |
| FEATURE_DEPS="lib/dependencies" |
| FEATURE_LIB="lib/feature" |
| FEATURE_CONFIG="config" |
| FEATURE_INSTALL="install" |
| |
| featureJars=$(find "${FEATURES}" -name "feature-*.jar" -type f -exec basename {} \; 2> /dev/null) |
| if [[ -z ${featureJars} ]]; then |
| echo "no features" |
| usage |
| exit 0 |
| fi |
| |
| # 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 |
| 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 |
| } |
| |
| # ########################################################## |
| # depEnableAnalysis(featureName): |
| # reports on potential dependency conflicts |
| # featureName: name of the feature |
| # ########################################################## |
| function depEnableAnalysis() |
| { |
| if [[ ${DEBUG} == y ]]; then |
| echo "-- ${FUNCNAME[0]} $@ --" |
| set -x |
| fi |
| |
| local featureName="$1" |
| local featureDepJars featureDepJarPath depJarName multiVersionJars |
| |
| if [[ -z ${featureName} ]]; then |
| echo "WARN: 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 "WARN: 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 |
| |
| multiVersionJars=$(ls "${LIB}"/"${depJarName%%-[0-9]*.jar}"-*.jar 2> /dev/null) |
| if [[ -n "${multiVersionJars}" ]]; then |
| echo "WARN: other version of library ${depJarName} present: ${multiVersionJars}" |
| return 2 |
| fi |
| done |
| } |
| |
| # ########################################################## |
| # configEnableAnalysis(featureName): |
| # reports on potential dependency conflicts |
| # featureName: name of the feature |
| # ########################################################## |
| function configEnableAnalysis() |
| { |
| if [[ ${DEBUG} == y ]]; then |
| echo "-- ${FUNCNAME[0]} $@ --" |
| set -x |
| fi |
| |
| local featureName="$1" |
| local featureConfigs configPath configFileName |
| |
| if [[ -z ${featureName} ]]; then |
| echo "WARN: 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 "${LIB}"/"${configFileName}" ]]; then |
| echo "ERROR: a config file of the same name is already in the base: ${configFileName}" |
| return 2 |
| fi |
| done |
| } |
| |
| # ########################################################## |
| # 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 "WARN: 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 "WARN: 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 |
| } |
| |
| # ########################################################## |
| # enableFeatureOp(featureName): 'enable' feature operation |
| # featureName: name of the feature |
| # ########################################################## |
| function enableFeatureOp() |
| { |
| if [[ ${DEBUG} == y ]]; then |
| echo "-- ${FUNCNAME[0]} $@ --" |
| set -x |
| fi |
| |
| local featureName="$1" |
| |
| if [[ -z ${featureName} ]]; then |
| echo "WARN: no feature name" |
| return 1 |
| fi |
| |
| enableScript="${FEATURES}"/"${featureName}"/"${FEATURE_INSTALL}"/enable |
| if [[ -f ${enableScript} ]]; then |
| ( |
| cd "${FEATURES}"/"${featureName}"/"${FEATURE_INSTALL}" |
| chmod u+x enable |
| ./enable |
| ) |
| 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 "WARN: no feature name" |
| return 1 |
| fi |
| |
| if [[ -z ${featureJar} ]]; then |
| echo "WARN: no feature jar" |
| return 2 |
| fi |
| |
| if ! depEnableAnalysis "${featureName}"; then |
| return 3 |
| fi |
| |
| if ! configEnableAnalysis "${featureName}"; then |
| return 4 |
| fi |
| |
| # enable feature itself |
| |
| ln -s -f "${featureJar}" "${LIB}/" |
| |
| # enable dependent libraries if any |
| |
| enableFeatureDeps "${featureName}" |
| |
| # enable configuration |
| |
| enableFeatureConfig "${featureName}" |
| |
| # TODO: run feature install DB scripts if any |
| |
| # run custom enable if any |
| |
| enableFeatureOp "${featureName}" |
| } |
| |
| # ########################################################## |
| # 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 "WARN: 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 "WARN: 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 |
| } |
| |
| # ########################################################## |
| # disableFeatureOp(featureName): 'enable' feature operation |
| # featureName: name of the feature |
| # ########################################################## |
| function disableFeatureOp() |
| { |
| if [[ ${DEBUG} == y ]]; then |
| echo "-- ${FUNCNAME[0]} $@ --" |
| set -x |
| fi |
| |
| local featureName="$1" |
| |
| if [[ -z ${featureName} ]]; then |
| echo "WARN: no feature name" |
| return 1 |
| fi |
| |
| disableScript="${FEATURES}"/"${featureName}"/"${FEATURE_INSTALL}"/disable |
| if [[ -f ${disableScript} ]]; then |
| ( |
| cd "${FEATURES}"/"${featureName}"/"${FEATURE_INSTALL}" |
| chmod u+x disable |
| ./disable |
| ) |
| fi |
| } |
| |
| # ########################################################## |
| # disableFeature(featureName, featureJar): enables 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 "WARN: 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}" |
| |
| # run feature uninstall DB scripts if any |
| # TODO: future |
| |
| # run custom disable if any |
| disableFeatureOp "${featureName}" |
| } |
| |
| 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 |
| };; |
| |
| *) |
| { |
| usage |
| };; |
| esac |
| exit |