Add script and playbook to test dhcp

It will run a play where it will spin up five vms, and will
truncate inventory to consider only three. The play will
configure dns using dynamic inventory, and will take an
extra parameter to specify if we want static ips or not.
It will perform a test on dnsmasq leases file, to ensure that
the dhcp behaviour is working as expected, depending on
the settings.

Change-Id: If56488f78524ceba201b50f76df306620744cda5
This commit is contained in:
Yolanda Robla 2016-02-04 12:35:03 +01:00
parent 87a44986b6
commit a93a1e6b61
10 changed files with 376 additions and 0 deletions

View File

@ -25,6 +25,8 @@
- name: "Remove testvm hosts from SSH known_hosts file." - name: "Remove testvm hosts from SSH known_hosts file."
command: ssh-keygen -R "{{ ipv4_address }}" command: ssh-keygen -R "{{ ipv4_address }}"
when: ipv4_address is defined when: ipv4_address is defined
- name: "Pause before asking for keyscan, to avoid races"
pause: minutes=2
- name: "Add testvm hosts from SSH known_hosts file." - name: "Add testvm hosts from SSH known_hosts file."
shell: ssh-keyscan "{{ ipv4_address }}" >> "{{ ansible_env.HOME }}/.ssh/known_hosts" shell: ssh-keyscan "{{ ipv4_address }}" >> "{{ ansible_env.HOME }}/.ssh/known_hosts"
when: ipv4_address is defined when: ipv4_address is defined

View File

@ -0,0 +1,54 @@
bifrost-test-dhcp
=================
Perform checks on dnsmasq generated files to ensure that it
behaves as expected on bifrost.
Requirements
------------
None at this time. See Dependencies.
Role Variables
--------------
None at this time. See Dependencies.
Dependencies
------------
This role is intended to be executed as part of bifrost, as part
of bifrost-test-dhcp scripts.
Example Playbook
----------------
hosts: localhost
name: "Tests DCHP settings"
become: no
gather_facts: yes
remote_user: root
roles:
- role: bifrost-test-dhcp
License
-------
Copyright (c) 2016 Hewlett-Packard Enterprise Development Company LP
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.
Author Information
------------------
Infra-cloud Developers

View File

@ -0,0 +1,2 @@
---
# defaults file for bifrost-test-dhcp

View File

@ -0,0 +1,97 @@
#!/usr/bin/env python
#
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company LP
#
# 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 __future__ import print_function
import csv
import os
import sys
def main(argv):
# first item is the inventory_dhcp setting
# second item is the inventory_dhcp_static_ip setting
inventory_dhcp = (argv[0] == 'True' or argv[0] == 'true')
inventory_dhcp_static_ip = (argv[1] == 'True' or argv[1] == 'true')
if not inventory_dhcp:
# nothing to validate
sys.exit(0)
# extract data from csv file
inventory = []
if not os.path.exists('/tmp/baremetal.csv'):
print('ERROR: Inventory file has not been generated')
sys.exit(1)
with open('/tmp/baremetal.csv') as csvfile:
inventory_reader = csv.reader(csvfile)
for row in inventory_reader:
inventory.append(row)
# now check that we only have these entries in leases file
leases = []
if not os.path.exists('/var/lib/misc/dnsmasq.leases'):
print('ERROR: dnsmasq leases file has not been generated')
sys.exit(1)
with open('/var/lib/misc/dnsmasq.leases') as csvfile:
leases_reader = csv.reader(csvfile, delimiter=' ')
for row in leases_reader:
leases.append(row)
# first we test number of entries
if len(leases) != len(inventory):
print('ERROR: Number of entries do not match with inventory')
sys.exit(1)
# then we check that all macs and hostnames are present
for entry in inventory:
mac = entry[0]
hostname = entry[10]
ip = entry[11]
# mac check
found = False
for lease_entry in leases:
if lease_entry[1] == mac:
found = True
break
if not found:
print('ERROR: No mac found in leases')
sys.exit(1)
# hostname check
found = False
for lease_entry in leases:
if lease_entry[3] == hostname:
found = True
# if we use static ip, we need to check that ip matches
# with hostname in leases
if inventory_dhcp_static_ip:
if lease_entry[2] != ip:
print('ERROR: IP does not match with inventory')
sys.exit(1)
break
if not found:
print('ERROR: No hostname found in leases')
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main(sys.argv[1:])

View File

@ -0,0 +1,3 @@
---
# handlers file for bifrost-test-dhcp

View File

@ -0,0 +1,15 @@
---
galaxy_info:
author: Infra-cloud Developers
description: Basic dnsmasq checks created by Bifrost.
company: OpenStack
license: Apache
min_ansible_version: 1.9
platforms:
- name: Ubuntu
versions:
- trusty
categories:
- cloud
- cloud:openstack
dependencies: []

View File

@ -0,0 +1,17 @@
# Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
#
# 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.
---
- name: Execute python dhcp check file
become: true
script: test-dhcp.py "{{inventory_dhcp}}" "{{inventory_dhcp_static_ip}}"

View File

@ -0,0 +1,2 @@
---
# vars file for bifrost-test-dhcp

View File

@ -0,0 +1,118 @@
# Example command line to use:
# Create a VM:
# ansible-playbook -vvvv -i inventory/localhost test-bifrost-dhcp.yaml
# Set BIFROST_INVENTORY_SOURCE
# export BIFROST_INVENTORY_SOURCE=/tmp/baremetal.csv
# Execute the installation and VM startup test.
# ansible-playbook -vvvv -i inventory/bifrost_inventory.py test-bifrost-dhcp.yaml -e use_cirros=true -e testing_user=cirros
---
- hosts: localhost
connection: local
name: "Remove existing leases file"
become: yes
ignore_errors: yes
tasks:
- command: rm /var/lib/misc/dnsmasq.leases
- hosts: localhost
connection: local
name: "Executes install, enrollment, and testing in one playbook"
become: no
gather_facts: yes
pre_tasks:
- name: "Set ci_testing_zuul if it appears we are running in upstream OpenStack CI"
set_fact:
ci_testing: true
ci_testing_zuul: true
ironic_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/ironic"
ironicclient_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/python-ironicclient"
shade_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack-infra/shade"
dib_git_url: "/opt/git/openstack/diskimage-builder"
# TODO(TheJulia) Fix the above paths to be consistent, because the NV job gets the dib
# folder cloned, while the gate job does not. Likely need to work out a semi-hybrid
# solution.
when: lookup('env', 'ZUUL_BRANCH') | length > 0
- name: "Set ci_testing_zuul_changes if ZUUL_CHANGES is set"
set_fact:
ci_testing_zuul_changes: true
when: lookup('env', 'ZUUL_CHANGES') | length > 0
- name: "Override the ipv4_gateway setting"
set_fact:
ipv4_gateway: "192.168.122.1"
roles:
- { role: bifrost-prep-for-install, when: skip_install is not defined }
- { role: bifrost-openstack-ci-prep, when: ci_testing_zuul is defined }
environment:
http_proxy: "{{ lookup('env','http_proxy') }}"
https_proxy: "{{ lookup('env','https_proxy') }}"
- hosts: localhost
connection: local
name: "Executes install, enrollment, and testing in one playbook"
become: yes
gather_facts: yes
vars:
inventory_dhcp: "{{ inventory_dhcp | bool }}"
roles:
- role: bifrost-ironic-install
cleaning: false
testing: true
# NOTE(TheJulia): While the next step creates a ramdisk, some elements
# do not support ramdisk-image-create as they invoke steps to cleanup
# the ramdisk which causes ramdisk-image-create to believe it failed.
- { role: bifrost-create-dib-image, dib_imagename: "{{ http_boot_folder }}/ipa", build_ramdisk: false, dib_os_element: "{{ ipa_dib_os_element|default('debian') }}", dib_os_release: "jessie", dib_elements: "ironic-agent {{ ipa_extra_dib_elements | default('') }}", when: create_ipa_image | bool == true }
- { role: bifrost-create-dib-image, dib_imagetype: "qcow2", dib_imagename: "{{deploy_image}}", dib_os_element: "debian", dib_os_release: "jessie", dib_elements: "vm serial-console simple-init {{ extra_dib_elements|default('') }}", when: create_image_via_dib == true and transform_boot_image == false }
environment:
http_proxy: "{{ lookup('env','http_proxy') }}"
https_proxy: "{{ lookup('env','https_proxy') }}"
- hosts: baremetal
name: "Enroll node with Ironic"
become: no
connection: local
roles:
- role: ironic-enroll-dynamic
- { role: ironic-inspect-node, when: inspect_nodes | default('false') | bool }
- hosts: baremetal
vars:
inventory_dhcp_static_ip: "{{ inventory_dhcp_static_ip | bool }}"
name: "Creat configuration drive files and deploy machines."
become: no
connection: local
roles:
- role: bifrost-configdrives-dynamic
- role: bifrost-deploy-nodes-dynamic
- role: bifrost-prepare-for-test-dynamic
serial: 1
# The testvm Host group is added by bifrost-prepare-for-test based
# on the contents of the CSV file.
- hosts: test
name: "Tests connectivity to the VM"
become: no
gather_facts: no
remote_user: "{{ testing_user }}"
serial: 1
any_errors_fatal: yes
max_fail_percentage: 0
roles:
- role: bifrost-test-vm
- hosts: localhost
connection: local
name: "Executes test script"
become: yes
gather_facts: yes
vars:
inventory_dhcp: "{{ inventory_dhcp | bool }}"
inventory_dhcp_static_ip: "{{ inventory_dhcp_static_ip | bool }}"
roles:
- role: bifrost-test-dhcp
cleaning: false
testing: true
environment:
http_proxy: "{{ lookup('env','http_proxy') }}"
https_proxy: "{{ lookup('env','https_proxy') }}"
- hosts: baremetal
connection: local
name: "Unprovisions the test node"
become: no
gather_facts: no
roles:
- role: bifrost-unprovision-node-dynamic
- role: ironic-delete-dynamic

View File

@ -0,0 +1,66 @@
#!/bin/bash
# Note(TheJulia): If there is a workspace variable, we want to utilize that as
# the preference of where to put logs
LOG_LOCATION="${WORKSPACE:-..}/logs"
set -eux
set -o pipefail
export PYTHONUNBUFFERED=1
SCRIPT_HOME="$(cd "$(dirname "$0")" && pwd)"
BIFROST_HOME=$SCRIPT_HOME/..
# Install Ansible
$SCRIPT_HOME/env-setup.sh
# Source Ansible
# NOTE(TheJulia): Ansible stable-1.9 source method tosses an error deep
# under the hood which -x will detect, so for this step, we need to suspend
# and then re-enable the feature.
set +x
source /opt/stack/ansible/hacking/env-setup
set -x
# Change working directory
cd $BIFROST_HOME/playbooks
# Syntax check of dynamic inventory test path
ansible-playbook -vvvv -i inventory/localhost test-bifrost-create-vm.yaml --syntax-check --list-tasks
ansible-playbook -vvvv -i inventory/localhost test-bifrost-dynamic.yaml --syntax-check --list-tasks
# Create the test VMS
ansible-playbook -vvvv -i inventory/localhost test-bifrost-create-vm.yaml -e test_vm_num_nodes="5" -e test_vm_memory_size="512"
# cut file
head -n -2 /tmp/baremetal.csv > /tmp/baremetal.csv.new && mv /tmp/baremetal.csv.new /tmp/baremetal.csv
set +e
# Set BIFROST_INVENTORY_SOURCE
export BIFROST_INVENTORY_SOURCE=/tmp/baremetal.csv
# Execute the installation and VM startup test.
# NOTE(TheJulia): The variables defined on the command line are to
# drive the use of Cirros as the deployed operating system, and
# as such sets the test user to cirros, and writes a debian style
# interfaces file out to the configuration drive as cirros does
# not support the network_info.json format file placed in the
# configuration drive.
ansible-playbook -vvvv \
-i inventory/bifrost_inventory.py \
test-bifrost-dhcp.yaml \
-e use_cirros=true \
-e testing_user=cirros \
-e inventory_dhcp=true \
-e inventory_dhcp_static_ip=true
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
echo "****************************"
echo "Test failed. See logs folder"
echo "****************************"
fi
$SCRIPT_HOME/collect-test-info.sh
exit $EXITCODE