From ff842dd8134a2c5f4a717a719c210cdb22aa82da Mon Sep 17 00:00:00 2001 From: Vladimir Kozhukalov Date: Wed, 28 Oct 2015 20:04:48 +0300 Subject: [PATCH] Deprecate network_checker directory Change-Id: I549f6c177a4e1fd459666410954accea9c30ae3c Related-Bug: #1506896 --- MAINTAINERS | 9 - debian/control | 8 +- debian/rules | 3 - network_checker/Dockerfile | 10 - network_checker/MANIFEST.in | 1 - network_checker/Vagrantfile | 25 - network_checker/conftest.py | 44 -- network_checker/debian/changelog | 35 - network_checker/debian/compat | 1 - network_checker/debian/control | 14 - network_checker/debian/rules | 18 - network_checker/debian/source/format | 1 - network_checker/dhcp_checker/__init__.py | 13 - network_checker/dhcp_checker/api.py | 152 ---- network_checker/dhcp_checker/cli.py | 52 -- network_checker/dhcp_checker/commands.py | 111 --- .../dhcp_checker/tests/system/__init__.py | 13 - .../dhcp_checker/tests/system/tests.py | 119 --- .../dhcp_checker/tests/unit/__init__.py | 13 - .../dhcp_checker/tests/unit/dhcp.pcap | Bin 1868 -> 0 bytes .../dhcp_checker/tests/unit/test_api.py | 100 --- .../dhcp_checker/tests/unit/test_commands.py | 61 -- .../dhcp_checker/tests/unit/test_utils.py | 176 ----- network_checker/dhcp_checker/utils.py | 236 ------ .../fuel_network_checker/__init__.py | 0 .../fuel_network_checker/base_app.py | 43 -- network_checker/network_checker/__init__.py | 0 network_checker/network_checker/api.py | 62 -- network_checker/network_checker/cli.py | 62 -- network_checker/network_checker/config.py | 30 - network_checker/network_checker/config.yaml | 13 - network_checker/network_checker/daemon.py | 51 -- .../network_checker/multicast/__init__.py | 0 .../network_checker/multicast/api.py | 93 --- .../network_checker/net_check/__init__.py | 13 - .../network_checker/net_check/api.py | 706 ------------------ .../network_checker/net_check/utils.py | 53 -- .../network_checker/tests/__init__.py | 13 - .../network_checker/tests/simple.py | 27 - .../network_checker/tests/test_multicast.py | 83 -- .../network_checker/tests/test_net_check.py | 190 ----- network_checker/network_checker/xmlrpc.py | 68 -- network_checker/requirements.txt | 10 - network_checker/run_tests.sh | 21 - network_checker/setup.py | 53 -- network_checker/specs/nailgun-net-check.spec | 41 - network_checker/test-requirements.txt | 6 - network_checker/test_utils/dhcp_relay.conf | 6 - network_checker/test_utils/dhcpd.conf.sample | 12 - network_checker/test_utils/dhcpd.conf.sample2 | 12 - network_checker/tox.ini | 37 - .../url_access_checker/__init__.py | 0 network_checker/url_access_checker/api.py | 112 --- network_checker/url_access_checker/cli.py | 42 -- .../url_access_checker/commands.py | 63 -- network_checker/url_access_checker/errors.py | 25 - network_checker/url_access_checker/network.py | 207 ----- .../url_access_checker/tests/unit/__init__.py | 0 .../url_access_checker/tests/unit/test_api.py | 68 -- .../tests/unit/test_commands.py | 47 -- .../tests/unit/test_with_network_setup.py | 114 --- network_checker/url_access_checker/utils.py | 32 - run_tests.sh | 1 - specs/fuel-nailgun.spec | 31 - 64 files changed, 1 insertion(+), 3661 deletions(-) delete mode 100644 network_checker/Dockerfile delete mode 100644 network_checker/MANIFEST.in delete mode 100644 network_checker/Vagrantfile delete mode 100644 network_checker/conftest.py delete mode 100644 network_checker/debian/changelog delete mode 100644 network_checker/debian/compat delete mode 100644 network_checker/debian/control delete mode 100755 network_checker/debian/rules delete mode 100644 network_checker/debian/source/format delete mode 100644 network_checker/dhcp_checker/__init__.py delete mode 100644 network_checker/dhcp_checker/api.py delete mode 100644 network_checker/dhcp_checker/cli.py delete mode 100644 network_checker/dhcp_checker/commands.py delete mode 100644 network_checker/dhcp_checker/tests/system/__init__.py delete mode 100644 network_checker/dhcp_checker/tests/system/tests.py delete mode 100644 network_checker/dhcp_checker/tests/unit/__init__.py delete mode 100644 network_checker/dhcp_checker/tests/unit/dhcp.pcap delete mode 100644 network_checker/dhcp_checker/tests/unit/test_api.py delete mode 100644 network_checker/dhcp_checker/tests/unit/test_commands.py delete mode 100644 network_checker/dhcp_checker/tests/unit/test_utils.py delete mode 100644 network_checker/dhcp_checker/utils.py delete mode 100644 network_checker/fuel_network_checker/__init__.py delete mode 100644 network_checker/fuel_network_checker/base_app.py delete mode 100644 network_checker/network_checker/__init__.py delete mode 100644 network_checker/network_checker/api.py delete mode 100644 network_checker/network_checker/cli.py delete mode 100644 network_checker/network_checker/config.py delete mode 100644 network_checker/network_checker/config.yaml delete mode 100644 network_checker/network_checker/daemon.py delete mode 100644 network_checker/network_checker/multicast/__init__.py delete mode 100644 network_checker/network_checker/multicast/api.py delete mode 100644 network_checker/network_checker/net_check/__init__.py delete mode 100755 network_checker/network_checker/net_check/api.py delete mode 100644 network_checker/network_checker/net_check/utils.py delete mode 100644 network_checker/network_checker/tests/__init__.py delete mode 100644 network_checker/network_checker/tests/simple.py delete mode 100644 network_checker/network_checker/tests/test_multicast.py delete mode 100644 network_checker/network_checker/tests/test_net_check.py delete mode 100644 network_checker/network_checker/xmlrpc.py delete mode 100644 network_checker/requirements.txt delete mode 100755 network_checker/run_tests.sh delete mode 100644 network_checker/setup.py delete mode 100644 network_checker/specs/nailgun-net-check.spec delete mode 100644 network_checker/test-requirements.txt delete mode 100644 network_checker/test_utils/dhcp_relay.conf delete mode 100644 network_checker/test_utils/dhcpd.conf.sample delete mode 100644 network_checker/test_utils/dhcpd.conf.sample2 delete mode 100644 network_checker/tox.ini delete mode 100644 network_checker/url_access_checker/__init__.py delete mode 100644 network_checker/url_access_checker/api.py delete mode 100644 network_checker/url_access_checker/cli.py delete mode 100644 network_checker/url_access_checker/commands.py delete mode 100644 network_checker/url_access_checker/errors.py delete mode 100644 network_checker/url_access_checker/network.py delete mode 100644 network_checker/url_access_checker/tests/unit/__init__.py delete mode 100644 network_checker/url_access_checker/tests/unit/test_api.py delete mode 100644 network_checker/url_access_checker/tests/unit/test_commands.py delete mode 100644 network_checker/url_access_checker/tests/unit/test_with_network_setup.py delete mode 100644 network_checker/url_access_checker/utils.py diff --git a/MAINTAINERS b/MAINTAINERS index c76163ed84..9cf871a8d4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -40,15 +40,6 @@ maintainers: email: ikalnitsky@mirantis.com IRC: ikalnitsky -- network_checker/: - - name: Dmytro Shuliak - email: dshulyak@mirantis.com - IRC: dshulyak - - - name: Lukasz Oles - email: loles@mirantis.com - IRC: salmon_ - - nailgun/: - name: Aleksandr Kislitskii email: akislitsky@mirantis.com diff --git a/debian/control b/debian/control index 6009469e9d..3617cde9ea 100644 --- a/debian/control +++ b/debian/control @@ -15,11 +15,5 @@ Depends: ohai (<< 7), ruby-cstruct, ruby-json, ${misc:Depends} -Description: - - -Package: nailgun-net-check -Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python-pypcap, vlan, python-scapy, cliff-tablib, python-stevedore, python-daemonize, python-yaml, tcpdump, python-requests, python-six -Description: NailGun client net-check +Description: Fencing agent . diff --git a/debian/rules b/debian/rules index c008583716..97312077be 100755 --- a/debian/rules +++ b/debian/rules @@ -7,12 +7,9 @@ topdir=$(shell pwd) dh $@ --with python2 override_dh_auto_install: - cd network_checker && python setup.py install -O0 --single-version-externally-managed --install-layout=deb --root=$(topdir)/debian/nailgun-net-check dh_auto_install override_dh_auto_build: dh_clean - cd network_checker && python setup.py build dh_auto_build override_dh_auto_clean: - cd network_checker && python setup.py clean dh_auto_clean diff --git a/network_checker/Dockerfile b/network_checker/Dockerfile deleted file mode 100644 index 7a2455e0c6..0000000000 --- a/network_checker/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM phusion/baseimage -ENV ARCH amd64 -ENV DIST trusty -RUN echo 'deb http://fuel-repository.mirantis.com/fwm/5.0/ubuntu trusty main' >> /etc/apt/sources.list -RUN apt-get -q update -RUN apt-get -y --force-yes install cliff-tablib python-pyparsing python-pypcap scapy python-pip wget openssh-server -RUN pip install pytest mock -RUN sudo locale-gen en_US.UTF-8 - -RUN mkdir -p /app diff --git a/network_checker/MANIFEST.in b/network_checker/MANIFEST.in deleted file mode 100644 index be4c0b51ea..0000000000 --- a/network_checker/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -recursive-include network_checker * \ No newline at end of file diff --git a/network_checker/Vagrantfile b/network_checker/Vagrantfile deleted file mode 100644 index 438733498e..0000000000 --- a/network_checker/Vagrantfile +++ /dev/null @@ -1,25 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - - config.vm.box = "precise64" - - config.vm.provider "virtualbox" do |v| - v.customize ["modifyvm", :id, "--memory", 348] - end - - config.vm.define :develop do |config| - config.vm.network :private_network, ip: '10.100.0.0', type: "dhcp" - config.vm.network :private_network, ip: '10.200.0.0', type: 'dhcp' - config.vm.provision :shell, :inline => "echo 'deb http://fuel-repository.mirantis.com/fwm/5.0/ubuntu trusty main' >> /etc/apt/sources.list" - config.vm.provision :shell, :inline => "sudo apt-get update" - config.vm.provision :shell, :inline => "sudo apt-get -y --force-yes install cliff-tablib python-pyparsing python-pypcap scapy python-pip vde2" - config.vm.provision :shell, :inline => "sudo pip install pytest mock" - config.vm.provision :shell, :inline => "cd /vagrant && sudo python setup.py develop" - end - -end diff --git a/network_checker/conftest.py b/network_checker/conftest.py deleted file mode 100644 index c8aabfaa46..0000000000 --- a/network_checker/conftest.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import os - - -PIDFILE = '/tmp/vde_network_checker' -IFACES = ['tap11', 'tap12'] - - -def pytest_addoption(parser): - parser.addoption("--vde", action='store_true', default=False, - help="Use vde switch for network verification.") - - -def pytest_configure(config): - if config.getoption('vde'): - base = 'vde_switch -p {pidfile} -d'.format(pidfile=PIDFILE) - command = [base] - taps = ['-tap {tap}'.format(tap=tap) for tap in IFACES] - full_command = command + taps - os.system(' '.join(full_command)) - for tap in IFACES: - os.system('ifconfig {tap} up'.format(tap=tap)) - os.environ['NET_CHECK_IFACE_1'] = IFACES[0] - os.environ['NET_CHECK_IFACE_2'] = IFACES[1] - - -def pytest_unconfigure(config): - if os.path.exists(PIDFILE): - with open(PIDFILE) as f: - pid = f.read().strip() - os.kill(int(pid), 15) diff --git a/network_checker/debian/changelog b/network_checker/debian/changelog deleted file mode 100644 index 0c6078f182..0000000000 --- a/network_checker/debian/changelog +++ /dev/null @@ -1,35 +0,0 @@ -nailgun (8.0.0-1) trusty; urgency=low - - * Change version to 8.0.0 - - -- Vladimir Kozhukalov Mon, 03 Sep 2015 11:12:00 +0300 - -nailgun (7.0.0-1) trusty; urgency=low - - * Update version to 7.0.0 - - -- Aleksandra Fedorova Mon, 08 Jun 2015 18:15:00 +0300 - -nailgun (6.1.0-1) trusty; urgency=low - - * Update version to 6.1.0 - - -- Matthew Mosesohn Wed, 22 Apr 2015 14:44:00 +0300 - -nailgun (6.0.0-1) trusty; urgency=low - - * Update code from upstream - - -- Igor Kalnitsky Wed, 26 Nov 2014 19:49:00 +0200 - -nailgun (0.1.0-ubuntu1) precise; urgency=low - - * Update code from upstream - - -- OSCI Jenkins Wed, 03 Sep 2014 15:17:07 +0400 - -nailgun (0.1.0-1ubuntu0) precise; urgency=low - - * Add fencing agent script as a separated task - - -- Bogdan Dobrelya Thu, 23 Jan 2014 18:55:00 +0400 diff --git a/network_checker/debian/compat b/network_checker/debian/compat deleted file mode 100644 index 45a4fb75db..0000000000 --- a/network_checker/debian/compat +++ /dev/null @@ -1 +0,0 @@ -8 diff --git a/network_checker/debian/control b/network_checker/debian/control deleted file mode 100644 index d7dc10f249..0000000000 --- a/network_checker/debian/control +++ /dev/null @@ -1,14 +0,0 @@ -Source: network-checker -Section: unknown -Priority: net -Maintainer: Mirantis Product -Build-Depends: debhelper (>= 8.0.0), python-setuptools -X-Python-Version: 2.6, 2.7 -Standards-Version: 3.9.2 -Homepage: mirantis.com - -Package: nailgun-net-check -Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python-pypcap, vlan, python-scapy, cliff-tablib, python-stevedore, python-daemonize, python-yaml, tcpdump, python-requests, python-six -Description: Nailgun network connectivity check tool - . diff --git a/network_checker/debian/rules b/network_checker/debian/rules deleted file mode 100755 index 2b152333a0..0000000000 --- a/network_checker/debian/rules +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/make -f -DH_VERBOSE=1 - -topdir=$(shell pwd) - -%: - dh $@ --with python2 - -override_dh_auto_install: - python setup.py install -O0 --single-version-externally-managed --install-layout=deb --root=$(topdir)/debian/nailgun-net-check - dh_auto_install -override_dh_auto_build: - dh_clean - python setup.py build - dh_auto_build -override_dh_auto_clean: - python setup.py clean - dh_auto_clean diff --git a/network_checker/debian/source/format b/network_checker/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/network_checker/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/network_checker/dhcp_checker/__init__.py b/network_checker/dhcp_checker/__init__.py deleted file mode 100644 index 141ca6ab9a..0000000000 --- a/network_checker/dhcp_checker/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/network_checker/dhcp_checker/api.py b/network_checker/dhcp_checker/api.py deleted file mode 100644 index 22794ef4cb..0000000000 --- a/network_checker/dhcp_checker/api.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -import itertools -import logging -import time - -from scapy import config as scapy_config - -scapy_config.use_pcap = True - -logging.getLogger('scapy.runtime').setLevel(logging.CRITICAL) - -from dhcp_checker import utils -import pcap -from scapy import all as scapy - -LOG = logging.getLogger(__name__) - - -def _get_dhcp_discover_message(iface): - - dhcp_options = [("message-type", "discover"), - ("param_req_list", utils.format_options( - [1, 2, 3, 4, 5, 6, - 11, 12, 13, 15, 16, 17, 18, 22, 23, - 28, 40, 41, 42, 43, 50, 51, 54, 58, 59, 60, 66, 67])), - "end"] - - fam, hw = scapy.get_if_raw_hwaddr(iface) - - dhcp_discover = ( - scapy.Ether(src=hw, dst="ff:ff:ff:ff:ff:ff") / - scapy.IP(src="0.0.0.0", dst="255.255.255.255") / - scapy.UDP(sport=68, dport=67) / - scapy.BOOTP(chaddr=hw) / - scapy.DHCP(options=dhcp_options)) - - return dhcp_discover - - -@utils.single_format -def check_dhcp_on_eth(iface, timeout): - """Check if there is roque dhcp server in network on given iface - - @iface - name of the ethernet interface - @timeout - scapy timeout for waiting on response - >>> check_dhcp_on_eth('eth1') - """ - scapy.conf.iface = iface - scapy.conf.checkIPaddr = False - dhcp_discover = _get_dhcp_discover_message(iface) - ans, unans = scapy.srp(dhcp_discover, multi=True, - nofilter=1, timeout=timeout, verbose=0) - - return ans - - -def check_dhcp(ifaces, timeout=5, repeat=2): - """Given list of ifaces. Process them in separate processes - - @ifaces - lsit of ifaces - @timeout - timeout for scapy to wait for response - @repeat - number of packets sended - >>> check_dhcp(['eth1', 'eth2']) - """ - config = {} - for iface in ifaces: - config[iface] = () - return check_dhcp_with_vlans(config, timeout=timeout, repeat=repeat) - - -def send_dhcp_discover(iface): - dhcp_discover = _get_dhcp_discover_message(iface) - scapy.sendp(dhcp_discover, iface=iface, verbose=0) - - -def make_listeners(ifaces): - listeners = [] - for iface in ifaces: - try: - listener = pcap.pcap(iface) - mac_filter = utils.create_mac_filter(iface) - # catch the answers only for this iface - listener.setfilter('((dst port 68) and {0})'.format(mac_filter)) - listeners.append(listener) - except Exception: - LOG.warning( - 'Spawning listener for {iface} failed.'.format(iface=iface)) - return listeners - - -@utils.filter_duplicated_results -def check_dhcp_with_vlans(config, timeout=5, repeat=2): - """Provide config of {iface: [vlans..]} pairs - - @config - {'eth0': (100, 101), 'eth1': (100, 102)} - """ - # vifaces - list of pairs ('eth0', ['eth0.100', 'eth0.101']) - with utils.VlansContext(config) as vifaces: - ifaces, vlans = zip(*vifaces) - listeners = make_listeners(ifaces) - - for _ in xrange(repeat): - for i in utils.filtered_ifaces(itertools.chain(ifaces, *vlans)): - send_dhcp_discover(i) - time.sleep(timeout) - - for l in listeners: - for pkt in l.readpkts(): - yield utils.format_answer(scapy.Ether(pkt[1]), l.name) - - -@utils.single_format -def check_dhcp_request(iface, server, range_start, range_end, timeout=5): - """Provide interface, server endpoint and pool of ip adresses - - Should be used after offer received - >>> check_dhcp_request('eth1','10.10.0.5','10.10.0.10','10.10.0.15') - """ - - scapy.conf.iface = iface - - scapy.conf.checkIPaddr = False - - fam, hw = scapy.get_if_raw_hwaddr(iface) - - ip_address = next(utils.pick_ip(range_start, range_end)) - - # note lxc dhcp server does not respond to unicast - dhcp_request = (scapy.Ether(src=hw, dst="ff:ff:ff:ff:ff:ff") / - scapy.IP(src="0.0.0.0", dst="255.255.255.255") / - scapy.UDP(sport=68, dport=67) / - scapy.BOOTP(chaddr=hw) / - scapy.DHCP(options=[("message-type", "request"), - ("server_id", server), - ("requested_addr", ip_address), - "end"])) - ans, unans = scapy.srp(dhcp_request, nofilter=1, multi=True, - timeout=timeout, verbose=0) - return ans diff --git a/network_checker/dhcp_checker/cli.py b/network_checker/dhcp_checker/cli.py deleted file mode 100644 index 4b97ffdeb9..0000000000 --- a/network_checker/dhcp_checker/cli.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -import logging -import os -import sys -# fixed in cmd2 >=0.6.6 -os.environ['EDITOR'] = '/usr/bin/nano' - -from cliff.commandmanager import CommandManager - -from fuel_network_checker import base_app - - -class DhcpApp(base_app.BaseApp): - DEFAULT_VERBOSE_LEVEL = 0 - LOG_FILENAME = '/var/log/dhcp_checker.log' - - def __init__(self): - super(DhcpApp, self).__init__( - description='Dhcp check application', - version='0.1', - command_manager=CommandManager('dhcp.check'), - ) - - def configure_logging(self): - super(DhcpApp, self).configure_logging() - - # set scapy logger level only to ERROR - # due to a lot of spam - runtime_logger = logging.getLogger('scapy.runtime') - runtime_logger.setLevel(logging.ERROR) - - -def main(argv=sys.argv[1:]): - myapp = DhcpApp() - return myapp.run(argv) - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/network_checker/dhcp_checker/commands.py b/network_checker/dhcp_checker/commands.py deleted file mode 100644 index eba13b37f4..0000000000 --- a/network_checker/dhcp_checker/commands.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -import json -import logging - -from cliff import command -from cliff import lister -from dhcp_checker import api -from dhcp_checker import utils - - -LOG = logging.getLogger(__name__) - - -class BaseCommand(command.Command): - """Base command for all app""" - def get_parser(self, prog_name): - parser = super(BaseCommand, self).get_parser(prog_name) - parser.add_argument('--timeout', default=5, type=int, - help="Provide timeout for each network request") - parser.add_argument('--repeat', default=2, type=int, - help="Provide number of repeats for request") - return parser - - -class ListDhcpServers(lister.Lister, BaseCommand): - """Show list of dhcp servers on ethernet interfaces""" - - def get_parser(self, prog_name): - parser = super(ListDhcpServers, self).get_parser(prog_name) - parser.add_argument( - '--ifaces', metavar='I', nargs='+', - help='If no eth provided - will run against all except lo') - return parser - - def take_action(self, parsed_args): - LOG.info('Starting dhcp discover for {0}'.format(parsed_args.ifaces)) - res = list(api.check_dhcp( - parsed_args.ifaces, - timeout=parsed_args.timeout, - repeat=parsed_args.repeat)) - # NOTE(dshulyak) unfortunately cliff doesnt allow to configure - # PrettyTable output, see link: - # https://github.com/dhellmann/cliff/blob/master/ - # cliff/formatters/table.py#L34 - # and in case i want always print empty table if nothing found - # it is not possible by configuration - if not res: - res = [{}] - return (utils.DHCP_OFFER_COLUMNS, - [utils.get_item_properties(item, utils.DHCP_OFFER_COLUMNS) - for item in res]) - - -class ListDhcpAssignment(lister.Lister, BaseCommand): - """Make dhcp request to servers and receive acknowledgement messages""" - - def get_parser(self, prog_name): - parser = super(ListDhcpAssignment, self).get_parser(prog_name) - parser.add_argument('iface', - help='Ethernet interface name') - parser.add_argument('endpoint', - help='Endpoint of server or multicast group') - parser.add_argument('--range_start', dest='range_start', - help='Start of the range') - parser.add_argument('--range_end', dest='range_end', default=None, - help='Start of the range') - return parser - - def take_action(self, parsed_args): - res = iter(api.check_dhcp_request( - parsed_args.iface, - parsed_args.endpoint, - parsed_args.range_start, - parsed_args.range_end, timeout=parsed_args.timeout)) - first = res.next() - columns = first.keys() - return columns, [first.values()] + [item.values() for item in res] - - -class DhcpWithVlansCheck(lister.Lister, BaseCommand): - """Provide iface with list of vlans to check - - If no vlans created - they will be. After creation they won't be deleted. - """ - - def get_parser(self, prog_name): - parser = super(DhcpWithVlansCheck, self).get_parser(prog_name) - parser.add_argument('config', - help='Ethernet interface name') - return parser - - def take_action(self, parsed_args): - res = api.check_dhcp_with_vlans(json.loads(parsed_args.config), - timeout=parsed_args.timeout, - repeat=parsed_args.repeat) - first = res.next() - columns = first.keys() - return columns, [first.values()] + [item.values() for item in res] diff --git a/network_checker/dhcp_checker/tests/system/__init__.py b/network_checker/dhcp_checker/tests/system/__init__.py deleted file mode 100644 index 141ca6ab9a..0000000000 --- a/network_checker/dhcp_checker/tests/system/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/network_checker/dhcp_checker/tests/system/tests.py b/network_checker/dhcp_checker/tests/system/tests.py deleted file mode 100644 index 5afa5701ea..0000000000 --- a/network_checker/dhcp_checker/tests/system/tests.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. -""" -For this tests you need -vagrant up develop dhcp1 dhcp2 -""" - -import unittest - -from dhcp_checker import api -from dhcp_checker import utils - - -class TestDhcpServers(unittest.TestCase): - - def test_dhcp_server_on_eth1(self): - """Test verifies dhcp server on eth1 iface""" - response = api.check_dhcp_on_eth('eth1', 2) - self.assertEqual(len(response), 1) - # we need to guarantee that received answer has server_ip - # but dont want to check its real address - self.assertTrue(response[0]['server_ip']) - - def test_dhcp_server_on_eth2(self): - """Test verifies dhcp server on eth2 iface""" - response = api.check_dhcp_on_eth('eth2', 2) - self.assertEqual(len(response), 1) - self.assertTrue(response[0]['server_ip']) - - -class TestDhcpUtils(unittest.TestCase): - - def setUp(self): - self.iface_down = 'eth1' - utils.command_util('ifconfig', self.iface_down, 'down') - - def test_check_network_up(self): - """Verify that true would be returned on test network up""" - result = utils.check_network_up('eth0') - self.assertTrue(result) - - def test_check_network_down(self): - """Verify that false would be returned on test network down""" - self.assertFalse(utils.check_network_up(self.iface_down)) - - def tearDown(self): - utils.command_util('ifconfig', self.iface_down, 'up') - - -class TestDhcpWithNetworkDown(unittest.TestCase): - - def setUp(self): - self.iface_up = 'eth0' - self.iface_down = 'eth2' - utils.command_util('ifconfig', self.iface_down, 'down') - - def test_dhcp_server_on_eth2_down(self): - """iface should be ifuped in case it's down and rolledback after""" - manager = utils.IfaceState(self.iface_down) - with manager as iface: - response = api.check_dhcp_on_eth(iface, 2) - - self.assertEqual(len(response), 1) - self.assertTrue(response[0]['server_ip']) - self.assertEqual(manager.pre_iface_state, 'DOWN') - self.assertEqual(manager.iface_state, 'UP') - self.assertEqual(manager.post_iface_state, 'DOWN') - - def test_dhcp_server_on_eth0_up(self): - """Test verifies that if iface is up, it won't be touched""" - manager = utils.IfaceState(self.iface_up) - with manager as iface: - response = api.check_dhcp_on_eth(iface, 2) - - self.assertEqual(len(response), 1) - self.assertTrue(response[0]['server_ip']) - self.assertEqual(manager.pre_iface_state, 'UP') - self.assertEqual(manager.iface_state, 'UP') - self.assertEqual(manager.post_iface_state, 'UP') - - def test_dhcp_server_on_nonexistent_iface(self): - - def test_check(): - manager = utils.IfaceState('eth10') - with manager as iface: - api.check_dhcp_on_eth(iface, 2) - self.assertRaises(EnvironmentError, test_check) - - def tearDown(self): - utils.command_util('ifconfig', self.iface_down, 'up') - - -class TestMainFunctions(unittest.TestCase): - - def test_with_vlans(self): - config = {'eth1': (103, 105), - 'eth2': range(106, 120)} - result = api.check_dhcp_with_vlans(config) - self.assertEqual(len(list(result)), 2) - - def test_with_duplicated_with_repeat(self): - ifaces = ['eth1', 'eth2'] - result = api.check_dhcp(ifaces, repeat=3) - self.assertEqual(len(list(result)), 2) - - -if __name__ == '__main__': - unittest.main() diff --git a/network_checker/dhcp_checker/tests/unit/__init__.py b/network_checker/dhcp_checker/tests/unit/__init__.py deleted file mode 100644 index 141ca6ab9a..0000000000 --- a/network_checker/dhcp_checker/tests/unit/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/network_checker/dhcp_checker/tests/unit/dhcp.pcap b/network_checker/dhcp_checker/tests/unit/dhcp.pcap deleted file mode 100644 index 131ea0bef70832185a787608aac0a10cf264b528..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1868 zcmca|c+)~A1{MYw`2U}Qff2}Ad@em`XAcX54UhxE|G|JGAuqpxlY_yPfl&{n%t5en zKS(D?lEH<+nNcco6(b`X%rFcZq8~$e$OjWHMs`dQit0m?GIZ z7+FB+iWw+!h>;B}&cmHjoKc!nnV79xkjyWTosp=Qn^}~YSCUz*mzP@N#A|47q-SWM zXJlZZXKV%zd94+rA&);EX%+HYx1fi7PzVFh!zn0f-V_+Q%%F4)P4nyUq(*XEz&#yZHDQz diff --git a/network_checker/dhcp_checker/tests/unit/test_api.py b/network_checker/dhcp_checker/tests/unit/test_api.py deleted file mode 100644 index 9a22482646..0000000000 --- a/network_checker/dhcp_checker/tests/unit/test_api.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -import os -import unittest - -from mock import patch -from scapy import all as scapy - -from dhcp_checker import api - -dhcp_options = [("message-type", "offer"), "end"] - -request = ( - scapy.Ether(), - scapy.Ether(src="", dst="ff:ff:ff:ff:ff:ff") / - scapy.IP(src="0.0.0.0", dst="255.255.255.255") / - scapy.UDP(sport=68, dport=67) / - scapy.BOOTP(chaddr="") / - scapy.DHCP(options=dhcp_options) -) - -expected_response = { - 'dport': 67, - 'gateway': '172.18.194.2', - 'iface': 'eth1', - 'mac': '00:15:17:ee:0a:a8', - 'message': 'offer', - 'server_id': '172.18.208.44', - 'server_ip': '172.18.194.2', - 'yiaddr': '172.18.194.35' -} - - -class TestDhcpApi(unittest.TestCase): - - def setUp(self): - directory_path = os.path.dirname(__file__) - self.scapy_data = list(scapy.rdpcap(os.path.join(directory_path, - 'dhcp.pcap'))) - self.dhcp_response = self.scapy_data[1:] - - @patch('dhcp_checker.api.scapy.srp') - @patch('dhcp_checker.api.scapy.get_if_raw_hwaddr') - def test_check_dhcp_on_eth(self, raw_hwaddr, srp_mock): - raw_hwaddr.return_value = ('111', '222') - srp_mock.return_value = ([self.dhcp_response], []) - response = api.check_dhcp_on_eth('eth1', timeout=5) - self.assertEqual([expected_response], response) - - @patch('dhcp_checker.api.scapy.srp') - @patch('dhcp_checker.api.scapy.get_if_raw_hwaddr') - def test_check_dhcp_on_eth_empty_response(self, raw_hwaddr, srp_mock): - raw_hwaddr.return_value = ('111', '222') - srp_mock.return_value = ([], []) - response = api.check_dhcp_on_eth('eth1', timeout=5) - self.assertEqual([], response) - - @patch('dhcp_checker.api.send_dhcp_discover') - @patch('dhcp_checker.api.make_listeners') - def test_check_dhcp_with_multiple_ifaces( - self, make_listeners, send_discover): - api.check_dhcp(['eth1', 'eth2'], repeat=1) - make_listeners.assert_called_once_with(('eth2', 'eth1')) - self.assertEqual(send_discover.call_count, 2) - - @patch('dhcp_checker.api.send_dhcp_discover') - @patch('dhcp_checker.api.make_listeners') - def test_check_dhcp_with_vlans(self, make_listeners, send_discover): - config_sample = { - 'eth0': (100, 101), - 'eth1': (100, 102) - } - api.check_dhcp_with_vlans(config_sample, timeout=1) - make_listeners.assert_called_once_with(('eth1', 'eth0')) - self.assertEqual(send_discover.call_count, 6) - - @patch('dhcp_checker.api.time.sleep') - @patch('dhcp_checker.api.send_dhcp_discover') - @patch('dhcp_checker.api.make_listeners') - def test_check_dhcp_with_vlans_repeat_2(self, make_listeners, - send_discover, sleep_mock): - config_sample = { - 'eth0': (), - } - api.check_dhcp_with_vlans(config_sample, timeout=1, repeat=3) - self.assertEqual(sleep_mock.call_count, 3) - make_listeners.assert_called_once_with(('eth0',)) - self.assertEqual(send_discover.call_count, 3) diff --git a/network_checker/dhcp_checker/tests/unit/test_commands.py b/network_checker/dhcp_checker/tests/unit/test_commands.py deleted file mode 100644 index d0f169e099..0000000000 --- a/network_checker/dhcp_checker/tests/unit/test_commands.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -import json -from mock import patch -import unittest - -from dhcp_checker import cli - -expected_response = { - 'dport': 67, - 'gateway': '172.18.194.2', - 'iface': 'eth1', - 'mac': '00:15:17:ee:0a:a8', - 'message': 'offer', - 'server_id': '172.18.208.44', - 'server_ip': '172.18.194.2', - 'yiaddr': '172.18.194.35' -} - - -@patch('dhcp_checker.commands.api') -class TestCommandsInterface(unittest.TestCase): - - def test_list_dhcp_servers(self, api): - api.check_dhcp.return_value = iter([expected_response]) - command = cli.main(['discover', '--ifaces', 'eth0', 'eth1', - '--format', 'json']) - self.assertEqual(command, 0) - api.check_dhcp.assert_called_once_with(['eth0', 'eth1'], - repeat=2, timeout=5) - - def test_list_dhcp_assignment(self, api): - api.check_dhcp_request.return_value = iter([expected_response]) - command = cli.main(['request', 'eth1', '10.20.0.2', - '--range_start', '10.20.0.10', - '--range_end', '10.20.0.20']) - self.assertEqual(command, 0) - api.check_dhcp_request.assert_called_once_with( - 'eth1', '10.20.0.2', '10.20.0.10', '10.20.0.20', timeout=5 - ) - - def test_list_dhcp_vlans_info(self, api): - config_sample = {'eth1': ['100', '101'], - 'eth2': range(103, 110)} - api.check_dhcp_with_vlans.return_value = iter([expected_response]) - command = cli.main(['vlans', json.dumps(config_sample)]) - self.assertEqual(command, 0) - api.check_dhcp_with_vlans.assert_called_once_with( - config_sample, repeat=2, timeout=5) diff --git a/network_checker/dhcp_checker/tests/unit/test_utils.py b/network_checker/dhcp_checker/tests/unit/test_utils.py deleted file mode 100644 index e0649c6f99..0000000000 --- a/network_checker/dhcp_checker/tests/unit/test_utils.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -from mock import call -from mock import patch -import os -import unittest - -from scapy import all as scapy - -from dhcp_checker import utils - -IP_LINK_SHOW_UP = ( - "2: eth0: " - "mtu 1500 qdisc pfifo_fast state UP qlen 1000" - "link/ether 08:60:6e:6f:70:09 brd ff:ff:ff:ff:ff:ff" -) - -IP_LINK_SHOW_DOES_NOT_EXIST = 'Device "eth2" does not exist.' - -expected_response = { - 'dport': 67, - 'gateway': '172.18.194.2', - 'iface': 'eth1', - 'mac': '00:15:17:ee:0a:a8', - 'message': 'offer', - 'server_id': '172.18.208.44', - 'server_ip': '172.18.194.2', - 'yiaddr': '172.18.194.35' -} - - -class TestDhcpUtils(unittest.TestCase): - - def test_command_utils_helper(self): - command = utils.command_util('echo', 'hello') - self.assertEqual(command.stdout.read(), 'hello\n') - - @patch('dhcp_checker.utils.command_util') - def test_check_iface_state_up(self, command_util): - command_util().stdout.read.return_value = IP_LINK_SHOW_UP - self.assertEqual(utils._iface_state('eth0'), 'UP') - - @patch('dhcp_checker.utils.command_util') - def test_check_network_up(self, command_util): - command_util().stdout.read.return_value = IP_LINK_SHOW_UP - self.assertTrue(utils.check_network_up('eth0')) - - @patch('dhcp_checker.utils.command_util') - def test_check_iface_doesnot_exist(self, command_util): - command_util().stderr.read.return_value = IP_LINK_SHOW_DOES_NOT_EXIST - self.assertFalse(utils.check_iface_exist('eth2')) - - @patch('dhcp_checker.utils.command_util') - def test_check_iface_exist(self, command_util): - command_util().stderr.read.return_value = '' - self.assertTrue(utils.check_iface_exist('eth0')) - - def test_filter_duplicated_results(self): - test_data = [{'first': 'value'}, {'first': 'value'}] - - @utils.filter_duplicated_results - def test_func(values): - return values - - self.assertEqual(list(test_func(test_data)), [{'first': 'value'}]) - - def test_filter_duplicated_results_diff(self): - test_data = [{'first': 'value'}, {'second': 'value'}] - - @utils.filter_duplicated_results - def test_func(values): - return values - - self.assertEqual(list(test_func(test_data)), test_data) - - -class TestDhcpFormat(unittest.TestCase): - - def setUp(self): - directory_path = os.path.dirname(__file__) - self.scapy_data = list(scapy.rdpcap(os.path.join(directory_path, - 'dhcp.pcap'))) - self.dhcp_response = self.scapy_data[1:] - - def test_single_format_decorator(self): - """Test modifying scapy response objects - - Test verifies that single_format decorator contains logic to modify - scapy response object into dict with predefined fields - """ - - @utils.single_format - def tobe_decorated(iface, timeout=5): - return [self.dhcp_response] - - self.assertEqual(tobe_decorated('eth1'), [expected_response]) - - def test_order_preserver(self): - example = {'first': 'first', 'second': 'second'} - columns = ['second', 'first'] - items = utils.get_item_properties(example, columns) - self.assertEqual(columns, items) - - -class TestMultiprocMap(unittest.TestCase): - """Check if multiproc_map decorator works the same for different arg types - - Test verifies that working with function decorated by multiproc_map - will work indifirently either args passed as tuple, or *args - """ - - def test_multiproc_map_first_tuple(self): - - @utils.multiproc_map - def test_multiproc(*args, **kwargs): - return args, kwargs - - rargs, rkwargs = test_multiproc(('h', 'e')) - self.assertEqual(rargs, ('h', 'e')) - self.assertEqual(rkwargs, {}) - - def test_multiproc_mapn_normal(self): - - @utils.multiproc_map - def test_multiproc(*args, **kwargs): - return args, kwargs - - rargs, rkwargs = test_multiproc('h', 'e') - self.assertEqual(rargs, ('h', 'e')) - self.assertEqual(rkwargs, {}) - - -@patch('dhcp_checker.utils._iface_state') -@patch('dhcp_checker.utils.command_util') -class TestIfaceStateHelper(unittest.TestCase): - - def test_iface_is_up(self, command, iface_state): - iface_value = iter(('UP',) * 3) - iface_state.side_effect = lambda *args, **kwargs: next(iface_value) - with utils.IfaceState('eth1') as iface: - self.assertEqual(iface, 'eth1') - self.assertEqual(iface_state.call_count, 2) - self.assertEqual(command.call_count, 0) - - def test_iface_is_down(self, command, iface_state): - iface_value = iter(('DOWN', 'UP', 'DOWN')) - iface_state.side_effect = lambda *args, **kwargs: next(iface_value) - with utils.IfaceState('eth1') as iface: - self.assertEqual(iface, 'eth1') - self.assertEqual(iface_state.call_count, 3) - self.assertEqual(command.call_count, 2) - self.assertEqual(command.call_args_list, - [call('ifconfig', 'eth1', 'up'), - call('ifconfig', 'eth1', 'down')]) - - def test_iface_cant_ifup(self, command, iface_state): - iface_value = iter(('DOWN',) * 10) - iface_state.side_effect = lambda *args, **kwargs: next(iface_value) - - def test_raises(): - with utils.IfaceState('eth1', retry=4) as iface: - self.assertEqual(iface, 'eth1') - self.assertRaises(EnvironmentError, test_raises) - self.assertEqual(command.call_count, 4) diff --git a/network_checker/dhcp_checker/utils.py b/network_checker/dhcp_checker/utils.py deleted file mode 100644 index 6e8149c25c..0000000000 --- a/network_checker/dhcp_checker/utils.py +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. -import functools -import re -import subprocess -import sys - -from scapy import all as scapy - - -DHCP_OFFER_COLUMNS = ('iface', 'mac', 'server_ip', 'server_id', 'gateway', - 'dport', 'message', 'yiaddr') - - -def command_util(*command): - """object with stderr and stdout""" - return subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - -def _check_vconfig(): - """Check vconfig installed or not""" - return not command_util('which', 'vconfig').stderr.read() - - -def _iface_state(iface): - """For a given iface return it's state - - returns UP, DOWN, UNKNOWN - """ - state = command_util('ip', 'link', 'show', iface).stdout.read() - search_result = re.search(r'.*<(?P.*)>.*', state) - if search_result: - state_list = search_result.groupdict().get('state', []) - if 'UP' in state_list: - return 'UP' - else: - return 'DOWN' - return 'UNKNOWN' - - -def check_network_up(iface): - return _iface_state(iface) == 'UP' - - -def check_iface_exist(iface): - """Check provided interface exists""" - return not command_util("ip", "link", "show", iface).stderr.read() - - -def filtered_ifaces(ifaces): - for iface in ifaces: - if not check_iface_exist(iface): - sys.stderr.write('Iface {0} does not exist.'.format(iface)) - else: - if not check_network_up(iface): - sys.stderr.write('Network for iface {0} is down.'.format( - iface)) - else: - yield iface - - -def pick_ip(range_start, range_end): - """Given start_range, end_range generate list of ips - - >>> next(pick_ip('192.168.1.10','192.168.1.13')) - '192.168.1.10' - """ - split_address = lambda ip_address: \ - [int(item) for item in ip_address.split('.')] - range_start = split_address(range_start) - range_end = split_address(range_end) - i = 0 - # ipv4 subnet cant be longer that 4 items - while i < 4: - # 255 - end of subnet - if not range_start[i] == range_end[i] and range_start[i] < 255: - yield '.'.join([str(item) for item in range_start]) - range_start[i] += 1 - else: - i += 1 - - -def get_item_properties(item, columns): - """Get specified in columns properties, with preserved order. - - Required for correct cli table generation - - :param item: dict - :param columns: list with arbitrary keys - """ - properties = [] - for key in columns: - properties.append(item.get(key, '')) - return properties - - -def format_options(options): - """Util for serializing dhcp options - - @options = [1,2,3] - >>> format_options([1, 2, 3]) - '\x01\x02\x03' - """ - return "".join((chr(item) for item in options)) - - -def _dhcp_options(dhcp_options): - """Dhcp options returned by scapy is not in usable format - - [('message-type', 2), ('server_id', '192.168.0.5'), - ('name_server', '192.168.0.1', '192.168.0.2'), 'end'] - """ - for option in dhcp_options: - if isinstance(option, (tuple, list)): - header = option[0] - if len(option[1:]) > 1: - yield (header, option) - else: - yield (header, option[1]) - - -def format_answer(ans, iface): - dhcp_options = dict(_dhcp_options(ans[scapy.DHCP].options)) - results = ( - iface, ans[scapy.Ether].src, ans[scapy.IP].src, - dhcp_options['server_id'], ans[scapy.BOOTP].giaddr, - ans[scapy.UDP].sport, - scapy.DHCPTypes[dhcp_options['message-type']], - ans[scapy.BOOTP].yiaddr) - return dict(zip(DHCP_OFFER_COLUMNS, results)) - - -def single_format(func): - """Manage format of dhcp response""" - @functools.wraps(func) - def formatter(*args, **kwargs): - iface = args[0] - ans = func(*args, **kwargs) - # scapy stores all sequence of requests - # so ans[0][1] would be response to first request - return [format_answer(response[1], iface) for response in ans] - return formatter - - -def multiproc_map(func): - # multiproc map could not work with format *args - @functools.wraps(func) - def workaround(*args, **kwargs): - args = args[0] if isinstance(args[0], (tuple, list)) else args - return func(*args, **kwargs) - return workaround - - -def filter_duplicated_results(func): - # due to network infra on broadcast multiple duplicated results - # returned. This helper filter them out - @functools.wraps(func) - def wrapper(*args, **kwargs): - resp = func(*args, **kwargs) - return (dict(t) for t in set([tuple(d.items()) for d in resp])) - return wrapper - - -class VlansContext(object): - """Contains all logic to manage vlans""" - - def __init__(self, config): - """Initialize VlansContext - - @config - list or tuple of (iface, vlan) pairs - """ - self.config = config - - def __enter__(self): - for iface, vlans in self.config.iteritems(): - vifaces = [] - for vlan in vlans: - if vlan > 0: - vifaces.append('{0}.{1}'.format(iface, vlan)) - yield str(iface), vifaces - - def __exit__(self, type, value, trace): - pass - - -class IfaceState(object): - """Context manager to control state of iface while dhcp checker runs""" - - def __init__(self, iface, rollback=True, retry=3): - self.rollback = rollback - self.retry = retry - self.iface = iface - self.pre_iface_state = _iface_state(iface) - self.iface_state = self.pre_iface_state - self.post_iface_state = '' - - def iface_up(self): - while self.retry and self.iface_state != 'UP': - command_util('ifconfig', self.iface, 'up') - self.iface_state = _iface_state(self.iface) - self.retry -= 1 - if self.iface_state != 'UP': - raise EnvironmentError( - 'Tried my best to ifup iface {0}.'.format(self.iface)) - - def __enter__(self): - self.iface_up() - return self.iface - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.pre_iface_state != 'UP' and self.rollback: - command_util('ifconfig', self.iface, 'down') - self.post_iface_state = _iface_state(self.iface) - - -def create_mac_filter(iface): - """tcpdump can not catch all 6 octets so it is splitted - - See http://blog.jasonantman.com/2010/04/dhcp-debugging-and-handy-tcpdump-filters # noqa - """ - mac = scapy.get_if_hwaddr(iface).split(':') - filter1 = '(udp[36:2] = 0x{0})'.format(''.join(mac[:2])) - filter2 = '(udp[38:4] = 0x{0})'.format(''.join(mac[2:])) - return '{0} and {1}'.format(filter1, filter2) diff --git a/network_checker/fuel_network_checker/__init__.py b/network_checker/fuel_network_checker/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/network_checker/fuel_network_checker/base_app.py b/network_checker/fuel_network_checker/base_app.py deleted file mode 100644 index 0fe0c75234..0000000000 --- a/network_checker/fuel_network_checker/base_app.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. -# -import logging -from logging import handlers - -from cliff.app import App - - -class BaseApp(App): - DEFAULT_VERBOSE_LEVEL = 0 - LOG_FILENAME = '' # This needs to be redefined in child class - - def configure_logging(self): - super(BaseApp, self).configure_logging() - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) - formatter = logging.Formatter( - '%(asctime)s %(levelname)s (%(module)s) %(message)s', - "%Y-%m-%d %H:%M:%S") - - stream_handler = logging.StreamHandler() - stream_handler.setLevel(logging.ERROR) - stream_handler.setFormatter(formatter) - - file_handler = handlers.TimedRotatingFileHandler( - self.LOG_FILENAME) - file_handler.setLevel(logging.DEBUG) - file_handler.setFormatter(formatter) - - logger.addHandler(stream_handler) - logger.addHandler(file_handler) diff --git a/network_checker/network_checker/__init__.py b/network_checker/network_checker/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/network_checker/network_checker/api.py b/network_checker/network_checker/api.py deleted file mode 100644 index 256a217941..0000000000 --- a/network_checker/network_checker/api.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - - -from stevedore import driver - -from network_checker import config -from network_checker import daemon -from network_checker import xmlrpc - - -class Api(object): - - namespace = 'network_checker' - - def __init__(self, verification, **kwargs): - self.verification = verification - self.server_config = config.get_config()[verification] - self.verification_config = dict(self.server_config['defaults'], - **kwargs) - - def serve(self): - daemon.cleanup(self.server_config) - self.manager = driver.DriverManager( - self.namespace, - self.verification, - invoke_on_load=True, - invoke_kwds=self.verification_config) - self.driver = self.manager.driver - rpc_server = xmlrpc.get_server(self.server_config) - # TODO(dshulyak) verification api should know what methods to serve - rpc_server.register_function(self.driver.listen, 'listen') - rpc_server.register_function(self.driver.send, 'send') - rpc_server.register_function(self.driver.get_info, 'get_info') - rpc_server.register_function(self.driver.test, 'test') - return daemon.run_server(rpc_server, self.server_config) - - def listen(self): - return xmlrpc.get_client(self.server_config).listen() - - def send(self): - return xmlrpc.get_client(self.server_config).send() - - def info(self): - return xmlrpc.get_client(self.server_config).get_info() - - def clean(self): - return daemon.cleanup(self.server_config) - - def test(self): - return xmlrpc.get_client(self.server_config).test() diff --git a/network_checker/network_checker/cli.py b/network_checker/network_checker/cli.py deleted file mode 100644 index 4d90d59df7..0000000000 --- a/network_checker/network_checker/cli.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. -"""Fuel network checker -Available verifications: multicast - -Example: - fuel-netcheck multicast serve listen send info clean - -Multicast config options: - group: 225.0.0.250 - port: 13310 - ttl: 5 - uid: '1001' - repeat: 3 - iface: eth0 - timeout: 10 - -""" - -import argparse -import json -import textwrap - -from network_checker import api - - -def parse_args(): - parser = argparse.ArgumentParser( - description=textwrap.dedent(__doc__), - formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument( - 'verification', - help="Type of verification that should be started.") - parser.add_argument( - 'actions', nargs='+', - help="List of actions to perform.") - # TODO(dshulyak) Add posibility to provide args like regular shell args - parser.add_argument( - '-c', '--config', default='{}', - help="User defined configuration in json format.") - return parser.parse_args() - - -def main(): - args = parse_args() - user_data = json.loads(args.config) - api_instance = api.Api(args.verification, **user_data) - # Print only last response if user requires multiple sequantial actions - for action in args.actions: - result = getattr(api_instance, action)() - print(json.dumps(result)) diff --git a/network_checker/network_checker/config.py b/network_checker/network_checker/config.py deleted file mode 100644 index c50599b039..0000000000 --- a/network_checker/network_checker/config.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import os - -import yaml - - -def _get_config_path(): - if os.path.exists('/etc/network_checker/config.yaml'): - return '/etc/network_checker/config.yaml' - return os.path.join( - os.path.dirname(os.path.realpath(__file__)), - 'config.yaml') - - -def get_config(): - with open(_get_config_path()) as conf: - return yaml.load(conf.read()) diff --git a/network_checker/network_checker/config.yaml b/network_checker/network_checker/config.yaml deleted file mode 100644 index 890093eb9b..0000000000 --- a/network_checker/network_checker/config.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -multicast: - app: multicast - pidfile: /var/run/multicast.pid - unix: /var/run/multicast.sock - defaults: - group: 225.0.0.250 - port: 13310 - ttl: 5 - uid: '1001' - repeat: 3 - iface: eth0 - timeout: 10 diff --git a/network_checker/network_checker/daemon.py b/network_checker/network_checker/daemon.py deleted file mode 100644 index 5574834cca..0000000000 --- a/network_checker/network_checker/daemon.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import logging -import os - -import daemonize - -LOG = logging.getLogger(__name__) - - -def run_server(server, config): - daemon = daemonize.Daemonize( - app=config['app'], - pid=config['pidfile'], - action=server.serve_forever, - # keep open stdin, stdout, stderr and socket file - keep_fds=[0, 1, 2, server.fileno()]) - try: - daemon.start() - # this is required to do some stuff after server is daemonized - except SystemExit as e: - if e.code is 0: - return True - raise - - -def cleanup(config): - if os.path.exists(config['unix']): - os.unlink(config['unix']) - if os.path.exists(config['pidfile']): - with open(config['pidfile'], 'r') as f: - pid = f.read().strip('\n') - try: - os.kill(int(pid), 9) - except OSError: - # it is ok if proc already stopped - pass - os.unlink(config['pidfile']) - return True diff --git a/network_checker/network_checker/multicast/__init__.py b/network_checker/network_checker/multicast/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/network_checker/network_checker/multicast/api.py b/network_checker/network_checker/multicast/api.py deleted file mode 100644 index 76eadefcf5..0000000000 --- a/network_checker/network_checker/multicast/api.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import logging -import socket -import struct - -import pcap -import scapy.all as scapy - -LOG = logging.getLogger(__name__) - -# it is not defined in every python version -SO_BINDTODEVICE = 25 - - -class MulticastChecker(object): - - def __init__(self, group='225.0.0.250', port='13100', - uid='999', iface='eth0', - ttl=1, repeat=1, timeout=3): - self.group = group - self.port = int(port) - self.ttl = ttl - self.uid = uid - self.repeat = repeat - self.timeout = timeout - self.receiver = None - self.messages = [] - self.iface = iface - - def send(self): - ttl_data = struct.pack('@i', self.ttl) - _socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - _socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, - ttl_data) - _socket.setsockopt( - socket.SOL_SOCKET, - SO_BINDTODEVICE, self.iface) - - for _ in xrange(self.repeat): - _socket.sendto(self.uid, (self.group, self.port)) - return {'group': self.group, - 'port': self.port, - 'iface': self.iface, - 'uid': self.uid} - - def listen(self): - self._register_group() - self._start_listeners() - return {'group': self.group, - 'port': self.port, - 'iface': self.iface, - 'uid': self.uid} - - def _register_group(self): - self.receiver = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.receiver.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.receiver.setsockopt( - socket.SOL_SOCKET, - SO_BINDTODEVICE, self.iface) - self.receiver.bind(('', self.port)) - group_packed = socket.inet_aton(self.group) - group_data = struct.pack('4sL', group_packed, socket.INADDR_ANY) - self.receiver.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, - group_data) - - def _start_listeners(self): - self.listener = pcap.pcap(self.iface) - udp_filter = 'udp and dst port {0}'.format(self.port) - self.listener.setfilter(udp_filter) - - def get_info(self): - for sock, pack in self.listener.readpkts(): - pack = scapy.Ether(pack) - data, _ = pack[scapy.UDP].extract_padding(pack[scapy.UDP].load) - self.messages.append(data.decode()) - self.receiver.close() - return list(set(self.messages)) - - def test(self): - return {'test': 'test'} diff --git a/network_checker/network_checker/net_check/__init__.py b/network_checker/network_checker/net_check/__init__.py deleted file mode 100644 index ce4c00840c..0000000000 --- a/network_checker/network_checker/net_check/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. diff --git a/network_checker/network_checker/net_check/api.py b/network_checker/network_checker/net_check/api.py deleted file mode 100755 index 60b74452e9..0000000000 --- a/network_checker/network_checker/net_check/api.py +++ /dev/null @@ -1,706 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2014 Mirantis, Inc. -# -# 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. - -# -# Generate and send Ethernet packets to specified interfaces. -# Collect data from interfaces. -# Analyse dumps for packets with special cookie in UDP payload. -# -import argparse -import json -import logging -import os -import re -import shutil -import signal -import socket -import subprocess -import sys -import time -import traceback - -import logging.handlers - - -from scapy import config as scapy_config - -scapy_config.logLevel = 40 -scapy_config.use_pcap = True -import scapy.all as scapy -from scapy import error - -from scapy.utils import PcapReader - -from network_checker.net_check.utils import signal_timeout - - -class ActorFabric(object): - @classmethod - def getInstance(cls, config): - if config.get('action') not in ('listen', 'generate'): - raise Exception( - 'Wrong config, you need define ' - 'valid action instead of {0}'.format(config.get('action'))) - if config['action'] in ('listen',): - return Listener(config) - elif config['action'] in ('generate',): - return Sender(config) - - -class ActorException(Exception): - def __init__(self, logger, message='', level='error'): - getattr(logger, level, logger.error)(message) - super(ActorException, self).__init__(message) - - -class Actor(object): - def __init__(self, config=None): - self.config = { - 'src_mac': None, - 'src': '198.18.1.1', - 'dst': '198.18.1.2', - 'sport': 31337, - 'dport': 31337, - 'cookie': "Nailgun:", - 'pcap_dir': "/var/run/pcap_dir/", - 'duration': 5, - 'repeat': 1, - 'collect_timeout': 300, - } - if config: - self.config.update(config) - - self.logger.debug("Running with config: %s", json.dumps(self.config)) - self.iface_down_after = {} - self.viface_remove_after = {} - - def _define_logger(self, filename=None, - appname='netprobe', level=logging.DEBUG): - logger = logging.getLogger(appname) - logger.setLevel(level) - - syslog_formatter = logging.Formatter( - '{appname}: %(message)s'.format(appname=appname) - ) - syslog_handler = logging.handlers.SysLogHandler('/dev/log') - syslog_handler.setFormatter(syslog_formatter) - logger.addHandler(syslog_handler) - - # A syslog handler should be always. But a file handler is the option. - # If you don't want it you can keep 'filename' variable as None to skip - # this handler. - if filename: - file_formatter = logging.Formatter( - '%(asctime)s %(levelname)s %(name)s %(message)s' - ) - - file_handler = logging.FileHandler(filename) - file_handler.setFormatter(file_formatter) - logger.addHandler(file_handler) - - return logger - - def _execute(self, command, expected_exit_codes=(0,)): - self.logger.debug("Running command: %s" % " ".join(command)) - env = os.environ - env["PATH"] = "/bin:/usr/bin:/sbin:/usr/sbin" - p = subprocess.Popen(command, shell=False, - env=env, stdout=subprocess.PIPE) - output, _ = p.communicate() - if p.returncode not in expected_exit_codes: - raise ActorException( - self.logger, - "Command exited with error: %s: %s" % (" ".join(command), - p.returncode) - ) - return output.split('\n') - - def _viface_by_iface_vid(self, iface, vid): - return (self._try_viface_create(iface, vid) or "%s.%d" % (iface, vid)) - - def _iface_name(self, iface, vid=None): - if vid: - return self._viface_by_iface_vid(iface, vid) - return iface - - def _look_for_link(self, iface, vid=None): - viface = None - if vid: - viface = self._viface_by_iface_vid(iface, vid) - - command = ['ip', 'link'] - r = re.compile(ur"(\d+?):\s+((?P[^:@]+)@)?(?P[^:]+?):" - ".+?(?PUP|DOWN|UNKNOWN).*$") - for line in self._execute(command): - m = r.search(line) - if m: - md = m.groupdict() - if (iface == md.get('iface') and - viface == md.get('viface') and md.get('state')): - return (iface, viface, md.get('state')) - # If we are here we aren't able to say if iface with vid is up - raise ActorException( - self.logger, - "Cannot find interface %s with vid=%s" % (iface, vid) - ) - - def _try_iface_up(self, iface, vid=None): - if vid and not self._try_viface_create(iface, vid): - # if viface does not exist we raise exception - raise ActorException( - self.logger, - "Vlan %s on interface %s does not exist" % (str(vid), iface) - ) - - self.logger.debug("Checking if interface %s with vid %s is up", - iface, str(vid)) - _, _, state = self._look_for_link(iface, vid) - return (state == 'UP') - - def _iface_up(self, iface, vid=None): - """Brings interface with vid up""" - if vid and not self._try_viface_create(iface, vid): - # if viface does not exist we raise exception - raise ActorException( - self.logger, - "Vlan %s on interface %s does not exist" % (str(vid), iface) - ) - - set_iface = self._iface_name(iface, vid) - - self.logger.debug("Brining interface %s with vid %s up", - set_iface, str(vid)) - self._execute([ - "ip", - "link", "set", - "dev", set_iface, - "up"]) - - def _ensure_iface_up(self, iface, vid=None): - """Ensures interface is with vid up.""" - if not self._try_iface_up(iface, vid): - # if iface is not up we try to bring it up - self._iface_up(iface, vid) - if self._try_iface_up(iface, vid): - # if iface was down and we have brought it up - # we should mark it to be brought down after probing - self.iface_down_after[self._iface_name(iface, vid)] = True - else: - # if viface is still down we raise exception - raise ActorException( - self.logger, - "Can not bring interface %s with vid %s up" % (iface, - str(vid)) - ) - - def _ensure_iface_down(self, iface, vid=None): - set_iface = self._iface_name(iface, vid) - if self.iface_down_after.get(set_iface, False): - # if iface with vid have been marked to be brought down - # after probing we try to bring it down - self.logger.debug("Brining down interface %s with vid %s", - iface, str(vid)) - self._execute([ - "ip", - "link", "set", - "dev", set_iface, - "down"]) - self.iface_down_after.pop(set_iface) - - def _try_viface_create(self, iface, vid): - """Tries to find vlan interface on iface with VLAN_ID=vid and return it - - :returns: name of vlan interface if it exists or None - """ - self.logger.debug("Checking if vlan %s on interface %s exists", - str(vid), iface) - with open("/proc/net/vlan/config", "r") as f: - for line in f: - m = re.search(ur'(.+?)\s+\|\s+(.+?)\s+\|\s+(.+?)\s*$', line) - if m and m.group(2) == str(vid) and m.group(3) == iface: - return m.group(1) - - def _viface_create(self, iface, vid): - """Creates VLAN interface with VLAN_ID=vid on interface iface - - :returns: None - """ - self.logger.debug("Creating vlan %s on interface %s", str(vid), iface) - self._execute([ - "ip", - "link", "add", - "link", iface, - "name", self._viface_by_iface_vid(iface, vid), - "type", "vlan", - "id", str(vid)]) - - def _ensure_viface_create(self, iface, vid): - """Ensures that vlan interface exists. - - If it does not already - exist, then we need it to be created. It also marks newly created - vlan interface to remove it after probing procedure. - """ - if not self._try_viface_create(iface, vid): - # if viface does not exist we try to create it - self._viface_create(iface, vid) - if self._try_viface_create(iface, vid): - # if viface had not existed and have been created - # we mark it to be removed after probing procedure - self.viface_remove_after[ - self._viface_by_iface_vid(iface, vid) - ] = True - else: - # if viface had not existed and still does not - # we raise exception - raise ActorException( - self.logger, - "Can not create vlan %d on interface %s" % (vid, iface) - ) - - def _ensure_viface_remove(self, iface, vid): - viface = self._viface_by_iface_vid(iface, vid) - if self.viface_remove_after.get(viface, False): - # if viface have been marked to be removed after probing - # we try to remove it - self.logger.debug("Removing vlan %s on interface %s", - str(vid), iface) - self._execute([ - "ip", - "link", "del", - "dev", viface]) - self.viface_remove_after.pop(viface) - - def _parse_vlan_list(self, vlan_string): - self.logger.debug("Parsing vlan list: %s", vlan_string) - validate = lambda x: (x >= 0) and (x < 4095) - chunks = vlan_string.split(",") - vlan_list = [] - for chunk in chunks: - delim = chunk.find("-") - try: - if delim > 0: - left = int(chunk[:delim]) - right = int(chunk[delim + 1:]) - if validate(left) and validate(right): - vlan_list.extend(xrange(left, right + 1)) - else: - raise ValueError - else: - vlan = int(chunk) - if validate(vlan): - vlan_list.append(vlan) - else: - raise ValueError - except ValueError: - raise ActorException(self.logger, "Incorrect vlan: %s" % chunk) - self.logger.debug("Parsed vlans: %s", str(vlan_list)) - return vlan_list - - def _ensure_viface_create_and_up(self, iface, vid): - self._ensure_viface_create(iface, vid) - self._ensure_iface_up(iface, vid) - - def _ensure_viface_down_and_remove(self, iface, vid): - self._ensure_iface_down(iface, vid) - self._ensure_viface_remove(iface, vid) - - def _iface_vlan_iterator(self): - for iface, vlan_list in self.config['interfaces'].iteritems(): - # Variables iface and vlan_list are getted from decoded JSON - # and json.dump convert all string data to Python unicode string. - # We use these variables in logging messages later. - # CentOS 6.4 uses Python 2.6 and logging module 0.5.0.5 which has - # a bug with converting unicode strings to message in - # SysLogHandler. So we need to convert all unicode to plain - # strings to avoid syslog message corruption. - for vlan in self._parse_vlan_list(str(vlan_list)): - yield (str(iface), vlan) - - def _iface_iterator(self): - for iface in self.config['interfaces']: - yield iface - - def _log_ifaces(self, prefix="Current interfaces"): - self.logger.debug("%s: ", prefix) - for line in self._execute(['ip', 'address']): - self.logger.debug(line.rstrip()) - - -class Sender(Actor): - - def __init__(self, config=None): - self.logger = self._define_logger('/var/log/netprobe_sender.log', - 'netprobe_sender') - super(Sender, self).__init__(config) - self.logger.info("=== Starting Sender ===") - self._log_ifaces("Interfaces just before sending probing packages") - - def run(self): - try: - self._run() - except Exception as e: - self.logger.error("An internal error occured: %s\n%s", str(e), - traceback.format_exc()) - - def _get_iface_mac(self, iface): - path = '/sys/class/net/{iface}/address'.format(iface=iface) - with open(path, 'r') as address: - return address.read().strip('\n') - - def _run(self): - for iface, vlan in self._iface_vlan_iterator(): - self._ensure_iface_up(iface) - self._send_packets() - self._log_ifaces("Interfaces just after sending probing packages") - for iface in self._iface_iterator(): - self._ensure_iface_down(iface) - self._log_ifaces("Interfaces just after ensuring them down in sender") - self.logger.info("=== Sender Finished ===") - - def _send_packets(self): - start_time = time.time() - - while time.time() - start_time <= self.config['duration']: - for iface, vlan in self._iface_vlan_iterator(): - self.logger.debug("Sending packets: iface=%s vlan=%s", - iface, str(vlan)) - for _ in xrange(self.config['repeat']): - self._sendp(iface, vlan) - - def _sendp(self, iface, vlan): - try: - data = str(''.join((self.config['cookie'], iface, ' ', - self.config['uid']))) - - p = scapy.Ether(src=self._get_iface_mac(iface), - dst="ff:ff:ff:ff:ff:ff") - if vlan > 0: - p = p / scapy.Dot1Q(vlan=vlan) - p = p / scapy.IP(src=self.config['src'], dst=self.config['dst']) - p = p / scapy.UDP(sport=self.config['sport'], - dport=self.config['dport']) / data - scapy.sendp(p, iface=iface) - except socket.error as e: - self.logger.error("Socket error: %s, %s", e, iface) - - -class Listener(Actor): - def __init__(self, config=None): - self.logger = self._define_logger('/var/log/netprobe_listener.log', - 'netprobe_listener') - super(Listener, self).__init__(config) - self.logger.info("=== Starting Listener ===") - self._log_ifaces("Interfaces just before starting listerning " - "for probing packages") - - self.pidfile = self.addpid('/var/run/net_probe') - - self.neighbours = {} - self._define_pcap_dir() - - def addpid(self, piddir): - pid = os.getpid() - if not os.path.exists(piddir): - os.mkdir(piddir) - pidfile = os.path.join(piddir, str(pid)) - with open(pidfile, 'w') as fo: - fo.write('') - return pidfile - - def _define_pcap_dir(self): - if os.path.exists(self.config['pcap_dir']): - shutil.rmtree(self.config['pcap_dir']) - os.mkdir(self.config['pcap_dir']) - - def run(self): - try: - self._run() - except Exception as e: - self.logger.error("An internal error occured: %s\n%s", str(e), - traceback.format_exc()) - - def _run(self): - sniffers = set() - listeners = [] - - for iface in self._iface_iterator(): - self._ensure_iface_up(iface) - if iface not in sniffers: - listeners.append(self.get_probe_frames(iface)) - listeners.append(self.get_probe_frames(iface, vlan=True)) - sniffers.add(iface) - - try: - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((self.config.get('ready_address', 'locahost'), - self.config.get('ready_port', 31338))) - except socket.error as e: - self.logger.error("Socket error: %s", e) - else: - self.logger.debug("Listener threads have been launched. " - "Reporting READY.") - msg = "READY" - total_sent = 0 - while total_sent < len(msg): - sent = s.send(msg[total_sent:]) - if sent == 0: - raise ActorException( - self.logger, - "Socket broken. Cannot send %s status." % msg - ) - total_sent += sent - s.shutdown(socket.SHUT_RDWR) - s.close() - - try: - while True: - time.sleep(1) - except KeyboardInterrupt: - self.logger.debug("Interruption signal catched") - - with signal_timeout(self.config['collect_timeout'], raise_exc=False): - for listener in listeners: - # terminate and flush pipes - listener.terminate() - out, err = listener.communicate() - - if err and listener.returncode: - self.logger.error('Listerner: %s', err) - elif err: - self.logger.warning('Listener: %s', err) - - self.logger.debug('Start reading dumped information.') - self.read_packets() - self._log_ifaces("Interfaces just before ensuring interfaces down") - - for iface in self._iface_iterator(): - self._ensure_iface_down(iface) - self._log_ifaces( - "Interfaces just after ensuring them down in listener") - - with open(self.config['dump_file'], 'w') as fo: - fo.write(json.dumps(self.neighbours)) - os.unlink(self.pidfile) - self.logger.info("=== Listener Finished ===") - - def read_packets(self): - for iface in self._iface_iterator(): - filenames = ['{0}.pcap'.format(iface), - 'vlan_{0}.pcap'.format(iface)] - for filename in filenames: - self.read_pcap_file(iface, filename) - - def read_pcap_file(self, iface, filename): - try: - pcap_file = os.path.join(self.config['pcap_dir'], filename) - for pkt in PcapReader(pcap_file): - self.fprn(pkt, iface) - except (IOError, error.Scapy_Exception) as exc: - self.logger.exception( - 'Cant read pcap file %s, err: %s', pcap_file, str(exc)) - - def fprn(self, p, iface): - - if scapy.Dot1Q in p: - vlan = p[scapy.Dot1Q].vlan - else: - vlan = 0 - - self.logger.debug("Catched packet: vlan=%s len=%s payload=%s", - str(vlan), p[scapy.UDP].len, p[scapy.UDP].payload) - received_msg, _ = p[scapy.UDP].extract_padding(p[scapy.UDP].load) - decoded_msg = received_msg.decode() - riface, uid = decoded_msg[len(self.config["cookie"]):].split(' ', 1) - - self.neighbours[iface].setdefault(vlan, {}) - - if riface not in self.neighbours[iface][vlan].setdefault(uid, []): - self.neighbours[iface][vlan][uid].append(riface) - - def get_probe_frames(self, iface, vlan=False): - if iface not in self.neighbours: - self.neighbours[iface] = {} - filter_string = 'udp and dst port {0}'.format(self.config['dport']) - filename = '{0}.pcap'.format(iface) - if vlan: - filter_string = '{0} {1}'.format('vlan and', filter_string) - filename = '{0}_{1}'.format('vlan', filename) - pcap_file = os.path.join(self.config['pcap_dir'], filename) - - return subprocess.Popen( - ['tcpdump', '-i', iface, '-w', pcap_file, filter_string], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - -# -------------- main --------------- - - -def define_parser(): - config_examples = """ - -Config file examples: - -Capture frames config file example is: -{"action": "listen", "interfaces": {"eth0": "1-4094"}, - "dump_file": "/var/tmp/net-probe-dump-eth0"} - -Simple frame generation config file example is: -{"action": "generate", "uid": "aaa-bb-cccccc", - "interfaces": { "eth0": "1-4094"}} - -Full frame generation config file example is: -{ "action": "generate", - "uid": "aaa-bb-cccccc", "cookie": "Some cookie", - "src_mac": "11:22:33:44:55:66", - "src": "10.0.0.1", "dst": "10.255.255.255", - "sport": 4056, "dport": 4057, - "interfaces": { - "eth0": "10, 15, 20, 201-210, 301-310, 1000-2000", - "eth1": "1-4094" - } -} - """ - - parser = argparse.ArgumentParser(epilog=config_examples) - parser.add_argument( - '-c', '--config', dest='config', action='store', type=str, - help='config file', default=None - ) - return parser - - -def define_subparsers(parser): - subparsers = parser.add_subparsers( - dest="action", help='actions' - ) - listen_parser = subparsers.add_parser( - 'listen', help='listen for probe packets' - ) - listen_parser.add_argument( - '-i', '--interface', dest='interface', action='store', type=str, - help='interface to listen on', required=True - ) - listen_parser.add_argument( - '-v', '--vlans', dest='vlan_list', action='store', type=str, - help='vlan list to send tagged packets ("100,200-300")', required=True - ) - listen_parser.add_argument( - '-k', '--cookie', dest='cookie', action='store', type=str, - help='cookie string to insert into probe packets payload', - default='Nailgun:' - ) - listen_parser.add_argument( - '-o', '--file', dest='dump_file', action='store', type=str, - help='file to dump captured packets', default=None - ) - listen_parser.add_argument( - '-a', '--address', dest='ready_address', action='store', type=str, - help='address to report listener ready state', default='localhost' - ) - listen_parser.add_argument( - '-p', '--port', dest='ready_port', action='store', type=int, - help='port to report listener ready state', default=31338 - ) - generate_parser = subparsers.add_parser( - 'generate', help='generate and send probe packets' - ) - generate_parser.add_argument( - '-i', '--interface', dest='interface', action='store', type=str, - help='interface to send packets from', required=True - ) - generate_parser.add_argument( - '-v', '--vlans', dest='vlan_list', action='store', type=str, - help='vlan list to send tagged packets ("100,200-300")', required=True - ) - generate_parser.add_argument( - '-k', '--cookie', dest='cookie', action='store', type=str, - help='cookie string to insert into probe packets payload', - default='Nailgun:' - ) - generate_parser.add_argument( - '-u', '--uid', dest='uid', action='store', type=str, - help='uid to insert into probe packets payload', default='1' - ) - generate_parser.add_argument( - '-d', '--duration', dest='duration', type=int, default=5, - help='Amount of time to generate network packets. In seconds', - ) - generate_parser.add_argument( - '-r', '--repeat', dest='repeat', type=int, default=1, - help='Amount of packets sended in one iteration.', - ) - - -def term_handler(signum, sigframe): - sys.exit() - - -def main(): - signal.signal(signal.SIGTERM, term_handler) - - parser = define_parser() - params, other_params = parser.parse_known_args() - - config = {} - if params.config: - # if config file is set then we discard all other - # command line parameters - try: - if params.config == '-': - fo = sys.stdin - else: - fo = open(params.config, 'r') - config = json.load(fo) - fo.close() - except IOError: - print("Can not read config file %s" % params.config) - exit(1) - except ValueError as e: - print("Can not parse config file: %s" % str(e)) - exit(1) - - else: - define_subparsers(parser) - params, other_params = parser.parse_known_args() - - if params.action == 'listen': - config['action'] = 'listen' - config['interfaces'] = {} - config['interfaces'][params.interface] = params.vlan_list - config['cookie'] = params.cookie - config['ready_address'] = params.ready_address - config['ready_port'] = params.ready_port - if params.dump_file: - config['dump_file'] = params.dump_file - else: - config['dump_file'] = "/var/tmp/net-probe-dump-%s" %\ - config['interface'] - - elif params.action == 'generate': - config['action'] = 'generate' - config['interfaces'] = {} - config['interfaces'][params.interface] = params.vlan_list - config['uid'] = params.uid - config['cookie'] = params.cookie - config['duration'] = params.duration - config['repeat'] = params.repeat - - actor = ActorFabric.getInstance(config) - actor.run() - -if __name__ == "__main__": - main() diff --git a/network_checker/network_checker/net_check/utils.py b/network_checker/network_checker/net_check/utils.py deleted file mode 100644 index c8484cb4b3..0000000000 --- a/network_checker/network_checker/net_check/utils.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -from contextlib import contextmanager -from functools import partial -import logging -import signal - - -log = logging.getLogger(__name__) - - -class TimeoutException(KeyboardInterrupt): - """Exception should be raised if timeout is exceeded.""" - - -def timeout_handler(timeout, signum, frame): - raise TimeoutException("Timeout {0} seconds exceeded".format(timeout)) - - -@contextmanager -def signal_timeout(timeout, raise_exc=True): - """Timeout handling using signals - - :param timeout: timeout in seconds, integer - :param raise_exc: bool to control suppressing of exception - """ - handler = partial(timeout_handler, timeout) - - signal.signal(signal.SIGALRM, handler) - signal.alarm(timeout) - - try: - yield - except TimeoutException as exc: - if raise_exc: - raise - else: - log.warning(str(exc)) - finally: - signal.alarm(0) - signal.signal(signal.SIGALRM, signal.SIG_DFL) diff --git a/network_checker/network_checker/tests/__init__.py b/network_checker/network_checker/tests/__init__.py deleted file mode 100644 index ce4c00840c..0000000000 --- a/network_checker/network_checker/tests/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. diff --git a/network_checker/network_checker/tests/simple.py b/network_checker/network_checker/tests/simple.py deleted file mode 100644 index a08f229332..0000000000 --- a/network_checker/network_checker/tests/simple.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - - -class SimpleChecker(object): - - name = 'simple' - - def send(self): - return 'ready' - - def listen(self): - return 'ready' - - def get_info(self): - return {} diff --git a/network_checker/network_checker/tests/test_multicast.py b/network_checker/network_checker/tests/test_multicast.py deleted file mode 100644 index c167b17196..0000000000 --- a/network_checker/network_checker/tests/test_multicast.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import json -import subprocess -import unittest - -from network_checker.multicast import api as multicast_api - - -class TestMulticastVerification(unittest.TestCase): - - def setUp(self): - self.config_node_112 = {"uid": "112", "group": "225.0.0.250", - "port": 8890} - self.config_node_113 = {"uid": "113", "group": "225.0.0.250", - "port": 8890} - self.mchecker_node_112 = multicast_api.MulticastChecker( - **self.config_node_112) - self.mchecker_node_113 = multicast_api.MulticastChecker( - **self.config_node_113) - - def test_multicast_verification(self): - self.mchecker_node_112.listen() - self.mchecker_node_113.listen() - self.mchecker_node_112.send() - self.mchecker_node_113.send() - - info_node_112 = self.mchecker_node_112.get_info() - info_node_113 = self.mchecker_node_113.get_info() - - self.assertEqual(info_node_112, [u"113", u"112"]) - self.assertEqual(info_node_113, [u"113", u"112"]) - - -class TestSystemMulticastVerification(unittest.TestCase): - - def shell_helper(self, args): - proc = subprocess.Popen(args, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out, err = proc.communicate() - return json.loads(out) - - def test_multicast_verification_with_detach(self): - init_args = ['fuel-netcheck', 'multicast', 'serve', 'listen'] - listen_data = self.shell_helper(init_args) - self.assertIn('uid', listen_data) - - args = ['fuel-netcheck', 'multicast', 'send', 'info'] - info = self.shell_helper(args) - self.assertEqual([listen_data['uid']], info) - - cleanup_args = ['fuel-netcheck', 'multicast', 'clean'] - clean = self.shell_helper(cleanup_args) - self.assertTrue(clean) - - def test_mutlicast_with_config(self): - config = {"uid": "112", "group": "225.0.0.250", - "port": 8890, "iface": "eth0"} - config_json = json.dumps(config) - - init_args = ["fuel-netcheck", "multicast", "serve", - "--config", config_json] - self.shell_helper(init_args) - - args = ['fuel-netcheck', 'multicast', 'listen', 'send', 'info'] - info = self.shell_helper(args) - self.assertEqual([config['uid']], info) - - cleanup_args = ['fuel-netcheck', 'multicast', 'clean'] - clean = self.shell_helper(cleanup_args) - self.assertTrue(clean) diff --git a/network_checker/network_checker/tests/test_net_check.py b/network_checker/network_checker/tests/test_net_check.py deleted file mode 100644 index 0a37089d0a..0000000000 --- a/network_checker/network_checker/tests/test_net_check.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import json -import multiprocessing -import os -import signal -import socket -import time -import unittest - -import pcap -from scapy import all as scapy - -from network_checker.net_check import api - - -class BaseListenerTestCase(unittest.TestCase): - - def setUp(self, config=None): - self.iface = os.environ.get('NET_CHECK_IFACE_1', 'eth1') - default_config = { - "src": "1.0.0.0", "ready_port": None, - "ready_address": "localhost", "dst": "1.0.0.0", - "interfaces": {self.iface: "0,100,101,102,103,104,105,106,107"}, - "action": "listen", - "cookie": "Nailgun:", "dport": 31337, "sport": 31337, - "src_mac": None, "dump_file": "/var/tmp/net-probe-dump" - } - self.config = config or default_config - self.start_socket() - listener = api.Listener(self.config) - self.listener = multiprocessing.Process(target=listener.run) - self.listener.start() - - connection, address = self.ready_socket.accept() - request = connection.recv(1024) - self.assertEqual('READY', request.decode()) - connection.close() - self.ready_socket.shutdown(socket.SHUT_RDWR) - self.ready_socket.close() - - self.send_packets() - os.kill(self.listener.pid, signal.SIGINT) - self.listener.join() - - def start_socket(self): - self.ready_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.ready_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.ready_socket.bind((self.config['ready_address'], 0)) - self.config['ready_port'] = self.ready_socket.getsockname()[1] - self.ready_socket.listen(1) - self.ready_socket.settimeout(5) - - def send_packets(self): - pass - - def tearDown(self): - self.ready_socket.close() - self.listener.terminate() - if os.path.exists(self.config['dump_file']): - os.unlink(self.config['dump_file']) - - -class TestCaseListenerPcap(BaseListenerTestCase): - - def send_packets(self): - for vlan in self.config['interfaces'][self.iface].split(','): - p = self.get_packet(vlan) - for i in xrange(5): - scapy.sendp(p, iface=self.iface) - - def get_packet(self, vlan): - normal_data = 'Nailgun:{iface} 1'.format(iface=self.iface) - p = scapy.Ether(src='64:0b:36:0e:0a:b7', - dst="ff:ff:ff:ff:ff:ff") - if int(vlan) > 0: - p = p / scapy.Dot1Q(vlan=int(vlan)) - message_len = len(normal_data) + 8 - p = p / scapy.IP(src=self.config['src'], dst=self.config['dst']) - p = p / scapy.UDP(sport=self.config['sport'], - dport=self.config['dport'], - len=message_len) / normal_data - return p - - def test_listener_pcap_file(self): - - with open(self.config['dump_file'], 'r') as f: - data = json.loads(f.read()) - - self.assertEqual(data, {self.iface: { - u'0': {u'1': [self.iface]}, - u'102': {u'1': [self.iface]}, - u'103': {u'1': [self.iface]}, - u'100': {u'1': [self.iface]}, - u'101': {u'1': [self.iface]}, - u'106': {u'1': [self.iface]}, - u'107': {u'1': [self.iface]}, - u'104': {u'1': [self.iface]}, - u'105': {u'1': [self.iface]}}}) - - -class TestCaseListenerCorruptedData(BaseListenerTestCase): - - def send_packets(self): - normal_data = 'Nailgun:{iface} 2'.format(iface=self.iface) - corrupted_data = normal_data + '7h 7\00\00\00' - message_len = len(normal_data) + 8 - p = scapy.Ether(src=self.config['src_mac'], - dst="ff:ff:ff:ff:ff:ff") - p = p / scapy.IP(src=self.config['src'], dst=self.config['dst']) - p = p / scapy.UDP(sport=self.config['sport'], - dport=self.config['dport'], - len=message_len) / corrupted_data - for i in xrange(5): - scapy.sendp(p, iface=self.iface) - - def test_listener_corrupted_data(self): - - with open(self.config['dump_file'], 'r') as f: - data = json.loads(f.read()) - - self.assertEqual(data, {self.iface: {u'0': {u'2': [self.iface]}}}) - - -class TestNetCheckSender(unittest.TestCase): - - def setUp(self): - self.iface = os.environ.get('NET_CHECK_IFACE_1', 'eth1') - self.config = { - "src": "1.0.0.0", "ready_port": 31338, - "ready_address": "localhost", "dst": "1.0.0.0", - "interfaces": {self.iface: "0,100,101,102,106,107,108"}, - "action": "listen", - "cookie": "Nailgun:", "dport": 31337, "sport": 31337, - "src_mac": None, - "dump_file": "/var/tmp/net-probe-dump", - "uid": "2" - } - - def start_pcap_listener(self): - self.pcap_listener = pcap.pcap(self.iface) - self.vlan_pcap_listener = pcap.pcap(self.iface) - filter_string = 'udp and dst port {0}'.format(self.config['dport']) - self.vlan_pcap_listener.setfilter('vlan and {0}'.format(filter_string)) - self.pcap_listener.setfilter(filter_string) - - def start_sender(self): - sender = api.Sender(self.config) - self.sender = multiprocessing.Process(target=sender.run) - self.sender.start() - - @property - def pcap_packets(self): - for pkt in self.pcap_listener.readpkts(): - yield pkt - for pkt in self.vlan_pcap_listener.readpkts(): - yield pkt - - @property - def received_vlans(self): - results = set() - for pkt in self.pcap_packets: - ether = scapy.Ether(pkt[1]) - if scapy.Dot1Q in ether: - vlan = str(ether[scapy.Dot1Q].vlan) - else: - vlan = '0' - results.update([vlan]) - return results - - def test_sender(self): - self.start_pcap_listener() - self.start_sender() - time.sleep(3) - self.sender.join() - - expected_vlans = set(self.config['interfaces'][self.iface].split(',')) - self.assertEqual(expected_vlans, self.received_vlans) diff --git a/network_checker/network_checker/xmlrpc.py b/network_checker/network_checker/xmlrpc.py deleted file mode 100644 index 71b0c0e2e3..0000000000 --- a/network_checker/network_checker/xmlrpc.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import httplib -import SimpleXMLRPCServer -import socket -import xmlrpclib - - -class UnixStreamHTTPConnection(httplib.HTTPConnection): - - def connect(self): - self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sock.connect(self.host) - - def getreply(self): - response = self.getresponse() - self.file = response.fp - return response.status, response.reason, response.msg - - def getfile(self): - return self.file - - -class UnixStreamTransport(xmlrpclib.Transport, object): - - def __init__(self, socket_path): - self.socket_path = socket_path - super(UnixStreamTransport, self).__init__() - - def make_connection(self, host): - return UnixStreamHTTPConnection(self.socket_path) - - -class UnixStreamHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): - - # if True leads to calling TCP_NODELAY on AF_UNIX socket - # which results in Errno 95 - disable_nagle_algorithm = False - - -class UnixXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): - - address_family = socket.AF_UNIX - - -def get_client(config): - return xmlrpclib.Server( - 'http://arg_unused', - transport=UnixStreamTransport(config['unix'])) - - -def get_server(config): - return UnixXMLRPCServer( - config['unix'], - requestHandler=UnixStreamHandler, - logRequests=False) diff --git a/network_checker/requirements.txt b/network_checker/requirements.txt deleted file mode 100644 index 39f80c698b..0000000000 --- a/network_checker/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -argparse -cliff-tablib -scapy==2.2.0-dev -pypcap==1.1.1 -stevedore -daemonize -pyyaml -requests -netifaces -six diff --git a/network_checker/run_tests.sh b/network_checker/run_tests.sh deleted file mode 100755 index 2feb0bf065..0000000000 --- a/network_checker/run_tests.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# Copyright 2015 Mirantis, Inc. -# -# 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. - -set -e -set -x - -tox -v - diff --git a/network_checker/setup.py b/network_checker/setup.py deleted file mode 100644 index a03eb01906..0000000000 --- a/network_checker/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# 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. - -import setuptools - - -setuptools.setup( - name="nailgun-net-check", - version='8.0.0', - author="Mirantis Inc", - classifiers=[ - "License :: OSI Approved :: Apache 2.0", - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Operating System :: POSIX", - "Programming Language :: Python", - "Topic :: Software Development :: Testing" - ], - include_package_data=True, - packages=setuptools.find_packages(), - entry_points={ - 'console_scripts': [ - 'net_probe.py = network_checker.net_check.api:main', - 'fuel-netcheck = network_checker.cli:main', - 'dhcpcheck = dhcp_checker.cli:main', - 'urlaccesscheck = url_access_checker.cli:main', - ], - 'dhcp.check': [ - 'discover = dhcp_checker.commands:ListDhcpServers', - 'request = dhcp_checker.commands:ListDhcpAssignment', - 'vlans = dhcp_checker.commands:DhcpWithVlansCheck' - ], - 'network_checker': [ - 'multicast = network_checker.multicast.api:MulticastChecker', - 'simple = network_checker.tests.simple:SimpleChecker' - ], - 'urlaccesscheck': [ - 'check = url_access_checker.commands:CheckUrls', - 'with_setup = url_access_checker.commands:CheckUrlsWithSetup' - ], - }, -) diff --git a/network_checker/specs/nailgun-net-check.spec b/network_checker/specs/nailgun-net-check.spec deleted file mode 100644 index 5647e5c877..0000000000 --- a/network_checker/specs/nailgun-net-check.spec +++ /dev/null @@ -1,41 +0,0 @@ -%define name nailgun-net-check -%{!?version: %define version 8.0.0} -%{!?release: %define release 1} - -Name: %{name} -Summary: Network checking package for CentOS6.x -Version: %{version} -Release: %{release} -License: GPLv2 -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot -URL: http://github.com/Mirantis -Requires: vconfig -Requires: scapy -Requires: python-argparse -Requires: python-pypcap -Requires: python-cliff-tablib -Requires: python-stevedore -Requires: python-daemonize -Requires: python-yaml -Requires: tcpdump -Requires: python-requests -Requires: python-netifaces - -%prep -%setup -cq -n %{name}-%{version} - -%build -cd %{_builddir}/%{name}-%{version}/network_checker && python setup.py build - -%install -cd %{_builddir}/%{name}-%{version}/network_checker && python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=%{_builddir}/%{name}-%{version}/network_checker/INSTALLED_FILES - -%clean -rm -rf $RPM_BUILD_ROOT - -%description -This is a network tool that helps to verify networks connectivity -between hosts in network. - -%files -f %{_builddir}/%{name}-%{version}/network_checker/INSTALLED_FILES -%defattr(-,root,root) diff --git a/network_checker/test-requirements.txt b/network_checker/test-requirements.txt deleted file mode 100644 index 3b89e32b9e..0000000000 --- a/network_checker/test-requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ --r requirements.txt -hacking==0.7 -mock==1.0.1 -pytest -unittest2 -requests-mock diff --git a/network_checker/test_utils/dhcp_relay.conf b/network_checker/test_utils/dhcp_relay.conf deleted file mode 100644 index 0ca9233f23..0000000000 --- a/network_checker/test_utils/dhcp_relay.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Command line options here -DHCRELAYARGS="" -# DHCPv4 only -INTERFACES="eth1" -# DHCPv4 only -DHCPSERVERS="10.10.0.8" \ No newline at end of file diff --git a/network_checker/test_utils/dhcpd.conf.sample b/network_checker/test_utils/dhcpd.conf.sample deleted file mode 100644 index 28ed0af8df..0000000000 --- a/network_checker/test_utils/dhcpd.conf.sample +++ /dev/null @@ -1,12 +0,0 @@ -default-lease-time 600; -max-lease-time 7200; -option subnet-mask 255.255.255.0; -option broadcast-address 192.168.0.255; -option routers 192.168.0.254; -option domain-name-servers 192.168.0.1, 192.168.0.2; -option domain-name "mydomain.org"; - -subnet 192.168.0.0 netmask 255.255.255.0 { - range 192.168.0.10 192.168.0.100; - range 192.168.0.150 192.168.0.200; -} \ No newline at end of file diff --git a/network_checker/test_utils/dhcpd.conf.sample2 b/network_checker/test_utils/dhcpd.conf.sample2 deleted file mode 100644 index 1c979386b5..0000000000 --- a/network_checker/test_utils/dhcpd.conf.sample2 +++ /dev/null @@ -1,12 +0,0 @@ -default-lease-time 600; -max-lease-time 7200; -option subnet-mask 255.255.255.0; -option broadcast-address 10.10.0.255; -option routers 10.10.0.254; -option domain-name-servers 10.10.0.1; -option domain-name "mydomain1.org"; -option dhcp-server-identifier 10.10.0.8; - -subnet 10.10.0.0 netmask 255.255.255.0 { - range 10.10.0.10 10.10.0.100; -} \ No newline at end of file diff --git a/network_checker/tox.ini b/network_checker/tox.ini deleted file mode 100644 index 3b928eec53..0000000000 --- a/network_checker/tox.ini +++ /dev/null @@ -1,37 +0,0 @@ -[tox] -minversion = 1.6 -skipsdist = True -envlist = py26,py27,pep8 - -[testenv] -usedevelop = True -install_command = pip install --allow-external -U {opts} {packages} -setenv = VIRTUAL_ENV={envdir} -deps = -r{toxinidir}/test-requirements.txt -commands = py.test {toxinidir}/url_access_checker/tests - -[tox:jenkins] -downloadcache = ~/cache/pip - -[testenv:pep8] -deps = hacking==0.10 -usedevelop = False -commands = - flake8 {posargs:.} - -[testenv:venv] -commands = {posargs:} - -[testenv:devenv] -envdir = devenv -usedevelop = True - -[flake8] -ignore = H234,H302,H802 -exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools,__init__.py,docs -show-pep8 = True -show-source = True -count = True - -[hacking] -import_exceptions = testtools.matchers diff --git a/network_checker/url_access_checker/__init__.py b/network_checker/url_access_checker/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/network_checker/url_access_checker/api.py b/network_checker/url_access_checker/api.py deleted file mode 100644 index 0af4e5838d..0000000000 --- a/network_checker/url_access_checker/api.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -import json -import os -import socket - -import requests -from six.moves import urllib - -import url_access_checker.errors as errors - - -def check_urls(urls, proxies=None, timeout=60): - """Checks a set of urls to see if they are valid - - Url is valid if - - it returns 200 upon requesting it with http (if it doesn't specify - protocol as "file") - - it is an existing file or directory (if the protocol used in url is - "file") - - Arguments: - urls -- an iterable containing urls for testing - proxies -- proxy servers to use for the request - timeout -- the max time to wait for a response, default 60 seconds - """ - responses = map(lambda u: _get_response_tuple( - u, proxies=proxies, timeout=timeout), urls) - failed_responses = filter(lambda x: x[0], responses) - - if failed_responses: - raise errors.UrlNotAvailable(json.dumps( - {'failed_urls': map(lambda r: r[1], failed_responses)})) - else: - return True - - -def _get_response_tuple(url, proxies=None, timeout=60): - """Return a tuple which contains a result of url test - - Arguments: - url -- a string containing url for testing, can be local file - proxies -- proxy servers to use for the request - timeout -- the max time to wait for a response, default 60 seconds - - Result tuple content: - result[0] -- boolean value, True if the url is deemed failed - result[1] -- unchange url argument - """ - - parsed = urllib.parse.urlparse(url) - if parsed.scheme == 'file': - return _get_file_existence_tuple(url) - elif parsed.scheme in ['http', 'https']: - return _get_http_response_tuple(url, proxies, timeout) - elif parsed.scheme == 'ftp': - return _get_ftp_response_tuple(url, timeout) - else: - raise errors.InvalidProtocol(url) - - -def _get_file_existence_tuple(url): - path = url[len('file://'):] - return (not os.path.exists(path), url) - - -def _get_http_response_tuple(url, proxies=None, timeout=60): - try: - # requests seems to correctly handle various corner cases: - # proxies=None or proxies={} mean 'use the default' rather than - # "don't use proxy". To force a direct connection one should pass - # proxies={'http': None}. - # Setting the timeout for requests.get(...) sets max request time. We - # want to set a value to prevent this process from hanging as the - # default timeout is None which can lead to bad things when processes - # never exit. LP#1478138 - response = requests.get(url, proxies=proxies, timeout=timeout) - return (response.status_code != 200, url) - except (requests.exceptions.ConnectionError, - requests.exceptions.Timeout, - requests.exceptions.HTTPError, - requests.exceptions.ProxyError, - ValueError, - socket.timeout): - return (True, url) - - -def _get_ftp_response_tuple(url, timeout=60): - """Return a tuple which contains a result of ftp url test - - It will try to open ftp url as anonymous user and return (True, url) if - any errors occur, or return (False, url) otherwise. - """ - try: - # NOTE(mkwiek): requests don't have tested ftp adapter yet, so - # lower level urllib2 is used here - urllib.request.urlopen(url, timeout=timeout) - return (False, url) - except urllib.error.URLError: - return (True, url) diff --git a/network_checker/url_access_checker/cli.py b/network_checker/url_access_checker/cli.py deleted file mode 100644 index 5690d32cb3..0000000000 --- a/network_checker/url_access_checker/cli.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -import os -import sys -# fixed in cmd2 >=0.6.6 -os.environ['EDITOR'] = '/usr/bin/nano' - -from cliff.commandmanager import CommandManager - -from fuel_network_checker import base_app - - -class UrlAccessCheckApp(base_app.BaseApp): - LOG_FILENAME = '/var/log/url_access_checker.log' - - def __init__(self): - super(UrlAccessCheckApp, self).__init__( - description='Url access check application', - version='0.1', - command_manager=CommandManager('urlaccesscheck'), - ) - - -def main(argv=sys.argv[1:]): - myapp = UrlAccessCheckApp() - return myapp.run(argv) - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/network_checker/url_access_checker/commands.py b/network_checker/url_access_checker/commands.py deleted file mode 100644 index 28797e0fb7..0000000000 --- a/network_checker/url_access_checker/commands.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -import logging -import sys - -from cliff import command - -import url_access_checker.api as api -import url_access_checker.errors as errors -from url_access_checker.network import manage_network - - -LOG = logging.getLogger(__name__) - - -class CheckUrls(command.Command): - """Check if it is possible to retrieve urls.""" - def get_parser(self, prog_name): - parser = super(CheckUrls, self).get_parser(prog_name) - parser.add_argument('urls', type=str, nargs='+', - help='List of urls to check') - parser.add_argument('--timeout', type=int, default=60, - help='Max time to wait for response, Default: 60') - return parser - - def take_action(self, parsed_args): - LOG.info('Starting url access check for {0}'.format(parsed_args.urls)) - try: - api.check_urls(parsed_args.urls, timeout=parsed_args.timeout) - except errors.UrlNotAvailable as e: - sys.stdout.write(str(e)) - raise e - - -class CheckUrlsWithSetup(CheckUrls): - - def get_parser(self, prog_name): - parser = super(CheckUrlsWithSetup, self).get_parser( - prog_name) - parser.add_argument('-i', type=str, help='Interface', required=True) - parser.add_argument('-a', type=str, help='Addr/Mask pair', - required=True) - parser.add_argument('-g', type=str, required=True, - help='Gateway to be used as default') - parser.add_argument('--vlan', type=int, help='Vlan tag') - return parser - - def take_action(self, pa): - with manage_network(pa.i, pa.a, pa.g, pa.vlan): - return super( - CheckUrlsWithSetup, self).take_action(pa) diff --git a/network_checker/url_access_checker/errors.py b/network_checker/url_access_checker/errors.py deleted file mode 100644 index f2b184c132..0000000000 --- a/network_checker/url_access_checker/errors.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - - -class UrlNotAvailable(Exception): - pass - - -class CommandFailed(Exception): - pass - - -class InvalidProtocol(Exception): - pass diff --git a/network_checker/url_access_checker/network.py b/network_checker/url_access_checker/network.py deleted file mode 100644 index 97f3814ef4..0000000000 --- a/network_checker/url_access_checker/network.py +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -from contextlib import contextmanager -from logging import getLogger - -import netifaces - -from url_access_checker.errors import CommandFailed -from url_access_checker.utils import execute - - -logger = getLogger(__name__) - - -def get_default_gateway(): - """Return ipaddress, interface pair for default gateway""" - gws = netifaces.gateways() - if 'default' in gws: - return gws['default'][netifaces.AF_INET] - return None, None - - -def check_ifaddress_present(iface, addr): - """Check if required ipaddress already assigned to the iface""" - for ifaddress in netifaces.ifaddresses(iface).get(netifaces.AF_INET, []): - if ifaddress['addr'] in addr: - return True - return False - - -def check_exist(iface): - rc, _, err = execute(['ip', 'link', 'show', iface]) - if rc == 1 and 'does not exist' in err: - return False - elif rc: - msg = 'ip link show {0} failed with {1}'.format(iface, err) - raise CommandFailed(msg) - return True - - -def check_up(iface): - rc, stdout, _ = execute(['ip', 'link', 'show', iface]) - return 'UP' in stdout - - -def log_network_info(stage): - logger.info('Logging networking info at %s', stage) - stdout = execute(['ip', 'a'])[1] - logger.info('ip a: %s', stdout) - stdout = execute(['ip', 'ro'])[1] - logger.info('ip ro: %s', stdout) - - -class Eth(object): - - def __init__(self, iface): - self.iface = iface - self.is_up = None - - def setup(self): - self.is_up = check_up(self.iface) - if self.is_up is False: - rc, out, err = execute(['ip', 'link', 'set', - 'dev', self.iface, 'up']) - if rc: - msg = 'Cannot up interface {0}. Err: {1}'.format( - self.iface, err) - raise CommandFailed(msg) - - def teardown(self): - if self.is_up is False: - execute(['ip', 'link', 'set', 'dev', self.iface, 'down']) - - -class Vlan(Eth): - - def __init__(self, iface, vlan): - self.parent = iface - self.vlan = str(vlan) - self.iface = '{0}.{1}'.format(iface, vlan) - self.is_present = None - self.is_up = None - - def setup(self): - self.is_present = check_exist(self.iface) - if self.is_present is False: - rc, out, err = execute( - ['ip', 'link', 'add', - 'link', self.parent, 'name', - self.iface, 'type', 'vlan', 'id', self.vlan]) - - if rc: - msg = ( - 'Cannot create tagged interface {0}.' - ' With parent {1}. Err: {2}'.format( - self.iface, self.parent, err)) - raise CommandFailed(msg) - super(Vlan, self).setup() - - def teardown(self): - super(Vlan, self).teardown() - if self.is_present is False: - execute(['ip', 'link', 'delete', self.iface]) - - -class IP(object): - - def __init__(self, iface, addr): - self.iface = iface - self.addr = addr - self.is_present = None - - def setup(self): - self.is_present = check_ifaddress_present(self.iface, self.addr) - if self.is_present is False: - rc, out, err = execute(['ip', 'a', 'add', self.addr, - 'dev', self.iface]) - if rc: - msg = 'Cannot add address {0} to {1}. Err: {2}'.format( - self.addr, self.iface, err) - raise CommandFailed(msg) - - def teardown(self): - if self.is_present is False: - execute(['ip', 'a', 'del', self.addr, 'dev', self.iface]) - - -class Route(object): - - def __init__(self, iface, gateway): - self.iface = iface - self.gateway = gateway - self.default_gateway = None - self.df_iface = None - - def setup(self): - self.default_gateway, self.df_iface = get_default_gateway() - - rc = None - if (self.default_gateway, self.df_iface) == (None, None): - rc, out, err = execute( - ['ip', 'ro', 'add', - 'default', 'via', self.gateway, 'dev', self.iface]) - elif ((self.default_gateway, self.df_iface) - != (self.gateway, self.iface)): - rc, out, err = execute( - ['ip', 'ro', 'change', - 'default', 'via', self.gateway, 'dev', self.iface]) - - if rc: - msg = ('Cannot add default gateway {0} on iface {1}.' - ' Err: {2}'.format(self.gateway, self.iface, err)) - raise CommandFailed(msg) - - def teardown(self): - if (self.default_gateway, self.df_iface) == (None, None): - execute(['ip', 'ro', 'del', - 'default', 'via', self.gateway, 'dev', self.iface]) - elif ((self.default_gateway, self.df_iface) - != (self.gateway, self.iface)): - execute(['ip', 'ro', 'change', - 'default', 'via', self.default_gateway, - 'dev', self.df_iface]) - - -@contextmanager -def manage_network(iface, addr, gateway, vlan=None): - - log_network_info('before setup') - - actions = [Eth(iface)] - if vlan: - vlan_action = Vlan(iface, vlan) - actions.append(vlan_action) - iface = vlan_action.iface - actions.append(IP(iface, addr)) - actions.append(Route(iface, gateway)) - executed = [] - - try: - for a in actions: - a.setup() - executed.append(a) - - log_network_info('after setup') - - yield - except Exception: - logger.exception('Unexpected failure.') - raise - finally: - for a in reversed(executed): - a.teardown() - - log_network_info('after teardown') diff --git a/network_checker/url_access_checker/tests/unit/__init__.py b/network_checker/url_access_checker/tests/unit/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/network_checker/url_access_checker/tests/unit/test_api.py b/network_checker/url_access_checker/tests/unit/test_api.py deleted file mode 100644 index f55a0abba7..0000000000 --- a/network_checker/url_access_checker/tests/unit/test_api.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -import unittest2 - -import mock -import requests_mock - -from url_access_checker import api -from url_access_checker import errors - - -class TestApi(unittest2.TestCase): - - def setUp(self): - self.urls = ['http://url{0}'.format(i) for i in range(10)] - self.paths = ['file:///tmp/test_api{0}'.format(i) for i in range(10)] - self.ftps = ['ftp://url{0}'.format(i) for i in range(10)] - - @requests_mock.Mocker() - def test_check_urls(self, req_mocker): - for url in self.urls: - req_mocker.get(url, status_code=200) - - check_result = api.check_urls(self.urls) - - self.assertTrue(check_result) - - @requests_mock.Mocker() - def test_check_urls_fail(self, req_mocker): - for url in self.urls: - req_mocker.get(url, status_code=404) - - with self.assertRaises(errors.UrlNotAvailable): - api.check_urls(self.urls) - - @mock.patch('os.path.exists') - def test_check_paths(self, mock_exists): - mock_exists.return_value = True - check_result = api.check_urls(self.paths) - - self.assertTrue(check_result) - - @mock.patch('os.path.exists') - def test_check_paths_fail(self, mock_exists): - mock_exists.return_value = False - with self.assertRaises(errors.UrlNotAvailable): - api.check_urls(self.paths) - - @mock.patch('urllib2.urlopen') - def test_check_ftp(self, _): - check_result = api.check_urls(self.ftps, timeout=5) - self.assertTrue(check_result) - - def test_check_ftp_fail(self): - with self.assertRaises(errors.UrlNotAvailable): - api.check_urls(self.paths) diff --git a/network_checker/url_access_checker/tests/unit/test_commands.py b/network_checker/url_access_checker/tests/unit/test_commands.py deleted file mode 100644 index b8836cc20b..0000000000 --- a/network_checker/url_access_checker/tests/unit/test_commands.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -import unittest - -import mock - -from url_access_checker import cli - - -class TestUrlCheckerCommands(unittest.TestCase): - - def setUp(self): - self.urls = ['http://url{0}'.format(i) for i in range(10)] - - @mock.patch('requests.get') - def test_check_urls_success(self, get_mock): - response_mock = mock.Mock() - response_mock.status_code = 200 - get_mock.return_value = response_mock - - exit_code = cli.main(['check'] + self.urls) - self.assertEqual(exit_code, 0) - - @mock.patch('requests.get') - def test_check_urls_fail(self, get_mock): - response_mock = mock.Mock() - response_mock.status_code = 404 - get_mock.return_value = response_mock - - exit_code = cli.main(['check'] + self.urls) - self.assertEqual(exit_code, 1) - - def test_check_urls_fail_on_requests_error(self): - exit_code = cli.main(['check'] + self.urls) - self.assertEqual(exit_code, 1) diff --git a/network_checker/url_access_checker/tests/unit/test_with_network_setup.py b/network_checker/url_access_checker/tests/unit/test_with_network_setup.py deleted file mode 100644 index 90bf8e49ed..0000000000 --- a/network_checker/url_access_checker/tests/unit/test_with_network_setup.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -import unittest - -from mock import call -from mock import Mock -from mock import patch -import netifaces - -from url_access_checker import cli - - -@patch('url_access_checker.network.execute') -@patch('url_access_checker.network.netifaces.gateways') -@patch('requests.get', Mock(status_code=200)) -@patch('url_access_checker.network.check_up') -@patch('url_access_checker.network.check_exist') -@patch('url_access_checker.network.check_ifaddress_present') -class TestVerificationWithNetworkSetup(unittest.TestCase): - - def assert_by_items(self, expected_items, received_items): - """In case of failure will show difference only for failed item.""" - for expected, executed in zip(expected_items, received_items): - self.assertEqual(expected, executed) - - def test_verification_route(self, mifaddr, mexist, mup, mgat, mexecute): - mexecute.return_value = (0, '', '') - mup.return_value = True - mexist.return_value = True - mifaddr.return_value = False - - default_gw, default_iface = '172.18.0.1', 'eth2' - mgat.return_value = { - 'default': {netifaces.AF_INET: (default_gw, default_iface)}} - - iface = 'eth1' - addr = '10.10.0.2/24' - gw = '10.10.0.1' - - cmd = ['with', 'setup', '-i', iface, - '-a', addr, '-g', gw, 'test.url'] - - cli.main(cmd) - - execute_stack = [ - call(['ip', 'a']), - call(['ip', 'ro']), - call(['ip', 'a', 'add', addr, 'dev', iface]), - call(['ip', 'ro', 'change', 'default', 'via', gw, 'dev', iface]), - call(['ip', 'a']), - call(['ip', 'ro']), - call(['ip', 'ro', 'change', 'default', 'via', default_gw, - 'dev', default_iface]), - call(['ip', 'a', 'del', addr, 'dev', iface]), - call(['ip', 'a']), - call(['ip', 'ro'])] - - self.assert_by_items(mexecute.call_args_list, execute_stack) - - def test_verification_vlan(self, mifaddr, mexist, mup, mgat, mexecute): - mexecute.return_value = (0, '', '') - mup.return_value = False - mexist.return_value = False - mifaddr.return_value = False - - default_gw, default_iface = '172.18.0.1', 'eth2' - mgat.return_value = { - 'default': {netifaces.AF_INET: (default_gw, default_iface)}} - - iface = 'eth1' - addr = '10.10.0.2/24' - gw = '10.10.0.1' - vlan = '101' - tagged_iface = '{0}.{1}'.format(iface, vlan) - - cmd = ['with', 'setup', '-i', iface, - '-a', addr, '-g', gw, '--vlan', vlan, 'test.url'] - - cli.main(cmd) - - execute_stack = [ - call(['ip', 'a']), - call(['ip', 'ro']), - call(['ip', 'link', 'set', 'dev', iface, 'up']), - call(['ip', 'link', 'add', 'link', 'eth1', 'name', - tagged_iface, 'type', 'vlan', 'id', vlan]), - call(['ip', 'link', 'set', 'dev', tagged_iface, 'up']), - call(['ip', 'a', 'add', addr, 'dev', tagged_iface]), - call(['ip', 'ro', 'change', 'default', - 'via', gw, 'dev', tagged_iface]), - call(['ip', 'a']), - call(['ip', 'ro']), - call(['ip', 'ro', 'change', 'default', 'via', - default_gw, 'dev', default_iface]), - call(['ip', 'a', 'del', addr, 'dev', tagged_iface]), - call(['ip', 'link', 'set', 'dev', tagged_iface, 'down']), - call(['ip', 'link', 'delete', tagged_iface]), - call(['ip', 'link', 'set', 'dev', iface, 'down']), - call(['ip', 'a']), - call(['ip', 'ro'])] - - self.assert_by_items(mexecute.call_args_list, execute_stack) diff --git a/network_checker/url_access_checker/utils.py b/network_checker/url_access_checker/utils.py deleted file mode 100644 index bfdd23a28d..0000000000 --- a/network_checker/url_access_checker/utils.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# 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. - -from logging import getLogger -import subprocess - -logger = getLogger(__name__) - - -def execute(cmd): - logger.debug('Executing command %s', cmd) - command = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = command.communicate() - msg = 'Command {0} executed. RC {1}, stdout {2}, stderr {3}'.format( - cmd, command.returncode, stdout, stderr) - if command.returncode: - logger.error(msg) - else: - logger.debug(msg) - return command.returncode, stdout, stderr diff --git a/run_tests.sh b/run_tests.sh index 019cc5e765..bad2b2009c 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -399,7 +399,6 @@ function run_extensions_tests { function run_flake8 { local result=0 run_flake8_subproject nailgun && \ - run_flake8_subproject network_checker && \ run_flake8_subproject fuel_upgrade_system/fuel_upgrade && \ run_flake8_subproject fuel_upgrade_system/fuel_package_updates && \ return $result diff --git a/specs/fuel-nailgun.spec b/specs/fuel-nailgun.spec index af8df1c0ef..e77fa8cff0 100644 --- a/specs/fuel-nailgun.spec +++ b/specs/fuel-nailgun.spec @@ -116,12 +116,10 @@ cd %{_builddir}/%{name}-%{version}/nailgun && %{_builddir}/%{name}-%{version}/na [ -n %{_builddir} ] && rm -rf %{_builddir}/%{name}-%{version}/nailgun/static mv %{_builddir}/%{name}-%{version}/nailgun/compressed_static %{_builddir}/%{name}-%{version}/nailgun/static cd %{_builddir}/%{name}-%{version}/nailgun && python setup.py build -cd %{_builddir}/%{name}-%{version}/network_checker && python setup.py build cd %{_builddir}/%{name}-%{version}/fuel_upgrade_system/fuel_package_updates && python setup.py build %install cd %{_builddir}/%{name}-%{version}/nailgun && python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=%{_builddir}/%{name}-%{version}/nailgun/INSTALLED_FILES -cd %{_builddir}/%{name}-%{version}/network_checker && python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=%{_builddir}/%{name}-%{version}/network_checker/INSTALLED_FILES cd %{_builddir}/%{name}-%{version}/fuel_upgrade_system/fuel_package_updates && python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=%{_builddir}/%{name}-%{version}/fuel_upgrade_system/fuel_package_updates/INSTALLED_FILES mkdir -p %{buildroot}/opt/nailgun/bin mkdir -p %{buildroot}/etc/cron.d @@ -155,35 +153,6 @@ This package currently installs just a single file openstack.yaml %{_datadir}/fuel-openstack-metadata/* %{_sysconfdir}/fuel_openstack_version -%package -n nailgun-net-check - -Summary: Network checking package for CentOS6.x -Version: %{version} -Release: %{release} -License: GPLv2 -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot -URL: http://github.com/Mirantis -Requires: vconfig -Requires: scapy -Requires: python-argparse -Requires: python-pypcap -Requires: python-cliff-tablib -Requires: python-stevedore -Requires: python-daemonize -Requires: python-yaml -Requires: tcpdump -Requires: python-requests -Requires: python-netifaces - - -%description -n nailgun-net-check -This is a network tool that helps to verify networks connectivity -between hosts in network. - -%files -n nailgun-net-check -f %{_builddir}/%{name}-%{version}/network_checker/INSTALLED_FILES -%defattr(-,root,root) - - %package -n fencing-agent Summary: Fencing agent Version: %{version}