From ae4a935b835c0dc588c7a53aef846dd6506b732f Mon Sep 17 00:00:00 2001 From: Jorge Hernandez Date: Tue, 18 Jul 2017 01:06:39 -0500 Subject: [POLICY-66] self-contained features support installation/enable/disable of self contained package features: Feature 3rd party dependencies, configuration files, and custom installation scripts do not need to be packaged within the policy core base to be used. Change-Id: I35a472e63bd0f9f7aa6cd0c112d41d2b4604a892 Signed-off-by: Jorge Hernandez --- packages/base/src/files/bin/features | 640 +++++++++++++++++++++++++++++++++++ 1 file changed, 640 insertions(+) create mode 100644 packages/base/src/files/bin/features (limited to 'packages/base') diff --git a/packages/base/src/files/bin/features b/packages/base/src/files/bin/features new file mode 100644 index 00000000..7b14644f --- /dev/null +++ b/packages/base/src/files/bin/features @@ -0,0 +1,640 @@ +#! /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/ +# └── */ +#     └── [config]/ +#     │   └── * +#     └── lib/ +#     │  └── [dependencies]/ +#     │  │ └── * +#     │  └── feature/ +#     │  └── +#     └── [install] +#      └── [enable] +#      └── [disable] +#      └── [other-future-operations] +#      └── [other-files] +# +# directory should not have the "feature-" prefix. +# preferable with "feature-" prefix. +# +# Example: +# +# POLICY_HOME/ +# └── features/ +# ├── eelf/ +# │   ├── config/ +# │   │   ├── logback-eelf.xml +# │   └── lib/ +# │   │ └── dependencies/ +# │   │ │ └── ECOMP-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 ... + Enable the specified feature + features disable ... + 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 -- cgit 1.2.3-korg