Browse Source

Fix Eoan.

Moved to pure Python where clib conflicts arose in using command line
tools.

Fixed erroneous assumptions about the presence and reliability of a
$HOME variable while running init.

Added tests specific to eoan, disco and xenial. They are not yet part
of the gate.

Change-Id: I2fc74fcc2ae9876442bb87a3446aef48d0428f2f
changes/44/692944/1
Pete Vander Giessen 2 years ago
parent
commit
cb940157ab
7 changed files with 188 additions and 26 deletions
  1. +3
    -4
      snapcraft.yaml
  2. +2
    -1
      tests/framework.py
  3. +52
    -1
      tests/test_basic.py
  4. +9
    -13
      tools/init/init/questions/__init__.py
  5. +5
    -7
      tools/init/init/shell.py
  6. +85
    -0
      tools/update_path.py
  7. +32
    -0
      tox.ini

+ 3
- 4
snapcraft.yaml View File

@ -8,8 +8,9 @@ description: |
grade: stable
confinement: classic
environment:
LD_LIBRARY_PATH: $SNAP/lib:$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET
PATH: $SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:/snap/core18/current/bin:$PATH
# Edit the following lines with tools/update_path.py
LD_LIBRARY_PATH: $SNAP/lib:$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio
PATH: $SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH
LC_ALL: C
OS_PLACEMENT_CONFIG_DIR: $SNAP/etc/nova/
@ -219,8 +220,6 @@ apps:
libvirtd:
command: libvirtd
daemon: simple
environment:
LD_LIBRARY_PATH: $SNAP/lib:$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio
virtlogd:
command: virtlogd
daemon: simple


+ 2
- 1
tests/framework.py View File

@ -72,10 +72,11 @@ class Framework(unittest.TestCase):
self.MACHINE = petname.generate()
self.PREFIX = ['multipass', 'exec', self.MACHINE, '--']
distro = os.environ.get('DISTRO') or self.DISTRO
check('sudo', 'snap', 'install', '--classic', '--edge', 'multipass')
check('multipass', 'launch', '--cpus', '2', '--mem', '8G', self.DISTRO,
check('multipass', 'launch', '--cpus', '2', '--mem', '8G', distro,
'--name', self.MACHINE)
check('multipass', 'copy-files', self.SNAP, '{}:'.format(self.MACHINE))


+ 52
- 1
tests/test_basic.py View File

@ -14,8 +14,10 @@ Web IDE.
"""
import json
import os
import sys
import time
import unittest
import xvfbwrapper
from selenium import webdriver
@ -50,7 +52,7 @@ class TestBasics(Framework):
"""
launch = '/snap/bin/microstack.launch'
# openstack = '/snap/bin/microstack.openstack'
openstack = '/snap/bin/microstack.openstack'
print("Testing microstack.launch ...")
@ -66,6 +68,55 @@ class TestBasics(Framework):
# Endpoints should not contain localhost
self.assertFalse("localhost" in endpoints)
if 'multipass' in self.PREFIX:
# Verify that microstack.launch completed successfully
# Skip these tests in the gate, as they are not reliable there.
# TODO: fix these in the gate!
# Ping the instance
ip = None
servers = check_output(*self.PREFIX, openstack,
'server', 'list', '--format', 'json')
servers = json.loads(servers)
for server in servers:
if server['Name'] == 'breakfast':
ip = server['Networks'].split(",")[1].strip()
break
self.assertTrue(ip)
pings = 1
max_pings = 600 # ~10 minutes!
while not call(*self.PREFIX, 'ping', '-c1', '-w1', ip):
pings += 1
if pings > max_pings:
self.assertFalse(True, msg='Max pings reached!')
print("Testing instances' ability to connect to the Internet")
# Test Internet connectivity
attempts = 1
max_attempts = 300 # ~10 minutes!
username = check_output(*self.PREFIX, 'whoami')
while not call(
*self.PREFIX,
'ssh',
'-oStrictHostKeyChecking=no',
'-i', '/home/{}/.ssh/id_microstack'.format(username),
'cirros@{}'.format(ip),
'--', 'ping', '-c1', '91.189.94.250'):
attempts += 1
if attempts > max_attempts:
self.assertFalse(
True,
msg='Unable to access the Internet!')
time.sleep(1)
else:
# Artificial wait, to allow for stuff to settle for the GUI test.
# TODO: get rid of this, when we drop the ping tests back int.
time.sleep(10)
if 'multipass' in self.PREFIX:
print("Opening {}:80 up to the outside world".format(
self.HORIZON_IP))


+ 9
- 13
tools/init/init/questions/__init__.py View File

@ -291,12 +291,10 @@ class RabbitMq(Question):
(actions may have already been run, in which case we fail silently).
"""
# Add Erlang HOME to env.
env = dict(**_env)
env['HOME'] = '{SNAP_COMMON}/lib/rabbitmq'.format(**_env)
# Configure RabbitMQ
call('rabbitmqctl', 'add_user', 'openstack', 'rabbitmq', env=env)
shell('rabbitmqctl set_permissions openstack ".*" ".*" ".*"', env=env)
call('microstack.rabbitmqctl', 'add_user', 'openstack', 'rabbitmq')
shell(
'microstack.rabbitmqctl set_permissions openstack ".*" ".*" ".*"')
def yes(self, answer: str) -> None:
log.info('Waiting for RabbitMQ to start ...')
@ -692,20 +690,18 @@ class KeyPair(Question):
def yes(self, answer: str) -> None:
if 'microstack' not in check_output('openstack', 'keypair', 'list'):
user = check_output('logname')
home = '/home/{}'.format(user) # TODO make more portable!
log.info('Creating microstack keypair (~/.ssh/{})'.format(answer))
check('mkdir', '-p', '{HOME}/.ssh'.format(**_env))
check('chmod', '700', '{HOME}/.ssh'.format(**_env))
check('mkdir', '-p', '{home}/.ssh'.format(home=home))
check('chmod', '700', '{home}/.ssh'.format(home=home))
id_ = check_output('openstack', 'keypair', 'create', 'microstack')
id_path = '{HOME}/.ssh/{answer}'.format(
HOME=_env['HOME'],
answer=answer
)
id_path = '{home}/.ssh/{answer}'.format(home=home, answer=answer)
with open(id_path, 'w') as file_:
file_.write(id_)
check('chmod', '600', id_path)
# TODO: too many assumptions in the below. Make it portable!
user = _env['HOME'].split("/")[2]
check('chown', '{}:{}'.format(user, user), id_path)


+ 5
- 7
tools/init/init/shell.py View File

@ -30,6 +30,7 @@ from typing import Dict, List
import netaddr
import netifaces
import pymysql
import socket
import wget
from init.config import Env, log
@ -107,16 +108,12 @@ def shell(cmd: str, env: Dict = _env) -> int:
"""
proc = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, bufsize=1,
universal_newlines=True, shell=True,
executable='/snap/core18/current/bin/bash')
universal_newlines=True, shell=True)
for line in iter(proc.stdout.readline, ''):
log.debug(line)
proc.wait()
if proc.returncode:
raise subprocess.CalledProcessError(
"Command '{}' returned non-zero exit status {}".format(
cmd,
proc.returncode))
raise subprocess.CalledProcessError(proc.returncode, cmd)
return proc.returncode
@ -141,7 +138,8 @@ def sql(cmd: str) -> None:
def nc_wait(addr: str, port: str) -> None:
"""Wait for a service to be answering on a port."""
print('Waiting for {}:{}'.format(addr, port))
while not call('nc', '-z', addr, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while sock.connect_ex((addr, int(port))) != 0:
sleep(1)


+ 85
- 0
tools/update_path.py View File

@ -0,0 +1,85 @@
#!/usr/bin/python3
"""Update LD_LIBRARY_PATH and PATH snapcraft.yaml in the current
working directory.
Editing the lines in question directly in snapcraft.yaml is pretty
terrible, as the lines are long, and we cannot break them up into a
normal yaml string w/ a | and still get snapcraft's variable
expansion. (Or, if we can, I don't know what magic invocation will do
so.)
This script will not check in the new snapcraft.yaml. You should
inspect the updates and check in the file yourself!
"""
import os
import shutil
import sys
LD_LIBRARY_PATH = (
'$SNAP/lib',
'$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET',
'$SNAP/usr/lib',
'$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET',
'$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio',
# '/snap/core18/current/lib',
# '/snap/core18/current/lib/$SNAPCRAFT_ARCH_TRIPLET',
# '/snap/core18/current/lib/systemd',
# '/snap/core18/current/usr/lib',
# '/snap/core18/current/var/lib',
# '/snap/core18/current/usr/lib/$SNAPCRAFT_ARCH_TRIPLET',
)
PATH = (
'$SNAP/usr/sbin',
'$SNAP/usr/bin',
'$SNAP/sbin',
'$SNAP/bin',
# '/snap/core18/current/bin',
# '/snap/core18/current/usr/sbin',
# '/snap/core18/current/usr/bin',
# '/snap/core18/current/sbin',
'$PATH'
)
def main():
"""Replace PATH and LD_LIBRARY_PATH with lists above.
This is dead simple code that relies on there being one setting
for LD_LIBRARY_PATH and PATH. It needs to be updated to be made
smarter if more instances are added.
Note that it would be nice if we could just read and write the
yaml, but we'd chomp comments if we did so. And we like our
comments!
"""
if not os.path.isfile('./snapcraft.yaml'):
print('Cannot file snapcraft.yaml in the current working dir!')
print('Exiting.')
sys.exit(1)
print('snapcraft.yaml found in the current working dir. '
'Updating LD_LIBRARY_PATH and PATH ...')
libs = ':'.join(LD_LIBRARY_PATH)
path_ = ':'.join(PATH)
with open('./snapcraft.yaml', 'r') as source:
with open('./snapcraft.yaml.updated', 'w') as dest:
lines = source.readlines()
for line in lines:
if line.startswith(' LD_LIBRARY_PATH: '):
line = ' LD_LIBRARY_PATH: {}\n'.format(libs)
if line.startswith(' PATH: '):
line = ' PATH: {}\n'.format(path_)
dest.write(line)
shutil.move('./snapcraft.yaml.updated', './snapcraft.yaml')
print('File updated! Please manually inspect the changes '
'and commit them via git.')
if __name__ == '__main__':
main()

+ 32
- 0
tox.ini View File

@ -53,6 +53,38 @@ commands =
flake8 {toxinidir}/tests/
{toxinidir}/tests/test_basic.py
[testenv:eoan]
# Just run basic_test.sh, with multipass support, on eoan.
# TODO: refactor so that there isn't so much copypasta here and below.
deps = -r{toxinidir}/test-requirements.txt
setenv =
MULTIPASS=true
DISTRO=eoan
commands =
{toxinidir}/tools/basic_setup.sh
flake8 {toxinidir}/tests/
{toxinidir}/tests/test_basic.py
[testenv:disco]
# Just run basic_test.sh, with multipass support, on disco.
deps = -r{toxinidir}/test-requirements.txt
setenv =
MULTIPASS=true
DISTRO=disco
[testenv:xenial]
# Just run basic_test.sh, with multipass support, on xenial.
deps = -r{toxinidir}/test-requirements.txt
setenv =
MULTIPASS=true
DISTRO=xenial
commands =
{toxinidir}/tools/basic_setup.sh
flake8 {toxinidir}/tests/
{toxinidir}/tests/test_basic.py
[testenv:cluster]
# Test out clustering!
# Requires multipass.


Loading…
Cancel
Save