Merge "Print undercloud IP after deployment"
authorMichael Chapman <michapma@redhat.com>
Tue, 14 Jun 2016 04:57:47 +0000 (04:57 +0000)
committerGerrit Code Review <gerrit@172.30.200.206>
Tue, 14 Jun 2016 04:57:47 +0000 (04:57 +0000)
13 files changed:
build/Makefile
ci/PR_revision.log
ci/build.sh
ci/deploy.sh
ci/test.sh [new file with mode: 0755]
lib/python/apex/network_environment.py
tests/python-coverage.sh [deleted file]
tests/python_coverage_ip_utils.py [deleted file]
tests/test_apex_common_utils.py [new file with mode: 0644]
tests/test_apex_deploy_env.py [new file with mode: 0644]
tests/test_apex_ip_utils.py [new file with mode: 0644]
tests/test_apex_network_environment.py [new file with mode: 0644]
tests/test_apex_network_settings.py [new file with mode: 0644]

index 3f3d1c3..f599f42 100644 (file)
@@ -19,6 +19,10 @@ export RPMODL = $(shell pwd)/noarch/opnfv-apex-$(RPMVERS)-$(shell echo ${RELEASE
 export RPMONO = $(shell pwd)/noarch/opnfv-apex-onos-$(RPMVERS)-$(shell echo ${RELEASE} | tr -d '_-').noarch.rpm
 export RPMSFC = $(shell pwd)/noarch/opnfv-apex-opendaylight-sfc-$(RPMVERS)-$(shell echo ${RELEASE} | tr -d '_-').noarch.rpm
 
+all_networks="admin_network private_network storage_network external_network api_network"
+
+
+
 .PHONY: all
 all: iso
 
@@ -62,7 +66,11 @@ $(RPMCOM):
 
 .PHONY: python-tests
 python-tests:
-       cd ../tests && ./python-coverage.sh
+       # run nose tests
+       cd ../tests && PYTHONPATH=../lib/python/ nosetests-3.4 . --with-coverage --cover-package apex
+       # generate reports
+       cd ../tests && coverage3 html --include '*lib/python/*'
+       cd ../tests && coverage3 report --include '*lib/python/*' -m
 
 
 ###############
index 0b479c6..ea30648 100644 (file)
@@ -7,3 +7,4 @@
 21,Serialize db_sync calls and increase sql-sleep timer
 23,Fix odl env files
 25,Force metadata on all scenarios
+26,Fixes ODL ML2 IP
index 1bd96d5..dd9f9fd 100755 (executable)
@@ -34,7 +34,6 @@ BUILD_BASE=$(readlink -e ../build/)
 CACHE_DEST=""
 CACHE_DIR="cache"
 CACHE_NAME="apex-cache"
-PYTHON_TESTS="TRUE"
 MAKE_TARGETS="images"
 REQUIRED_PKGS="rpm-build python-docutils"
 
@@ -64,11 +63,6 @@ parse_cmdline() {
                 echo "Buiding opnfv-apex RPMs"
                 shift 1
             ;;
-        --skip-python-tests )
-                PYTHON_TESTS="FALSE"
-                echo "Skipping Python Tests"
-                shift 1
-            ;;
         --debug )
                 debug="TRUE"
                 echo "Enable debug output"
@@ -151,20 +145,6 @@ if ! rpm -q python34-devel > /dev/null; then
     fi
 fi
 
-if [ "$PYTHON_TESTS" == "TRUE" ]; then
-    # Make sure coverage is installed
-    if ! python3 -c "import coverage" &> /dev/null; then sudo easy_install-3.4 coverage; fi
-
-    run_make python-tests
-    pushd ../tests/ > /dev/null
-    percent=$(coverage3 report --include '*lib/python/*' -m | grep TOTAL | tr -s ' ' | awk '{ print $4 }' | cut -d % -f 1)
-    if [[ percent -lt 80 ]]; then
-        echo "Python Coverage: $percent"
-        echo "WARNING: Does not meet 80% requirement"
-    fi
-    popd
-fi
-
 # Execute make against targets
 for t in $MAKE_TARGETS; do
     run_make $t
index 7de3c7f..5fcc388 100755 (executable)
@@ -40,7 +40,7 @@ DEPLOY_OPTIONS=""
 CONFIG=${CONFIG:-'/var/opt/opnfv'}
 RESOURCES=${RESOURCES:-"$CONFIG/images"}
 LIB=${LIB:-"$CONFIG/lib"}
-OPNFV_NETWORK_TYPES="admin_network private_network public_network storage_network"
+OPNFV_NETWORK_TYPES="admin_network private_network public_network storage_network api_network"
 
 VM_CPUS=4
 VM_RAM=8
@@ -51,6 +51,7 @@ NET_MAP['admin_network']="br-admin"
 NET_MAP['private_network']="br-private"
 NET_MAP['public_network']="br-public"
 NET_MAP['storage_network']="br-storage"
+NET_MAP['api_network']="br-api"
 ext_net_type="interface"
 ip_address_family=4
 
@@ -1004,9 +1005,9 @@ EOI
       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
 source overcloudrc
 echo "Keystone Endpoint List:"
-keystone endpoint-list
+openstack endpoint list
 echo "Keystone Service List"
-keystone service-list
+openstack service list
 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
 EOI
   fi
@@ -1024,14 +1025,14 @@ function configure_post_install {
 source overcloudrc
 set -o errexit
 echo "Configuring Neutron external network"
-neutron net-create external --router:external=True --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }')
-neutron subnet-create --name external-net --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }') --disable-dhcp external --gateway ${public_network_gateway} --allocation-pool start=${public_network_floating_ip_range%%,*},end=${public_network_floating_ip_range##*,} ${public_network_cidr}
+neutron net-create external --router:external=True --tenant-id \$(openstack project show service | grep id | awk '{ print \$4 }')
+neutron subnet-create --name external-net --tenant-id \$(openstack project show service | grep id | awk '{ print \$4 }') --disable-dhcp external --gateway ${public_network_gateway} --allocation-pool start=${public_network_floating_ip_range%%,*},end=${public_network_floating_ip_range##*,} ${public_network_cidr}
 
 echo "Removing swift endpoint and service"
-swift_service_id=\$(keystone service-list | grep swift | cut -d ' ' -f 2)
-swift_endpoint_id=\$(keystone endpoint-list | grep \$swift_service_id | cut -d ' ' -f 2)
-keystone endpoint-delete \$swift_endpoint_id
-keystone service-delete \$swift_service_id
+swift_service_id=\$(openstack service list | grep swift | cut -d ' ' -f 2)
+swift_endpoint_id=\$(openstack endpoint list | grep swift | cut -d ' ' -f 2)
+openstack endpoint delete \$swift_endpoint_id
+openstack service delete \$swift_service_id
 EOI
 
   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
diff --git a/ci/test.sh b/ci/test.sh
new file mode 100755 (executable)
index 0000000..0f2bc04
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+##############################################################################
+# Copyright (c) 2016 Dan Radez (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
+##############################################################################
+
+set -e
+
+# Make sure python is installed
+if ! rpm -q python34-devel > /dev/null; then
+    sudo yum install -y epel-release
+    if ! sudo yum install -y python34-devel; then
+        echo "Failed to install python34-devel package..."
+        exit 1
+    fi
+fi
+
+# Make sure coverage is installed
+if ! python3 -c "import coverage" &> /dev/null; then sudo easy_install-3.4 coverage; fi
+
+make python-tests
+pushd ../tests/ > /dev/null
+percent=$(coverage3 report --include '*lib/python/*' -m | grep TOTAL | tr -s ' ' | awk '{ print $4 }' | cut -d % -f 1)
+if [[ percent -lt 80 ]]; then
+    echo "Python Coverage: $percent"
+    echo "Does not meet 80% requirement"
+    exit 1
+fi
+popd > /dev/nul
index c9b7d3c..c6483d1 100644 (file)
@@ -13,6 +13,10 @@ from .common import constants
 
 PORTS = '/ports'
 # Resources defined by <resource name>: <prefix>
+EXTERNAL_RESOURCES = {'OS::TripleO::Network::External': None,
+                      'OS::TripleO::Network::Ports::ExternalVipPort': PORTS,
+                      'OS::TripleO::Controller::Ports::ExternalPort': PORTS,
+                      'OS::TripleO::Compute::Ports::ExternalPort': PORTS}
 TENANT_RESOURCES = {'OS::TripleO::Network::Tenant': None,
                     'OS::TripleO::Controller::Ports::TenantPort': PORTS,
                     'OS::TripleO::Compute::Ports::TenantPort': PORTS}
@@ -21,9 +25,13 @@ STORAGE_RESOURCES = {'OS::TripleO::Network::Storage': None,
                      'OS::TripleO::Controller::Ports::StoragePort': PORTS,
                      'OS::TripleO::Compute::Ports::StoragePort': PORTS}
 API_RESOURCES = {'OS::TripleO::Network::InternalApi': None,
-                    'OS::TripleO::Network::Ports::InternalApiVipPort': PORTS,
-                    'OS::TripleO::Controller::Ports::InternalApiPort': PORTS,
-                    'OS::TripleO::Compute::Ports::InternalApiPort': PORTS}
+                 'OS::TripleO::Network::Ports::InternalApiVipPort': PORTS,
+                 'OS::TripleO::Controller::Ports::InternalApiPort': PORTS,
+                 'OS::TripleO::Compute::Ports::InternalApiPort': PORTS}
+
+# A list of flags that will be set to true when IPv6 is enabled
+IPV6_FLAGS = ["NovaIPv6", "MongoDbIPv6", "CorosyncIPv6", "CephIPv6",
+              "RabbitIPv6", "MemcachedIPv6"]
 
 
 class NetworkEnvironment:
@@ -37,22 +45,19 @@ class NetworkEnvironment:
     def __init__(self, net_settings, filename):
         with open(filename, 'r') as net_env_fh:
             self.netenv_obj = yaml.load(net_env_fh)
-            if net_settings:
-                settings_obj = net_settings.get_network_settings()
-                enabled_networks = net_settings.get_enabled_networks()
-                self.netenv_obj = \
-                    self._update_net_environment(settings_obj,
-                                                 enabled_networks)
-            else:
-                raise NetworkEnvException("Network Settings does not exist")
+            self._update_net_environment(net_settings)
 
-    def _update_net_environment(self, net_settings, enabled_networks):
+    def _update_net_environment(self, settings_obj):
         """
         Updates Network Environment according to Network Settings
-        :param: network settings dictionary
-        :param: enabled network list
+        :param: network settings object
         :return:  None
         """
+        if not settings_obj:
+            raise NetworkEnvException("Network Settings does not exist")
+
+        net_settings = settings_obj.get_network_settings()
+        enabled_networks = settings_obj.get_enabled_networks()
         param_def = 'parameter_defaults'
         reg = 'resource_registry'
         for key, prefix in TENANT_RESOURCES.items():
@@ -84,6 +89,17 @@ class NetworkEnvironment:
             net_settings[constants.ADMIN_NETWORK]['provisioner_ip']
         self.netenv_obj[param_def]['DnsServers'] = net_settings['dns_servers']
 
+        if public_cidr.version == 6:
+            postfix = '/external_v6.yaml'
+        else:
+            postfix = '/external.yaml'
+
+        for key, prefix in EXTERNAL_RESOURCES.items():
+            if prefix is None:
+                prefix = ''
+            self.netenv_obj[reg][key] = tht_dir + prefix + postfix
+
+
         if constants.PRIVATE_NETWORK in enabled_networks:
             priv_range = net_settings[constants.PRIVATE_NETWORK][
                 'usable_ip_range'].split(',')
@@ -94,7 +110,10 @@ class NetworkEnvironment:
                   }]
             priv_cidr = net_settings[constants.PRIVATE_NETWORK]['cidr']
             self.netenv_obj[param_def]['TenantNetCidr'] = str(priv_cidr)
-            postfix = '/tenant.yaml'
+            if priv_cidr.version == 6:
+                postfix = '/tenant_v6.yaml'
+            else:
+                postfix = '/tenant.yaml'
         else:
             postfix = '/noop.yaml'
 
@@ -114,7 +133,10 @@ class NetworkEnvironment:
                   }]
             storage_cidr = net_settings[constants.STORAGE_NETWORK]['cidr']
             self.netenv_obj[param_def]['StorageNetCidr'] = str(storage_cidr)
-            postfix = '/storage.yaml'
+            if storage_cidr.version == 6:
+                postfix = '/storage_v6.yaml'
+            else:
+                postfix = '/storage.yaml'
         else:
             postfix = '/noop.yaml'
 
@@ -134,7 +156,12 @@ class NetworkEnvironment:
                   }]
             api_cidr = net_settings[constants.API_NETWORK]['cidr']
             self.netenv_obj[param_def]['InternalApiNetCidr'] = str(api_cidr)
-            postfix = '/internal_api.yaml'
+            if api_cidr.version == 6:
+                postfix = '/internal_api_v6.yaml'
+            else:
+                postfix = '/internal_api.yaml'
+
+
         else:
             postfix = '/noop.yaml'
 
@@ -143,7 +170,12 @@ class NetworkEnvironment:
                 prefix = ''
             self.netenv_obj[reg][key] = tht_dir + prefix + postfix
 
-        return self.netenv_obj
+        # Set IPv6 related flags to True. Not that we do not set those to False
+        # when IPv4 is configured, we'll use the default or whatever the user
+        # may have set.
+        if settings_obj.get_ip_addr_family() == 6:
+            for flag in IPV6_FLAGS:
+                self.netenv_obj[param_def][flag] = True
 
     def get_netenv_settings(self):
         """
diff --git a/tests/python-coverage.sh b/tests/python-coverage.sh
deleted file mode 100755 (executable)
index 8de6157..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/bash
-set -x
-all_networks="admin_network private_network storage_network external_network"
-
-# exercise help
-coverage3 run ../lib/python/apex-python-utils.py -l /dev/null > /dev/null
-
-# exercise parse-net-settings
-# throw debug on the first to exercise it
-coverage3 run -a ../lib/python/apex-python-utils.py --debug parse-net-settings -s ../config/network/network_settings.yaml -i True -e ../build/network-environment.yaml > /dev/null
-
-# exercise proper nic-template runs
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null nic-template -t ../config/network/network_settings.yaml -n "$all_networks" -e interface -af 4 > /dev/null
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null nic-template -t ../config/network/network_settings.yaml -n "$all_networks" -e interface -af 6 > /dev/null
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null nic-template -t ../config/network/network_settings.yaml -n "$all_networks" -e br-ex -af 4 > /dev/null
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null nic-template -t ../config/network/network_settings.yaml -n "$all_networks" -e br-ex -af 6 > /dev/null
-
-# exercise find-ip
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null find-ip -i $(ip a | grep 2: | cut -d \  -f 2 | head -n 1 | cut -d : -f 1) > /dev/null
-
-# exercise parse-deploy-settings
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f ../config/deploy/os-nosdn-nofeature-noha.yaml > /dev/null
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f ../config/deploy/os-nosdn-performance-ha.yaml > /dev/null
-
-# exercise parse-deploy-settings errors
-echo "global_params:" > /tmp/python-coverage.test
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-echo "deploy_options: string" > /tmp/python-coverage.test
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-echo "global_params:" >> /tmp/python-coverage.test
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-cat > /tmp/python-coverage.test << EOF
-global_params:
-deploy_options:
-  error: error
-EOF
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-cat > /tmp/python-coverage.test << EOF
-global_params:
-deploy_options:
-  performance: string
-EOF
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-cat > /tmp/python-coverage.test << EOF
-global_params:
-deploy_options:
-  performance:
-    error: error
-EOF
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-cat > /tmp/python-coverage.test << EOF
-global_params:
-deploy_options:
-  performance:
-    Controller:
-      error: error
-EOF
-coverage3 run -a ../lib/python/apex-python-utils.py -l /dev/null parse-deploy-settings -f /tmp/python-coverage.test &> /dev/null
-
-# coverage for ip_utils
-PYTHONPATH=../lib/python/ coverage3 run -a python_coverage_ip_utils.py $(ip r | grep default | awk '{ print $5 }')
-
-# generate reports
-coverage3 html --include '*lib/python/*'
-coverage3 report --include '*lib/python/*' -m
diff --git a/tests/python_coverage_ip_utils.py b/tests/python_coverage_ip_utils.py
deleted file mode 100644 (file)
index 35280c1..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-import sys
-from apex import ip_utils
-
-iface = ip_utils.get_interface(sys.argv[1])
-
-erroring_tests = (
-        "ip_utils.get_interface('')",
-        "ip_utils.get_interface('lo', address_family=0)",
-        "ip_utils.get_interface('lo', address_family=6)",
-        "ip_utils.get_interface('lo')",
-        "ip_utils.get_ip_range()",
-        "ip_utils.get_ip_range(interface=iface)")
-
-for t in erroring_tests:
-    try:
-        eval(t)
-    except:
-        pass
-
-ip_utils.find_gateway(interface=iface)
-ip_utils.get_ip(1, cidr="10.10.10.0/24")
-ip_utils.get_ip(1, interface=iface)
-ip_utils.get_ip_range(interface=iface, start_offset=1, end_offset=20)
-ip_utils.get_ip_range(interface=iface, start_offset=1, count=10)
-ip_utils.get_ip_range(interface=iface, end_offset=20, count=10)
diff --git a/tests/test_apex_common_utils.py b/tests/test_apex_common_utils.py
new file mode 100644 (file)
index 0000000..7c988e3
--- /dev/null
@@ -0,0 +1,34 @@
+##############################################################################
+# Copyright (c) 2016 Dan Radez (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
+##############################################################################
+
+from apex.common.utils import str2bool
+
+from nose.tools import assert_equal
+
+
+class TestCommonUtils(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_str2bool(self):
+        assert_equal(str2bool(True), True)
+        assert_equal(str2bool(False), False)
+        assert_equal(str2bool("True"), True)
+        assert_equal(str2bool("YES"), True)
diff --git a/tests/test_apex_deploy_env.py b/tests/test_apex_deploy_env.py
new file mode 100644 (file)
index 0000000..0cd144e
--- /dev/null
@@ -0,0 +1,88 @@
+##############################################################################
+# Copyright (c) 2016 Dan Radez (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 io
+# https://docs.python.org/3/library/io.html
+
+from apex.deploy_env import DeploySettings
+from apex.deploy_env import DeploySettingsException
+
+from nose.tools import assert_equal
+from nose.tools import assert_raises
+
+deploy_files = ('deploy_settings.yaml',
+                'os-nosdn-nofeature-noha.yaml',
+                'os-nosdn-ovs-noha.yaml',
+                'os-ocl-nofeature-ha.yaml',
+                'os-odl_l2-sdnvpn-ha.yaml',
+                'os-odl_l3-nofeature-ha.yaml',
+                'os-nosdn-nofeature-ha.yaml',
+                'os-nosdn-ovs-ha.yaml',
+                'os-nosdn-performance-ha.yaml',
+                'os-odl_l2-nofeature-ha.yaml',
+                'os-odl_l2-sfc-noha.yaml',
+                'os-onos-nofeature-ha.yaml')
+
+test_deploy_content = (
+'global_params:',
+'deploy_options: string',
+"""deploy_options: string
+global_params:""",
+"""global_params:
+deploy_options:
+  error: error
+""",
+"""global_params:
+deploy_options:
+  performance: string
+""",
+"""global_params:
+deploy_options:
+  dataplane: invalid
+""",
+"""global_params:
+deploy_options:
+  performance:
+    Controller:
+      error: error
+""",)
+
+
+class TestIpUtils(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_init(self):
+        for f in deploy_files:
+            ds = DeploySettings('../config/deploy/{}'.format(f))
+
+    def test__validate_settings(self):
+        for c in test_deploy_content:
+            f = open('/tmp/apex_deploy_test_file', 'w')
+            f.write(c)
+            f.close()
+            assert_raises(DeploySettingsException, DeploySettings, '/tmp/apex_deploy_test_file')
+
+    def test_dump_bash(self):
+        # the performance file has the most use of the function
+        # so using that as the test case
+        ds = DeploySettings('../config/deploy/os-nosdn-performance-ha.yaml')
+        assert_equal(ds.dump_bash(), None)
+        assert_equal(ds.dump_bash(path='/dev/null'), None)
diff --git a/tests/test_apex_ip_utils.py b/tests/test_apex_ip_utils.py
new file mode 100644 (file)
index 0000000..0b44bdd
--- /dev/null
@@ -0,0 +1,95 @@
+##############################################################################
+# Copyright (c) 2016 Dan Radez (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 re
+
+from apex.ip_utils import IPUtilsException
+from apex.ip_utils import get_interface
+from apex.ip_utils import find_gateway
+from apex.ip_utils import get_ip
+from apex.ip_utils import get_ip_range
+
+from nose.tools import assert_equal
+from nose.tools import assert_raises
+from nose.tools import assert_is_instance
+from nose.tools import assert_regexp_matches
+
+from ipaddress import IPv4Address
+from ipaddress import IPv6Address
+from ipaddress import ip_network
+
+
+ip4_pattern = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
+ip4_range_pattern = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3},\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
+
+def get_default_gateway_linux():
+    """Read the default gateway directly from /proc."""
+    with open("/proc/net/route") as fh:
+        for line in fh:
+            fields = line.strip().split()
+            if fields[2] not in ('00000000', 'Gateway'):
+                return fields[0]
+
+
+class TestIpUtils(object):
+    @classmethod
+    def setup_class(klass):
+        """This method is run once for each class before any tests are run"""
+        klass.iface_name = get_default_gateway_linux()
+        iface = get_interface(klass.iface_name)
+        klass.iface = iface
+
+    @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_get_interface(self):
+        assert_equal(get_interface(''), None)
+        assert_equal(get_interface('notreal'), None)
+        assert_is_instance(get_interface(
+                               self.iface_name,
+                               address_family=4), IPv4Address)
+        assert_is_instance(get_interface(
+                               self.iface_name,
+                               address_family=6), IPv6Address)
+        assert_raises(IPUtilsException,
+                      get_interface, self.iface_name, 0)
+
+    def test_find_gateway(self):
+        assert_is_instance(find_gateway(self.iface), str)
+        iface_virbr0 = get_interface('virbr0')
+        assert_equal(find_gateway(iface_virbr0), None)
+
+    def test_get_ip(self):
+        assert_equal(get_ip(1, cidr="10.10.10.0/24"), "0")
+        assert_regexp_matches(get_ip(1, interface=self.iface), ip4_pattern)
+        assert_raises(IPUtilsException, get_ip, 1)
+
+
+    def test_get_ip_range_raises(self):
+        assert_raises(IPUtilsException, get_ip_range)
+        assert_raises(IPUtilsException, get_ip_range, interface=self.iface)
+
+    def test_get_ip_range_with_interface(self):
+        assert_regexp_matches(get_ip_range(interface=self.iface, start_offset=1, end_offset=20), ip4_range_pattern)
+        assert_regexp_matches(get_ip_range(interface=self.iface, start_offset=1, count=10), ip4_range_pattern)
+        assert_regexp_matches(get_ip_range(interface=self.iface, end_offset=20, count=10), ip4_range_pattern)
+
+    def test_get_ip_range_with_cidr(self):
+        cidr = ip_network('10.10.10.0/24')
+        assert_raises(IPUtilsException, get_ip_range, cidr=cidr)
+        assert_regexp_matches(get_ip_range(cidr=cidr, start_offset=1, end_offset=20), ip4_pattern)
+        assert_regexp_matches(get_ip_range(cidr=cidr, start_offset=1, count=10), ip4_pattern)
+        assert_regexp_matches(get_ip_range(cidr=cidr, end_offset=20, count=10), ip4_pattern)
diff --git a/tests/test_apex_network_environment.py b/tests/test_apex_network_environment.py
new file mode 100644 (file)
index 0000000..90c8907
--- /dev/null
@@ -0,0 +1,42 @@
+##############################################################################
+# Copyright (c) 2016 Dan Radez (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
+##############################################################################
+
+from apex.network_settings import NetworkSettings
+from apex.network_environment import NetworkEnvironment
+from apex.network_environment import NetworkEnvException
+
+from nose.tools import assert_equal
+from nose.tools import assert_raises
+from nose.tools import assert_is_instance
+from nose.tools import assert_not_equal
+
+
+class TestNetworkEnvironment(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_init(self):
+        assert_raises(NetworkEnvException, NetworkEnvironment, None, '../build/network-environment.yaml')
+
+    def test_get_netenv_settings(self):
+        ns = NetworkSettings('../config/network/network_settings.yaml', True)
+        ne = NetworkEnvironment(ns, '../build/network-environment.yaml')
+        assert_is_instance(ne.get_netenv_settings(), dict)
+        assert_not_equal(ne.get_netenv_settings(), {})
diff --git a/tests/test_apex_network_settings.py b/tests/test_apex_network_settings.py
new file mode 100644 (file)
index 0000000..a891473
--- /dev/null
@@ -0,0 +1,45 @@
+##############################################################################
+# Copyright (c) 2016 Dan Radez (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
+##############################################################################
+
+from apex.network_settings import NetworkSettings
+
+from nose.tools import assert_equal
+from nose.tools import assert_is_instance
+
+
+class TestNetworkSettings(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_init(self):
+        ns = NetworkSettings('../config/network/network_settings.yaml', True)
+
+    def test_dump_bash(self):
+        ns = NetworkSettings('../config/network/network_settings.yaml', True)
+        assert_equal(ns.dump_bash(), None)
+        assert_equal(ns.dump_bash(path='/dev/null'), None)
+
+    def test_get_network_settings(self):
+        ns = NetworkSettings('../config/network/network_settings.yaml', True)
+        assert_is_instance(ns.get_network_settings(), dict)
+
+    def test_get_enabled_networks(self):
+        ns = NetworkSettings('../config/network/network_settings.yaml', True)
+        assert_is_instance(ns.get_enabled_networks(), list)