Execute service setup against a delegated host

In order to reduce the packages required to pip install
on to the hosts, we allow the service setup to be delegated
to a specific host, defaulting to the deploy host.

1. We no longer need tempest_requires_pip_packages,
   so it is removed.
2. The openstack_openrc role is executed in the playbook,
   so we do not need it as a meta-dep any more.
3. All uses of our custom keystone module have been
   replaced with standard Ansible modules.
4. Using the service delegation model, it makes no sense
   to run the resource creation on all hosts, so we
   use run_once instead.
5. Given that we're using developer mode for master
   integrated builds, and pip.conf is present, we need
   to use the CLI to create the virtualenv so that we
   can use the '--never-download' option.

Change-Id: I572db645b64a4a0ac6255bc36eaac1be13336989
This commit is contained in:
Jesse Pretorius 2018-08-08 20:25:59 +01:00 committed by Jesse Pretorius (odyssey4me)
parent 79f14d202d
commit 81f6bda4c0
10 changed files with 295 additions and 280 deletions

View File

@ -21,6 +21,11 @@ debug: False
tempest_package_state: "latest"
tempest_pip_package_state: "latest"
# Set the host which will execute the shade modules
# for the service setup. The host must already have
# clouds.yaml properly configured.
tempest_service_setup_host: "{{ openstack_service_setup_host | default('localhost') }}"
# Toggle whether tempest actually executes
tempest_run: no
# Define 0 (serial) or more to use a non default concurrency
@ -202,10 +207,7 @@ tempest_images:
# The location where images are downloaded to
tempest_image_dir: "/opt/cache/files"
# Where the download is executed from.
# Options are ['deployment-host', 'target-host']
tempest_image_downloader: "deployment-host"
tempest_image_dir_owner: "{{ lookup('env', 'USER') }}"
tempest_enable_instance_password: True
@ -221,6 +223,17 @@ tempest_flavors:
disk: 1
vcpus: 1
# The projects for tempest to use
tempest_projects:
- "demo"
- "alt_demo"
# The users for tempest to use
tempest_users:
- name: "demo"
- name: "alt_demo"
# The keystone roles for tempest to use
tempest_roles: []
# This variable is used by the repo_build process to determine

View File

@ -39,4 +39,3 @@ galaxy_info:
- openstack
dependencies:
- apt_package_pinning
- openstack_openrc

View File

@ -0,0 +1,25 @@
---
features:
- |
The service setup in keystone for tempest will now be executed
through delegation to the ``tempest_service_setup_host`` which,
by default, is ``localhost`` (the deploy host). Deployers can
opt to rather change this to the utility container by implementing
the following override in ``user_variables.yml``.
.. code-block:: yaml
tempest_service_setup_host: "{{ groups['utility_all'][0] }}"
- |
Rather than a hard-coded set of projects and users, tempest can
now be configured with a custom list with the variables
``tempest_projects`` and ``tempest_users``.
deprecations:
- |
The variable ``tempest_requires_pip_packages`` is no longer required
and has therefore been removed.
- |
The variable ``tempest_image_downloader`` has been removed. The image
download now uses the same host designated by the
``tempest_service_setup_host`` for the image download.

View File

@ -30,13 +30,7 @@
- tempest-install
- include: tempest_resources.yml
when: inventory_hostname == groups[tempest_main_group][0]
tags:
- tempest-config
# Called a second time to set facts on the other utility containers.
- include: tempest_resources.yml
when: inventory_hostname != groups[tempest_main_group][0]
run_once: yes
tags:
- tempest-config

View File

@ -33,19 +33,6 @@
{% endfor %}
when: tempest_developer_mode | bool
- name: Install requires pip packages
pip:
name: "{{ tempest_requires_pip_packages }}"
state: "{{ tempest_pip_package_state }}"
extra_args: >-
{{ tempest_developer_mode | ternary(pip_install_developer_constraints | default('--constraint /opt/developer-pip-constraints.txt'), '') }}
{{ pip_install_options | default('') }}
when: tempest_requires_pip_packages | length > 0
register: install_packages
until: install_packages is success
retries: 5
delay: 2
- name: Retrieve checksum for venv download
uri:
url: "{{ tempest_venv_download_url | replace('tgz', 'checksum') }}"
@ -65,7 +52,7 @@
file:
path: "{{ tempest_venv_bin | dirname }}"
state: absent
when: tempest_get_venv is changed
when: tempest_get_venv is changed
- name: Create tempest venv dir
file:
@ -73,14 +60,20 @@
state: directory
mode: "0755"
register: tempest_venv_dir
when: tempest_get_venv is changed
when: tempest_get_venv is changed
- name: Unarchive pre-built venv
unarchive:
src: "/var/cache/{{ tempest_venv_download_url | basename }}"
dest: "{{ tempest_venv_bin | dirname }}"
copy: "no"
when: tempest_get_venv is changed
when: tempest_get_venv is changed
- name: Create the virtualenv (if it does not exist)
command: "virtualenv --never-download --no-site-packages {{ tempest_venv_bin | dirname }}"
args:
creates: "{{ tempest_venv_bin }}/activate"
when: tempest_get_venv | failed or tempest_get_venv | skipped
- name: Install pip packages
pip:
@ -104,7 +97,7 @@
state: "absent"
when:
- ansible_pkg_mgr in ['yum', 'dnf', 'zypper']
- tempest_get_venv is changed
- tempest_get_venv is changed
# NOTE(odyssey4me):
# We reinitialize the venv to ensure that the right
@ -122,7 +115,7 @@
--no-pip \
--no-setuptools \
--no-wheel
when: tempest_get_venv is changed
when: tempest_get_venv is changed
tags:
- skip_ansible_lint

View File

@ -13,25 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- name: Get admin tenant id
keystone:
command: get_tenant
tenant_name: admin
endpoint: "{{ keystone_service_adminurl }}"
login_user: "{{ keystone_admin_user_name }}"
login_password: "{{ keystone_auth_admin_password }}"
login_project_name: "{{ keystone_admin_tenant_name }}"
insecure: "{{ keystone_service_adminuri_insecure }}"
register: add_service
until: add_service is success
retries: 6
delay: 5
no_log: True
- name: Store admin tenant id
set_fact:
tempest_admin_tenant_id: "{{ keystone_facts.id }}"
- name: Create tempest directories
file:
path: "{{ item.path }}"

View File

@ -13,244 +13,263 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- name: Ensures you have at least one image to upload
assert:
that:
- "tempest_images | length > 0"
when:
- tempest_service_available_glance | bool
# We set the python interpreter to the ansible runtime venv if
# the delegation is to localhost so that we get access to the
# appropriate python libraries in that venv. If the delegation
# is to another host, we assume that it is accessible by the
# system python instead.
- name: Setup the tempest resources
delegate_to: "{{ tempest_service_setup_host }}"
vars:
ansible_python_interpreter: >-
{{ (tempest_service_setup_host == 'localhost') | ternary(ansible_playbook_python, ansible_python['executable']) }}
block:
- name: Ensures you have at least one image to upload
assert:
that:
- "tempest_images | length > 0"
when:
- tempest_service_available_glance | bool
- name: Create deployment-host tempest_image_dir
file:
path: "{{ tempest_image_dir }}"
state: directory
delegate_to: localhost
when:
- tempest_service_available_glance | bool
- tempest_image_downloader == "deployment-host"
- name: Create deployment-host tempest_image_dir
file:
path: "{{ tempest_image_dir }}"
state: directory
mode: "0750"
owner: "{{ tempest_image_dir_owner }}"
recurse: yes
become: yes
when:
- tempest_service_available_glance | bool
- name: Image(s) download
get_url:
url: "{{ item.url }}"
dest: "{{ tempest_image_dir }}/"
checksum: "{{ item.checksum | default(omit) }}"
with_items: "{{ tempest_images }}"
when: tempest_service_available_glance | bool
register: fetch_url
until: fetch_url is success
retries: 6
delay: 5
delegate_to: "{{ (tempest_image_downloader == 'deployment-host') | ternary('localhost', inventory_hostname) }}"
- name: Image(s) download
get_url:
url: "{{ item.url }}"
dest: "{{ tempest_image_dir }}/"
checksum: "{{ item.checksum | default(omit) }}"
with_items: "{{ tempest_images }}"
when:
- tempest_service_available_glance | bool
register: fetch_url
until: fetch_url is success
retries: 6
delay: 5
- name: Copy download images from deployment-host to target-host
copy:
src: "{{ tempest_image_dir }}/{{ item.url | basename }}"
dest: "{{ tempest_image_dir }}/"
with_items: "{{ tempest_images }}"
when:
- tempest_service_available_glance | bool
- tempest_image_downloader == "deployment-host"
register: fetch_url
until: fetch_url is success
retries: 6
delay: 5
- name: Upload tempest images to glance
os_image:
cloud: default
interface: internal
validate_certs: "{{ not (keystone_service_internaluri_insecure | bool) }}"
name: "{{ item.name | default(item.url | basename) }}"
filename: "{{ tempest_image_dir }}/{{ item.url | basename }}"
container_format: bare
disk_format: "{{ item.format }}"
is_public: True
with_items: "{{ tempest_images }}"
register: tempest_image_create
until: tempest_image_create is success
retries: 5
delay: 15
when:
- tempest_service_available_glance | bool
- name: Upload tempest images to glance
os_image:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ item.name | default(item.url | basename) }}"
filename: "{{ tempest_image_dir }}/{{ item.url | basename }}"
container_format: bare
disk_format: "{{ item.format }}"
is_public: True
with_items: "{{ tempest_images }}"
register: tempest_image_create
until: tempest_image_create is success
retries: 5
delay: 15
when: tempest_service_available_glance | bool
# These facts are used in tempest.conf.j2; we set an empty string if it is not
# set above to ensure the template will parse correctly.
- name: Store first tempest image id
set_fact:
tempest_glance_image_id_1: "{{ tempest_service_available_glance | ternary(tempest_image_create['results'][0]['id'], '') }}"
tempest_glance_image_id_2: "{{ tempest_service_available_glance | ternary(tempest_image_create['results'][-1]['id'], '') }}"
# These facts are used in tempest.conf.j2; we set an empty string if it is not
# set above to ensure the template will parse correctly.
- name: Store first tempest image id
set_fact:
tempest_glance_image_id_1: "{{ tempest_service_available_glance | ternary(tempest_image_create['results'][0]['id'], '') }}"
tempest_glance_image_id_2: "{{ tempest_service_available_glance | ternary(tempest_image_create['results'][-1]['id'], '') }}"
- name: Add tempest projects
os_project:
cloud: default
state: present
name: "{{ item }}"
description: "{{ item }} project"
domain_id: "default"
interface: internal
verify: "{{ not (keystone_service_internaluri_insecure | bool) }}"
register: add_project
until: add_project is success
retries: 5
delay: 10
with_items: "{{ tempest_projects }}"
- name: Ensure tempest tenants
keystone:
command: ensure_tenant
tenant_name: "{{ item }}"
description: "{{ item }} Tenant"
endpoint: "{{ keystone_service_adminurl }}"
login_user: "{{ keystone_admin_user_name }}"
login_password: "{{ keystone_auth_admin_password }}"
login_project_name: "{{ keystone_admin_tenant_name }}"
insecure: "{{ keystone_service_adminuri_insecure }}"
register: add_service
until: add_service is success
retries: 5
delay: 10
with_items:
- demo
- alt_demo
no_log: True
- name: Add tempest users
os_user:
cloud: default
state: present
name: "{{ item.name }}"
password: "{{ item.password | default(item.name) }}"
domain: default
default_project: "{{ item.project | default(item.name) }}"
interface: internal
verify: "{{ not (keystone_service_internaluri_insecure | bool) }}"
register: add_user
until: add_user is success
retries: 5
delay: 10
with_items: "{{ tempest_users }}"
no_log: True
- name: Ensure tempest users
keystone:
command: ensure_user
tenant_name: "{{ item }}"
user_name: "{{ item }}"
password: "{{ item }}"
description: "{{ item }} User"
endpoint: "{{ keystone_service_adminurl }}"
login_user: "{{ keystone_admin_user_name }}"
login_password: "{{ keystone_auth_admin_password }}"
login_project_name: "{{ keystone_admin_tenant_name }}"
insecure: "{{ keystone_service_adminuri_insecure }}"
register: add_service
until: add_service is success
retries: 5
delay: 10
with_items:
- demo
- alt_demo
no_log: True
- name: Add tempest roles
os_keystone_role:
cloud: default
interface: internal
validate_certs: "{{ not (keystone_service_internaluri_insecure | bool) }}"
name: "{{ item }}"
register: add_role
until: add_role is success
retries: 5
delay: 10
with_items: "{{ tempest_roles }}"
- name: Ensure tempest roles
os_keystone_role:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ item }}"
register: add_service
until: add_service is success
retries: 5
delay: 10
with_items: "{{ tempest_roles }}"
- name: Add tempest users to heat_stack_owner role
os_user_role:
cloud: default
state: present
user: "{{ item.name }}"
role: "heat_stack_owner"
project: "{{ item.project | default(item.name) }}"
interface: internal
verify: "{{ not (keystone_service_internaluri_insecure | bool) }}"
register: add_user_role
until: add_user_role is success
retries: 5
delay: 10
with_items: "{{ tempest_users }}"
when:
- tempest_service_available_heat | bool
- name: Ensure tempest users have heat_stack_owner role
keystone:
command: ensure_user_role
tenant_name: "{{ item }}"
user_name: "{{ item }}"
role_name: heat_stack_owner
endpoint: "{{ keystone_service_adminurl }}"
login_user: "{{ keystone_admin_user_name }}"
login_password: "{{ keystone_auth_admin_password }}"
login_project_name: "{{ keystone_admin_tenant_name }}"
insecure: "{{ keystone_service_adminuri_insecure }}"
register: add_service
until: add_service is success
retries: 5
delay: 10
when: tempest_service_available_heat | bool
with_items:
- demo
- alt_demo
no_log: True
- name: Store demo tenant id
set_fact:
keystone_demo_tenant_id: "{{ (add_project.results | json_query('[*].project.id'))[0] }}"
- name: Get demo tenant id
keystone:
command: get_tenant
tenant_name: demo
endpoint: "{{ keystone_service_adminurl }}"
login_user: "{{ keystone_admin_user_name }}"
login_password: "{{ keystone_auth_admin_password }}"
login_project_name: "{{ keystone_admin_tenant_name }}"
insecure: "{{ keystone_service_adminuri_insecure }}"
register: add_service
until: add_service is success
retries: 5
delay: 10
no_log: True
- name: Ensure private network exists
os_network:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ tempest_private_net_name }}"
provider_network_type: "{{ tempest_private_net_provider_type }}"
provider_segmentation_id: "{{ tempest_private_net_seg_id | default(omit) }}"
project: "{{ keystone_demo_tenant_id }}"
register: tempest_private_network
until: tempest_private_network is success
retries: 5
delay: 10
when:
- tempest_service_available_neutron | bool
- name: Store demo tenant id
set_fact:
keystone_demo_tenant_id: "{{ keystone_facts.id }}"
- name: Store neutron private network id
set_fact:
tempest_neutron_private_network_id: "{{ tempest_private_network.id }}"
when:
- tempest_service_available_neutron | bool
- name: Ensure private network exists
os_network:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ tempest_private_net_name }}"
provider_network_type: "{{ tempest_private_net_provider_type }}"
provider_segmentation_id: "{{ tempest_private_net_seg_id | default(omit) }}"
project: "{{ keystone_demo_tenant_id }}"
register: tempest_private_network
when: tempest_service_available_neutron | bool
- name: Ensure public network exists
os_network:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ tempest_public_net_name }}"
provider_network_type: "{{ tempest_public_net_provider_type }}"
provider_physical_network: "{{ tempest_public_net_physical_type | default(omit) }}"
provider_segmentation_id: "{{ tempest_public_net_seg_id | default(omit) }}"
external: "{{ tempest_public_router_external }}"
project: "{{ keystone_demo_tenant_id }}"
register: tempest_public_network
until: tempest_public_network is success
retries: 5
delay: 10
when:
- tempest_service_available_neutron | bool
- name: Store neutron private network id
set_fact:
tempest_neutron_private_network_id: "{{ tempest_private_network.id }}"
when: tempest_service_available_neutron | bool
- name: Store neutron public network id
set_fact:
tempest_neutron_public_network_id: "{{ tempest_service_available_neutron | ternary(tempest_public_network.id, '') }}"
- name: Ensure public network exists
os_network:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ tempest_public_net_name }}"
provider_network_type: "{{ tempest_public_net_provider_type }}"
provider_physical_network: "{{ tempest_public_net_physical_type | default(omit) }}"
provider_segmentation_id: "{{ tempest_public_net_seg_id | default(omit) }}"
external: "{{ tempest_public_router_external }}"
project: "{{ keystone_demo_tenant_id }}"
register: tempest_public_network
when: tempest_service_available_neutron | bool
- name: Ensure private subnet exists
os_subnet:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
network_name: "{{ tempest_private_net_name }}"
name: "{{ tempest_private_subnet_name }}"
cidr: "{{ tempest_private_subnet_cidr }}"
project: "{{ keystone_demo_tenant_id }}"
register: _add_private_subnet
until: _add_private_subnet is success
retries: 5
delay: 10
when:
- tempest_service_available_neutron | bool
- name: Store neutron public network id
set_fact:
tempest_neutron_public_network_id: "{{ tempest_service_available_neutron | ternary(tempest_public_network.id, '') }}"
- name: Ensure public subnet exists
os_subnet:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
network_name: "{{ tempest_public_net_name }}"
name: "{{ tempest_public_subnet_name }}"
cidr: "{{ tempest_public_subnet_cidr }}"
allocation_pool_start: "{{ tempest_public_subnet_allocation_pools.split('-')[0] | default(omit) }}"
allocation_pool_end: "{{ tempest_public_subnet_allocation_pools.split('-')[1] | default(omit) }}"
gateway_ip: "{{ tempest_public_subnet_gateway_ip | default(omit) }}"
register: _add_public_subnet
until: _add_public_subnet is success
retries: 5
delay: 10
when:
- tempest_service_available_neutron | bool
- name: Ensure private subnet exists
os_subnet:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
network_name: "{{ tempest_private_net_name }}"
name: "{{ tempest_private_subnet_name }}"
cidr: "{{ tempest_private_subnet_cidr }}"
project: "{{ keystone_demo_tenant_id }}"
when: tempest_service_available_neutron | bool
- name: Create router
os_router:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: router
network: "{{ tempest_public_net_name }}"
interfaces:
- "{{ tempest_private_subnet_name }}"
project: "{{ keystone_demo_tenant_id }}"
register: _add_router
until: _add_router is success
retries: 5
delay: 10
when:
- tempest_service_available_neutron | bool
- name: Ensure public subnet exists
os_subnet:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
network_name: "{{ tempest_public_net_name }}"
name: "{{ tempest_public_subnet_name }}"
cidr: "{{ tempest_public_subnet_cidr }}"
allocation_pool_start: "{{ tempest_public_subnet_allocation_pools.split('-')[0] | default(omit) }}"
allocation_pool_end: "{{ tempest_public_subnet_allocation_pools.split('-')[1] | default(omit) }}"
gateway_ip: "{{ tempest_public_subnet_gateway_ip | default(omit) }}"
when: tempest_service_available_neutron | bool
- name: Create tempest flavors
os_nova_flavor:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ item.name }}"
flavorid: "{{ item.id }}"
ram: "{{ item.ram }}"
disk: "{{ item.disk }}"
vcpus: "{{ item.vcpus }}"
with_items: "{{ tempest_flavors }}"
register: _add_flavors
until: _add_flavors is success
retries: 5
delay: 10
when:
- tempest_service_available_nova | bool
- name: Create router
os_router:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: router
network: "{{ tempest_public_net_name }}"
interfaces:
- "{{ tempest_private_subnet_name }}"
project: "{{ keystone_demo_tenant_id }}"
when: tempest_service_available_neutron | bool
- name: Get the admin user project id
os_project_facts:
cloud: default
name: admin
interface: internal
validate_certs: "{{ not (keystone_service_internaluri_insecure | bool) }}"
register: _get_admin_project
until: _get_admin_project is success
retries: 5
delay: 15
- name: Store admin project id
set_fact:
tempest_admin_tenant_id: "{{ ansible_facts.openstack_projects[0].id }}"
- name: Create tempest flavors
os_nova_flavor:
cloud: default
endpoint_type: internal
validate_certs: "{{ keystone_service_internaluri_insecure | ternary(false, true) }}"
name: "{{ item.name }}"
flavorid: "{{ item.id }}"
ram: "{{ item.ram }}"
disk: "{{ item.disk }}"
vcpus: "{{ item.vcpus }}"
with_items: "{{ tempest_flavors }}"
when: tempest_service_available_nova | bool

View File

@ -23,5 +23,3 @@ tempest_distro_packages:
- python2-shade
- rsync
- which
tempest_requires_pip_packages: []

View File

@ -24,5 +24,3 @@ tempest_distro_packages:
- python-shade
- rsync
- which
tempest_requires_pip_packages: []

View File

@ -24,8 +24,3 @@ tempest_distro_packages:
- python-neutronclient
- python-novaclient
- rsync
tempest_requires_pip_packages:
- shade # ubuntu xenial provides a rather old shade library. We need >= 1.9.0 for Rocky
- virtualenv
- setuptools # Ubuntu's setuptools package does not contain pkg-resources and that's causing troubles