feature matrix definition in yaml
This adds a definition mechanism for the d-g feature matrix in yaml, a python tool to process that into an ENABLED_SERVICES list and a test script to verify that it works as expected. The theory here is that we create configs (which match to d-g DEVSTACK_GATE_ vars) that enable or disable "features". The features then enable or disable "services" (and eventually extensions). An important part of this is the ability to rm-* content. That means the neutron feature can rm-services: n-net. The hope is this makes reviewing changes more straight forward, and also makes it so if something goes wrong we don't run a job missing services, because we don't need to make sure we add things in the else clauses. A follow up patch integrates this into d-g proper, but this patch seemed easier to review on it's own. Change-Id: Ib030f820073dd0b450b362fd721f9477778c04b0
This commit is contained in:
123
features.yaml
Normal file
123
features.yaml
Normal file
@@ -0,0 +1,123 @@
|
||||
config:
|
||||
default:
|
||||
master: [default, ceilometer, glance, horizon, nova, swift, cinder, keystone, heat, trove]
|
||||
icehouse: [default, ceilometer, glance, horizon, nova, swift, cinder, keystone, heat, trove]
|
||||
havana: [default, ceilometer, glance, horizon, nova, swift, cinder, keystone, heat]
|
||||
neutron:
|
||||
features: [neutron]
|
||||
# different backends
|
||||
postgres:
|
||||
features: [postgresql]
|
||||
# feature changes for different test matrixes
|
||||
grenade:
|
||||
rm-features: [ceilometer, heat, trove, sahara]
|
||||
tempest:
|
||||
features: [tempest]
|
||||
# feature changes for different configs of existing services
|
||||
nova_api_metadata_split:
|
||||
features: [nova-md]
|
||||
cells:
|
||||
features: [nova-cells]
|
||||
# feature declarations for incubated or recently integrated projects (so they
|
||||
# can be tested outside the releases they were supported in)
|
||||
trove:
|
||||
features: [trove]
|
||||
marconi:
|
||||
features: [marconi]
|
||||
sahara:
|
||||
features: [sahara]
|
||||
ironic:
|
||||
features: [ironic]
|
||||
|
||||
features:
|
||||
default:
|
||||
base:
|
||||
services: [mysql, rabbit, dstat]
|
||||
|
||||
ceilometer:
|
||||
base:
|
||||
services: [ceilometer-acompute, ceilometer-acentral, ceilometer-collector, ceilometer-api, ceilometer-alarm-notifier, ceilometer-alarm-evaluator, ceilometer-anotification]
|
||||
havana:
|
||||
rm-services: [ceilometer-alarm-notifier, ceilometer-alarm-evaluator, ceilometer-anotification]
|
||||
|
||||
glance:
|
||||
base:
|
||||
services: [g-api, g-reg]
|
||||
|
||||
keystone:
|
||||
base:
|
||||
services: [key]
|
||||
|
||||
horizon:
|
||||
base:
|
||||
services: [horizon]
|
||||
|
||||
nova:
|
||||
base:
|
||||
services: [n-api, n-cond, n-cpu, n-crt, n-net, n-obj, n-sch]
|
||||
havana:
|
||||
rm-compute-ext:
|
||||
icehouse:
|
||||
compute-ext:
|
||||
|
||||
nova-md:
|
||||
base:
|
||||
services: [n-api-meta]
|
||||
|
||||
nova-cells:
|
||||
base:
|
||||
services: [n-cell]
|
||||
rm-compute-ext: [agregates, hosts]
|
||||
|
||||
neutron:
|
||||
base:
|
||||
services: [quantum, q-svc, q-agt, q-dhcp, q-l3, q-meta, q-lbaas, q-vpn, q-fwaas, q-metering]
|
||||
rm-services: [n-net]
|
||||
|
||||
swift:
|
||||
base:
|
||||
services: [s-proxy, s-account, s-container, s-object]
|
||||
|
||||
cinder:
|
||||
base:
|
||||
services: [cinder, c-api, c-vol, c-sch, c-bak]
|
||||
|
||||
heat:
|
||||
base:
|
||||
services: [heat, h-api, h-api-cfn, h-api-cw, h-eng]
|
||||
|
||||
trove:
|
||||
base:
|
||||
services: [trove, tr-api, tr-tmgr, tr-cond]
|
||||
|
||||
ironic:
|
||||
base:
|
||||
services: [ir-api, ir-cond]
|
||||
|
||||
sahara:
|
||||
base:
|
||||
services: [sahara]
|
||||
|
||||
marconi:
|
||||
base:
|
||||
services: [marconi-server]
|
||||
|
||||
tempest:
|
||||
base:
|
||||
services: [tempest]
|
||||
|
||||
# service overrides
|
||||
postgresql:
|
||||
base:
|
||||
services: [postgresql]
|
||||
rm-services: [mysql]
|
||||
|
||||
zeromq:
|
||||
base:
|
||||
services: [zeromq]
|
||||
rm-services: [rabbit]
|
||||
|
||||
qpid:
|
||||
base:
|
||||
services: [qpid]
|
||||
rm-services: [rabbit]
|
||||
86
test-features.sh
Executable file
86
test-features.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
ERRORS=0
|
||||
|
||||
TEMPEST_FULL_MASTER="n-api,n-crt,n-obj,n-cpu,n-sch,n-cond,g-api,g-reg,key,horizon,c-api,c-vol,c-sch,c-bak,cinder,s-proxy,s-account,s-container,s-object,mysql,rabbit,dstat,tempest,heat,h-api,h-api-cfn,h-api-cw,h-eng,ceilometer-acompute,ceilometer-acentral,ceilometer-collector,ceilometer-api,ceilometer-alarm-notifier,ceilometer-alarm-evaluator,ceilometer-anotification,trove,tr-api,tr-tmgr,tr-cond,n-net"
|
||||
|
||||
TEMPEST_NEUTRON_MASTER="n-api,n-crt,n-obj,n-cpu,n-sch,n-cond,g-api,g-reg,key,horizon,c-api,c-vol,c-sch,c-bak,cinder,s-proxy,s-account,s-container,s-object,mysql,rabbit,dstat,tempest,heat,h-api,h-api-cfn,h-api-cw,h-eng,ceilometer-acompute,ceilometer-acentral,ceilometer-collector,ceilometer-api,ceilometer-alarm-notifier,ceilometer-alarm-evaluator,ceilometer-anotification,trove,tr-api,tr-tmgr,tr-cond,quantum,q-svc,q-agt,q-dhcp,q-l3,q-meta,q-lbaas,q-vpn,q-fwaas,q-metering"
|
||||
|
||||
TEMPEST_HEAT_SLOW_MASTER="n-api,n-crt,n-obj,n-cpu,n-sch,n-cond,g-api,g-reg,key,horizon,c-api,c-vol,c-sch,c-bak,cinder,s-proxy,s-account,s-container,s-object,mysql,rabbit,dstat,tempest,heat,h-api,h-api-cfn,h-api-cw,h-eng,ceilometer-acompute,ceilometer-acentral,ceilometer-collector,ceilometer-api,ceilometer-alarm-notifier,ceilometer-alarm-evaluator,ceilometer-anotification,trove,tr-api,tr-tmgr,tr-cond,quantum,q-svc,q-agt,q-dhcp,q-l3,q-meta,q-lbaas,q-vpn,q-fwaas,q-metering"
|
||||
|
||||
GRENADE_NEW_MASTER="n-api,n-crt,n-obj,n-cpu,n-sch,n-cond,g-api,g-reg,key,horizon,c-api,c-vol,c-sch,c-bak,cinder,s-proxy,s-account,s-container,s-object,mysql,rabbit,dstat,tempest,n-net"
|
||||
|
||||
GRENADE_OLD_MASTER="n-api,n-crt,n-obj,n-cpu,n-sch,n-cond,g-api,g-reg,key,horizon,c-api,c-vol,c-sch,c-bak,cinder,s-proxy,s-account,s-container,s-object,mysql,rabbit,dstat,tempest,n-net"
|
||||
|
||||
TEMPEST_FULL_HAVANA="n-api,n-crt,n-obj,n-cpu,n-sch,n-cond,g-api,g-reg,key,horizon,c-api,c-vol,c-sch,c-bak,cinder,s-proxy,s-account,s-container,s-object,mysql,rabbit,dstat,tempest,heat,h-api,h-api-cfn,h-api-cw,h-eng,ceilometer-acompute,ceilometer-acentral,ceilometer-collector,ceilometer-api,n-net"
|
||||
|
||||
# Utility function for tests
|
||||
function assert_list_equal {
|
||||
local source=$(echo $1 | awk 'BEGIN{RS=",";} {print $1}' | sort -V | xargs echo)
|
||||
local target=$(echo $2 | awk 'BEGIN{RS=",";} {print $1}' | sort -V | xargs echo)
|
||||
if [[ "$target" != "$source" ]]; then
|
||||
echo -n `caller 0 | awk '{print $2}'`
|
||||
echo -e " - ERROR\n $target \n != $source"
|
||||
ERRORS=1
|
||||
else
|
||||
# simple backtrace progress detector
|
||||
echo -n `caller 0 | awk '{print $2}'`
|
||||
echo " - ok"
|
||||
fi
|
||||
}
|
||||
|
||||
function test_full_master {
|
||||
local results=$(DEVSTACK_GATE_TEMPEST=1 ./test-matrix.py)
|
||||
assert_list_equal $TEMPEST_FULL_MASTER $results
|
||||
}
|
||||
|
||||
function test_full_havana {
|
||||
local results=$(DEVSTACK_GATE_TEMPEST=1 ./test-matrix.py -b stable/havana)
|
||||
assert_list_equal $TEMPEST_FULL_HAVANA $results
|
||||
}
|
||||
|
||||
function test_neutron_master {
|
||||
local results=$(DEVSTACK_GATE_NEUTRON=1 DEVSTACK_GATE_TEMPEST=1 ./test-matrix.py)
|
||||
assert_list_equal $TEMPEST_NEUTRON_MASTER $results
|
||||
}
|
||||
|
||||
function test_heat_slow_master {
|
||||
local results=$(DEVSTACK_GATE_TEMPEST_HEAT_SLOW=1 DEVSTACK_GATE_NEUTRON=1 DEVSTACK_GATE_TEMPEST=1 ./test-matrix.py)
|
||||
assert_list_equal $TEMPEST_HEAT_SLOW_MASTER $results
|
||||
}
|
||||
|
||||
function test_grenade_new_master {
|
||||
local results=$(DEVSTACK_GATE_TEMPEST_HEAT_SLOW=1 DEVSTACK_GATE_GRENADE=1 DEVSTACK_GATE_TEMPEST=1 ./test-matrix.py)
|
||||
assert_list_equal $GRENADE_NEW_MASTER $results
|
||||
}
|
||||
|
||||
function test_grenade_old_master {
|
||||
local results=$(DEVSTACK_GATE_GRENADE=1 DEVSTACK_GATE_TEMPEST=1 ./test-matrix.py -b stable/havana)
|
||||
assert_list_equal $GRENADE_OLD_MASTER $results
|
||||
}
|
||||
|
||||
test_full_master
|
||||
test_neutron_master
|
||||
test_heat_slow_master
|
||||
test_grenade_new_master
|
||||
test_grenade_old_master
|
||||
test_full_havana
|
||||
|
||||
if [[ "$ERRORS" -ne 0 ]]; then
|
||||
echo "Errors detected, job failed"
|
||||
exit 1
|
||||
fi
|
||||
126
test-matrix.py
Executable file
126
test-matrix.py
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# 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 argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
GRID = None
|
||||
ALLOWED_BRANCHES = ('havana', 'icehouse', 'master')
|
||||
|
||||
FORMAT = '%(asctime)s %(levelname)s: %(message)s'
|
||||
logging.basicConfig(format=FORMAT)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def parse_features(fname):
|
||||
with open(fname) as f:
|
||||
return yaml.load(f)
|
||||
|
||||
|
||||
def normalize_branch(branch):
|
||||
if branch.startswith("stable/"):
|
||||
branch = branch[len("stable/"):]
|
||||
if branch not in ALLOWED_BRANCHES:
|
||||
LOG.error("unknown branch name %s" % branch)
|
||||
sys.exit(1)
|
||||
return branch
|
||||
|
||||
|
||||
def configs_from_env():
|
||||
configs = []
|
||||
for k, v in os.environ.iteritems():
|
||||
if k.startswith('DEVSTACK_GATE_'):
|
||||
if v == '1':
|
||||
f = k.split('DEVSTACK_GATE_')[1]
|
||||
configs.append(f.lower())
|
||||
return configs
|
||||
|
||||
|
||||
def calc_services(branch, features):
|
||||
services = set()
|
||||
for feature in features:
|
||||
services.update(GRID['features'][feature]['base'].get('services', []))
|
||||
if branch in GRID['features'][feature]:
|
||||
services.update(
|
||||
GRID['features'][feature][branch].get('services', []))
|
||||
|
||||
# deletes always trump adds
|
||||
for feature in features:
|
||||
services.difference_update(
|
||||
GRID['features'][feature]['base'].get('rm-services', []))
|
||||
|
||||
if branch in GRID['features'][feature]:
|
||||
services.difference_update(
|
||||
GRID['features'][feature][branch].get('rm-services', []))
|
||||
return sorted(list(services))
|
||||
|
||||
|
||||
def calc_features(branch, configs=[]):
|
||||
LOG.debug("Branch: %s" % branch)
|
||||
LOG.debug("Configs: %s" % configs)
|
||||
features = set(GRID['config']['default'][branch])
|
||||
# do all the adds first
|
||||
for config in configs:
|
||||
if config in GRID['config']:
|
||||
features.update(GRID['config'][config].get('features', []))
|
||||
|
||||
# removes always trump
|
||||
for config in configs:
|
||||
if config in GRID['config']:
|
||||
features.difference_update(
|
||||
GRID['config'][config].get('rm-features', []))
|
||||
return sorted(list(features))
|
||||
|
||||
|
||||
def get_opts():
|
||||
usage = """
|
||||
Compute the test matrix for devstack gate jobs from a combination
|
||||
of environmental feature definitions and flags.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=usage)
|
||||
parser.add_argument('-f', '--features',
|
||||
default='features.yaml',
|
||||
help="Yaml file describing the features matrix")
|
||||
parser.add_argument('-b', '--branch',
|
||||
default="master",
|
||||
help="Branch to compute the matrix for")
|
||||
parser.add_argument('-m', '--mode',
|
||||
default="services",
|
||||
help="What to return (services, compute-ext)")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
global GRID
|
||||
opts = get_opts()
|
||||
GRID = parse_features(opts.features)
|
||||
branch = normalize_branch(opts.branch)
|
||||
|
||||
features = calc_features(branch, configs_from_env())
|
||||
LOG.debug("Features: %s " % features)
|
||||
|
||||
services = calc_services(branch, features)
|
||||
LOG.debug("Services: %s " % services)
|
||||
|
||||
if opts.mode == "services":
|
||||
print ",".join(services)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user