From ae26e2717c408225534033726614a25e16fe18ca Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Tue, 30 Aug 2016 13:06:33 -0400 Subject: Adds ability to power off nodes in clean Now if an inventory file is provided to clean, those nodes will be powered off. JIRA: APEX-250 Change-Id: I2d78285717726c3d1c9d7d88c38e706d4617e337 Signed-off-by: Tim Rozet --- build/rpm_specs/opnfv-apex-common.spec | 3 ++ ci/clean.sh | 63 +++++++++++++++++++++++++++++++--- ci/dev_deploy_check.sh | 3 ++ lib/python/apex/__init__.py | 1 + lib/python/apex/clean.py | 39 +++++++++++++++++++++ lib/python/apex/common/utils.py | 8 +++++ lib/python/apex_python_utils.py | 11 ++++++ tests/config/inventory.yaml | 56 ++++++++++++++++++++++++++++++ tests/test_apex_clean.py | 41 ++++++++++++++++++++++ tests/test_apex_common_utils.py | 17 +++++---- 10 files changed, 232 insertions(+), 10 deletions(-) create mode 100644 lib/python/apex/clean.py create mode 100644 tests/config/inventory.yaml create mode 100644 tests/test_apex_clean.py diff --git a/build/rpm_specs/opnfv-apex-common.spec b/build/rpm_specs/opnfv-apex-common.spec index 39bcd289..af4351e8 100644 --- a/build/rpm_specs/opnfv-apex-common.spec +++ b/build/rpm_specs/opnfv-apex-common.spec @@ -69,6 +69,7 @@ install lib/python/apex/deploy_env.py %{buildroot}%{python3_sitelib}/apex/ install lib/python/apex/ip_utils.py %{buildroot}%{python3_sitelib}/apex/ install lib/python/apex/network_environment.py %{buildroot}%{python3_sitelib}/apex/ install lib/python/apex/network_settings.py %{buildroot}%{python3_sitelib}/apex/ +install lib/python/apex/clean.py %{buildroot}%{python3_sitelib}/apex/ mkdir -p %{buildroot}%{python3_sitelib}/apex/common install lib/python/apex/common/__init__.py %{buildroot}%{python3_sitelib}/apex/common/ install lib/python/apex/common/constants.py %{buildroot}%{python3_sitelib}/apex/common/ @@ -131,6 +132,8 @@ install config/inventory/pod_example_settings.yaml %{buildroot}%{_docdir}/opnfv/ %doc %{_docdir}/opnfv/inventory.yaml.example %changelog +* Tue Aug 30 2016 Tim Rozet - 3.0-12 +- Add clean library. * Mon Aug 1 2016 Tim Rozet - 3.0-11 - Add nosdn fdio scenarios. * Tue Jul 5 2016 Dan Radez - 3.0-10 diff --git a/ci/clean.sh b/ci/clean.sh index 4cf6b64a..e4b2d106 100755 --- a/ci/clean.sh +++ b/ci/clean.sh @@ -16,17 +16,72 @@ CONFIG=${CONFIG:-'/var/opt/opnfv'} RESOURCES=${RESOURCES:-"$CONFIG/images"} LIB=${LIB:-"$CONFIG/lib"} +reset=$(tput sgr0 || echo "") +blue=$(tput setaf 4 || echo "") +red=$(tput setaf 1 || echo "") +green=$(tput setaf 2 || echo "") ##LIBRARIES -if ! source $LIB/common-functions.sh; then - echo "Failed to source $LIB/common-functions.sh" - exit 1 -fi +for lib in common-functions parse-functions; do + if ! source $LIB/${lib}.sh; then + echo "Failed to source $LIB/${lib}.sh" + exit 1 + fi +done vm_index=4 ovs_bridges="br-admin br-private br-public br-storage" OPNFV_NETWORK_TYPES="admin_network private_network public_network storage_network api_network" + +display_usage() { + echo -e "Usage:\n$0 [arguments] \n" + echo -e " -i|--inventory : Full path to inventory yaml file. Required only for baremetal node clean" +} + +##translates the command line parameters into variables +##params: $@ the entire command line is passed +##usage: parse_cmd_line() "$@" +parse_cmdline() { + echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n" + echo "Use -h to display help" + sleep 2 + + while [ "${1:0:1}" = "-" ] + do + case "$1" in + -h|--help) + display_usage + exit 0 + ;; + -i|--inventory) + INVENTORY_FILE=$2 + shift 2 + ;; + *) + display_usage + exit 1 + ;; + esac + done + + if [[ ! -z "$INVENTORY_FILE" && ! -f "$INVENTORY_FILE" ]]; then + echo -e "{$red}ERROR: Inventory File: ${INVENTORY_FILE} does not exist! Exiting...${reset}" + exit 1 + fi +} + +parse_cmdline "$@" + +if [ -n "$INVENTORY_FILE" ]; then + echo -e "${blue}INFO: Parsing inventory file...${reset}" + if ! python3.4 -B $LIB/python/apex_python_utils.py clean -f ${INVENTORY_FILE}; then + echo -e "${red}WARN: Unable to shutdown all nodes! Please check /var/log/apex.log${reset}" + else + echo -e "${blue}INFO: Node shutdown complete...${reset}" + fi +fi + # Clean off instack/undercloud VM for vm in instack undercloud; do virsh destroy $vm 2> /dev/null | xargs echo -n diff --git a/ci/dev_deploy_check.sh b/ci/dev_deploy_check.sh index 68a9ac2b..0ce135ad 100755 --- a/ci/dev_deploy_check.sh +++ b/ci/dev_deploy_check.sh @@ -42,6 +42,9 @@ for i in epel-release python34-PyYAML openvswitch openstack-tripleo libguestfs l fi done +# install pip dependencies +easy_install-3.4 pip +sudo pip3 install python-ipmi # Make sure jinja2 is installed easy_install-3.4 jinja2 diff --git a/lib/python/apex/__init__.py b/lib/python/apex/__init__.py index 5b158501..068d0780 100644 --- a/lib/python/apex/__init__.py +++ b/lib/python/apex/__init__.py @@ -11,3 +11,4 @@ from .network_settings import NetworkSettings from .deploy_env import DeploySettings from .network_environment import NetworkEnvironment +from .clean import clean_nodes diff --git a/lib/python/apex/clean.py b/lib/python/apex/clean.py new file mode 100644 index 00000000..184b5ec9 --- /dev/null +++ b/lib/python/apex/clean.py @@ -0,0 +1,39 @@ +############################################################################## +# Copyright (c) 2016 Tim Rozet (trozet@redhat.com) and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +# Clean will eventually be migrated to this file + +import logging +import pyipmi +import pyipmi.interfaces +import sys + +from .common import utils + + +def clean_nodes(inventory): + inv_dict = utils.parse_yaml(inventory) + if inv_dict is None or 'nodes' not in inv_dict: + logging.error("Inventory file is empty or missing nodes definition") + sys.exit(1) + for node, node_info in inv_dict['nodes'].items(): + logging.info("Cleaning node: {}".format(node)) + try: + interface = pyipmi.interfaces.create_interface( + 'ipmitool', interface_type='lanplus') + connection = pyipmi.create_connection(interface) + connection.session.set_session_type_rmcp(node_info['ipmi_ip']) + connection.target = pyipmi.Target(0x20) + connection.session.set_auth_type_user(node_info['ipmi_user'], + node_info['ipmi_pass']) + connection.session.establish() + connection.chassis_control_power_down() + except Exception as e: + logging.error("Failure while shutting down node {}".format(e)) + sys.exit(1) diff --git a/lib/python/apex/common/utils.py b/lib/python/apex/common/utils.py index b7678a20..fe34096d 100644 --- a/lib/python/apex/common/utils.py +++ b/lib/python/apex/common/utils.py @@ -7,9 +7,17 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import yaml + def str2bool(var): if isinstance(var, bool): return var else: return var.lower() in ("true", "yes") + + +def parse_yaml(yaml_file): + with open(yaml_file) as f: + parsed_dict = yaml.load(f) + return parsed_dict diff --git a/lib/python/apex_python_utils.py b/lib/python/apex_python_utils.py index 829b3a0f..f8cb93cc 100755 --- a/lib/python/apex_python_utils.py +++ b/lib/python/apex_python_utils.py @@ -7,6 +7,7 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import apex import argparse import sys import logging @@ -61,6 +62,10 @@ def parse_deploy_settings(args): settings.dump_bash() +def run_clean(args): + apex.clean_nodes(args.file) + + def find_ip(args): """ Get and print the IP from a specific interface @@ -195,6 +200,12 @@ def get_parser(): help='path to deploy settings file') deploy_settings.set_defaults(func=parse_deploy_settings) + clean = subparsers.add_parser('clean', + help='Parse deploy settings file') + clean.add_argument('-f', '--file', + help='path to inventory file') + clean.set_defaults(func=run_clean) + return parser diff --git a/tests/config/inventory.yaml b/tests/config/inventory.yaml new file mode 100644 index 00000000..607df29e --- /dev/null +++ b/tests/config/inventory.yaml @@ -0,0 +1,56 @@ +nodes: + node1: + mac_address: "00:25:B5:cc:00:1e" + ipmi_ip: 72.30.8.69 + ipmi_user: admin + ipmi_pass: octopus + pm_type: "pxe_ipmitool" + cpus: 2 + memory: 8192 + disk: 40 + arch: "x86_64" + capabilities: "profile:control" + node2: + mac_address: "00:25:B5:cc:00:5d" + ipmi_ip: 72.30.8.78 + ipmi_user: admin + ipmi_pass: octopus + pm_type: "pxe_ipmitool" + cpus: 2 + memory: 8192 + disk: 40 + arch: "x86_64" + capabilities: "profile:control" + node3: + mac_address: "00:25:B5:cc:00:1d" + ipmi_ip: 72.30.8.67 + ipmi_user: admin + ipmi_pass: octopus + pm_type: "pxe_ipmitool" + cpus: 2 + memory: 8192 + disk: 40 + arch: "x86_64" + capabilities: "profile:control" + node4: + mac_address: "00:25:B5:cc:00:3c" + ipmi_ip: 72.30.8.76 + ipmi_user: admin + ipmi_pass: octopus + pm_type: "pxe_ipmitool" + cpus: 2 + memory: 8192 + disk: 40 + arch: "x86_64" + capabilities: "profile:compute" + node5: + mac_address: "00:25:B5:cc:00:5b" + ipmi_ip: 72.30.8.71 + ipmi_user: admin + ipmi_pass: octopus + pm_type: "pxe_ipmitool" + cpus: 2 + memory: 8192 + disk: 40 + arch: "x86_64" + capabilities: "profile:compute" diff --git a/tests/test_apex_clean.py b/tests/test_apex_clean.py new file mode 100644 index 00000000..2a436a7c --- /dev/null +++ b/tests/test_apex_clean.py @@ -0,0 +1,41 @@ +############################################################################## +# Copyright (c) 2016 Tim Rozet (Red Hat) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +import mock +import pyipmi +import pyipmi.chassis + +from apex import clean_nodes +from mock import patch +from nose import tools + + +class TestClean(object): + @classmethod + def setup_class(klass): + """This method is run once for each class before any tests are run""" + + @classmethod + def teardown_class(klass): + """This method is run once for each class _after_ all tests are run""" + + def setUp(self): + """This method is run once before _each_ test method is executed""" + + def teardown(self): + """This method is run once after _each_ test method is executed""" + + def test_clean(self): + with mock.patch.object(pyipmi.Session, 'establish') as mock_method: + with patch.object(pyipmi.chassis.Chassis, + 'chassis_control_power_down') as mock_method2: + clean_nodes('config/inventory.yaml') + + tools.assert_equal(mock_method.call_count, 5) + tools.assert_equal(mock_method2.call_count, 5) diff --git a/tests/test_apex_common_utils.py b/tests/test_apex_common_utils.py index 7c988e3d..94598657 100644 --- a/tests/test_apex_common_utils.py +++ b/tests/test_apex_common_utils.py @@ -7,9 +7,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from apex.common.utils import str2bool +import nose.tools -from nose.tools import assert_equal +from apex.common import utils class TestCommonUtils(object): @@ -28,7 +28,12 @@ class TestCommonUtils(object): """This method is run once after _each_ test method is executed""" def test_str2bool(self): - assert_equal(str2bool(True), True) - assert_equal(str2bool(False), False) - assert_equal(str2bool("True"), True) - assert_equal(str2bool("YES"), True) + nose.tools.assert_equal(utils.str2bool(True), True) + nose.tools.assert_equal(utils.str2bool(False), False) + nose.tools.assert_equal(utils.str2bool("True"), True) + nose.tools.assert_equal(utils.str2bool("YES"), True) + + def test_parse_yaml(self): + nose.tools.assert_is_instance( + utils.parse_yaml('../config/network/network_settings.yaml'), + dict) -- cgit 1.2.3-korg