From 0725e015b9a856c79167973aa4a056da3b4d506b Mon Sep 17 00:00:00 2001 From: Christoph Albers Date: Wed, 21 Dec 2016 12:29:28 +0100 Subject: [PATCH] Tempest fixes for Newton - added venv for tempest - added python_execute for install tempest - added tempest dependencies (python / debian) - added needed tempest.conf attributes (especially identity v3) - removed tempest template - refactored tempest template to use openstack-common strategy - added tempest_conf.rb for easier configuration - removed ruby_block to fetch image ids - added static image ids Change-Id: I0431f09c5898bc2a42b17d27b60592ed5d2a4353 Depends-On: I29fd680ca4b16160a015fbf809cdd81860df9eeb --- attributes/default.rb | 25 ++-- attributes/tempest_conf.rb | 94 +++++++++++++++ metadata.rb | 1 + recipes/setup.rb | 94 ++++++++------- spec/setup-redhat_spec.rb | 6 +- spec/setup_spec.rb | 52 +-------- spec/spec_helper.rb | 10 +- templates/default/tempest.conf.erb | 178 ----------------------------- 8 files changed, 175 insertions(+), 285 deletions(-) create mode 100644 attributes/tempest_conf.rb delete mode 100644 templates/default/tempest.conf.erb diff --git a/attributes/default.rb b/attributes/default.rb index d622235..0f28884 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -41,14 +41,14 @@ default['openstack']['integration-test'] = { 'domain_name' => 'Default' }, 'image1' => { - 'name' => 'cirros', - 'id' => nil, + 'name' => 'cirros-test1', + 'id' => '1ac790f6-903a-4833-979f-a38f1819e3b1', 'flavor' => 99, 'source' => 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img' }, 'image2' => { - 'name' => 'cirros', - 'id' => nil, + 'name' => 'cirros-test2', + 'id' => 'f7c2ac6d-0011-499f-a9ec-ca71348bf2e4', 'flavor' => 99, 'source' => 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img' } @@ -58,15 +58,18 @@ default['openstack']['integration-test'] = { case platform_family when 'fedora', 'rhel' # :pragma-foodcritic: ~FC024 - won't fix this default['openstack']['integration-test']['platform'] = { - 'tempest_packages' => %w(git libxslt-devel - libxml2-devel python-testrepository - libffi-devel python-setuptools), - 'package_overrides' => '' + tempest_packages: %w(git libxslt-devel + libxml2-devel python-testrepository + libffi-devel python-setuptools), + package_overrides: '', + python_packages: [] } when 'debian' default['openstack']['integration-test']['platform'] = { - 'tempest_packages' => %w(git libxml2-dev libxslt-dev testrepository - python-dev libffi-dev), - 'package_overrides' => "-o Dpkg::Options::='--force-confold' -o Dpkg::Options::='--force-confdef'" + tempest_packages: %w( git libssl-dev libffi-dev python-dev libxml2-dev + libxslt1-dev libpq-dev libxml2-dev libxslt-dev + testrepository python-dev libffi-dev), + package_overrides: "-o Dpkg::Options::='--force-confold' -o Dpkg::Options::='--force-confdef'", + python_packages: %w(oslotest ddt testscenarios) } end diff --git a/attributes/tempest_conf.rb b/attributes/tempest_conf.rb new file mode 100644 index 0000000..f25adc4 --- /dev/null +++ b/attributes/tempest_conf.rb @@ -0,0 +1,94 @@ +default['openstack']['integration-test']['conf_secrets'] = {} +default['openstack']['integration-test']['conf'].tap do |conf| + conf['auth']['use_dynamic_credentials'] = node['openstack']['integration-test']['use_dynamic_credentials'] + conf['auth']['default_credentials_domain_name'] = 'Default' + conf['auth']['admin_domain_name'] = 'Default' + conf['identity']['catalog_type'] = 'identity' + conf['identity']['disable_ssl_certificate_validation'] = node['openstack']['integration-test']['disable_ssl_validation'] + conf['identity']['v3_endpoint_type'] = 'publicURL' + conf['identity']['strategy'] = 'keystone' + conf['identity']['region'] = 'RegionOne' + conf['identity']['username'] = node['openstack']['integration-test']['user1']['user_name'] + conf['identity']['password'] = node['openstack']['integration-test']['user1']['password'] + conf['identity']['user_domain_name'] = 'Default' + conf['identity']['project_domain_name'] = 'Default' + conf['identity']['project_name'] = node['openstack']['integration-test']['user1']['project_name'] + conf['identity']['alt_username'] = node['openstack']['integration-test']['user2']['user_name'] + conf['identity']['alt_password'] = node['openstack']['integration-test']['user2']['password'] + conf['identity']['alt_project_name'] = node['openstack']['integration-test']['user2']['project_name'] + conf['identity']['default_domain_id'] = 'default' + conf['identity']['admin_domain_scope'] = false + conf['validation']['image_alt_ssh_user'] = node['openstack']['integration-test']['alt_ssh_user'] + conf['validation']['image_ssh_user'] = node['openstack']['integration-test']['ssh_user'] + conf['compute']['flavor_ref'] = node['openstack']['integration-test']['image1']['flavor'] + conf['compute']['flavor_ref_alt'] = node['openstack']['integration-test']['image2']['flavor'] + conf['compute']['fixed_network_name'] = node['openstack']['integration-test']['fixed_network'] + conf['compute']['build_interval'] = 3 + conf['compute']['build_timeout'] = 400 + conf['compute']['run_ssh'] = false + conf['compute']['ssh_user'] = node['openstack']['integration-test']['ssh_user'] + conf['compute']['ip_version_for_ssh'] + conf['compute']['ssh_timeout'] = 400 + conf['compute']['ssh_channel_timeout'] = 60 + conf['compute']['catalog_type'] = 'compute' + conf['compute']['create_image_enabled'] = true + conf['compute']['resize_available'] = true + conf['compute']['change_password_available'] = false + conf['compute']['live_migration_available'] = false + conf['compute']['use_block_migration_for_live_migration'] = false + conf['compute']['disk_config_enabled_override'] = true + conf['identity-feature-enabled']['api_v3'] = true + conf['identity-feature-enabled']['api_v2'] = false + conf['whitebox']['whitebox_enabled'] = false + conf['whitebox']['source_dir'] = '/usr/share/pyshared/nova' + conf['whitebox']['config_path'] = '/etc/nova/nova.conf' + conf['whitebox']['bin_dir'] = '/usr/bin' + conf['whitebox']['path_to_private_key'] = '' + conf['whitebox']['db_uri'] = '' + conf['compute-feature-enabled']['api_v3'] = false + conf['image']['catalog_type'] = 'image' + conf['image']['api_version'] = 1 + conf['network']['api_version'] = 2.0 + conf['network']['catalog_type'] = 'network' + conf['network']['project_network_cidr'] = '10.100.0.0/16' + conf['network']['project_network_mask_bits'] = 28 + conf['network']['project_networks_reachable'] = false + conf['network']['public_network_id'] = '' + conf['network']['public_router_id'] = '' + conf['network']['quantum_available'] = false + conf['volume']['catalog_type'] = 'volume' + conf['volume']['build_interval'] = 3 + conf['volume']['build_timeout'] = 400 + conf['volume']['backup'] = false + conf['volume-feature-enabled']['snapshot'] = false + conf['object-storage']['catalog_type'] = 'object-storage' + conf['object-storage']['container_sync_timeout'] = 120 + conf['object-storage']['container_sync_interval'] = 5 + conf['orchestration']['catalog_type'] = 'orchestration' + conf['boto']['ssh_user'] = 'cirros' + conf['boto']['ec2_url'] = '' + conf['boto']['s3_url'] = '' + conf['boto']['aws_access'] = '' + conf['boto']['aws_secret'] = '' + conf['boto']['s3_materials_path'] = '/opt/stack/devstack/files/images/s3-materials/cirros-0.3.0' + conf['boto']['ari_manifest'] = 'cirros-0.3.0-x86_64-initrd.manifest.xml' + conf['boto']['ami_manifest'] = 'cirros-0.3.0-x86_64-blank.img.manifest.xml' + conf['boto']['aki_manifest'] = 'cirros-0.3.0-x86_64-vmlinuz.manifest.xml' + conf['boto']['instance_type'] = 'm1.tiny' + conf['boto']['http_socket_timeout'] = 30 + conf['boto']['num_retries'] = 1 + conf['boto']['build_timeout'] = 400 + conf['boto']['build_interval'] = 3 + conf['service_available']['marconi'] = false + conf['service_available']['trove'] = false + conf['service_available']['savanna'] = false + conf['service_available']['ironic'] = false + conf['service_available']['ceilometer'] = true + conf['service_available']['horizon'] = true + conf['service_available']['heat'] = true + conf['service_available']['swift'] = false + conf['service_available']['neutron'] = false + conf['service_available']['glance'] = true + conf['service_available']['cinder'] = false + conf['service_available']['nova'] = true +end diff --git a/metadata.rb b/metadata.rb index c7709cd..10e4b0c 100644 --- a/metadata.rb +++ b/metadata.rb @@ -20,3 +20,4 @@ depends 'openstack-image', '>= 14.0.0' depends 'openstack-compute', '>= 14.0.0' depends 'openstack-block-storage', '>= 14.0.0' depends 'openstackclient' +depends 'poise-python', '~> 1.5' diff --git a/recipes/setup.rb b/recipes/setup.rb index 9599560..5975213 100644 --- a/recipes/setup.rb +++ b/recipes/setup.rb @@ -25,6 +25,9 @@ class Chef::Resource::RubyBlock # rubocop:disable Documentation include ::Openstack end +package 'python-dev' +python_runtime '2' + platform_options = node['openstack']['integration-test']['platform'] platform_options['tempest_packages'].each do |pkg| @@ -98,15 +101,34 @@ openstack_role heat_stack_user_role do connection_params connection_params end -git '/opt/tempest' do +venv_path = '/opt/tempest' + +python_execute 'install tempest' do + action :nothing + command '-m pip install .' + cwd venv_path +end + +git venv_path do repository 'https://github.com/openstack/tempest' reference 'master' depth 1 action :sync + notifies :run, 'python_execute[install tempest]', :immediately +end + +python_virtualenv venv_path + +platform_options['python_packages'].each do |pkg| + python_package pkg do + virtualenv venv_path + action :upgrade + end end %w(image1 image2).each do |img| image_name = node['openstack']['integration-test'][img]['name'] + image_id = node['openstack']['integration-test'][img]['id'] openstack_image_image img do identity_user admin_user identity_pass admin_pass @@ -115,23 +137,9 @@ end identity_user_domain_name admin_domain identity_project_domain_name admin_project_domain_name image_name image_name + image_id image_id image_url node['openstack']['integration-test'][img]['source'] end - - # NOTE: This has to be done in a ruby_block so it gets executed at execution - # time and not compile time (when glance does not yet exist). - ruby_block "Get and set #{img}'s ID" do - block do - begin - env = openstack_command_env admin_user, admin_project - id = image_id image_name, env - node.set['openstack']['integration-test'][img]['id'] = id - rescue RuntimeError => e - Chef::Log.error("UUID not found for Glance image #{image_name}. Error was #{e.message}") - end - end - not_if { node['openstack']['integration-test'][img]['id'] } - end end # NOTE: This has to be done in a ruby_block so it gets executed at execution @@ -139,7 +147,7 @@ end ruby_block 'Create nano flavor 99' do block do begin - env = openstack_command_env(admin_user, admin_project) + env = openstack_command_env(admin_user, admin_project, 'Default', 'Default') output = openstack_command('nova', 'flavor-list', env) unless output.include? 'm1.nano' openstack_command('nova', 'flavor-create m1.nano 99 64 0 1', env) @@ -150,34 +158,38 @@ ruby_block 'Create nano flavor 99' do end end +node.default['openstack']['integration-test']['conf'].tap do |conf| + conf['compute']['image_ref'] = node['openstack']['integration-test']['image1']['id'] + conf['compute']['image_ref_alt'] = node['openstack']['integration-test']['image2']['id'] + conf['identity']['uri'] = "#{identity_public_endpoint.scheme}://#{identity_public_endpoint.host}:#{identity_public_endpoint.port}/v2.0/" + conf['identity']['uri_v3'] = "#{identity_public_endpoint.scheme}://#{identity_public_endpoint.host}:#{identity_public_endpoint.port}/v3/" +end + +node.default['openstack']['integration-test']['conf_secrets'].tap do |conf_secrets| + conf_secrets['auth']['admin_username'] = admin_user + conf_secrets['auth']['admin_password'] = admin_pass + conf_secrets['auth']['admin_project_name'] = admin_project +end + +# merge all config options and secrets to be used in the nova.conf.erb +integration_test_conf_options = merge_config_options 'integration-test' + +# create the keystone.conf from attributes template '/opt/tempest/etc/tempest.conf' do - source 'tempest.conf.erb' + source 'openstack-service.conf.erb' + cookbook 'openstack-common' owner 'root' group 'root' mode 00600 - # NOTE: We do not pass the image1/image2 node attributes above to the - # template but embed directly in the template itself instead to work - # around the variables being evaluated at compile time (prior to - # get_image_id being executed). variables( - 'tempest_disable_ssl_validation' => node['openstack']['integration-test']['disable_ssl_validation'], - 'identity_endpoint_host' => identity_public_endpoint.host, - 'identity_endpoint_port' => identity_public_endpoint.port, - 'identity_endpoint_scheme' => identity_public_endpoint.scheme, - 'tempest_use_dynamic_credentials' => node['openstack']['integration-test']['use_dynamic_credentials'], - 'tempest_user1' => node['openstack']['integration-test']['user1']['user_name'], - 'tempest_user1_pass' => node['openstack']['integration-test']['user1']['password'], - 'tempest_user1_project' => node['openstack']['integration-test']['user1']['project_name'], - 'tempest_img_flavor1' => node['openstack']['integration-test']['image1']['flavor'], - 'tempest_img_flavor2' => node['openstack']['integration-test']['image2']['flavor'], - 'tempest_admin' => node['openstack']['identity']['admin_user'], - 'tempest_admin_project' => admin_project, - 'tempest_admin_pass' => admin_pass, - 'tempest_alt_ssh_user' => node['openstack']['integration-test']['alt_ssh_user'], - 'tempest_ssh_user' => node['openstack']['integration-test']['ssh_user'], - 'tempest_user2' => node['openstack']['integration-test']['user2']['user_name'], - 'tempest_user2_pass' => node['openstack']['integration-test']['user2']['password'], - 'tempest_user2_tenant' => node['openstack']['integration-test']['user2']['project_name'], - 'tempest_fixed_network' => node['openstack']['integration-test']['fixed_network'] + service_config: integration_test_conf_options ) end + +# delete all secrets saved in the attribute +# node['openstack']['identity']['conf_secrets'] after creating the keystone.conf +ruby_block "delete all attributes in node['openstack']['integration-test']['conf_secrets']" do + block do + node.rm(:openstack, :'integration-test', :conf_secrets) + end +end diff --git a/spec/setup-redhat_spec.rb b/spec/setup-redhat_spec.rb index 004c440..396ac5d 100644 --- a/spec/setup-redhat_spec.rb +++ b/spec/setup-redhat_spec.rb @@ -12,10 +12,8 @@ describe 'openstack-integration-test::setup' do include_context 'tempest-stubs' it 'installs tempest dependencies' do - packages = %w(git libxslt-devel libxml2-devel - python-testrepository libffi-devel) - - packages.each do |pkg| + %w(git libxslt-devel libxml2-devel + python-testrepository libffi-devel).each do |pkg| expect(chef_run).to upgrade_package(pkg) end end diff --git a/spec/setup_spec.rb b/spec/setup_spec.rb index 0006d84..b13e1a9 100644 --- a/spec/setup_spec.rb +++ b/spec/setup_spec.rb @@ -142,7 +142,8 @@ describe 'openstack-integration-test::setup' do identity_uri: 'http://127.0.0.1:35357/v3', identity_user_domain_name: 'default', identity_project_domain_name: 'default', - image_name: 'cirros', + image_name: 'cirros-test1', + image_id: '1ac790f6-903a-4833-979f-a38f1819e3b1', image_url: 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img' ) end @@ -155,49 +156,12 @@ describe 'openstack-integration-test::setup' do identity_uri: 'http://127.0.0.1:35357/v3', identity_user_domain_name: 'default', identity_project_domain_name: 'default', - image_name: 'cirros', + image_name: 'cirros-test2', + image_id: 'f7c2ac6d-0011-499f-a9ec-ca71348bf2e4', image_url: 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img' ) end - it 'runs ruby_block for image1' do - expect(chef_run).to run_ruby_block("Get and set image1's ID") - end - - it 'runs ruby_block for image2' do - expect(chef_run).to run_ruby_block("Get and set image2's ID") - end - - it 'sets attribute when ruby_block is run for for image1' do - # run actual ruby_block resource - chef_run.find_resource(:ruby_block, "Get and set image1's ID").old_run_action(:create) - image_id = chef_run.node['openstack']['integration-test']['image1']['id'] - expect(image_id).to eq('5d1ff378-e9c1-4db7-97c1-d35f07824595') - end - - it 'sets attribute when ruby_block is run for for image2' do - # run actual ruby_block resource - chef_run.find_resource(:ruby_block, "Get and set image2's ID").old_run_action(:create) - image_id = chef_run.node['openstack']['integration-test']['image2']['id'] - expect(image_id).to eq('5d1ff378-e9c1-4db7-97c1-d35f07824595') - end - - it 'does not run ruby_block for image1 when id already set' do - image_id = '5F7D0C44-F60E-404C-A28A-62140ADF1412' - node.set['openstack']['integration-test']['image1']['id'] = image_id - expect(chef_run).to_not run_ruby_block("Get and set image1's ID") - end - - it 'does not run ruby_block for image2 when id already set' do - image_id = '5F7D0C44-F60E-404C-A28A-62140ADF1413' - node.set['openstack']['integration-test']['image2']['id'] = image_id - expect(chef_run).to_not run_ruby_block("Get and set image2's ID") - end - - it 'runs ruby_block for nano flavor' do - expect(chef_run).to run_ruby_block('Create nano flavor 99') - end - describe 'tempest.conf default' do let(:file) { chef_run.template('/opt/tempest/etc/tempest.conf') } @@ -210,18 +174,14 @@ describe 'openstack-integration-test::setup' do end it 'has a populated entry for image_ref' do - # run actual ruby_block resource - chef_run.find_resource(:ruby_block, "Get and set image1's ID").old_run_action(:create) expect(chef_run).to render_file(file.name).with_content( - 'image_ref = 5d1ff378-e9c1-4db7-97c1-d35f07824595' + 'image_ref = 1ac790f6-903a-4833-979f-a38f1819e3b1' ) end it 'has a populated entry for image_ref_alt' do - # run actual ruby_block resource - chef_run.find_resource(:ruby_block, "Get and set image2's ID").old_run_action(:create) expect(chef_run).to render_file(file.name).with_content( - 'image_ref_alt = 5d1ff378-e9c1-4db7-97c1-d35f07824595' + 'image_ref_alt = f7c2ac6d-0011-499f-a9ec-ca71348bf2e4' ) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2384286..50c71e6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,7 +25,10 @@ shared_context 'tempest-stubs' do 'OS_USERNAME' => 'admin', 'OS_PASSWORD' => 'admin', 'OS_PROJECT_NAME' => 'admin', - 'OS_AUTH_URL' => 'http://127.0.0.1:35357/v3' + 'OS_AUTH_URL' => 'http://127.0.0.1:35357/v3', + 'OS_USER_DOMAIN_NAME' => 'default', + 'OS_PROJECT_DOMAIN_NAME' => 'default', + 'OS_IDENTITY_API_VERSION' => 3 } allow_any_instance_of(Chef::Recipe).to receive(:get_password) @@ -34,11 +37,8 @@ shared_context 'tempest-stubs' do allow_any_instance_of(Chef::Recipe).to receive(:get_password) .with('user', 'admin') .and_return('admin') - allow_any_instance_of(Chef::Resource::RubyBlock).to receive(:image_id) - .with('cirros', env) - .and_return('5d1ff378-e9c1-4db7-97c1-d35f07824595') allow_any_instance_of(Chef::Resource::RubyBlock).to receive(:openstack_command_env) - .with('admin', 'admin') + .with('admin', 'admin', 'Default', 'Default') .and_return(env) allow(Chef::Application).to receive(:fatal!) end diff --git a/templates/default/tempest.conf.erb b/templates/default/tempest.conf.erb deleted file mode 100644 index 5c30fc6..0000000 --- a/templates/default/tempest.conf.erb +++ /dev/null @@ -1,178 +0,0 @@ -[auth] -use_dynamic_credentials = <%= @tempest_use_dynamic_credentials %> - -default_credentials_domain_name = Default -admin_username = <%= @tempest_admin %> -admin_password = <%= @tempest_admin_pass %> -admin_project_name = <%= @tempest_admin_project %> -admin_domain_name = Default - -[identity] - -catalog_type = identity - -disable_ssl_certificate_validation = <%= @tempest_disable_ssl_validation %> - -uri = <%= @identity_endpoint_scheme %>://<%= @identity_endpoint_host %>:<%= @identity_endpoint_port %>/v2.0/ -uri_v3 = <%= @identity_endpoint_scheme %>://<%= @identity_endpoint_host %>:<%= @identity_endpoint_port %>/v3/ -v3_endpoint_type = publicURL - -strategy = keystone - -region = RegionOne - -username = <%= @tempest_user1 %> -password = <%= @tempest_user1_pass %> -user_domain_name = Default -project_domain_name = Default -project_name = <%= @tempest_user1_project %> - -alt_username = <%= @tempest_user2 %> -alt_password = <%= @tempest_user2_pass %> -alt_project_name = <%= @tempest_user2_project %> -default_domain_id = default -admin_domain_scope = false - -[validation] -image_alt_ssh_user = <%= @tempest_alt_ssh_user %> -image_ssh_user = <%= @tempest_ssh_user %> - -[compute] -image_ref = <%= node['openstack']['integration-test']['image1']['id'] %> -image_ref_alt = <%= node['openstack']['integration-test']['image2']['id'] %> -flavor_ref = <%= @tempest_img_flavor1 %> -flavor_ref_alt = <%= @tempest_img_flavor2 %> - -fixed_network_name = <%= @tempest_fixed_network %> - -build_interval = 3 - -build_timeout = 400 - -run_ssh = false - -ssh_user = <%= @tempest_ssh_user %> - -network_for_ssh = private - -ip_version_for_ssh = 4 - -ssh_timeout = 400 - -ssh_channel_timeout = 60 - -catalog_type = compute - -create_image_enabled = true - -resize_available = true - -change_password_available=false - -live_migration_available = False - -use_block_migration_for_live_migration = False - -disk_config_enabled_override = true - -[identity-feature-enabled] -api_v3 = true -api_v2 = false - -[whitebox] - -whitebox_enabled = false - -source_dir = /usr/share/pyshared/nova - -config_path = /etc/nova/nova.conf - -bin_dir = /usr/bin - -path_to_private_key = - -db_uri = - -[compute-feature-enabled] -api_v3 = false - -[image] -catalog_type = image - -api_version = 1 - -[network] - -api_version = 2.0 -catalog_type = network - -project_network_cidr = 10.100.0.0/16 - -project_network_mask_bits = 28 - -project_networks_reachable = false - -public_network_id = - -public_router_id = - -quantum_available = false - -[volume] - -catalog_type = volume -build_interval = 3 -build_timeout = 400 -backup = false - -[volume-feature-enabled] - -snapshot = false - -[object-storage] - -catalog_type = object-store - -container_sync_timeout = 120 -container_sync_interval = 5 - -[boto] -ssh_user = cirros - -ec2_url = -s3_url = - -aws_access = -aws_secret = - -s3_materials_path = /opt/stack/devstack/files/images/s3-materials/cirros-0.3.0 - -ari_manifest = cirros-0.3.0-x86_64-initrd.manifest.xml - -ami_manifest = cirros-0.3.0-x86_64-blank.img.manifest.xml - -aki_manifest = cirros-0.3.0-x86_64-vmlinuz.manifest.xml - -instance_type = m1.tiny - -http_socket_timeout = 30 - -num_retries = 1 - -build_timeout = 400 - -build_interval = 3 - -[service_available] -marconi = False -trove = False -savanna = False -ironic = False -ceilometer = True -horizon = True -heat = True -swift = False -neutron = False -glance = True -cinder = False -nova = True