Add devstack base job for zuul v3
This should be managed in the devstack repo, since it's a base job to run devstack. Change-Id: Iffe54fbccbccd68db08f79a1b51dd7f76dbff408 Depends-On: Ie2119f24360d56690ffd772b95a9ea6b98dd4a39
This commit is contained in:
parent
843b039b3c
commit
36ddea31a2
85
.zuul.yaml
Normal file
85
.zuul.yaml
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
- nodeset:
|
||||||
|
name: openstack-single-node
|
||||||
|
nodes:
|
||||||
|
- name: controller
|
||||||
|
label: ubuntu-xenial
|
||||||
|
groups:
|
||||||
|
- name: tempest
|
||||||
|
nodes:
|
||||||
|
- controller
|
||||||
|
|
||||||
|
- nodeset:
|
||||||
|
name: openstack-two-node
|
||||||
|
nodes:
|
||||||
|
- name: controller
|
||||||
|
label: ubuntu-xenial
|
||||||
|
- name: compute1
|
||||||
|
label: ubuntu-xenial
|
||||||
|
groups:
|
||||||
|
- name: tempest
|
||||||
|
nodes:
|
||||||
|
- controller
|
||||||
|
- name: compute
|
||||||
|
nodes:
|
||||||
|
- controller
|
||||||
|
- compute1
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: devstack
|
||||||
|
parent: multinode
|
||||||
|
description: Base devstack job
|
||||||
|
nodeset: openstack-single-node
|
||||||
|
required-projects:
|
||||||
|
- openstack-dev/devstack
|
||||||
|
- openstack/cinder
|
||||||
|
- openstack/glance
|
||||||
|
- openstack/keystone
|
||||||
|
- openstack/neutron
|
||||||
|
- openstack/nova
|
||||||
|
- openstack/requirements
|
||||||
|
- openstack/swift
|
||||||
|
timeout: 7200
|
||||||
|
vars:
|
||||||
|
devstack_localrc:
|
||||||
|
DATABASE_PASSWORD: secretdatabase
|
||||||
|
RABBIT_PASSWORD: secretrabbit
|
||||||
|
ADMIN_PASSWORD: secretadmin
|
||||||
|
SERVICE_PASSWORD: secretservice
|
||||||
|
NETWORK_GATEWAY: 10.1.0.1
|
||||||
|
Q_USE_DEBUG_COMMAND: True
|
||||||
|
FIXED_RANGE: 10.1.0.0/20
|
||||||
|
IPV4_ADDRS_SAFE_TO_USE: 10.1.0.0/20
|
||||||
|
FLOATING_RANGE: 172.24.5.0/24
|
||||||
|
PUBLIC_NETWORK_GATEWAY: 172.24.5.1
|
||||||
|
FLOATING_HOST_PREFIX: 172.24.4
|
||||||
|
FLOATING_HOST_MASK: 23
|
||||||
|
SWIFT_REPLICAS: 1
|
||||||
|
SWIFT_START_ALL_SERVICES: False
|
||||||
|
LOGFILE: /opt/stack/logs/devstacklog.txt
|
||||||
|
LOG_COLOR: False
|
||||||
|
VERBOSE: True
|
||||||
|
NETWORK_GATEWAY: 10.1.0.1
|
||||||
|
NOVNC_FROM_PACKAGE: True
|
||||||
|
ERROR_ON_CLONE: True
|
||||||
|
# NOTE(dims): etcd 3.x is not available in debian/ubuntu
|
||||||
|
# etc. As a stop gap measure, devstack uses wget to download
|
||||||
|
# from the location below for all the CI jobs.
|
||||||
|
ETCD_DOWNLOAD_URL: "http://tarballs.openstack.org/etcd/"
|
||||||
|
devstack_services:
|
||||||
|
horizon: False
|
||||||
|
tempest: False
|
||||||
|
pre-run: playbooks/pre
|
||||||
|
post-run: playbooks/post
|
||||||
|
|
||||||
|
|
||||||
|
- project:
|
||||||
|
name: openstack-dev/devstack
|
||||||
|
check:
|
||||||
|
jobs:
|
||||||
|
- devstack:
|
||||||
|
files:
|
||||||
|
- ^playbooks/pre
|
||||||
|
- ^playbooks/post
|
||||||
|
- ^playbooks/devstack
|
||||||
|
- ^roles/
|
||||||
|
- .zuul.yaml
|
3
playbooks/devstack.yaml
Normal file
3
playbooks/devstack.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
- hosts: all
|
||||||
|
roles:
|
||||||
|
- run-devstack
|
4
playbooks/post.yaml
Normal file
4
playbooks/post.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- hosts: all
|
||||||
|
roles:
|
||||||
|
- export-devstack-journal
|
||||||
|
- fetch-devstack-log-dir
|
22
playbooks/pre.yaml
Normal file
22
playbooks/pre.yaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
- hosts: all
|
||||||
|
roles:
|
||||||
|
- configure-swap
|
||||||
|
- setup-stack-user
|
||||||
|
- setup-tempest-user
|
||||||
|
- setup-devstack-source-dirs
|
||||||
|
- setup-devstack-log-dir
|
||||||
|
- setup-devstack-cache
|
||||||
|
- start-fresh-logging
|
||||||
|
- write-devstack-local-conf
|
||||||
|
# TODO(jeblair): remove when configure-mirrors is fixed
|
||||||
|
tasks:
|
||||||
|
- name: Hack mirror_info
|
||||||
|
shell:
|
||||||
|
_raw_params: |
|
||||||
|
mkdir /etc/ci
|
||||||
|
cat << "EOF" > /etc/ci/mirror_info.sh
|
||||||
|
export NODEPOOL_UCA_MIRROR=http://mirror.dfw.rax.openstack.org/ubuntu-cloud-archive
|
||||||
|
EOF
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
become: true
|
11
roles/configure-swap/README.rst
Normal file
11
roles/configure-swap/README.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Configure a swap partition
|
||||||
|
|
||||||
|
Creates a swap partition on the ephemeral block device (the rest of which
|
||||||
|
will be mounted on /opt).
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: configure_swap_size
|
||||||
|
:default: 8192
|
||||||
|
|
||||||
|
The size of the swap partition, in MiB.
|
1
roles/configure-swap/defaults/main.yaml
Normal file
1
roles/configure-swap/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
configure_swap_size: 8192
|
110
roles/configure-swap/tasks/ephemeral.yaml
Normal file
110
roles/configure-swap/tasks/ephemeral.yaml
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# Configure attached ephemeral devices for storage and swap
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "ephemeral_device is defined"
|
||||||
|
|
||||||
|
- name: Set partition names
|
||||||
|
set_fact:
|
||||||
|
swap_partition: "{{ ephemeral_device}}1"
|
||||||
|
opt_partition: "{{ ephemeral_device}}2"
|
||||||
|
|
||||||
|
- name: Ensure ephemeral device is unmounted
|
||||||
|
become: yes
|
||||||
|
mount:
|
||||||
|
name: "{{ ephemeral_device }}"
|
||||||
|
state: unmounted
|
||||||
|
|
||||||
|
- name: Get existing partitions
|
||||||
|
become: yes
|
||||||
|
parted:
|
||||||
|
device: "{{ ephemeral_device }}"
|
||||||
|
unit: MiB
|
||||||
|
register: ephemeral_partitions
|
||||||
|
|
||||||
|
- name: Remove any existing partitions
|
||||||
|
become: yes
|
||||||
|
parted:
|
||||||
|
device: "{{ ephemeral_device }}"
|
||||||
|
number: "{{ item.num }}"
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- "{{ ephemeral_partitions.partitions }}"
|
||||||
|
|
||||||
|
- name: Create new disk label
|
||||||
|
become: yes
|
||||||
|
parted:
|
||||||
|
label: msdos
|
||||||
|
device: "{{ ephemeral_device }}"
|
||||||
|
|
||||||
|
- name: Create swap partition
|
||||||
|
become: yes
|
||||||
|
parted:
|
||||||
|
device: "{{ ephemeral_device }}"
|
||||||
|
number: 1
|
||||||
|
state: present
|
||||||
|
part_start: '0%'
|
||||||
|
part_end: "{{ configure_swap_size }}MiB"
|
||||||
|
|
||||||
|
- name: Create opt partition
|
||||||
|
become: yes
|
||||||
|
parted:
|
||||||
|
device: "{{ ephemeral_device }}"
|
||||||
|
number: 2
|
||||||
|
state: present
|
||||||
|
part_start: "{{ configure_swap_size }}MiB"
|
||||||
|
part_end: "100%"
|
||||||
|
|
||||||
|
- name: Make swap on partition
|
||||||
|
become: yes
|
||||||
|
command: "mkswap {{ swap_partition }}"
|
||||||
|
|
||||||
|
- name: Write swap to fstab
|
||||||
|
become: yes
|
||||||
|
mount:
|
||||||
|
path: none
|
||||||
|
src: "{{ swap_partition }}"
|
||||||
|
fstype: swap
|
||||||
|
opts: sw
|
||||||
|
passno: 0
|
||||||
|
dump: 0
|
||||||
|
state: present
|
||||||
|
|
||||||
|
# XXX: does "parted" plugin ensure the partition is available
|
||||||
|
# before moving on? No udev settles here ...
|
||||||
|
|
||||||
|
- name: Add all swap
|
||||||
|
become: yes
|
||||||
|
command: swapon -a
|
||||||
|
|
||||||
|
- name: Create /opt filesystem
|
||||||
|
become: yes
|
||||||
|
filesystem:
|
||||||
|
fstype: ext4
|
||||||
|
dev: "{{ opt_partition }}"
|
||||||
|
|
||||||
|
# Rackspace at least does not have enough room for two devstack
|
||||||
|
# installs on the primary partition. We copy in the existing /opt to
|
||||||
|
# the new partition on the ephemeral device, and then overmount /opt
|
||||||
|
# to there for the test runs.
|
||||||
|
#
|
||||||
|
# NOTE(ianw): the existing "mount" touches fstab. There is currently (Sep2017)
|
||||||
|
# work in [1] to split mount & fstab into separate parts, but for now we bundle
|
||||||
|
# it into an atomic shell command
|
||||||
|
# [1] https://github.com/ansible/ansible/pull/27174
|
||||||
|
- name: Copy old /opt
|
||||||
|
become: yes
|
||||||
|
shell: |
|
||||||
|
mount {{ opt_partition }} /mnt
|
||||||
|
find /opt/ -mindepth 1 -maxdepth 1 -exec mv {} /mnt/ \;
|
||||||
|
umount /mnt
|
||||||
|
|
||||||
|
# This overmounts any existing /opt
|
||||||
|
- name: Add opt to fstab and mount
|
||||||
|
become: yes
|
||||||
|
mount:
|
||||||
|
path: /opt
|
||||||
|
src: "{{ opt_partition }}"
|
||||||
|
fstype: ext4
|
||||||
|
opts: noatime
|
||||||
|
state: mounted
|
63
roles/configure-swap/tasks/main.yaml
Normal file
63
roles/configure-swap/tasks/main.yaml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# On RAX hosts, we have a small root partition and a large,
|
||||||
|
# unallocated ephemeral device attached at /dev/xvde
|
||||||
|
- name: Set ephemeral device if /dev/xvde exists
|
||||||
|
when: ansible_devices["xvde"] is defined
|
||||||
|
set_fact:
|
||||||
|
ephemeral_device: "/dev/xvde"
|
||||||
|
|
||||||
|
# On other providers, we have a device called "ephemeral0".
|
||||||
|
#
|
||||||
|
# NOTE(ianw): Once [1] is in our ansible (2.4 era?), we can figure
|
||||||
|
# this out more directly by walking the device labels in the facts
|
||||||
|
#
|
||||||
|
# [1] https://github.com/ansible/ansible/commit/d46dd99f47c0ee5081d15bc5b741e9096d8bfd3e
|
||||||
|
- name: Set ephemeral device by label
|
||||||
|
when: ephemeral_device is undefined
|
||||||
|
block:
|
||||||
|
- name: Get ephemeral0 device node
|
||||||
|
command: /sbin/blkid -L ephemeral0
|
||||||
|
register: ephemeral0
|
||||||
|
# If this doesn't exist, returns !0
|
||||||
|
ignore_errors: yes
|
||||||
|
changed_when: False
|
||||||
|
|
||||||
|
- name: Set ephemeral device if LABEL exists
|
||||||
|
when: "ephemeral0.rc == 0"
|
||||||
|
set_fact:
|
||||||
|
ephemeral_device: "{{ ephemeral0.stdout }}"
|
||||||
|
|
||||||
|
# If we have ephemeral storage and we don't appear to have setup swap,
|
||||||
|
# we will create a swap and move /opt to a large data partition there.
|
||||||
|
- include: ephemeral.yaml
|
||||||
|
static: no
|
||||||
|
when:
|
||||||
|
- ephemeral_device is defined
|
||||||
|
- ansible_memory_mb['swap']['total'] | int + 10 <= configure_swap_size
|
||||||
|
|
||||||
|
# If no ephemeral device and no swap, then we will setup some swap
|
||||||
|
# space on the root device to ensure all hosts a consistent memory
|
||||||
|
# environment.
|
||||||
|
- include: root.yaml
|
||||||
|
static: no
|
||||||
|
when:
|
||||||
|
- ephemeral_device is undefined
|
||||||
|
- ansible_memory_mb['swap']['total'] | int + 10 <= configure_swap_size
|
||||||
|
|
||||||
|
# ensure a standard level of swappiness. Some platforms
|
||||||
|
# (rax+centos7) come with swappiness of 0 (presumably because the
|
||||||
|
# vm doesn't come with swap setup ... but we just did that above),
|
||||||
|
# which depending on the kernel version can lead to the OOM killer
|
||||||
|
# kicking in on some processes despite swap being available;
|
||||||
|
# particularly things like mysql which have very high ratio of
|
||||||
|
# anonymous-memory to file-backed mappings.
|
||||||
|
#
|
||||||
|
# This sets swappiness low; we really don't want to be relying on
|
||||||
|
# cloud I/O based swap during our runs if we can help it
|
||||||
|
- name: Set swappiness
|
||||||
|
become: yes
|
||||||
|
sysctl:
|
||||||
|
name: vm.swappiness
|
||||||
|
value: 30
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- debug: var=ephemeral_device
|
63
roles/configure-swap/tasks/root.yaml
Normal file
63
roles/configure-swap/tasks/root.yaml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# If no ephemeral devices are available, use root filesystem
|
||||||
|
|
||||||
|
- name: Calculate required swap
|
||||||
|
set_fact:
|
||||||
|
swap_required: "{{ configure_swap_size - ansible_memory_mb['swap']['total'] | int }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Get root filesystem
|
||||||
|
shell: df --output='fstype' /root | tail -1
|
||||||
|
register: root_fs
|
||||||
|
|
||||||
|
- name: Save root filesystem
|
||||||
|
set_fact:
|
||||||
|
root_filesystem: "{{ root_fs.stdout }}"
|
||||||
|
|
||||||
|
- debug: var=root_filesystem
|
||||||
|
|
||||||
|
# Note, we don't use a sparse device to avoid wedging when disk space
|
||||||
|
# and memory are both unavailable.
|
||||||
|
|
||||||
|
# Cannot fallocate on filesystems like XFS, so use slower dd
|
||||||
|
- name: Create swap backing file for non-EXT fs
|
||||||
|
when: '"ext" not in root_filesystem'
|
||||||
|
become: yes
|
||||||
|
command: dd if=/dev/zero of=/root/swapfile bs=1M count={{ swap_required }}
|
||||||
|
args:
|
||||||
|
creates: /root/swapfile
|
||||||
|
|
||||||
|
- name: Create sparse swap backing file for EXT fs
|
||||||
|
when: '"ext" in root_filesystem'
|
||||||
|
become: yes
|
||||||
|
command: fallocate -l {{ swap_required }}M /root/swapfile
|
||||||
|
args:
|
||||||
|
creates: /root/swapfile
|
||||||
|
|
||||||
|
- name: Ensure swapfile perms
|
||||||
|
become: yes
|
||||||
|
file:
|
||||||
|
path: /root/swapfile
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0600
|
||||||
|
|
||||||
|
- name: Make swapfile
|
||||||
|
become: yes
|
||||||
|
command: mkswap /root/swapfile
|
||||||
|
|
||||||
|
- name: Write swap to fstab
|
||||||
|
become: yes
|
||||||
|
mount:
|
||||||
|
path: none
|
||||||
|
src: /root/swapfile
|
||||||
|
fstype: swap
|
||||||
|
opts: sw
|
||||||
|
passno: 0
|
||||||
|
dump: 0
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Add all swap
|
||||||
|
become: yes
|
||||||
|
command: swapon -a
|
||||||
|
|
||||||
|
- debug: var=swap_required
|
15
roles/export-devstack-journal/README.rst
Normal file
15
roles/export-devstack-journal/README.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Export journal files from devstack services
|
||||||
|
|
||||||
|
Export the systemd journal for every devstack service in native
|
||||||
|
journal format as well as text. Also, export a syslog-style file with
|
||||||
|
kernal and sudo messages.
|
||||||
|
|
||||||
|
Writes the output to the ``logs/`` subdirectory of
|
||||||
|
``devstack_base_dir``.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
1
roles/export-devstack-journal/defaults/main.yaml
Normal file
1
roles/export-devstack-journal/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
29
roles/export-devstack-journal/tasks/main.yaml
Normal file
29
roles/export-devstack-journal/tasks/main.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# TODO: convert this to ansible
|
||||||
|
- name: Export journal files
|
||||||
|
become: true
|
||||||
|
shell:
|
||||||
|
cmd: |
|
||||||
|
u=""
|
||||||
|
name=""
|
||||||
|
for u in `systemctl list-unit-files | grep devstack | awk '{print $1}'`; do
|
||||||
|
name=$(echo $u | sed 's/devstack@/screen-/' | sed 's/\.service//')
|
||||||
|
journalctl -o short-precise --unit $u | tee {{ devstack_base_dir }}/logs/$name.txt > /dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Export the journal in export format to make it downloadable
|
||||||
|
# for later searching. It can then be rewritten to a journal native
|
||||||
|
# format locally using systemd-journal-remote. This makes a class of
|
||||||
|
# debugging much easier. We don't do the native conversion here as
|
||||||
|
# some distros do not package that tooling.
|
||||||
|
journalctl -u 'devstack@*' -o export | \
|
||||||
|
xz --threads=0 - > {{ devstack_base_dir }}/logs/devstack.journal.xz
|
||||||
|
|
||||||
|
# The journal contains everything running under systemd, we'll
|
||||||
|
# build an old school version of the syslog with just the
|
||||||
|
# kernel and sudo messages.
|
||||||
|
journalctl \
|
||||||
|
-t kernel \
|
||||||
|
-t sudo \
|
||||||
|
--no-pager \
|
||||||
|
--since="$(cat {{ devstack_base_dir }}/log-start-timestamp.txt)" \
|
||||||
|
| tee {{ devstack_base_dir }}/logs/syslog.txt > /dev/null
|
10
roles/fetch-devstack-log-dir/README.rst
Normal file
10
roles/fetch-devstack-log-dir/README.rst
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Fetch content from the devstack log directory
|
||||||
|
|
||||||
|
Copy logs from every host back to the zuul executor.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
1
roles/fetch-devstack-log-dir/defaults/main.yaml
Normal file
1
roles/fetch-devstack-log-dir/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
5
roles/fetch-devstack-log-dir/tasks/main.yaml
Normal file
5
roles/fetch-devstack-log-dir/tasks/main.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
- name: Collect devstack logs
|
||||||
|
synchronize:
|
||||||
|
dest: "{{ zuul.executor.log_root }}/{{ inventory_hostname }}"
|
||||||
|
mode: pull
|
||||||
|
src: "{{ devstack_base_dir }}/logs"
|
8
roles/run-devstack/README.rst
Normal file
8
roles/run-devstack/README.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Run devstack
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
1
roles/run-devstack/defaults/main.yaml
Normal file
1
roles/run-devstack/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
6
roles/run-devstack/tasks/main.yaml
Normal file
6
roles/run-devstack/tasks/main.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
- name: Run devstack
|
||||||
|
command: ./stack.sh
|
||||||
|
args:
|
||||||
|
chdir: "{{devstack_base_dir}}/devstack"
|
||||||
|
become: true
|
||||||
|
become_user: stack
|
15
roles/setup-devstack-cache/README.rst
Normal file
15
roles/setup-devstack-cache/README.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Set up the devstack cache directory
|
||||||
|
|
||||||
|
If the node has a cache of devstack image files, copy it into place.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_cache_dir
|
||||||
|
:default: /opt/cache
|
||||||
|
|
||||||
|
The directory with the cached files.
|
2
roles/setup-devstack-cache/defaults/main.yaml
Normal file
2
roles/setup-devstack-cache/defaults/main.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
||||||
|
devstack_cache_dir: /opt/cache
|
14
roles/setup-devstack-cache/tasks/main.yaml
Normal file
14
roles/setup-devstack-cache/tasks/main.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
- name: Copy cached devstack files
|
||||||
|
# This uses hard links to avoid using extra space.
|
||||||
|
command: "find {{ devstack_cache_dir }}/files -mindepth 1 -maxdepth 1 -exec cp -l {} {{ devstack_base_dir }}/devstack/files/ ;"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Set ownership of cached files
|
||||||
|
file:
|
||||||
|
path: '{{ devstack_base_dir }}/devstack/files'
|
||||||
|
state: directory
|
||||||
|
recurse: true
|
||||||
|
owner: stack
|
||||||
|
group: stack
|
||||||
|
mode: a+r
|
||||||
|
become: yes
|
11
roles/setup-devstack-log-dir/README.rst
Normal file
11
roles/setup-devstack-log-dir/README.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Set up the devstack log directory
|
||||||
|
|
||||||
|
Create a log directory on the ephemeral disk partition to save space
|
||||||
|
on the root device.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
1
roles/setup-devstack-log-dir/defaults/main.yaml
Normal file
1
roles/setup-devstack-log-dir/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
5
roles/setup-devstack-log-dir/tasks/main.yaml
Normal file
5
roles/setup-devstack-log-dir/tasks/main.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
- name: Create logs directory
|
||||||
|
file:
|
||||||
|
path: '{{ devstack_base_dir }}/logs'
|
||||||
|
state: directory
|
||||||
|
become: yes
|
11
roles/setup-devstack-source-dirs/README.rst
Normal file
11
roles/setup-devstack-source-dirs/README.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Set up the devstack source directories
|
||||||
|
|
||||||
|
Ensure that the base directory exists, and then move the source repos
|
||||||
|
into it.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
1
roles/setup-devstack-source-dirs/defaults/main.yaml
Normal file
1
roles/setup-devstack-source-dirs/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
22
roles/setup-devstack-source-dirs/tasks/main.yaml
Normal file
22
roles/setup-devstack-source-dirs/tasks/main.yaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
- name: Find all source repos used by this job
|
||||||
|
find:
|
||||||
|
paths:
|
||||||
|
- src/git.openstack.org/openstack
|
||||||
|
- src/git.openstack.org/openstack-dev
|
||||||
|
- src/git.openstack.org/openstack-infra
|
||||||
|
file_type: directory
|
||||||
|
register: found_repos
|
||||||
|
|
||||||
|
- name: Copy Zuul repos into devstack working directory
|
||||||
|
command: rsync -a {{ item.path }} {{ devstack_base_dir }}
|
||||||
|
with_items: '{{ found_repos.files }}'
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Set ownership of repos
|
||||||
|
file:
|
||||||
|
path: '{{ devstack_base_dir }}'
|
||||||
|
state: directory
|
||||||
|
recurse: true
|
||||||
|
owner: stack
|
||||||
|
group: stack
|
||||||
|
become: yes
|
16
roles/setup-stack-user/README.rst
Normal file
16
roles/setup-stack-user/README.rst
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Set up the `stack` user
|
||||||
|
|
||||||
|
Create the stack user, set up its home directory, and allow it to
|
||||||
|
sudo.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_stack_home_dir
|
||||||
|
:default: {{ devstack_base_dir }}
|
||||||
|
|
||||||
|
The home directory for the stack user.
|
2
roles/setup-stack-user/defaults/main.yaml
Normal file
2
roles/setup-stack-user/defaults/main.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
||||||
|
devstack_stack_home_dir: '{{ devstack_base_dir }}'
|
1
roles/setup-stack-user/files/50_stack_sh
Normal file
1
roles/setup-stack-user/files/50_stack_sh
Normal file
@ -0,0 +1 @@
|
|||||||
|
stack ALL=(root) NOPASSWD:ALL
|
45
roles/setup-stack-user/tasks/main.yaml
Normal file
45
roles/setup-stack-user/tasks/main.yaml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
- name: Create stack group
|
||||||
|
group:
|
||||||
|
name: stack
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
# NOTE(andreaf) Create a user home_dir is not safe via
|
||||||
|
# the user module since it will fail if the containing
|
||||||
|
# folder does not exists. If the folder does exists and
|
||||||
|
# it's empty, the skeleton is setup and ownership set.
|
||||||
|
- name: Create the stack user home folder
|
||||||
|
file:
|
||||||
|
path: '{{ devstack_stack_home_dir }}'
|
||||||
|
state: directory
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Create stack user
|
||||||
|
user:
|
||||||
|
name: stack
|
||||||
|
shell: /bin/bash
|
||||||
|
home: '{{ devstack_stack_home_dir }}'
|
||||||
|
group: stack
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Set stack user home directory permissions
|
||||||
|
file:
|
||||||
|
path: '{{ devstack_stack_home_dir }}'
|
||||||
|
mode: 0755
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Copy 50_stack_sh file to /etc/sudoers.d
|
||||||
|
copy:
|
||||||
|
src: 50_stack_sh
|
||||||
|
dest: /etc/sudoers.d
|
||||||
|
mode: 0440
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Create new/.cache folder within BASE
|
||||||
|
file:
|
||||||
|
path: '{{ devstack_stack_home_dir }}/.cache'
|
||||||
|
state: directory
|
||||||
|
owner: stack
|
||||||
|
group: stack
|
||||||
|
become: yes
|
10
roles/setup-tempest-user/README.rst
Normal file
10
roles/setup-tempest-user/README.rst
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Set up the `tempest` user
|
||||||
|
|
||||||
|
Create the tempest user and allow it to sudo.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
3
roles/setup-tempest-user/files/51_tempest_sh
Normal file
3
roles/setup-tempest-user/files/51_tempest_sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
tempest ALL=(root) NOPASSWD:/sbin/ip
|
||||||
|
tempest ALL=(root) NOPASSWD:/sbin/iptables
|
||||||
|
tempest ALL=(root) NOPASSWD:/usr/bin/ovsdb-client
|
20
roles/setup-tempest-user/tasks/main.yaml
Normal file
20
roles/setup-tempest-user/tasks/main.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
- name: Create tempest group
|
||||||
|
group:
|
||||||
|
name: tempest
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Create tempest user
|
||||||
|
user:
|
||||||
|
name: tempest
|
||||||
|
shell: /bin/bash
|
||||||
|
group: tempest
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Copy 51_tempest_sh to /etc/sudoers.d
|
||||||
|
copy:
|
||||||
|
src: 51_tempest_sh
|
||||||
|
dest: /etc/sudoers.d
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0440
|
||||||
|
become: yes
|
11
roles/start-fresh-logging/README.rst
Normal file
11
roles/start-fresh-logging/README.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Restart logging on all hosts
|
||||||
|
|
||||||
|
Restart syslog so that the system logs only include output from the
|
||||||
|
job.
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
1
roles/start-fresh-logging/defaults/main.yaml
Normal file
1
roles/start-fresh-logging/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
56
roles/start-fresh-logging/tasks/main.yaml
Normal file
56
roles/start-fresh-logging/tasks/main.yaml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
- name: Check for /bin/journalctl file
|
||||||
|
command: which journalctl
|
||||||
|
changed_when: False
|
||||||
|
failed_when: False
|
||||||
|
register: which_out
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Get current date
|
||||||
|
command: date +"%Y-%m-%d %H:%M:%S"
|
||||||
|
register: date_out
|
||||||
|
|
||||||
|
- name: Copy current date to log-start-timestamp.txt
|
||||||
|
copy:
|
||||||
|
dest: "{{ devstack_base_dir }}/log-start-timestamp.txt"
|
||||||
|
content: "{{ date_out.stdout }}"
|
||||||
|
when: which_out.rc == 0
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Stop rsyslog
|
||||||
|
service: name=rsyslog state=stopped
|
||||||
|
|
||||||
|
- name: Save syslog file prior to devstack run
|
||||||
|
command: mv /var/log/syslog /var/log/syslog-pre-devstack
|
||||||
|
|
||||||
|
- name: Save kern.log file prior to devstack run
|
||||||
|
command: mv /var/log/kern.log /var/log/kern_log-pre-devstack
|
||||||
|
|
||||||
|
- name: Recreate syslog file
|
||||||
|
file: name=/var/log/syslog state=touch
|
||||||
|
|
||||||
|
- name: Recreate syslog file owner and group
|
||||||
|
command: chown /var/log/syslog --ref /var/log/syslog-pre-devstack
|
||||||
|
|
||||||
|
- name: Recreate syslog file permissions
|
||||||
|
command: chmod /var/log/syslog --ref /var/log/syslog-pre-devstack
|
||||||
|
|
||||||
|
- name: Add read permissions to all on syslog file
|
||||||
|
file: name=/var/log/syslog mode=a+r
|
||||||
|
|
||||||
|
- name: Recreate kern.log file
|
||||||
|
file: name=/var/log/kern.log state=touch
|
||||||
|
|
||||||
|
- name: Recreate kern.log file owner and group
|
||||||
|
command: chown /var/log/kern.log --ref /var/log/kern_log-pre-devstack
|
||||||
|
|
||||||
|
- name: Recreate kern.log file permissions
|
||||||
|
command: chmod /var/log/kern.log --ref /var/log/kern_log-pre-devstack
|
||||||
|
|
||||||
|
- name: Add read permissions to all on kern.log file
|
||||||
|
file: name=/var/log/kern.log mode=a+r
|
||||||
|
|
||||||
|
- name: Start rsyslog
|
||||||
|
service: name=rsyslog state=started
|
||||||
|
when: which_out.rc == 1
|
||||||
|
become: yes
|
63
roles/write-devstack-local-conf/README.rst
Normal file
63
roles/write-devstack-local-conf/README.rst
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
Write the local.conf file for use by devstack
|
||||||
|
|
||||||
|
**Role Variables**
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_base_dir
|
||||||
|
:default: /opt/stack
|
||||||
|
|
||||||
|
The devstack base directory.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_local_conf_path
|
||||||
|
:default: {{ devstack_base_dir }}/devstack/local.conf
|
||||||
|
|
||||||
|
The path of the local.conf file.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_localrc
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
A dictionary of variables that should be written to the localrc
|
||||||
|
section of local.conf. The values (which are strings) may contain
|
||||||
|
bash shell variables, and will be ordered so that variables used by
|
||||||
|
later entries appear first.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_local_conf
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
A complex argument consisting of nested dictionaries which combine
|
||||||
|
to form the meta-sections of the local_conf file. The top level is
|
||||||
|
a dictionary of phases, followed by dictionaries of filenames, then
|
||||||
|
sections, which finally contain key-value pairs for the INI file
|
||||||
|
entries in those sections.
|
||||||
|
|
||||||
|
The keys in this dictionary are the devstack phases.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: [phase]
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
The keys in this dictionary are the filenames for this phase.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: [filename]
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
The keys in this dictionary are the INI sections in this file.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: [section]
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
This is a dictionary of key-value pairs which comprise
|
||||||
|
this section of the INI file.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_services
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
A dictionary mapping service names to boolean values. If the
|
||||||
|
boolean value is ``false``, a ``disable_service`` line will be
|
||||||
|
emitted for the service name. If it is ``true``, then
|
||||||
|
``enable_service`` will be emitted. All other values are ignored.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: devstack_plugins
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
A dictionary mapping a plugin name to a git repo location. If the
|
||||||
|
location is a non-empty string, then an ``enable_plugin`` line will
|
||||||
|
be emmitted for the plugin name.
|
2
roles/write-devstack-local-conf/defaults/main.yaml
Normal file
2
roles/write-devstack-local-conf/defaults/main.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
devstack_base_dir: /opt/stack
|
||||||
|
devstack_local_conf_path: "{{ devstack_base_dir }}/devstack/local.conf"
|
185
roles/write-devstack-local-conf/library/devstack_local_conf.py
Normal file
185
roles/write-devstack-local-conf/library/devstack_local_conf.py
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
# Copyright (C) 2017 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# 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 re
|
||||||
|
|
||||||
|
|
||||||
|
class VarGraph(object):
|
||||||
|
# This is based on the JobGraph from Zuul.
|
||||||
|
|
||||||
|
def __init__(self, vars):
|
||||||
|
self.vars = {}
|
||||||
|
self._varnames = set()
|
||||||
|
self._dependencies = {} # dependent_var_name -> set(parent_var_names)
|
||||||
|
for k, v in vars.items():
|
||||||
|
self._varnames.add(k)
|
||||||
|
for k, v in vars.items():
|
||||||
|
self._addVar(k, str(v))
|
||||||
|
|
||||||
|
bash_var_re = re.compile(r'\$\{?(\w+)')
|
||||||
|
def getDependencies(self, value):
|
||||||
|
return self.bash_var_re.findall(value)
|
||||||
|
|
||||||
|
def _addVar(self, key, value):
|
||||||
|
if key in self.vars:
|
||||||
|
raise Exception("Variable {} already added".format(key))
|
||||||
|
self.vars[key] = value
|
||||||
|
# Append the dependency information
|
||||||
|
self._dependencies.setdefault(key, set())
|
||||||
|
try:
|
||||||
|
for dependency in self.getDependencies(value):
|
||||||
|
if dependency == key:
|
||||||
|
# A variable is allowed to reference itself; no
|
||||||
|
# dependency link needed in that case.
|
||||||
|
continue
|
||||||
|
if dependency not in self._varnames:
|
||||||
|
# It's not necessary to create a link for an
|
||||||
|
# external variable.
|
||||||
|
continue
|
||||||
|
# Make sure a circular dependency is never created
|
||||||
|
ancestor_vars = self._getParentVarNamesRecursively(
|
||||||
|
dependency, soft=True)
|
||||||
|
ancestor_vars.add(dependency)
|
||||||
|
if any((key == anc_var) for anc_var in ancestor_vars):
|
||||||
|
raise Exception("Dependency cycle detected in var {}".
|
||||||
|
format(key))
|
||||||
|
self._dependencies[key].add(dependency)
|
||||||
|
except Exception:
|
||||||
|
del self.vars[key]
|
||||||
|
del self._dependencies[key]
|
||||||
|
raise
|
||||||
|
|
||||||
|
def getVars(self):
|
||||||
|
ret = []
|
||||||
|
keys = sorted(self.vars.keys())
|
||||||
|
seen = set()
|
||||||
|
for key in keys:
|
||||||
|
dependencies = self.getDependentVarsRecursively(key)
|
||||||
|
for var in dependencies + [key]:
|
||||||
|
if var not in seen:
|
||||||
|
ret.append((var, self.vars[var]))
|
||||||
|
seen.add(var)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def getDependentVarsRecursively(self, parent_var):
|
||||||
|
dependent_vars = []
|
||||||
|
|
||||||
|
current_dependent_vars = self._dependencies[parent_var]
|
||||||
|
for current_var in current_dependent_vars:
|
||||||
|
if current_var not in dependent_vars:
|
||||||
|
dependent_vars.append(current_var)
|
||||||
|
for dep in self.getDependentVarsRecursively(current_var):
|
||||||
|
if dep not in dependent_vars:
|
||||||
|
dependent_vars.append(dep)
|
||||||
|
return dependent_vars
|
||||||
|
|
||||||
|
def _getParentVarNamesRecursively(self, dependent_var, soft=False):
|
||||||
|
all_parent_vars = set()
|
||||||
|
vars_to_iterate = set([dependent_var])
|
||||||
|
while len(vars_to_iterate) > 0:
|
||||||
|
current_var = vars_to_iterate.pop()
|
||||||
|
current_parent_vars = self._dependencies.get(current_var)
|
||||||
|
if current_parent_vars is None:
|
||||||
|
if soft:
|
||||||
|
current_parent_vars = set()
|
||||||
|
else:
|
||||||
|
raise Exception("Dependent var {} not found: ".format(
|
||||||
|
dependent_var))
|
||||||
|
new_parent_vars = current_parent_vars - all_parent_vars
|
||||||
|
vars_to_iterate |= new_parent_vars
|
||||||
|
all_parent_vars |= new_parent_vars
|
||||||
|
return all_parent_vars
|
||||||
|
|
||||||
|
|
||||||
|
class LocalConf(object):
|
||||||
|
|
||||||
|
def __init__(self, localrc, localconf, services, plugins):
|
||||||
|
self.localrc = []
|
||||||
|
self.meta_sections = {}
|
||||||
|
if plugins:
|
||||||
|
self.handle_plugins(plugins)
|
||||||
|
if services:
|
||||||
|
self.handle_services(services)
|
||||||
|
if localrc:
|
||||||
|
self.handle_localrc(localrc)
|
||||||
|
if localconf:
|
||||||
|
self.handle_localconf(localconf)
|
||||||
|
|
||||||
|
def handle_plugins(self, plugins):
|
||||||
|
for k, v in plugins.items():
|
||||||
|
if v:
|
||||||
|
self.localrc.append('enable_plugin {} {}'.format(k, v))
|
||||||
|
|
||||||
|
def handle_services(self, services):
|
||||||
|
for k, v in services.items():
|
||||||
|
if v is False:
|
||||||
|
self.localrc.append('disable_service {}'.format(k))
|
||||||
|
elif v is True:
|
||||||
|
self.localrc.append('enable_service {}'.format(k))
|
||||||
|
|
||||||
|
def handle_localrc(self, localrc):
|
||||||
|
vg = VarGraph(localrc)
|
||||||
|
for k, v in vg.getVars():
|
||||||
|
self.localrc.append('{}={}'.format(k, v))
|
||||||
|
|
||||||
|
def handle_localconf(self, localconf):
|
||||||
|
for phase, phase_data in localconf.items():
|
||||||
|
for fn, fn_data in phase_data.items():
|
||||||
|
ms_name = '[[{}|{}]]'.format(phase, fn)
|
||||||
|
ms_data = []
|
||||||
|
for section, section_data in fn_data.items():
|
||||||
|
ms_data.append('[{}]'.format(section))
|
||||||
|
for k, v in section_data.items():
|
||||||
|
ms_data.append('{} = {}'.format(k, v))
|
||||||
|
ms_data.append('')
|
||||||
|
self.meta_sections[ms_name] = ms_data
|
||||||
|
|
||||||
|
def write(self, path):
|
||||||
|
with open(path, 'w') as f:
|
||||||
|
f.write('[[local|localrc]]\n')
|
||||||
|
f.write('\n'.join(self.localrc))
|
||||||
|
f.write('\n\n')
|
||||||
|
for section, lines in self.meta_sections.items():
|
||||||
|
f.write('{}\n'.format(section))
|
||||||
|
f.write('\n'.join(lines))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
plugins=dict(type='dict'),
|
||||||
|
services=dict(type='dict'),
|
||||||
|
localrc=dict(type='dict'),
|
||||||
|
local_conf=dict(type='dict'),
|
||||||
|
path=dict(type='str'),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
p = module.params
|
||||||
|
lc = LocalConf(p.get('localrc'),
|
||||||
|
p.get('local_conf'),
|
||||||
|
p.get('services'),
|
||||||
|
p.get('plugins'))
|
||||||
|
lc.write(p['path'])
|
||||||
|
|
||||||
|
module.exit_json()
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import * # noqa
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
9
roles/write-devstack-local-conf/tasks/main.yaml
Normal file
9
roles/write-devstack-local-conf/tasks/main.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
- name: Write a job-specific local_conf file
|
||||||
|
become: true
|
||||||
|
become_user: stack
|
||||||
|
devstack_local_conf:
|
||||||
|
path: "{{ devstack_local_conf_path }}"
|
||||||
|
plugins: "{{ devstack_plugins|default(omit) }}"
|
||||||
|
services: "{{ devstack_services|default(omit) }}"
|
||||||
|
localrc: "{{ devstack_localrc|default(omit) }}"
|
||||||
|
local_conf: "{{ devstack_local_conf|default(omit) }}"
|
Loading…
Reference in New Issue
Block a user