Update Amulet defs, series metadata and c-h sync

- Sync charm helpers if applicable.

- Fix test executable hashbags for virtualenv prep.

- Add Yakkety-Newton Amulet test definitions.

- Prep Xenial-Ocata Amulet test definitions (not yet enabled).

- Prep Zesty-Ocata Amulet test definitions (not yet enabled).

- Add Zesty charm series metadata.

- Remove Precise charm series metadata if present.

- Remove Precise Amulet test definitions if present.

Change-Id: Ie3c1f208dbb4497ad99f7f930457b7e8e057e6b3
This commit is contained in:
Ryan Beisner 2016-11-23 15:31:44 -06:00
parent d898647e8b
commit 73e2e7b594
20 changed files with 158 additions and 59 deletions

View File

@ -69,9 +69,9 @@ class OpenStackAmuletDeployment(AmuletDeployment):
# Charms outside the ~openstack-charmers # Charms outside the ~openstack-charmers
base_charms = { base_charms = {
'mysql': ['precise', 'trusty'], 'mysql': ['trusty'],
'mongodb': ['precise', 'trusty'], 'mongodb': ['trusty'],
'nrpe': ['precise', 'trusty', 'wily', 'xenial'], 'nrpe': ['trusty', 'xenial'],
} }
for svc in other_services: for svc in other_services:
@ -260,31 +260,20 @@ class OpenStackAmuletDeployment(AmuletDeployment):
release. release.
""" """
# Must be ordered by OpenStack release (not by Ubuntu release): # Must be ordered by OpenStack release (not by Ubuntu release):
(self.precise_essex, self.precise_folsom, self.precise_grizzly, (self.trusty_icehouse, self.trusty_kilo, self.trusty_liberty,
self.precise_havana, self.precise_icehouse, self.trusty_mitaka, self.xenial_mitaka, self.xenial_newton,
self.trusty_icehouse, self.trusty_juno, self.utopic_juno, self.yakkety_newton, self.xenial_ocata, self.zesty_ocata) = range(9)
self.trusty_kilo, self.vivid_kilo, self.trusty_liberty,
self.wily_liberty, self.trusty_mitaka,
self.xenial_mitaka, self.xenial_newton,
self.yakkety_newton) = range(16)
releases = { releases = {
('precise', None): self.precise_essex,
('precise', 'cloud:precise-folsom'): self.precise_folsom,
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
('precise', 'cloud:precise-havana'): self.precise_havana,
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
('trusty', None): self.trusty_icehouse, ('trusty', None): self.trusty_icehouse,
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo, ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
('trusty', 'cloud:trusty-liberty'): self.trusty_liberty, ('trusty', 'cloud:trusty-liberty'): self.trusty_liberty,
('trusty', 'cloud:trusty-mitaka'): self.trusty_mitaka, ('trusty', 'cloud:trusty-mitaka'): self.trusty_mitaka,
('utopic', None): self.utopic_juno,
('vivid', None): self.vivid_kilo,
('wily', None): self.wily_liberty,
('xenial', None): self.xenial_mitaka, ('xenial', None): self.xenial_mitaka,
('xenial', 'cloud:xenial-newton'): self.xenial_newton, ('xenial', 'cloud:xenial-newton'): self.xenial_newton,
('xenial', 'cloud:xenial-ocata'): self.xenial_ocata,
('yakkety', None): self.yakkety_newton, ('yakkety', None): self.yakkety_newton,
('zesty', None): self.zesty_ocata,
} }
return releases[(self.series, self.openstack)] return releases[(self.series, self.openstack)]
@ -294,16 +283,10 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Return a string representing the openstack release. Return a string representing the openstack release.
""" """
releases = OrderedDict([ releases = OrderedDict([
('precise', 'essex'),
('quantal', 'folsom'),
('raring', 'grizzly'),
('saucy', 'havana'),
('trusty', 'icehouse'), ('trusty', 'icehouse'),
('utopic', 'juno'),
('vivid', 'kilo'),
('wily', 'liberty'),
('xenial', 'mitaka'), ('xenial', 'mitaka'),
('yakkety', 'newton'), ('yakkety', 'newton'),
('zesty', 'ocata'),
]) ])
if self.openstack: if self.openstack:
os_origin = self.openstack.split(':')[1] os_origin = self.openstack.split(':')[1]

View File

@ -28,6 +28,7 @@ import keystoneclient.v2_0 as keystone_client
from keystoneclient.auth.identity import v3 as keystone_id_v3 from keystoneclient.auth.identity import v3 as keystone_id_v3
from keystoneclient import session as keystone_session from keystoneclient import session as keystone_session
from keystoneclient.v3 import client as keystone_client_v3 from keystoneclient.v3 import client as keystone_client_v3
from novaclient import exceptions
import novaclient.client as nova_client import novaclient.client as nova_client
import pika import pika
@ -377,6 +378,16 @@ class OpenStackAmuletUtils(AmuletUtils):
tenant_name=tenant, tenant_name=tenant,
auth_version='2.0') auth_version='2.0')
def create_flavor(self, nova, name, ram, vcpus, disk, flavorid="auto",
ephemeral=0, swap=0, rxtx_factor=1.0, is_public=True):
"""Create the specified flavor."""
try:
nova.flavors.find(name=name)
except (exceptions.NotFound, exceptions.NoUniqueMatch):
self.log.debug('Creating flavor ({})'.format(name))
nova.flavors.create(name, ram, vcpus, disk, flavorid,
ephemeral, swap, rxtx_factor, is_public)
def create_cirros_image(self, glance, image_name): def create_cirros_image(self, glance, image_name):
"""Download the latest cirros image and upload it to glance, """Download the latest cirros image and upload it to glance,
validate and return a resource pointer. validate and return a resource pointer.

View File

@ -344,6 +344,10 @@ class IdentityServiceContext(OSContextGenerator):
'auth_protocol': auth_protocol, 'auth_protocol': auth_protocol,
'api_version': api_version}) 'api_version': api_version})
if float(api_version) > 2:
ctxt.update({'admin_domain_name':
rdata.get('service_domain')})
if self.context_complete(ctxt): if self.context_complete(ctxt):
# NOTE(jamespage) this is required for >= icehouse # NOTE(jamespage) this is required for >= icehouse
# so a missing value just indicates keystone needs # so a missing value just indicates keystone needs
@ -644,7 +648,7 @@ class ApacheSSLContext(OSContextGenerator):
service_namespace = None service_namespace = None
def enable_modules(self): def enable_modules(self):
cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http'] cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http', 'headers']
check_call(cmd) check_call(cmd)
def configure_cert(self, cn=None): def configure_cert(self, cn=None):

View File

@ -32,6 +32,7 @@ def headers_package():
kver = check_output(['uname', '-r']).decode('UTF-8').strip() kver = check_output(['uname', '-r']).decode('UTF-8').strip()
return 'linux-headers-%s' % kver return 'linux-headers-%s' % kver
QUANTUM_CONF_DIR = '/etc/quantum' QUANTUM_CONF_DIR = '/etc/quantum'
@ -91,6 +92,7 @@ def quantum_plugins():
} }
} }
NEUTRON_CONF_DIR = '/etc/neutron' NEUTRON_CONF_DIR = '/etc/neutron'

View File

@ -9,10 +9,13 @@ Listen {{ ext_port }}
SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2 SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2
SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM
SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }} SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
# See LP 1484489 - this is to support <= 2.4.7 and >= 2.4.8
SSLCertificateChainFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }} SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }}
ProxyPass / http://localhost:{{ int }}/ ProxyPass / http://localhost:{{ int }}/
ProxyPassReverse / http://localhost:{{ int }}/ ProxyPassReverse / http://localhost:{{ int }}/
ProxyPreserveHost on ProxyPreserveHost on
RequestHeader set X-Forwarded-Proto "https"
</VirtualHost> </VirtualHost>
{% endfor -%} {% endfor -%}
<Proxy *> <Proxy *>

View File

@ -9,10 +9,13 @@ Listen {{ ext_port }}
SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2 SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2
SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM
SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }} SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
# See LP 1484489 - this is to support <= 2.4.7 and >= 2.4.8
SSLCertificateChainFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }} SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }}
ProxyPass / http://localhost:{{ int }}/ ProxyPass / http://localhost:{{ int }}/
ProxyPassReverse / http://localhost:{{ int }}/ ProxyPassReverse / http://localhost:{{ int }}/
ProxyPreserveHost on ProxyPreserveHost on
RequestHeader set X-Forwarded-Proto "https"
</VirtualHost> </VirtualHost>
{% endfor -%} {% endfor -%}
<Proxy *> <Proxy *>

View File

@ -3,8 +3,13 @@
auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }} auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }} auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
auth_type = password auth_type = password
{% if api_version == "3" -%}
project_domain_name = {{ admin_domain_name }}
user_domain_name = {{ admin_domain_name }}
{% else -%}
project_domain_name = default project_domain_name = default
user_domain_name = default user_domain_name = default
{% endif -%}
project_name = {{ admin_tenant_name }} project_name = {{ admin_tenant_name }}
username = {{ admin_user }} username = {{ admin_user }}
password = {{ admin_password }} password = {{ admin_password }}

View File

@ -109,7 +109,7 @@ UBUNTU_OPENSTACK_RELEASE = OrderedDict([
('wily', 'liberty'), ('wily', 'liberty'),
('xenial', 'mitaka'), ('xenial', 'mitaka'),
('yakkety', 'newton'), ('yakkety', 'newton'),
('zebra', 'ocata'), # TODO: upload with real Z name ('zesty', 'ocata'),
]) ])
@ -152,6 +152,8 @@ SWIFT_CODENAMES = OrderedDict([
['2.5.0', '2.6.0', '2.7.0']), ['2.5.0', '2.6.0', '2.7.0']),
('newton', ('newton',
['2.8.0', '2.9.0', '2.10.0']), ['2.8.0', '2.9.0', '2.10.0']),
('ocata',
['2.11.0']),
]) ])
# >= Liberty version->codename mapping # >= Liberty version->codename mapping
@ -410,14 +412,26 @@ def get_os_version_package(pkg, fatal=True):
os_rel = None os_rel = None
def os_release(package, base='essex'): def reset_os_release():
'''Unset the cached os_release version'''
global os_rel
os_rel = None
def os_release(package, base='essex', reset_cache=False):
''' '''
Returns OpenStack release codename from a cached global. Returns OpenStack release codename from a cached global.
If reset_cache then unset the cached os_release version and return the
freshly determined version.
If the codename can not be determined from either an installed package or If the codename can not be determined from either an installed package or
the installation source, the earliest release supported by the charm should the installation source, the earliest release supported by the charm should
be returned. be returned.
''' '''
global os_rel global os_rel
if reset_cache:
reset_os_release()
if os_rel: if os_rel:
return os_rel return os_rel
os_rel = (git_os_codename_install_source(config('openstack-origin-git')) or os_rel = (git_os_codename_install_source(config('openstack-origin-git')) or
@ -535,6 +549,9 @@ def configure_installation_source(rel):
'newton': 'xenial-updates/newton', 'newton': 'xenial-updates/newton',
'newton/updates': 'xenial-updates/newton', 'newton/updates': 'xenial-updates/newton',
'newton/proposed': 'xenial-proposed/newton', 'newton/proposed': 'xenial-proposed/newton',
'zesty': 'zesty-updates/ocata',
'zesty/updates': 'xenial-updates/ocata',
'zesty/proposed': 'xenial-proposed/ocata',
} }
try: try:
@ -668,6 +685,7 @@ def clean_storage(block_device):
else: else:
zap_disk(block_device) zap_disk(block_device)
is_ip = ip.is_ip is_ip = ip.is_ip
ns_query = ip.ns_query ns_query = ip.ns_query
get_host_ip = ip.get_host_ip get_host_ip = ip.get_host_ip

View File

@ -332,6 +332,8 @@ def config(scope=None):
config_cmd_line = ['config-get'] config_cmd_line = ['config-get']
if scope is not None: if scope is not None:
config_cmd_line.append(scope) config_cmd_line.append(scope)
else:
config_cmd_line.append('--all')
config_cmd_line.append('--format=json') config_cmd_line.append('--format=json')
try: try:
config_data = json.loads( config_data = json.loads(

View File

@ -732,3 +732,20 @@ def get_total_ram():
assert unit == 'kB', 'Unknown unit' assert unit == 'kB', 'Unknown unit'
return int(value) * 1024 # Classic, not KiB. return int(value) * 1024 # Classic, not KiB.
raise NotImplementedError() raise NotImplementedError()
UPSTART_CONTAINER_TYPE = '/run/container_type'
def is_container():
"""Determine whether unit is running in a container
@return: boolean indicating if unit is in a container
"""
if init_is_systemd():
# Detect using systemd-detect-virt
return subprocess.call(['systemd-detect-virt',
'--container']) == 0
else:
# Detect using upstart container file marker
return os.path.exists(UPSTART_CONTAINER_TYPE)

View File

@ -5,7 +5,7 @@ def persistent_modprobe(module):
"""Load a kernel module and configure for auto-load on reboot.""" """Load a kernel module and configure for auto-load on reboot."""
with open('/etc/modules', 'r+') as modules: with open('/etc/modules', 'r+') as modules:
if module not in modules.read(): if module not in modules.read():
modules.write(module) modules.write(module + "\n")
def update_initramfs(version='all'): def update_initramfs(version='all'):

View File

@ -105,6 +105,14 @@ CLOUD_ARCHIVE_POCKETS = {
'newton/proposed': 'xenial-proposed/newton', 'newton/proposed': 'xenial-proposed/newton',
'xenial-newton/proposed': 'xenial-proposed/newton', 'xenial-newton/proposed': 'xenial-proposed/newton',
'xenial-proposed/newton': 'xenial-proposed/newton', 'xenial-proposed/newton': 'xenial-proposed/newton',
# Ocata
'ocata': 'xenial-updates/ocata',
'xenial-ocata': 'xenial-updates/ocata',
'xenial-ocata/updates': 'xenial-updates/ocata',
'xenial-updates/ocata': 'xenial-updates/ocata',
'ocata/proposed': 'xenial-proposed/ocata',
'xenial-ocata/proposed': 'xenial-proposed/ocata',
'xenial-ocata/newton': 'xenial-proposed/ocata',
} }
APT_NO_LOCK = 100 # The return code for "couldn't acquire lock" in APT. APT_NO_LOCK = 100 # The return code for "couldn't acquire lock" in APT.

View File

@ -18,8 +18,8 @@ tags:
- openstack - openstack
series: series:
- xenial - xenial
- zesty
- trusty - trusty
- precise
- yakkety - yakkety
extra-bindings: extra-bindings:
data: data:

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# #
# Copyright 2016 Canonical Ltd # Copyright 2016 Canonical Ltd
# #

View File

@ -546,7 +546,7 @@ class AmuletUtils(object):
raise if it is present. raise if it is present.
:returns: List of process IDs :returns: List of process IDs
""" """
cmd = 'pidof -x {}'.format(process_name) cmd = 'pidof -x "{}"'.format(process_name)
if not expect_success: if not expect_success:
cmd += " || exit 0 && exit 1" cmd += " || exit 0 && exit 1"
output, code = sentry_unit.run(cmd) output, code = sentry_unit.run(cmd)

View File

@ -69,9 +69,9 @@ class OpenStackAmuletDeployment(AmuletDeployment):
# Charms outside the ~openstack-charmers # Charms outside the ~openstack-charmers
base_charms = { base_charms = {
'mysql': ['precise', 'trusty'], 'mysql': ['trusty'],
'mongodb': ['precise', 'trusty'], 'mongodb': ['trusty'],
'nrpe': ['precise', 'trusty', 'wily', 'xenial'], 'nrpe': ['trusty', 'xenial'],
} }
for svc in other_services: for svc in other_services:
@ -260,31 +260,20 @@ class OpenStackAmuletDeployment(AmuletDeployment):
release. release.
""" """
# Must be ordered by OpenStack release (not by Ubuntu release): # Must be ordered by OpenStack release (not by Ubuntu release):
(self.precise_essex, self.precise_folsom, self.precise_grizzly, (self.trusty_icehouse, self.trusty_kilo, self.trusty_liberty,
self.precise_havana, self.precise_icehouse, self.trusty_mitaka, self.xenial_mitaka, self.xenial_newton,
self.trusty_icehouse, self.trusty_juno, self.utopic_juno, self.yakkety_newton, self.xenial_ocata, self.zesty_ocata) = range(9)
self.trusty_kilo, self.vivid_kilo, self.trusty_liberty,
self.wily_liberty, self.trusty_mitaka,
self.xenial_mitaka, self.xenial_newton,
self.yakkety_newton) = range(16)
releases = { releases = {
('precise', None): self.precise_essex,
('precise', 'cloud:precise-folsom'): self.precise_folsom,
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
('precise', 'cloud:precise-havana'): self.precise_havana,
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
('trusty', None): self.trusty_icehouse, ('trusty', None): self.trusty_icehouse,
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo, ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
('trusty', 'cloud:trusty-liberty'): self.trusty_liberty, ('trusty', 'cloud:trusty-liberty'): self.trusty_liberty,
('trusty', 'cloud:trusty-mitaka'): self.trusty_mitaka, ('trusty', 'cloud:trusty-mitaka'): self.trusty_mitaka,
('utopic', None): self.utopic_juno,
('vivid', None): self.vivid_kilo,
('wily', None): self.wily_liberty,
('xenial', None): self.xenial_mitaka, ('xenial', None): self.xenial_mitaka,
('xenial', 'cloud:xenial-newton'): self.xenial_newton, ('xenial', 'cloud:xenial-newton'): self.xenial_newton,
('xenial', 'cloud:xenial-ocata'): self.xenial_ocata,
('yakkety', None): self.yakkety_newton, ('yakkety', None): self.yakkety_newton,
('zesty', None): self.zesty_ocata,
} }
return releases[(self.series, self.openstack)] return releases[(self.series, self.openstack)]
@ -294,16 +283,10 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Return a string representing the openstack release. Return a string representing the openstack release.
""" """
releases = OrderedDict([ releases = OrderedDict([
('precise', 'essex'),
('quantal', 'folsom'),
('raring', 'grizzly'),
('saucy', 'havana'),
('trusty', 'icehouse'), ('trusty', 'icehouse'),
('utopic', 'juno'),
('vivid', 'kilo'),
('wily', 'liberty'),
('xenial', 'mitaka'), ('xenial', 'mitaka'),
('yakkety', 'newton'), ('yakkety', 'newton'),
('zesty', 'ocata'),
]) ])
if self.openstack: if self.openstack:
os_origin = self.openstack.split(':')[1] os_origin = self.openstack.split(':')[1]

View File

@ -28,6 +28,7 @@ import keystoneclient.v2_0 as keystone_client
from keystoneclient.auth.identity import v3 as keystone_id_v3 from keystoneclient.auth.identity import v3 as keystone_id_v3
from keystoneclient import session as keystone_session from keystoneclient import session as keystone_session
from keystoneclient.v3 import client as keystone_client_v3 from keystoneclient.v3 import client as keystone_client_v3
from novaclient import exceptions
import novaclient.client as nova_client import novaclient.client as nova_client
import pika import pika
@ -377,6 +378,16 @@ class OpenStackAmuletUtils(AmuletUtils):
tenant_name=tenant, tenant_name=tenant,
auth_version='2.0') auth_version='2.0')
def create_flavor(self, nova, name, ram, vcpus, disk, flavorid="auto",
ephemeral=0, swap=0, rxtx_factor=1.0, is_public=True):
"""Create the specified flavor."""
try:
nova.flavors.find(name=name)
except (exceptions.NotFound, exceptions.NoUniqueMatch):
self.log.debug('Creating flavor ({})'.format(name))
nova.flavors.create(name, ram, vcpus, disk, flavorid,
ephemeral, swap, rxtx_factor, is_public)
def create_cirros_image(self, glance, image_name): def create_cirros_image(self, glance, image_name):
"""Download the latest cirros image and upload it to glance, """Download the latest cirros image and upload it to glance,
validate and return a resource pointer. validate and return a resource pointer.

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# 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.
# NeutronOVSBasicDeployment
"""Amulet tests on a basic neutron-openvswitch deployment on xenial-ocata."""
from basic_deployment import NeutronOVSBasicDeployment
if __name__ == '__main__':
deployment = NeutronOVSBasicDeployment(series='xenial',
openstack='cloud:xenial-ocata',
source='cloud:xenial-updates/ocata')
deployment.run_tests()

0
tests/gate-basic-yakkety-newton Normal file → Executable file
View File

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# 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.
"""Amulet tests on a basic neutron-openvswitch deployment on zesty-ocata."""
from basic_deployment import NeutronOVSBasicDeployment
if __name__ == '__main__':
deployment = NeutronOVSBasicDeployment(series='zesty')
deployment.run_tests()