WIP Move config generation to kolla-k8s
run it with ansible-playbook -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla ./site.yml Change-Id: I568475fa90cf446c9fedf04a45ea2eb35dbd47e7
This commit is contained in:
parent
3e1fb0d352
commit
1df5ebfc20
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Sam Yaple
|
||||
# Copyright 2017 99Cloud 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 collections
|
||||
import inspect
|
||||
import os
|
||||
|
||||
from ansible.plugins import action
|
||||
from six import StringIO
|
||||
|
||||
from oslo_config import iniparser
|
||||
|
||||
|
||||
class OverrideConfigParser(iniparser.BaseParser):
|
||||
|
||||
def __init__(self):
|
||||
self._cur_sections = collections.OrderedDict()
|
||||
self._sections = collections.OrderedDict()
|
||||
self._cur_section = None
|
||||
|
||||
def assignment(self, key, value):
|
||||
cur_value = self._cur_section.get(key)
|
||||
if len(value) == 1 and value[0] == '':
|
||||
value = []
|
||||
if not cur_value:
|
||||
self._cur_section[key] = [value]
|
||||
else:
|
||||
self._cur_section[key].append(value)
|
||||
|
||||
def parse(self, lineiter):
|
||||
self._cur_sections = collections.OrderedDict()
|
||||
super(OverrideConfigParser, self).parse(lineiter)
|
||||
|
||||
# merge _cur_sections into _sections
|
||||
for section, values in self._cur_sections.items():
|
||||
if section not in self._sections:
|
||||
self._sections[section] = collections.OrderedDict()
|
||||
for key, value in values.items():
|
||||
self._sections[section][key] = value
|
||||
|
||||
def new_section(self, section):
|
||||
cur_section = self._cur_sections.get(section)
|
||||
if not cur_section:
|
||||
cur_section = collections.OrderedDict()
|
||||
self._cur_sections[section] = cur_section
|
||||
self._cur_section = cur_section
|
||||
return cur_section
|
||||
|
||||
def write(self, fp):
|
||||
def write_key_value(key, values):
|
||||
for v in values:
|
||||
if not v:
|
||||
fp.write('{} =\n'.format(key))
|
||||
for index, value in enumerate(v):
|
||||
if index == 0:
|
||||
fp.write('{} = {}\n'.format(key, value))
|
||||
else:
|
||||
fp.write('{} {}\n'.format(len(key) * ' ', value))
|
||||
|
||||
def write_section(section):
|
||||
for key, values in section.items():
|
||||
write_key_value(key, values)
|
||||
|
||||
for section in self._sections:
|
||||
fp.write('[{}]\n'.format(section))
|
||||
write_section(self._sections[section])
|
||||
fp.write('\n')
|
||||
|
||||
|
||||
class ActionModule(action.ActionBase):
|
||||
|
||||
TRANSFERS_FILES = True
|
||||
|
||||
def read_config(self, source, config):
|
||||
# Only use config if present
|
||||
if os.access(source, os.R_OK):
|
||||
with open(source, 'r') as f:
|
||||
template_data = f.read()
|
||||
result = self._templar.template(template_data)
|
||||
fakefile = StringIO(result)
|
||||
config.parse(fakefile)
|
||||
fakefile.close()
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
# NOTE(jeffrey4l): Ansible 2.1 add a remote_user param to the
|
||||
# _make_tmp_path function. inspect the number of the args here. In
|
||||
# this way, ansible 2.0 and ansible 2.1 are both supported
|
||||
make_tmp_path_args = inspect.getargspec(self._make_tmp_path)[0]
|
||||
if not tmp and len(make_tmp_path_args) == 1:
|
||||
tmp = self._make_tmp_path()
|
||||
if not tmp and len(make_tmp_path_args) == 2:
|
||||
remote_user = (task_vars.get('ansible_user')
|
||||
or self._play_context.remote_user)
|
||||
tmp = self._make_tmp_path(remote_user)
|
||||
|
||||
sources = self._task.args.get('sources', None)
|
||||
extra_vars = self._task.args.get('vars', list())
|
||||
|
||||
if not isinstance(sources, list):
|
||||
sources = [sources]
|
||||
|
||||
temp_vars = task_vars.copy()
|
||||
temp_vars.update(extra_vars)
|
||||
|
||||
config = OverrideConfigParser()
|
||||
old_vars = self._templar._available_variables
|
||||
self._templar.set_available_variables(temp_vars)
|
||||
|
||||
for source in sources:
|
||||
self.read_config(source, config)
|
||||
|
||||
self._templar.set_available_variables(old_vars)
|
||||
# Dump configparser to string via an emulated file
|
||||
|
||||
fakefile = StringIO()
|
||||
config.write(fakefile)
|
||||
|
||||
remote_path = self._connection._shell.join_path(tmp, 'src')
|
||||
xfered = self._transfer_data(remote_path, fakefile.getvalue())
|
||||
fakefile.close()
|
||||
|
||||
new_module_args = self._task.args.copy()
|
||||
new_module_args.pop('vars', None)
|
||||
new_module_args.pop('sources', None)
|
||||
|
||||
new_module_args.update(
|
||||
dict(
|
||||
src=xfered
|
||||
)
|
||||
)
|
||||
|
||||
result.update(self._execute_module(module_name='copy',
|
||||
module_args=new_module_args,
|
||||
task_vars=task_vars,
|
||||
tmp=tmp))
|
||||
return result
|
|
@ -0,0 +1,96 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Sam Yaple
|
||||
# Copyright 2016 intel
|
||||
#
|
||||
# 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 inspect
|
||||
import os
|
||||
|
||||
from yaml import dump
|
||||
from yaml import safe_load
|
||||
try:
|
||||
from yaml import CDumper as Dumper # noqa: F401
|
||||
from yaml import CLoader as Loader # noqa: F401
|
||||
except ImportError:
|
||||
from yaml import Dumper # noqa: F401
|
||||
from yaml import Loader # noqa: F401
|
||||
|
||||
|
||||
from ansible.plugins import action
|
||||
|
||||
|
||||
class ActionModule(action.ActionBase):
|
||||
|
||||
TRANSFERS_FILES = True
|
||||
|
||||
def read_config(self, source):
|
||||
result = None
|
||||
# Only use config if present
|
||||
if os.access(source, os.R_OK):
|
||||
with open(source, 'r') as f:
|
||||
template_data = f.read()
|
||||
template_data = self._templar.template(template_data)
|
||||
result = safe_load(template_data)
|
||||
return result or {}
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
# NOTE(jeffrey4l): Ansible 2.1 add a remote_user param to the
|
||||
# _make_tmp_path function. inspect the number of the args here. In
|
||||
# this way, ansible 2.0 and ansible 2.1 are both supported
|
||||
make_tmp_path_args = inspect.getargspec(self._make_tmp_path)[0]
|
||||
if not tmp and len(make_tmp_path_args) == 1:
|
||||
tmp = self._make_tmp_path()
|
||||
if not tmp and len(make_tmp_path_args) == 2:
|
||||
remote_user = (task_vars.get('ansible_user')
|
||||
or self._play_context.remote_user)
|
||||
tmp = self._make_tmp_path(remote_user)
|
||||
# save template args.
|
||||
extra_vars = self._task.args.get('vars', list())
|
||||
old_vars = self._templar._available_variables
|
||||
|
||||
temp_vars = task_vars.copy()
|
||||
temp_vars.update(extra_vars)
|
||||
self._templar.set_available_variables(temp_vars)
|
||||
|
||||
output = {}
|
||||
sources = self._task.args.get('sources', None)
|
||||
if not isinstance(sources, list):
|
||||
sources = [sources]
|
||||
for source in sources:
|
||||
output.update(self.read_config(source))
|
||||
|
||||
# restore original vars
|
||||
self._templar.set_available_variables(old_vars)
|
||||
|
||||
remote_path = self._connection._shell.join_path(tmp, 'src')
|
||||
xfered = self._transfer_data(remote_path,
|
||||
dump(output,
|
||||
default_flow_style=False))
|
||||
new_module_args = self._task.args.copy()
|
||||
new_module_args.update(
|
||||
dict(
|
||||
src=xfered
|
||||
)
|
||||
)
|
||||
del new_module_args['sources']
|
||||
result.update(self._execute_module(module_name='copy',
|
||||
module_args=new_module_args,
|
||||
task_vars=task_vars,
|
||||
tmp=tmp))
|
||||
return result
|
|
@ -0,0 +1,544 @@
|
|||
---
|
||||
# The options in this file can be overridden in 'globals.yml'
|
||||
|
||||
# The "temp" files that are created before merge need to stay persistent due
|
||||
# to the fact that ansible will register a "change" if it has to create them
|
||||
# again. Persistent files allow for idempotency
|
||||
container_config_directory: "/var/lib/kolla/config_files"
|
||||
|
||||
# The directory to merge custom config files the kolla's config files
|
||||
node_custom_config: "/etc/kolla/config"
|
||||
|
||||
# The project to generate configuration files for
|
||||
project: ""
|
||||
|
||||
# The directory to store the config files on the destination node
|
||||
node_config_directory: "/etc/kolla/{{ project }}"
|
||||
|
||||
|
||||
###################
|
||||
# Kolla options
|
||||
###################
|
||||
|
||||
# Which orchestration engine to use. Valid options are [ ANSIBLE, KUBERNETES ]
|
||||
orchestration_engine: "ANSIBLE"
|
||||
|
||||
# Valid options are [ COPY_ONCE, COPY_ALWAYS ]
|
||||
config_strategy: "COPY_ALWAYS"
|
||||
|
||||
# Valid options are [ centos, oraclelinux, ubuntu ]
|
||||
kolla_base_distro: "centos"
|
||||
# Valid options are [ binary, source ]
|
||||
kolla_install_type: "binary"
|
||||
|
||||
kolla_internal_vip_address: "{{ kolla_internal_address }}"
|
||||
kolla_internal_fqdn: "{{ kolla_internal_vip_address }}"
|
||||
kolla_external_vip_address: "{{ kolla_internal_vip_address }}"
|
||||
kolla_external_fqdn: "{{ kolla_internal_fqdn if kolla_external_vip_address == kolla_internal_vip_address else kolla_external_vip_address }}"
|
||||
|
||||
kolla_enable_sanity_checks: "no"
|
||||
|
||||
kolla_enable_sanity_keystone: "{{ kolla_enable_sanity_checks }}"
|
||||
kolla_enable_sanity_glance: "{{ kolla_enable_sanity_checks }}"
|
||||
kolla_enable_sanity_cinder: "{{ kolla_enable_sanity_checks }}"
|
||||
kolla_enable_sanity_swift: "{{ kolla_enable_sanity_checks }}"
|
||||
|
||||
|
||||
####################
|
||||
# kolla-kubernetes
|
||||
####################
|
||||
# By default, Kolla API services bind to the network address assigned
|
||||
# to the api_interface. Allow the bind address to be an override. In
|
||||
# some cases (Kubernetes), the api_interface address is not known
|
||||
# until container runtime, and thus it is necessary to bind to all
|
||||
# interfaces "0.0.0.0". When used outside of Kubernetes, binding to
|
||||
# all interfaces may present a security issue, and thus is not
|
||||
# recommended.
|
||||
api_interface_address: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] if orchestration_engine == 'ANSIBLE' else '0.0.0.0' }}"
|
||||
|
||||
################
|
||||
# Chrony options
|
||||
################
|
||||
# A list contains ntp servers
|
||||
external_ntp_servers:
|
||||
- 0.pool.ntp.org
|
||||
- 1.pool.ntp.org
|
||||
- 2.pool.ntp.org
|
||||
- 3.pool.ntp.org
|
||||
|
||||
####################
|
||||
# Database options
|
||||
####################
|
||||
database_address: "{{ kolla_internal_fqdn }}"
|
||||
database_user: "root"
|
||||
database_port: "3306"
|
||||
|
||||
|
||||
####################
|
||||
# Docker options
|
||||
####################
|
||||
docker_registry_email:
|
||||
docker_registry:
|
||||
docker_namespace: "kolla"
|
||||
docker_registry_username:
|
||||
|
||||
# Valid options are [ never, on-failure, always, unless-stopped ]
|
||||
docker_restart_policy: "unless-stopped"
|
||||
|
||||
# '0' means unlimited retries
|
||||
docker_restart_policy_retry: "10"
|
||||
|
||||
# Common options used throughout Docker
|
||||
docker_common_options:
|
||||
auth_email: "{{ docker_registry_email }}"
|
||||
auth_password: "{{ docker_registry_password }}"
|
||||
auth_registry: "{{ docker_registry }}"
|
||||
auth_username: "{{ docker_registry_username }}"
|
||||
environment:
|
||||
KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
|
||||
restart_policy: "{{ docker_restart_policy }}"
|
||||
restart_retries: "{{ docker_restart_policy_retry }}"
|
||||
|
||||
|
||||
####################
|
||||
# keepalived options
|
||||
####################
|
||||
# Arbitrary unique number from 0..255
|
||||
keepalived_virtual_router_id: "51"
|
||||
|
||||
|
||||
####################
|
||||
# Networking options
|
||||
####################
|
||||
network_interface: "eth0"
|
||||
neutron_external_interface: "eth1"
|
||||
kolla_external_vip_interface: "{{ network_interface }}"
|
||||
api_interface: "{{ network_interface }}"
|
||||
storage_interface: "{{ network_interface }}"
|
||||
cluster_interface: "{{ network_interface }}"
|
||||
tunnel_interface: "{{ network_interface }}"
|
||||
bifrost_network_interface: "{{ network_interface }}"
|
||||
dns_interface: "{{ network_interface }}"
|
||||
tunnel_interface_address: "{{ hostvars[inventory_hostname]['ansible_' + tunnel_interface]['ipv4']['address'] if orchestration_engine == 'ANSIBLE' else '0.0.0.0' }}"
|
||||
|
||||
# Valid options are [ openvswitch, linuxbridge, sfc ]
|
||||
neutron_plugin_agent: "openvswitch"
|
||||
|
||||
# The default ports used by each service.
|
||||
aodh_api_port: "8042"
|
||||
|
||||
barbican_api_port: "9311"
|
||||
|
||||
ceilometer_api_port: "8777"
|
||||
|
||||
congress_api_port: "1789"
|
||||
|
||||
cloudkitty_api_port: "8889"
|
||||
|
||||
designate_api_port: "9001"
|
||||
designate_bind_port: "53"
|
||||
designate_mdns_port: "5354"
|
||||
designate_rndc_port: "953"
|
||||
|
||||
freezer_api_port: "9090"
|
||||
|
||||
iscsi_port: "3260"
|
||||
|
||||
gnocchi_api_port: "8041"
|
||||
|
||||
mariadb_port: "{{ database_port }}"
|
||||
mariadb_wsrep_port: "4567"
|
||||
mariadb_ist_port: "4568"
|
||||
mariadb_sst_port: "4444"
|
||||
|
||||
panko_api_port: "8977"
|
||||
|
||||
rabbitmq_port: "5672"
|
||||
rabbitmq_management_port: "15672"
|
||||
rabbitmq_cluster_port: "25672"
|
||||
rabbitmq_epmd_port: "4369"
|
||||
|
||||
mongodb_port: "27017"
|
||||
mongodb_web_port: "28017"
|
||||
|
||||
haproxy_stats_port: "1984"
|
||||
|
||||
keystone_public_port: "5000"
|
||||
keystone_admin_port: "35357"
|
||||
keystone_ssh_port: "8023"
|
||||
|
||||
glance_api_port: "9292"
|
||||
glance_registry_port: "9191"
|
||||
|
||||
octavia_api_port: "9876"
|
||||
octavia_health_manager_port: "5555"
|
||||
|
||||
placement_api_port: "8780"
|
||||
|
||||
nova_api_port: "8774"
|
||||
nova_metadata_port: "8775"
|
||||
nova_novncproxy_port: "6080"
|
||||
nova_spicehtml5proxy_port: "6082"
|
||||
nova_serialproxy_port: "6083"
|
||||
|
||||
neutron_server_port: "9696"
|
||||
|
||||
cinder_api_port: "8776"
|
||||
|
||||
memcached_servers: "memcached"
|
||||
memcached_port: "11211"
|
||||
|
||||
swift_proxy_server_port: "8080"
|
||||
swift_object_server_port: "6000"
|
||||
swift_account_server_port: "6001"
|
||||
swift_container_server_port: "6002"
|
||||
swift_rsync_port: "10873"
|
||||
|
||||
sahara_api_port: "8386"
|
||||
|
||||
heat_api_port: "8004"
|
||||
heat_api_cfn_port: "8000"
|
||||
|
||||
horizon_port: "80"
|
||||
|
||||
murano_api_port: "8082"
|
||||
|
||||
ironic_api_port: "6385"
|
||||
ironic_inspector_port: "5050"
|
||||
|
||||
magnum_api_port: "9511"
|
||||
|
||||
solum_application_deployment_port: "9777"
|
||||
|
||||
solum_image_builder_port: "9778"
|
||||
|
||||
rgw_port: "6780"
|
||||
|
||||
mistral_api_port: "8989"
|
||||
|
||||
kibana_server_port: "5601"
|
||||
|
||||
elasticsearch_port: "9200"
|
||||
|
||||
manila_api_port: "8786"
|
||||
|
||||
watcher_api_port: "9322"
|
||||
|
||||
influxdb_admin_port: "8083"
|
||||
influxdb_http_port: "8086"
|
||||
|
||||
senlin_api_port: "8778"
|
||||
|
||||
trove_api_port: "8779"
|
||||
|
||||
etcd_client_port: "2379"
|
||||
etcd_peer_port: "2380"
|
||||
|
||||
karbor_api_port: "8799"
|
||||
|
||||
kuryr_port: "23750"
|
||||
|
||||
searchlight_api_port: "9393"
|
||||
|
||||
grafana_server_port: "3000"
|
||||
|
||||
tacker_server_port: "9890"
|
||||
|
||||
fluentd_syslog_port: "5140"
|
||||
|
||||
public_protocol: "{{ 'https' if kolla_enable_tls_external | bool else 'http' }}"
|
||||
internal_protocol: "http"
|
||||
admin_protocol: "http"
|
||||
|
||||
####################
|
||||
# OpenStack options
|
||||
####################
|
||||
openstack_release: "auto"
|
||||
openstack_logging_debug: "False"
|
||||
|
||||
openstack_region_name: "RegionOne"
|
||||
|
||||
# In the context of multi-regions, list here the name of all your regions.
|
||||
multiple_regions_names:
|
||||
- "{{ openstack_region_name }}"
|
||||
|
||||
openstack_service_workers: "{{ [ansible_processor_vcpus, 5]|min if orchestration_engine == 'ANSIBLE' else '1'}}"
|
||||
|
||||
# Optionally allow Kolla to set sysctl values
|
||||
set_sysctl: "yes"
|
||||
|
||||
# Valid options are [ novnc, spice ]
|
||||
nova_console: "novnc"
|
||||
|
||||
# OpenStack authentication string. You should only need to override these if you
|
||||
# are changing the admin tenant/project or user.
|
||||
openstack_auth:
|
||||
auth_url: "{{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}"
|
||||
username: "admin"
|
||||
password: "{{ keystone_admin_password }}"
|
||||
project_name: "admin"
|
||||
domain_name: "default"
|
||||
|
||||
# These roles are required for Kolla to be operation, however a savvy deployer
|
||||
# could disable some of these required roles and run their own services.
|
||||
enable_glance: "yes"
|
||||
enable_haproxy: "yes"
|
||||
enable_keystone: "yes"
|
||||
enable_mariadb: "yes"
|
||||
enable_memcached: "yes"
|
||||
enable_neutron: "yes"
|
||||
enable_nova: "yes"
|
||||
enable_rabbitmq: "yes"
|
||||
|
||||
# Additional optional OpenStack features and services are specified here
|
||||
enable_aodh: "no"
|
||||
enable_barbican: "no"
|
||||
enable_cadf_notifications: "no"
|
||||
enable_ceilometer: "no"
|
||||
enable_central_logging: "no"
|
||||
enable_ceph: "no"
|
||||
enable_ceph_rgw: "no"
|
||||
enable_chrony: "no"
|
||||
enable_cinder: "no"
|
||||
enable_cinder_backend_hnas_iscsi: "no"
|
||||
enable_cinder_backend_hnas_nfs: "no"
|
||||
enable_cinder_backend_iscsi: "no"
|
||||
enable_cinder_backend_lvm: "no"
|
||||
enable_cinder_backend_nfs: "no"
|
||||
enable_cloudkitty: "no"
|
||||
enable_congress: "no"
|
||||
enable_designate: "no"
|
||||
enable_etcd: "no"
|
||||
enable_freezer: "no"
|
||||
enable_gnocchi: "no"
|
||||
enable_grafana: "no"
|
||||
enable_heat: "yes"
|
||||
enable_horizon: "yes"
|
||||
enable_horizon_cloudkitty: "{{ enable_cloudkitty | bool }}"
|
||||
enable_horizon_freezer: "{{ enable_freezer | bool }}"
|
||||
enable_horizon_ironic: "{{ enable_ironic | bool }}"
|
||||
enable_horizon_karbor: "{{ enable_karbor | bool }}"
|
||||
enable_horizon_magnum: "{{ enable_magnum | bool }}"
|
||||
enable_horizon_manila: "{{ enable_manila | bool }}"
|
||||
enable_horizon_mistral: "{{ enable_mistral | bool }}"
|
||||
enable_horizon_murano: "{{ enable_murano | bool }}"
|
||||
enable_horizon_neutron_lbaas: "{{ enable_neutron_lbaas | bool }}"
|
||||
enable_horizon_sahara: "{{ enable_sahara | bool }}"
|
||||
enable_horizon_searchlight: "{{ enable_searchlight | bool }}"
|
||||
enable_horizon_senlin: "{{ enable_senlin | bool }}"
|
||||
enable_horizon_solum: "{{ enable_solum | bool }}"
|
||||
enable_horizon_tacker: "{{ enable_tacker | bool }}"
|
||||
enable_horizon_trove: "{{ enable_trove | bool }}"
|
||||
enable_horizon_watcher: "{{ enable_watcher | bool }}"
|
||||
enable_influxdb: "no"
|
||||
enable_ironic: "no"
|
||||
enable_iscsid: "{{ enable_cinder_backend_iscsi | bool or enable_cinder_backend_lvm | bool or enable_ironic | bool }}"
|
||||
enable_karbor: "no"
|
||||
enable_kuryr: "no"
|
||||
enable_magnum: "no"
|
||||
enable_manila: "no"
|
||||
enable_manila_backend_generic: "no"
|
||||
enable_manila_backend_hnas: "no"
|
||||
enable_mistral: "no"
|
||||
enable_mongodb: "no"
|
||||
enable_multipathd: "no"
|
||||
enable_murano: "no"
|
||||
enable_neutron_vpnaas: "no"
|
||||
enable_neutron_dvr: "no"
|
||||
enable_neutron_lbaas: "no"
|
||||
enable_neutron_fwaas: "no"
|
||||
enable_neutron_qos: "no"
|
||||
enable_neutron_agent_ha: "no"
|
||||
enable_neutron_bgp_dragent: "no"
|
||||
enable_nova_serialconsole_proxy: "no"
|
||||
enable_octavia: "no"
|
||||
enable_panko: "no"
|
||||
enable_rally: "no"
|
||||
enable_sahara: "no"
|
||||
enable_searchlight: "no"
|
||||
enable_senlin: "no"
|
||||
enable_solum: "no"
|
||||
enable_swift: "no"
|
||||
enable_tacker: "no"
|
||||
enable_telegraf: "no"
|
||||
enable_tempest: "no"
|
||||
enable_trove: "no"
|
||||
enable_vmtp: "no"
|
||||
enable_watcher: "no"
|
||||
|
||||
ironic_keystone_user: "ironic"
|
||||
neutron_keystone_user: "neutron"
|
||||
nova_keystone_user: "nova"
|
||||
designate_keystone_user: "designate"
|
||||
|
||||
# Nova fake driver and the number of fake driver per compute node
|
||||
enable_nova_fake: "no"
|
||||
num_nova_fake_per_node: 5
|
||||
|
||||
# Monitoring options are specified here
|
||||
enable_collectd: "no"
|
||||
|
||||
# Clean images options are specified here
|
||||
enable_destroy_images: "no"
|
||||
|
||||
####################
|
||||
# Logging options
|
||||
####################
|
||||
|
||||
elasticsearch_address: "{{ kolla_internal_vip_address }}"
|
||||
elasticsearch_protocol: "{{ internal_protocol }}"
|
||||
|
||||
enable_elasticsearch: "{{ 'yes' if enable_central_logging | bool or enable_freezer | bool else 'no' }}"
|
||||
enable_kibana: "{{ 'yes' if enable_central_logging | bool else 'no' }}"
|
||||
|
||||
####################
|
||||
# RabbitMQ options
|
||||
####################
|
||||
rabbitmq_user: "openstack"
|
||||
rabbitmq_version: "rabbitmq_server-3.6/plugins/rabbitmq_clusterer-3.6.x.ez/rabbitmq_clusterer-3.6.x-667f92b0/ebin"
|
||||
|
||||
####################
|
||||
# HAProxy options
|
||||
####################
|
||||
haproxy_user: "openstack"
|
||||
haproxy_enable_external_vip: "{{ 'no' if kolla_external_vip_address == kolla_internal_vip_address else 'yes' }}"
|
||||
kolla_enable_tls_external: "no"
|
||||
kolla_external_fqdn_cert: "{{ node_config_directory }}/certificates/haproxy.pem"
|
||||
kolla_external_fqdn_cacert: "{{ node_config_directory }}/certificates/haproxy-ca.crt"
|
||||
|
||||
|
||||
####################
|
||||
# Kibana options
|
||||
####################
|
||||
kibana_user: "kibana"
|
||||
|
||||
|
||||
####################
|
||||
# Keystone options
|
||||
####################
|
||||
keystone_admin_url: "{{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}/v3"
|
||||
keystone_internal_url: "{{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_public_port }}/v3"
|
||||
keystone_public_url: "{{ public_protocol }}://{{ kolla_external_fqdn }}:{{ keystone_public_port }}/v3"
|
||||
|
||||
# Valid options are [ uuid, fernet ]
|
||||
keystone_token_provider: "uuid"
|
||||
fernet_token_expiry: 86400
|
||||
|
||||
keystone_default_user_role: "_member_"
|
||||
|
||||
#######################
|
||||
# Glance options
|
||||
#######################
|
||||
glance_backend_file: "{{ not enable_ceph | bool }}"
|
||||
glance_backend_ceph: "{{ enable_ceph }}"
|
||||
|
||||
|
||||
#######################
|
||||
# Ceilometer options
|
||||
#######################
|
||||
# Valid options are [ mongodb, mysql, gnocchi ]
|
||||
ceilometer_database_type: "mongodb"
|
||||
|
||||
# Valid options are [ mongodb, gnocchi, panko ]
|
||||
ceilometer_event_type: "mongodb"
|
||||
|
||||
|
||||
########################
|
||||
### Panko options
|
||||
########################
|
||||
# Valid options are [ mongodb, mysql ]
|
||||
panko_database_type: "mysql"
|
||||
|
||||
|
||||
#################
|
||||
# Gnocchi options
|
||||
#################
|
||||
# Vaid options are [file, ceph]
|
||||
gnocchi_backend_storage: "{{ 'ceph' if enable_ceph|bool else 'file' }}"
|
||||
|
||||
|
||||
#################################
|
||||
# Cinder options
|
||||
#################################
|
||||
cinder_backend_ceph: "{{ enable_ceph }}"
|
||||
cinder_volume_group: "cinder-volumes"
|
||||
cinder_backup_driver: "nfs"
|
||||
cinder_backup_share: ""
|
||||
cinder_backup_mount_options_nfs: ""
|
||||
|
||||
#######################
|
||||
# Cloudkitty options
|
||||
#######################
|
||||
# Valid options are [ ceilometer, gnocchi ]
|
||||
cloudkitty_collector_backend: "ceilometer"
|
||||
|
||||
#######################
|
||||
# Designate options
|
||||
#######################
|
||||
# Valid options are [ bind9 ]
|
||||
designate_backend: "bind9"
|
||||
designate_ns_record: "sample.openstack.org"
|
||||
|
||||
|
||||
#######################
|
||||
# Neutron options
|
||||
#######################
|
||||
neutron_bgp_router_id: "1.1.1.1"
|
||||
|
||||
|
||||
#######################
|
||||
# Nova options
|
||||
#######################
|
||||
nova_backend_ceph: "{{ enable_ceph }}"
|
||||
nova_backend: "{{ 'rbd' if nova_backend_ceph | bool else 'default' }}"
|
||||
|
||||
|
||||
#######################
|
||||
# Horizon options
|
||||
#######################
|
||||
horizon_backend_database: "{{ enable_murano | bool }}"
|
||||
|
||||
#################
|
||||
# Octavia options
|
||||
#################
|
||||
# Load balancer topology options are [ SINGLE, ACTIVE_STANDBY ]
|
||||
octavia_loadbalancer_topology: "SINGLE"
|
||||
octavia_amp_boot_network_list:
|
||||
octavia_amp_secgroup_list:
|
||||
octavia_amp_flavor_id:
|
||||
|
||||
###################
|
||||
# Ceph options
|
||||
###################
|
||||
# Ceph can be setup with a caching to improve performance. To use the cache you
|
||||
# must provide separate disks than those for the OSDs
|
||||
ceph_enable_cache: "no"
|
||||
# Valid options are [ forward, none, writeback ]
|
||||
ceph_cache_mode: "writeback"
|
||||
|
||||
# Valid options are [ ext4, btrfs, xfs ]
|
||||
ceph_osd_filesystem: "xfs"
|
||||
|
||||
# Set to 'yes-i-really-really-mean-it' to force wipe disks with existing partitions for OSDs. Only
|
||||
# set if you understand the consequences!
|
||||
ceph_osd_wipe_disk: ""
|
||||
|
||||
# These are /etc/fstab options. Comma separated, no spaces (see fstab(8))
|
||||
ceph_osd_mount_options: "defaults,noatime"
|
||||
|
||||
# A requirement for using the erasure-coded pools is you must setup a cache tier
|
||||
# Valid options are [ erasure, replicated ]
|
||||
ceph_pool_type: "replicated"
|
||||
|
||||
# Integrate Ceph Rados Object Gateway with OpenStack keystone
|
||||
enable_ceph_rgw_keystone: "no"
|
||||
|
||||
ceph_cinder_pool_name: "volumes"
|
||||
ceph_cinder_backup_pool_name: "backups"
|
||||
ceph_glance_pool_name: "images"
|
||||
ceph_gnocchi_pool_name: "gnocchi"
|
||||
ceph_nova_pool_name: "vms"
|
||||
|
||||
ceph_erasure_profile: "k=4 m=2 ruleset-failure-domain=host"
|
||||
ceph_rule: "default host {{ 'indep' if ceph_pool_type == 'erasure' else 'firstn' }}"
|
||||
ceph_cache_rule: "cache host firstn"
|
|
@ -0,0 +1,193 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Sam Yaple
|
||||
#
|
||||
# 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.
|
||||
|
||||
# This module has been relicensed from the source below:
|
||||
# https://github.com/SamYaple/yaodu/blob/master/ansible/library/bslurp
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: bslurp
|
||||
short_description: Slurps a file from a remote node
|
||||
description:
|
||||
- Used for fetching a binary blob containing the file, then push that file
|
||||
to other hosts.
|
||||
options:
|
||||
src:
|
||||
description:
|
||||
- File to fetch. When dest is used, src is expected to be a str with data
|
||||
required: True
|
||||
type: str
|
||||
compress:
|
||||
description:
|
||||
- Compress file with zlib
|
||||
default: True
|
||||
type: bool
|
||||
dest:
|
||||
description:
|
||||
- Where to write out binary blob
|
||||
required: False
|
||||
type: str
|
||||
mode:
|
||||
description:
|
||||
- Destination file permissions
|
||||
default: '0644'
|
||||
type: str
|
||||
sha1:
|
||||
description:
|
||||
- sha1 hash of the underlying data
|
||||
default: None
|
||||
type: bool
|
||||
author: Sam Yaple
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Distribute a file from single to many hosts:
|
||||
|
||||
- hosts: web_servers
|
||||
tasks:
|
||||
- name: Pull in web config
|
||||
bslurp: src="/path/to/file"
|
||||
register: file_data
|
||||
run_once: True
|
||||
- name: Push if changed
|
||||
bslurp:
|
||||
src: "{{ file_data.content }}"
|
||||
dest: "{{ file_data.source }}"
|
||||
mode: "{{ file_data.mode }}"
|
||||
sha1: "{{ file_data.sha1 }}"
|
||||
|
||||
Distribute multiple files from single to many hosts:
|
||||
|
||||
- hosts: web_servers
|
||||
tasks:
|
||||
- name: Pull in web config
|
||||
bslurp: src="{{ item }}"
|
||||
with_items:
|
||||
- "/path/to/file1"
|
||||
- "/path/to/file2"
|
||||
- "/path/to/file3"
|
||||
register: file_data
|
||||
run_once: True
|
||||
- name: Push if changed
|
||||
bslurp:
|
||||
src: "{{ item.content }}"
|
||||
dest: "{{ item.source }}"
|
||||
mode: "{{ item.mode }}"
|
||||
sha1: "{{ item.sha1 }}"
|
||||
with_items: file_data.results
|
||||
|
||||
Distribute a file to many hosts without compression; Change
|
||||
permissions on dest:
|
||||
|
||||
- hosts: web_servers
|
||||
tasks:
|
||||
- name: Pull in web config
|
||||
bslurp: src="/path/to/file"
|
||||
register: file_data
|
||||
run_once: True
|
||||
- name: Push if changed
|
||||
bslurp:
|
||||
src: "{{ file_data.content }}"
|
||||
dest: "/new/path/to/file"
|
||||
mode: "0777"
|
||||
compress: False
|
||||
sha1: "{{ file_data.sha1 }}"
|
||||
'''
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
import traceback
|
||||
import zlib
|
||||
|
||||
|
||||
def copy_from_host(module):
|
||||
compress = module.params.get('compress')
|
||||
src = module.params.get('src')
|
||||
|
||||
if not os.path.exists(src):
|
||||
module.fail_json(msg="file not found: {}".format(src))
|
||||
if not os.access(src, os.R_OK):
|
||||
module.fail_json(msg="file is not readable: {}".format(src))
|
||||
|
||||
mode = oct(os.stat(src).st_mode & 0o777)
|
||||
|
||||
with open(src, 'rb') as f:
|
||||
raw_data = f.read()
|
||||
|
||||
sha1 = hashlib.sha1(raw_data).hexdigest()
|
||||
data = zlib.compress(raw_data) if compress else raw_data
|
||||
|
||||
module.exit_json(content=base64.b64encode(data), sha1=sha1, mode=mode,
|
||||
source=src)
|
||||
|
||||
|
||||
def copy_to_host(module):
|
||||
compress = module.params.get('compress')
|
||||
dest = module.params.get('dest')
|
||||
mode = int(module.params.get('mode'), 0)
|
||||
sha1 = module.params.get('sha1')
|
||||
src = module.params.get('src')
|
||||
|
||||
data = base64.b64decode(src)
|
||||
raw_data = zlib.decompress(data) if compress else data
|
||||
|
||||
if sha1:
|
||||
if os.path.exists(dest):
|
||||
if os.access(dest, os.R_OK):
|
||||
with open(dest, 'rb') as f:
|
||||
if hashlib.sha1(f.read()).hexdigest() == sha1:
|
||||
module.exit_json(changed=False)
|
||||
else:
|
||||
module.exit_json(failed=True, changed=False,
|
||||
msg='file is not accessible: {}'.format(dest))
|
||||
|
||||
if sha1 != hashlib.sha1(raw_data).hexdigest():
|
||||
module.exit_json(failed=True, changed=False,
|
||||
msg='sha1 sum does not match data')
|
||||
|
||||
with os.fdopen(os.open(dest, os.O_WRONLY | os.O_CREAT, mode), 'wb') as f:
|
||||
f.write(raw_data)
|
||||
|
||||
module.exit_json(changed=True)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = dict(
|
||||
compress=dict(default=True, type='bool'),
|
||||
dest=dict(type='str'),
|
||||
mode=dict(default='0644', type='str'),
|
||||
sha1=dict(default=None, type='str'),
|
||||
src=dict(required=True, type='str')
|
||||
)
|
||||
module = AnsibleModule(argument_spec)
|
||||
|
||||
dest = module.params.get('dest')
|
||||
|
||||
try:
|
||||
if dest:
|
||||
copy_to_host(module)
|
||||
else:
|
||||
copy_from_host(module)
|
||||
except Exception:
|
||||
module.exit_json(failed=True, changed=True,
|
||||
msg=repr(traceback.format_exc()))
|
||||
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import * # noqa
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2016 99cloud
|
||||
#
|
||||
# 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.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: kolla_container_facts
|
||||
short_description: Module for collecting Docker container facts
|
||||
description:
|
||||
- A module targeting at collecting Docker container facts. It is used for
|
||||
detecting whether the container is running on host in Kolla.
|
||||
options:
|
||||
api_version:
|
||||
description:
|
||||
- The version of the api for docker-py to use when contacting docker
|
||||
required: False
|
||||
type: str
|
||||
default: auto
|
||||
name:
|
||||
description:
|
||||
- Name or names of the containers
|
||||
required: False
|
||||
type: str or list
|
||||
author: Jeffrey Zhang
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: Gather docker facts
|
||||
kolla_container_facts:
|
||||
|
||||
- name: Gather glance container facts
|
||||
kolla_container_facts:
|
||||
name:
|
||||
- glance_api
|
||||
- glance_registry
|
||||
'''
|
||||
|
||||
import docker
|
||||
|
||||
|
||||
def get_docker_client():
|
||||
try:
|
||||
return docker.Client
|
||||
except AttributeError:
|
||||
return docker.APIClient
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = dict(
|
||||
name=dict(required=False, type='list', default=[]),
|
||||
api_version=dict(required=False, type='str', default='auto')
|
||||
)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec)
|
||||
|
||||
results = dict(changed=False, _containers=[])
|
||||
client = get_docker_client()(version=module.params.get('api_version'))
|
||||
containers = client.containers()
|
||||
names = module.params.get('name')
|
||||
if names and not isinstance(names, list):
|
||||
names = [names]
|
||||
for container in containers:
|
||||
for container_name in container['Names']:
|
||||
# remove '/' prefix character
|
||||
container_name = container_name[1:]
|
||||
if names and container_name not in names:
|
||||
continue
|
||||
results['_containers'].append(container)
|
||||
results[container_name] = container
|
||||
module.exit_json(**results)
|
||||
|
||||
|
||||
from ansible.module_utils.basic import * # noqa
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,800 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Sam Yaple
|
||||
#
|
||||
# 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.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: kolla_docker
|
||||
short_description: Module for controlling Docker
|
||||
description:
|
||||
- A module targeting at controlling Docker as used by Kolla.
|
||||
options:
|
||||
common_options:
|
||||
description:
|
||||
- A dict containing common params such as login info
|
||||
required: False
|
||||
type: dict
|
||||
default: dict()
|
||||
action:
|
||||
description:
|
||||
- The action the module should take
|
||||
required: True
|
||||
type: str
|
||||
choices:
|
||||
- compare_container
|
||||
- compare_image
|
||||
- create_volume
|
||||
- get_container_env
|
||||
- get_container_state
|
||||
- pull_image
|
||||
- remove_container
|
||||
- remove_volume
|
||||
- recreate_or_restart_container
|
||||
- restart_container
|
||||
- start_container
|
||||
- stop_container
|
||||
api_version:
|
||||
description:
|
||||
- The version of the api for docker-py to use when contacting docker
|
||||
required: False
|
||||
type: str
|
||||
default: auto
|
||||
auth_email:
|
||||
description:
|
||||
- The email address used to authenticate
|
||||
required: False
|
||||
type: str
|
||||
auth_password:
|
||||
description:
|
||||
- The password used to authenticate
|
||||
required: False
|
||||
type: str
|
||||
auth_registry:
|
||||
description:
|
||||
- The registry to authenticate
|
||||
required: False
|
||||
type: str
|
||||
auth_username:
|
||||
description:
|
||||
- The username used to authenticate
|
||||
required: False
|
||||
type: str
|
||||
detach:
|
||||
description:
|
||||
- Detach from the container after it is created
|
||||
required: False
|
||||
default: True
|
||||
type: bool
|
||||
name:
|
||||
description:
|
||||
- Name of the container or volume to manage
|
||||
required: False
|
||||
type: str
|
||||
environment:
|
||||
description:
|
||||
- The environment to set for the container
|
||||
required: False
|
||||
type: dict
|
||||
image:
|
||||
description:
|
||||
- Name of the docker image
|
||||
required: False
|
||||
type: str
|
||||
ipc_mode:
|
||||
description:
|
||||
- Set docker ipc namespace
|
||||
required: False
|
||||
type: str
|
||||
default: None
|
||||
choices:
|
||||
- host
|
||||
cap_add:
|
||||
description:
|
||||
- Add capabilities to docker container
|
||||
required: False
|
||||
type: list
|
||||
default: list()
|
||||
security_opt:
|
||||
description:
|
||||
- Set container security profile
|
||||
required: False
|
||||
type: list
|
||||
default: list()
|
||||
labels:
|
||||
description:
|
||||
- List of labels to apply to container
|
||||
required: False
|
||||
type: dict
|
||||
default: dict()
|
||||
pid_mode:
|
||||
description:
|
||||
- Set docker pid namespace
|
||||
required: False
|
||||
type: str
|
||||
default: None
|
||||
choices:
|
||||
- host
|
||||
privileged:
|
||||
description:
|
||||
- Set the container to privileged
|
||||
required: False
|
||||
default: False
|
||||
type: bool
|
||||
remove_on_exit:
|
||||
description:
|
||||
- When not detaching from container, remove on successful exit
|
||||
required: False
|
||||
default: True
|
||||
type: bool
|
||||
restart_policy:
|
||||
description:
|
||||
- Determine what docker does when the container exits
|
||||
required: False
|
||||
type: str
|
||||
choices:
|
||||
- never
|
||||
- on-failure
|
||||
- always
|
||||
- unless-stopped
|
||||
restart_retries:
|
||||
description:
|
||||
- How many times to attempt a restart if restart_policy is set
|
||||
type: int
|
||||
default: 10
|
||||
volumes:
|
||||
description:
|
||||
- Set volumes for docker to use
|
||||
required: False
|
||||
type: list
|
||||
volumes_from:
|
||||
description:
|
||||
- Name or id of container(s) to use volumes from
|
||||
required: True
|
||||
type: list
|
||||
author: Sam Yaple
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- hosts: kolla_docker
|
||||
tasks:
|
||||
- name: Start container
|
||||
kolla_docker:
|
||||
image: ubuntu
|
||||
name: test_container
|
||||
action: start_container
|
||||
- name: Remove container
|
||||
kolla_docker:
|
||||
name: test_container
|
||||
action: remove_container
|
||||
- name: Pull image without starting container
|
||||
kolla_docker:
|
||||
action: pull_container
|
||||
image: private-registry.example.com:5000/ubuntu
|
||||
- name: Create named volume
|
||||
action: create_volume
|
||||
name: name_of_volume
|
||||
- name: Remove named volume
|
||||
action: remove_volume
|
||||
name: name_of_volume
|
||||
'''
|
||||
|
||||
import json
|
||||
import os
|
||||
import traceback
|
||||
|
||||
import docker
|
||||
|
||||
|
||||
def get_docker_client():
|
||||
try:
|
||||
return docker.Client
|
||||
except AttributeError:
|
||||
return docker.APIClient
|
||||
|
||||
|
||||
class DockerWorker(object):
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.params = self.module.params
|
||||
self.changed = False
|
||||
|
||||
# TLS not fully implemented
|
||||
# tls_config = self.generate_tls()
|
||||
|
||||
options = {
|
||||
'version': self.params.get('api_version')
|
||||
}
|
||||
|
||||
self.dc = get_docker_client()(**options)
|
||||
|
||||
def generate_tls(self):
|
||||
tls = {'verify': self.params.get('tls_verify')}
|
||||
tls_cert = self.params.get('tls_cert'),
|
||||
tls_key = self.params.get('tls_key'),
|
||||
tls_cacert = self.params.get('tls_cacert')
|
||||
|
||||
if tls['verify']:
|
||||
if tls_cert:
|
||||
self.check_file(tls_cert)
|
||||
self.check_file(tls_key)
|
||||
tls['client_cert'] = (tls_cert, tls_key)
|
||||
if tls_cacert:
|
||||
self.check_file(tls_cacert)
|
||||
tls['verify'] = tls_cacert
|
||||
|
||||
return docker.tls.TLSConfig(**tls)
|
||||
|
||||
def check_file(self, path):
|
||||
if not os.path.isfile(path):
|
||||
self.module.fail_json(
|
||||
failed=True,
|
||||
msg='There is no file at "{}"'.format(path)
|
||||
)
|
||||
if not os.access(path, os.R_OK):
|
||||
self.module.fail_json(
|
||||
failed=True,
|
||||
msg='Permission denied for file at "{}"'.format(path)
|
||||
)
|
||||
|
||||
def check_image(self):
|
||||
find_image = ':'.join(self.parse_image())
|
||||
for image in self.dc.images():
|
||||
repo_tags = image.get('RepoTags')
|
||||
if not repo_tags:
|
||||
continue
|
||||
for image_name in repo_tags:
|
||||
if image_name == find_image:
|
||||
return image
|
||||
|
||||
def check_volume(self):
|
||||
for vol in self.dc.volumes()['Volumes'] or list():
|
||||
if vol['Name'] == self.params.get('name'):
|
||||
return vol
|
||||
|
||||
def check_container(self):
|
||||
find_name = '/{}'.format(self.params.get('name'))
|
||||
for cont in self.dc.containers(all=True):
|
||||
if find_name in cont['Names']:
|
||||
return cont
|
||||
|
||||
def get_container_info(self):
|
||||
container = self.check_container()
|
||||
if not container:
|
||||
return None
|
||||
return self.dc.inspect_container(self.params.get('name'))
|
||||
|
||||
def compare_container(self):
|
||||
container = self.check_container()
|
||||
if not container or self.check_container_differs():
|
||||
self.changed = True
|
||||
return self.changed
|
||||
|
||||
def check_container_differs(self):
|
||||
container_info = self.get_container_info()
|
||||
return (
|
||||
self.compare_cap_add(container_info) or
|
||||
self.compare_security_opt(container_info) or
|
||||
self.compare_image(container_info) or
|
||||
self.compare_ipc_mode(container_info) or
|
||||
self.compare_labels(container_info) or
|
||||
self.compare_privileged(container_info) or
|
||||
self.compare_pid_mode(container_info) or
|
||||
self.compare_volumes(container_info) or
|
||||
self.compare_volumes_from(container_info) or
|
||||
self.compare_environment(container_info)
|
||||
)
|
||||
|
||||
def compare_ipc_mode(self, container_info):
|
||||
new_ipc_mode = self.params.get('ipc_mode')
|
||||
current_ipc_mode = container_info['HostConfig'].get('IpcMode')
|
||||
if not current_ipc_mode:
|
||||
current_ipc_mode = None
|
||||
|
||||
if new_ipc_mode != current_ipc_mode:
|
||||
return True
|
||||
|
||||
def compare_cap_add(self, container_info):
|
||||
new_cap_add = self.params.get('cap_add', list())
|
||||
current_cap_add = container_info['HostConfig'].get('CapAdd',
|
||||
list())
|
||||
if not current_cap_add:
|
||||
current_cap_add = list()
|
||||
if set(new_cap_add).symmetric_difference(set(current_cap_add)):
|
||||
return True
|
||||
|
||||
def compare_security_opt(self, container_info):
|
||||
ipc_mode = self.params.get('ipc_mode')
|
||||
pid_mode = self.params.get('pid_mode')
|
||||
privileged = self.params.get('privileged', False)
|
||||
# NOTE(jeffrey4l) security opt is disabled when using host ipc mode or
|
||||
# host pid mode or privileged. So no need to compare security opts
|
||||
if ipc_mode == 'host' or pid_mode == 'host' or privileged:
|
||||
return False
|
||||
new_sec_opt = self.params.get('security_opt', list())
|
||||
current_sec_opt = container_info['HostConfig'].get('SecurityOpt',
|
||||
list())
|
||||
if not current_sec_opt:
|
||||
current_sec_opt = list()
|
||||
if set(new_sec_opt).symmetric_difference(set(current_sec_opt)):
|
||||
return True
|
||||
|
||||
def compare_pid_mode(self, container_info):
|
||||
new_pid_mode = self.params.get('pid_mode')
|
||||
current_pid_mode = container_info['HostConfig'].get('PidMode')
|
||||
if not current_pid_mode:
|
||||
current_pid_mode = None
|
||||
|
||||
if new_pid_mode != current_pid_mode:
|
||||
return True
|
||||
|
||||
def compare_privileged(self, container_info):
|
||||
new_privileged = self.params.get('privileged')
|
||||
current_privileged = container_info['HostConfig']['Privileged']
|
||||
if new_privileged != current_privileged:
|
||||
return True
|
||||
|
||||
def compare_image(self, container_info=None):
|
||||
container_info = container_info or self.get_container_info()
|
||||
parse_repository_tag = docker.utils.parse_repository_tag
|
||||
if not container_info:
|
||||
return True
|
||||
new_image = self.check_image()
|
||||
current_image = container_info['Image']
|
||||
if not new_image:
|
||||
return True
|
||||
if new_image['Id'] != current_image:
|
||||
return True
|
||||
# NOTE(Jeffrey4l) when new image and the current image have
|
||||
# the same id, but the tag name different.
|
||||
elif (parse_repository_tag(container_info['Config']['Image']) !=
|
||||
parse_repository_tag(self.params.get('image'))):
|
||||
return True
|
||||
|
||||
def compare_labels(self, container_info):
|
||||
new_labels = self.params.get('labels')
|
||||
current_labels = container_info['Config'].get('Labels', dict())
|
||||
image_labels = self.check_image().get('Labels', dict())
|
||||
for k, v in image_labels.items():
|
||||
if k in new_labels:
|
||||
if v != new_labels[k]:
|
||||
return True
|
||||
else:
|
||||
del current_labels[k]
|
||||
|
||||
if new_labels != current_labels:
|
||||
return True
|
||||
|
||||
def compare_volumes_from(self, container_info):
|
||||
new_vols_from = self.params.get('volumes_from')
|
||||
current_vols_from = container_info['HostConfig'].get('VolumesFrom')
|
||||
if not new_vols_from:
|
||||
new_vols_from = list()
|
||||
if not current_vols_from:
|
||||
current_vols_from = list()
|
||||
|
||||
if set(current_vols_from).symmetric_difference(set(new_vols_from)):
|
||||
return True
|
||||
|
||||
def compare_volumes(self, container_info):
|
||||
volumes, binds = self.generate_volumes()
|
||||
current_vols = container_info['Config'].get('Volumes')
|
||||
current_binds = container_info['HostConfig'].get('Binds')
|
||||
if not volumes:
|
||||
volumes = list()
|
||||
if not current_vols:
|
||||
current_vols = list()
|
||||
if not current_binds:
|
||||
current_binds = list()
|
||||
|
||||
if set(volumes).symmetric_difference(set(current_vols)):
|
||||
return True
|
||||
|
||||
new_binds = list()
|
||||
if binds:
|
||||
for k, v in binds.items():
|
||||
new_binds.append("{}:{}:{}".format(k, v['bind'], v['mode']))
|
||||
|
||||
if set(new_binds).symmetric_difference(set(current_binds)):
|
||||
return True
|
||||
|
||||
def compare_environment(self, container_info):
|
||||
if self.params.get('environment'):
|
||||
current_env = dict()
|
||||
for kv in container_info['Config'].get('Env', list()):
|
||||
k, v = kv.split('=', 1)
|
||||
current_env.update({k: v})
|
||||
|
||||
for k, v in self.params.get('environment').items():
|
||||
if k not in current_env:
|
||||
return True
|
||||
if current_env[k] != v:
|
||||
return True
|
||||
|
||||
def parse_image(self):
|
||||
full_image = self.params.get('image')
|
||||
|
||||
if '/' in full_image:
|
||||
registry, image = full_image.split('/', 1)
|
||||
else:
|
||||
image = full_image
|
||||
|
||||
if ':' in image:
|
||||
return full_image.rsplit(':', 1)
|
||||
else:
|
||||
return full_image, 'latest'
|
||||
|
||||
def pull_image(self):
|
||||
if self.params.get('auth_username'):
|
||||
self.dc.login(
|
||||
username=self.params.get('auth_username'),
|
||||
password=self.params.get('auth_password'),
|
||||
registry=self.params.get('auth_registry'),
|
||||
email=self.params.get('auth_email')
|
||||
)
|
||||
|
||||
image, tag = self.parse_image()
|
||||
|
||||
statuses = [
|
||||
json.loads(line.strip().decode('utf-8')) for line in self.dc.pull(
|
||||
repository=image, tag=tag, stream=True
|
||||
)
|
||||
]
|
||||
|
||||
for status in reversed(statuses):
|
||||
if 'error' in status:
|
||||
if status['error'].endswith('not found'):
|
||||
self.module.fail_json(
|
||||
msg="The requested image does not exist: {}:{}".format(
|
||||
image, tag),
|
||||
failed=True
|
||||
)
|
||||
else:
|
||||
self.module.fail_json(
|
||||
msg="Unknown error message: {}".format(
|
||||
status['error']),
|
||||
failed=True
|
||||
)
|
||||
|
||||
if status and status.get('status'):
|
||||
# NOTE(SamYaple): This allows us to use v1 and v2 docker
|
||||
# registries. Eventually docker will stop supporting v1
|
||||
# registries and when that happens we can remove this.
|
||||
if 'legacy registry' in status['status']:
|
||||
continue
|
||||
elif 'Downloaded newer image for' in status['status']:
|
||||
self.changed = True
|
||||
return
|
||||
elif 'Image is up to date for' in status['status']:
|
||||
return
|
||||
else:
|
||||
self.module.fail_json(
|
||||
msg="Unknown status message: {}".format(
|
||||
status['status']),
|
||||
failed=True
|
||||
)
|
||||
|
||||
def remove_container(self):
|
||||
if self.check_container():
|
||||
self.changed = True
|
||||
self.dc.remove_container(
|
||||
container=self.params.get('name'),
|
||||
force=True
|
||||
)
|
||||
|
||||
def generate_volumes(self):
|
||||
volumes = self.params.get('volumes')
|
||||
if not volumes:
|
||||
return None, None
|
||||
|
||||
vol_list = list()
|
||||
vol_dict = dict()
|
||||
|
||||
for vol in volumes:
|
||||
if len(vol) == 0:
|
||||
continue
|
||||
|
||||
if ':' not in vol:
|
||||
vol_list.append(vol)
|
||||
continue
|
||||
|
||||
split_vol = vol.split(':')
|
||||
|
||||
if (len(split_vol) == 2
|
||||
and ('/' not in split_vol[0] or '/' in split_vol[1])):
|
||||
split_vol.append('rw')
|
||||
|
||||
vol_list.append(split_vol[1])
|
||||
vol_dict.update({
|
||||
split_vol[0]: {
|
||||
'bind': split_vol[1],
|
||||
'mode': split_vol[2]
|
||||
}
|
||||
})
|
||||
|
||||
return vol_list, vol_dict
|
||||
|
||||
def build_host_config(self, binds):
|
||||
options = {
|
||||
'network_mode': 'host',
|
||||
'ipc_mode': self.params.get('ipc_mode'),
|
||||
'cap_add': self.params.get('cap_add'),
|
||||
'security_opt': self.params.get('security_opt'),
|
||||
'pid_mode': self.params.get('pid_mode'),
|
||||
'privileged': self.params.get('privileged'),
|
||||
'volumes_from': self.params.get('volumes_from')
|
||||
}
|
||||
|
||||
if self.params.get('restart_policy') in ['on-failure',
|
||||
'always',
|
||||
'unless-stopped']:
|
||||
policy = {'Name': self.params.get('restart_policy')}
|
||||
# NOTE(Jeffrey4l): MaximumRetryCount is only needed for on-failure
|
||||
# policy
|
||||
if self.params.get('restart_policy') == 'on-failure':
|
||||
retries = self.params.get('restart_retries')
|
||||
policy['MaximumRetryCount'] = retries
|
||||
options['restart_policy'] = policy
|
||||
|
||||
if binds:
|
||||
options['binds'] = binds
|
||||
|
||||
return self.dc.create_host_config(**options)
|
||||
|
||||
def _inject_env_var(self, environment_info):
|
||||
newenv = {
|
||||
'KOLLA_SERVICE_NAME': self.params.get('name').replace('_', '-')
|
||||
}
|
||||
environment_info.update(newenv)
|
||||
return environment_info
|
||||
|
||||
def _format_env_vars(self):
|
||||
env = self._inject_env_var(self.params.get('environment'))
|
||||
return {k: "" if env[k] is None else env[k] for k in env}
|
||||
|
||||
def build_container_options(self):
|
||||
volumes, binds = self.generate_volumes()
|
||||
return {
|
||||
'detach': self.params.get('detach'),
|
||||
'environment': self._format_env_vars(),
|
||||
'host_config': self.build_host_config(binds),
|
||||
'labels': self.params.get('labels'),
|
||||
'image': self.params.get('image'),
|
||||
'name': self.params.get('name'),
|
||||
'volumes': volumes,
|
||||
'tty': True
|
||||
}
|
||||
|
||||
def create_container(self):
|
||||
self.changed = True
|
||||
options = self.build_container_options()
|
||||
self.dc.create_container(**options)
|
||||
|
||||
def recreate_or_restart_container(self):
|
||||
self.changed = True
|
||||
container = self.check_container()
|
||||
# get config_strategy from env
|
||||
environment = self.params.get('environment')
|
||||
config_strategy = environment.get('KOLLA_CONFIG_STRATEGY')
|
||||
|
||||
if not container:
|
||||
self.start_container()
|
||||
return
|
||||
# If config_strategy is COPY_ONCE or container's parameters are
|
||||
# changed, try to start a new one.
|
||||
if config_strategy == 'COPY_ONCE' or self.check_container_differs():
|
||||
self.remove_container()
|
||||
self.start_container()
|
||||
elif config_strategy == 'COPY_ALWAYS':
|
||||
self.restart_container()
|
||||
|
||||
def start_container(self):
|
||||
if not self.check_image():
|
||||
self.pull_image()
|
||||
|
||||
container = self.check_container()
|
||||
if container and self.check_container_differs():
|
||||
self.remove_container()
|
||||
container = self.check_container()
|
||||
|
||||
if not container:
|
||||
self.create_container()
|
||||
container = self.check_container()
|
||||
|
||||
if not container['Status'].startswith('Up '):
|
||||
self.changed = True
|
||||
self.dc.start(container=self.params.get('name'))
|
||||
|
||||
# We do not want to detach so we wait around for container to exit
|
||||
if not self.params.get('detach'):
|
||||
rc = self.dc.wait(self.params.get('name'))
|
||||
if rc != 0:
|
||||
self.module.fail_json(
|
||||
failed=True,
|
||||
changed=True,
|
||||
msg="Container exited with non-zero return code"
|
||||
)
|
||||
if self.params.get('remove_on_exit'):
|
||||
self.remove_container()
|
||||
|
||||
def get_container_env(self):
|
||||
name = self.params.get('name')
|
||||
info = self.get_container_info()
|
||||
if not info:
|
||||
self.module.fail_json(msg="No such container: {}".format(name))
|
||||
else:
|
||||
envs = dict()
|
||||
for env in info['Config']['Env']:
|
||||
if '=' in env:
|
||||
key, value = env.split('=', 1)
|
||||
else:
|
||||
key, value = env, ''
|
||||
envs[key] = value
|
||||
|
||||
self.module.exit_json(**envs)
|
||||
|
||||
def get_container_state(self):
|
||||
name = self.params.get('name')
|
||||
info = self.get_container_info()
|
||||
if not info:
|
||||
self.module.fail_json(msg="No such container: {}".format(name))
|
||||
else:
|
||||
self.module.exit_json(**info['State'])
|
||||
|
||||
def stop_container(self):
|
||||
name = self.params.get('name')
|
||||
container = self.check_container()
|
||||
if not container:
|
||||
self.module.fail_json(
|
||||
msg="No such container: {} to stop".format(name))
|
||||
elif not container['Status'].startswith('Exited '):
|
||||
self.changed = True
|
||||
self.dc.stop(name)
|
||||
|
||||
def restart_container(self):
|
||||
name = self.params.get('name')
|
||||
info = self.get_container_info()
|
||||
if not info:
|
||||
self.module.fail_json(
|
||||
msg="No such container: {}".format(name))
|
||||
else:
|
||||
self.changed = True
|
||||
self.dc.restart(name)
|
||||
|
||||
def create_volume(self):
|
||||
if not self.check_volume():
|
||||
self.changed = True
|
||||
self.dc.create_volume(name=self.params.get('name'), driver='local')
|
||||
|
||||
def remove_volume(self):
|
||||
if self.check_volume():
|
||||
self.changed = True
|
||||
try:
|
||||
self.dc.remove_volume(name=self.params.get('name'))
|
||||
except docker.errors.APIError as e:
|
||||
if e.response.status_code == 409:
|
||||
self.module.fail_json(
|
||||
failed=True,
|
||||
msg="Volume named '{}' is currently in-use".format(
|
||||
self.params.get('name')
|
||||
)
|
||||
)
|
||||
raise
|
||||
|
||||
|
||||
def generate_module():
|
||||
# NOTE(jeffrey4l): add empty string '' to choices let us use
|
||||
# pid_mode: "{{ service.pid_mode | default ('') }}" in yaml
|
||||
argument_spec = dict(
|
||||
common_options=dict(required=False, type='dict', default=dict()),
|
||||
action=dict(required=True, type='str',
|
||||
choices=['compare_container', 'compare_image',
|
||||
'create_volume', 'get_container_env',
|
||||
'get_container_state', 'pull_image',
|
||||
'recreate_or_restart_container',
|
||||
'remove_container', 'remove_volume',
|
||||
'restart_container', 'start_container',
|
||||
'stop_container']),
|
||||
api_version=dict(required=False, type='str', default='auto'),
|
||||
auth_email=dict(required=False, type='str'),
|
||||
auth_password=dict(required=False, type='str'),
|
||||
auth_registry=dict(required=False, type='str'),
|
||||
auth_username=dict(required=False, type='str'),
|
||||
detach=dict(required=False, type='bool', default=True),
|
||||
labels=dict(required=False, type='dict', default=dict()),
|
||||
name=dict(required=False, type='str'),
|
||||
environment=dict(required=False, type='dict'),
|
||||
image=dict(required=False, type='str'),
|
||||
ipc_mode=dict(required=False, type='str', choices=['host', '']),
|
||||
cap_add=dict(required=False, type='list', default=list()),
|
||||
security_opt=dict(required=False, type='list', default=list()),
|
||||
pid_mode=dict(required=False, type='str', choices=['host', '']),
|
||||
privileged=dict(required=False, type='bool', default=False),
|
||||
remove_on_exit=dict(required=False, type='bool', default=True),
|
||||
restart_policy=dict(required=False, type='str', choices=[
|
||||
'no',
|
||||
'never',
|
||||
'on-failure',
|
||||
'always',
|
||||
'unless-stopped']),
|
||||
restart_retries=dict(required=False, type='int', default=10),
|
||||
tls_verify=dict(required=False, type='bool', default=False),
|
||||
tls_cert=dict(required=False, type='str'),
|
||||
tls_key=dict(required=False, type='str'),
|
||||
tls_cacert=dict(required=False, type='str'),
|
||||
volumes=dict(required=False, type='list'),
|
||||
volumes_from=dict(required=False, type='list')
|
||||
)
|
||||
required_if = [
|
||||
['action', 'pull_image', ['image']],
|
||||
['action', 'start_container', ['image', 'name']],
|
||||
['action', 'compare_container', ['name']],
|
||||
['action', 'compare_image', ['name']],
|
||||
['action', 'create_volume', ['name']],
|
||||
['action', 'get_container_env', ['name']],
|
||||
['action', 'get_container_state', ['name']],
|
||||
['action', 'recreate_or_restart_container', ['name']],
|
||||
['action', 'remove_container', ['name']],
|
||||
['action', 'remove_volume', ['name']],
|
||||
['action', 'restart_container', ['name']],
|
||||
['action', 'stop_container', ['name']]
|
||||
]
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_if=required_if,
|
||||
bypass_checks=False
|
||||
)
|
||||
|
||||
new_args = module.params.pop('common_options', dict())
|
||||
|
||||
# NOTE(jeffrey4l): merge the environment
|
||||
env = module.params.pop('environment', dict())
|
||||
if env:
|
||||
new_args['environment'].update(env)
|
||||
|
||||
for key, value in module.params.items():
|
||||
if key in new_args and value is None:
|
||||
continue
|
||||
new_args[key] = value
|
||||
|
||||
# if pid_mode = ""/None/False, remove it
|
||||
if not new_args.get('pid_mode', False):
|
||||
new_args.pop('pid_mode', None)
|
||||
# if ipc_mode = ""/None/False, remove it
|
||||
if not new_args.get('ipc_mode', False):
|
||||
new_args.pop('ipc_mode', None)
|
||||
|
||||
module.params = new_args
|
||||
return module
|
||||
|
||||
|
||||
def main():
|
||||
module = generate_module()
|
||||
|
||||
try:
|
||||
dw = DockerWorker(module)
|
||||
# TODO(inc0): We keep it bool to have ansible deal with consistent
|
||||
# types. If we ever add method that will have to return some
|
||||
# meaningful data, we need to refactor all methods to return dicts.
|
||||
result = bool(getattr(dw, module.params.get('action'))())
|
||||
module.exit_json(changed=dw.changed, result=result)
|
||||
except Exception:
|
||||
module.exit_json(failed=True, changed=True,
|
||||
msg=repr(traceback.format_exc()))
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import * # noqa
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2016 99cloud 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.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: kolla_toolbox
|
||||
short_description: >
|
||||
Module for invoking ansible module in kolla_toolbox container.
|
||||
description:
|
||||
- A module targerting at invoking ansible module in kolla_toolbox
|
||||
container as used by Kolla project.
|
||||
options:
|
||||
module_name:
|
||||
description:
|
||||
- The module name to invoke
|
||||
required: True
|
||||
type: str
|
||||
module_args:
|
||||
description:
|
||||
- The module args use by the module
|
||||
required: False
|
||||
type: str or dict
|
||||
module_extra_vars:
|
||||
description:
|
||||
- The extra variables used by the module
|
||||
required: False
|
||||
type: str or dict
|
||||
author: Jeffrey Zhang
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- hosts: controller
|
||||
tasks:
|
||||
- name: Ensure the direct absent
|
||||
kolla_toolbox:
|
||||
module_name: file
|
||||
module_args: path=/tmp/a state=absent
|
||||
- name: Create mysql database
|
||||
kolla_toolbox:
|
||||
module_name: mysql_db
|
||||
module_args:
|
||||
login_host: 192.168.1.10
|
||||
login_user: root
|
||||
login_password: admin
|
||||
name: testdb
|
||||
- name: Creating default user role
|
||||
kolla_toolbox:
|
||||
module_name: os_keystone_role
|
||||
module_args:
|
||||
name: _member_
|
||||
auth: "{{ '{{ openstack_keystone_auth }}' }}"
|
||||
module_extra_vars:
|
||||
openstack_keystone_auth:
|
||||
auth_url: http://127.0.0.1:5000
|
||||
username: admin
|
||||
password: password
|
||||
project_name: "admin"
|
||||
domain_name: "default"
|
||||
'''
|
||||
|
||||
|
||||
import docker
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
JSON_REG = re.compile('^(?P<host>\w+) \| (?P<status>\w+)!? =>(?P<stdout>.*)$',
|
||||
re.MULTILINE | re.DOTALL)
|
||||
NON_JSON_REG = re.compile(('^(?P<host>\w+) \| (?P<status>\w+)!? \| '
|
||||
'rc=(?P<exit_code>\d+) >>\n(?P<stdout>.*)\n$'),
|
||||
re.MULTILINE | re.DOTALL)
|
||||
|
||||
|
||||
def gen_commandline(params):
|
||||
command = ['ansible', 'localhost']
|
||||
if params.get('module_name'):
|
||||
command.extend(['-m', params.get('module_name')])
|
||||
if params.get('module_args'):
|
||||
module_args = params.get('module_args')
|
||||
if isinstance(module_args, dict):
|
||||
module_args = ' '.join("{}='{}'".format(key, value)
|
||||
for key, value in module_args.items())
|
||||
command.extend(['-a', module_args])
|
||||
if params.get('module_extra_vars'):
|
||||
extra_vars = params.get('module_extra_vars')
|
||||
if isinstance(extra_vars, dict):
|
||||
extra_vars = json.dumps(extra_vars)
|
||||
command.extend(['--extra-vars', extra_vars])
|
||||
return command
|
||||
|
||||
|
||||
def get_docker_client():
|
||||
try:
|
||||
return docker.Client
|
||||
except AttributeError:
|
||||
return docker.APIClient
|
||||
|
||||
|
||||
def main():
|
||||
specs = dict(
|
||||
module_name=dict(type='str'),
|
||||
module_args=dict(type='str'),
|
||||
module_extra_vars=dict(type='json')
|
||||
)
|
||||
module = AnsibleModule(argument_spec=specs, bypass_checks=True)
|
||||
client = get_docker_client()()
|
||||
command_line = gen_commandline(module.params)
|
||||
kolla_toolbox = client.containers(filters=dict(name='kolla_toolbox',
|
||||
status='running'))
|
||||
if not kolla_toolbox:
|
||||
module.fail_json(msg='kolla_toolbox container is not running.')
|
||||
|
||||
kolla_toolbox = kolla_toolbox[0]
|
||||
job = client.exec_create(kolla_toolbox, command_line)
|
||||
output = client.exec_start(job)
|
||||
|
||||
for exp in [JSON_REG, NON_JSON_REG]:
|
||||
m = exp.match(output)
|
||||
if m:
|
||||
inner_output = m.groupdict().get('stdout')
|
||||
break
|
||||
else:
|
||||
module.fail_json(
|
||||
msg='Can not parse the inner module output: %s' % output)
|
||||
|
||||
ret = dict()
|
||||
try:
|
||||
ret = json.loads(inner_output)
|
||||
except ValueError:
|
||||
ret['stdout'] = inner_output
|
||||
|
||||
module.exit_json(**ret)
|
||||
|
||||
|
||||
from ansible.module_utils.basic import * # noqa
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Sam Yaple
|
||||
#
|
||||
# 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.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: merge_configs
|
||||
short_description: Merge ini-style configs
|
||||
description:
|
||||
- ConfigParser is used to merge several ini-style configs into one
|
||||
options:
|
||||
dest:
|
||||
description:
|
||||
- The destination file name
|
||||
required: True
|
||||
type: str
|
||||
sources:
|
||||
description:
|
||||
- A list of files on the destination node to merge together
|
||||
default: None
|
||||
required: True
|
||||
type: str
|
||||
author: Sam Yaple
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Merge multiple configs:
|
||||
|
||||
- hosts: database
|
||||
tasks:
|
||||
- name: Merge configs
|
||||
merge_configs:
|
||||
sources:
|
||||
- "/tmp/config_1.cnf"
|
||||
- "/tmp/config_2.cnf"
|
||||
- "/tmp/config_3.cnf"
|
||||
dest:
|
||||
- "/etc/mysql/my.cnf"
|
||||
'''
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Sam Yaple
|
||||
# Copyright 2016 intel
|
||||
#
|
||||
# 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.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: merge_yaml
|
||||
short_description: Merge yaml-style configs
|
||||
description:
|
||||
- PyYAML is used to merge several yaml files into one
|
||||
options:
|
||||
dest:
|
||||
description:
|
||||
- The destination file name
|
||||
required: True
|
||||
type: str
|
||||
sources:
|
||||
description:
|
||||
- A list of files on the destination node to merge together
|
||||
default: None
|
||||
required: True
|
||||
type: str
|
||||
author: Sean Mooney
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Merge multiple yaml files:
|
||||
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- name: Merge yaml files
|
||||
merge_yaml:
|
||||
sources:
|
||||
- "/tmp/default.yml"
|
||||
- "/tmp/override.yml"
|
||||
dest:
|
||||
- "/tmp/out.yml"
|
||||
'''
|
|
@ -0,0 +1,262 @@
|
|||
---
|
||||
project_name: "neutron"
|
||||
|
||||
neutron_services:
|
||||
openvswitch-db-server:
|
||||
container_name: "openvswitch_db"
|
||||
image: "{{ openvswitch_db_image_full }}"
|
||||
enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/openvswitch-db-server/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run:/run:shared"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
- "openvswitch_db:/var/lib/openvswitch/"
|
||||
openvswitch-vswitchd:
|
||||
container_name: "openvswitch_vswitchd"
|
||||
image: "{{ openvswitch_vswitchd_image_full }}"
|
||||
enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
|
||||
privileged: True
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/openvswitch-vswitchd/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/lib/modules:/lib/modules:ro"
|
||||
- "/run:/run:shared"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-server:
|
||||
container_name: "neutron_server"
|
||||
image: "{{ neutron_server_image_full }}"
|
||||
enabled: true
|
||||
group: "neutron-server"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-server/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-openvswitch-agent:
|
||||
container_name: "neutron_openvswitch_agent"
|
||||
image: "{{ neutron_openvswitch_agent_image_full }}"
|
||||
enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
|
||||
privileged: True
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-openvswitch-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/lib/modules:/lib/modules:ro"
|
||||
- "/run:/run:shared"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-sfc-agent:
|
||||
container_name: "neutron_sfc_agent"
|
||||
image: "{{ neutron_sfc_agent_image_full }}"
|
||||
enabled: "{{ neutron_plugin_agent == 'sfc' }}"
|
||||
privileged: True
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-sfc-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/lib/modules:/lib/modules:ro"
|
||||
- "/run:/run:shared"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-linuxbridge-agent:
|
||||
container_name: "neutron_linuxbridge_agent"
|
||||
image: "{{ neutron_linuxbridge_agent_image_full }}"
|
||||
privileged: True
|
||||
enabled: "{{ neutron_plugin_agent == 'linuxbridge' }}"
|
||||
environment:
|
||||
KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
|
||||
NEUTRON_BRIDGE: "br-ex"
|
||||
NEUTRON_INTERFACE: "{{ neutron_external_interface }}"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-linuxbridge-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/lib/modules:/lib/modules:ro"
|
||||
- "/run:/run:shared"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-dhcp-agent:
|
||||
container_name: "neutron_dhcp_agent"
|
||||
image: "{{ neutron_dhcp_agent_image_full }}"
|
||||
privileged: True
|
||||
enabled: True
|
||||
group: "neutron-dhcp-agent"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-dhcp-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run/:/run/:shared"
|
||||
- "/run/netns/:/run/netns/:shared"
|
||||
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-l3-agent:
|
||||
container_name: "neutron_l3_agent"
|
||||
image: "{{ neutron_l3_agent_image_full }}"
|
||||
privileged: True
|
||||
enabled: "{{ not enable_neutron_vpnaas | bool }}"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-l3-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run:/run:shared"
|
||||
- "/run/netns/:/run/netns/:shared"
|
||||
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-lbaas-agent:
|
||||
container_name: "neutron_lbaas_agent"
|
||||
image: "{{ neutron_lbaas_agent_image_full }}"
|
||||
privileged: True
|
||||
enabled: "{{ enable_neutron_lbaas | bool }}"
|
||||
group: "neutron-lbaas-agent"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-lbaas-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run:/run:shared"
|
||||
- "/run/netns/:/run/netns/:shared"
|
||||
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-metadata-agent:
|
||||
container_name: "neutron_metadata_agent"
|
||||
image: "{{ neutron_metadata_agent_image_full }}"
|
||||
privileged: True
|
||||
enabled: true
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-metadata-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run/netns/:/run/netns/:shared"
|
||||
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-vpnaas-agent:
|
||||
container_name: "neutron_vpnaas_agent"
|
||||
image: "{{ neutron_vpnaas_agent_image_full }}"
|
||||
privileged: True
|
||||
enabled: "{{ enable_neutron_vpnaas | bool }}"
|
||||
group: "neutron-vpnaas-agent"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-vpnaas-agent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run:/run:shared"
|
||||
- "/run/netns/:/run/netns/:shared"
|
||||
- "/lib/modules:/lib/modules:ro"
|
||||
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
neutron-bgp-dragent:
|
||||
container_name: "neutron_bgp_dragent"
|
||||
image: "{{ neutron_bgp_dragent_image_full }}"
|
||||
privileged: True
|
||||
enabled: "{{ enable_neutron_bgp_dragent | bool }}"
|
||||
group: "neutron-bgp-dragent"
|
||||
volumes:
|
||||
- "{{ node_config_directory }}/neutron-bgp-dragent/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/run:/run:shared"
|
||||
- "/run/netns/:/run/netns/:shared"
|
||||
- "/lib/modules:/lib/modules:ro"
|
||||
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
|
||||
|
||||
####################
|
||||
# Database
|
||||
####################
|
||||
neutron_database_name: "neutron"
|
||||
neutron_database_user: "neutron"
|
||||
neutron_database_address: "{{ kolla_internal_fqdn }}:{{ database_port }}"
|
||||
|
||||
|
||||
####################
|
||||
# Docker
|
||||
####################
|
||||
neutron_dhcp_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-dhcp-agent"
|
||||
neutron_dhcp_agent_tag: "{{ openstack_release }}"
|
||||
neutron_dhcp_agent_image_full: "{{ neutron_dhcp_agent_image }}:{{ neutron_dhcp_agent_tag }}"
|
||||
|
||||
neutron_l3_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-l3-agent"
|
||||
neutron_l3_agent_tag: "{{ openstack_release }}"
|
||||
neutron_l3_agent_image_full: "{{ neutron_l3_agent_image }}:{{ neutron_l3_agent_tag }}"
|
||||
|
||||
neutron_lbaas_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-lbaas-agent"
|
||||
neutron_lbaas_agent_tag: "{{ openstack_release }}"
|
||||
neutron_lbaas_agent_image_full: "{{ neutron_lbaas_agent_image }}:{{ neutron_lbaas_agent_tag }}"
|
||||
|
||||
neutron_linuxbridge_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-linuxbridge-agent"
|
||||
neutron_linuxbridge_agent_tag: "{{ openstack_release }}"
|
||||
neutron_linuxbridge_agent_image_full: "{{ neutron_linuxbridge_agent_image }}:{{ neutron_linuxbridge_agent_tag }}"
|
||||
|
||||
neutron_metadata_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-metadata-agent"
|
||||
neutron_metadata_agent_tag: "{{ openstack_release }}"
|
||||
neutron_metadata_agent_image_full: "{{ neutron_metadata_agent_image }}:{{ neutron_metadata_agent_tag }}"
|
||||
|
||||
neutron_openvswitch_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-openvswitch-agent"
|
||||
neutron_openvswitch_agent_tag: "{{ openstack_release }}"
|
||||
neutron_openvswitch_agent_image_full: "{{ neutron_openvswitch_agent_image }}:{{ neutron_openvswitch_agent_tag }}"
|
||||
|
||||
neutron_sfc_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-sfc-agent"
|
||||
neutron_sfc_agent_tag: "{{ openstack_release }}"
|
||||
neutron_sfc_agent_image_full: "{{ neutron_sfc_agent_image }}:{{ neutron_sfc_agent_tag }}"
|
||||
|
||||
neutron_server_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-server"
|
||||
neutron_server_tag: "{{ openstack_release }}"
|
||||
neutron_server_image_full: "{{ neutron_server_image }}:{{ neutron_server_tag }}"
|
||||
|
||||
neutron_vpnaas_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-vpnaas-agent"
|
||||
neutron_vpnaas_agent_tag: "{{ openstack_release }}"
|
||||
neutron_vpnaas_agent_image_full: "{{ neutron_vpnaas_agent_image }}:{{ neutron_vpnaas_agent_tag }}"
|
||||
|
||||
neutron_bgp_dragent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-bgp-dragent"
|
||||
neutron_bgp_dragent_tag: "{{ openstack_release }}"
|
||||
neutron_bgp_dragent_image_full: "{{ neutron_bgp_dragent_image }}:{{ neutron_bgp_dragent_tag }}"
|
||||
|
||||
openvswitch_db_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-openvswitch-db-server"
|
||||
openvswitch_db_tag: "{{ openstack_release }}"
|
||||
openvswitch_db_image_full: "{{ openvswitch_db_image }}:{{ openvswitch_db_tag }}"
|
||||
|
||||
openvswitch_vswitchd_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-openvswitch-vswitchd"
|
||||
openvswitch_vswitchd_tag: "{{ openstack_release }}"
|
||||
openvswitch_vswitchd_image_full: "{{ openvswitch_vswitchd_image }}:{{ openvswitch_vswitchd_tag }}"
|
||||
|
||||
|
||||
####################
|
||||
# OpenStack
|
||||
####################
|
||||
dhcp_agents_per_network: 2
|
||||
min_l3_agents_per_router: 2
|
||||
max_l3_agents_per_router: 3
|
||||
|
||||
neutron_admin_endpoint: "{{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ neutron_server_port }}"
|
||||
neutron_internal_endpoint: "{{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ neutron_server_port }}"
|
||||
neutron_public_endpoint: "{{ public_protocol }}://{{ kolla_external_fqdn }}:{{ neutron_server_port }}"
|
||||
|
||||
neutron_logging_debug: "{{ openstack_logging_debug }}"
|
||||
|
||||
neutron_bridge_name: "br-ex"
|
||||
|
||||
openstack_neutron_auth: "{{ openstack_auth }}"
|
||||
|
||||
####################
|
||||
# Extension drivers
|
||||
####################
|
||||
extension_drivers:
|
||||
- name: "qos"
|
||||
enabled: "{{ enable_neutron_qos | bool }}"
|
||||
- name: "port_security"
|
||||
enabled: "{{ enable_tacker | bool or enable_designate | bool }}"
|
||||
- name: "dns"
|
||||
enabled: "{{ enable_designate | bool }}"
|
||||
|
||||
neutron_extension_drivers: "{{ extension_drivers|selectattr('enabled', 'equalto', true)|list }}"
|
||||
|
||||
####################
|
||||
# Service Plugins
|
||||
####################
|
||||
service_plugins:
|
||||
- name: "flow_classifier"
|
||||
enabled: "{{ neutron_plugin_agent == 'sfc' }}"
|
||||
- name: "neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2"
|
||||
enabled: "{{ enable_neutron_lbaas | bool }}"
|
||||
- name: "neutron.services.firewall.fwaas_plugin.FirewallPlugin"
|
||||
enabled: "{{ enable_neutron_fwaas | bool }}"
|
||||
- name: "neutron_vpnaas.services.vpn.plugin.VPNDriverPlugin"
|
||||
enabled: "{{ enable_neutron_vpnaas | bool }}"
|
||||
- name: "qos"
|
||||
enabled: "{{ enable_neutron_qos | bool }}"
|
||||
- name: "router"
|
||||
enabled: true
|
||||
- name: "sfc"
|
||||
enabled: "{{ neutron_plugin_agent == 'sfc' }}"
|
||||
- name: "neutron_dynamic_routing.services.bgp.bgp_plugin.BgpPlugin"
|
||||
enabled: "{{ enable_neutron_bgp_dragent | bool }}"
|
||||
|
||||
neutron_service_plugins: "{{ service_plugins|selectattr('enabled', 'equalto', true)|list }}"
|
|
@ -0,0 +1,92 @@
|
|||
---
|
||||
- name: Ensuring config directories exist
|
||||
file:
|
||||
path: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}"
|
||||
state: "directory"
|
||||
recurse: yes
|
||||
with_sequence: start=1 end={{ num_nova_fake_per_node }}
|
||||
when: inventory_hostname in groups['compute']
|
||||
|
||||
- name: Copying over config.json files for services
|
||||
template:
|
||||
src: "neutron-openvswitch-agent.json.j2"
|
||||
dest: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}/config.json"
|
||||
register: fake_config_json
|
||||
with_sequence: start=1 end={{ num_nova_fake_per_node }}
|
||||
when:
|
||||
- inventory_hostname in groups['compute']
|
||||
- neutron_plugin_agent == "openvswitch"
|
||||
|
||||
- name: Copying over neutron.conf
|
||||
merge_configs:
|
||||
vars:
|
||||
service_name: "{{ item }}"
|
||||
sources:
|
||||
- "{{ role_path }}/templates/neutron.conf.j2"
|
||||
- "{{ node_config_directory }}/config/global.conf"
|
||||
- "{{ node_config_directory }}/config/database.conf"
|
||||
- "{{ node_config_directory }}/config/messaging.conf"
|
||||
- "{{ node_config_directory }}/config/neutron.conf"
|
||||
- "{{ node_config_directory }}/config/neutron/{{ item }}.conf"
|
||||
- "{{ node_config_directory }}/config/neutron/{{ inventory_hostname }}/neutron.conf"
|
||||
dest: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}/neutron.conf"
|
||||
register: fake_neutron_conf
|
||||
with_sequence: start=1 end={{ num_nova_fake_per_node }}
|
||||
when:
|
||||
- inventory_hostname in groups['compute']
|
||||
- neutron_plugin_agent == "openvswitch"
|
||||
|
||||
- name: Copying over ml2_conf.ini
|
||||
merge_configs:
|
||||
vars:
|
||||
service_name: "{{ item }}"
|
||||
sources:
|
||||
- "{{ role_path }}/templates/ml2_conf.ini.j2"
|
||||
- "{{ node_config_directory }}/config/neutron/ml2_conf.ini"
|
||||
- "{{ node_config_directory }}/config/neutron/{{ inventory_hostname }}/neutron.conf"
|
||||
dest: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}/ml2_conf.ini"
|
||||
register: fake_neutron_ml2_conf_ini
|
||||
with_sequence: start=1 end={{ num_nova_fake_per_node }}
|
||||
when:
|
||||
- inventory_hostname in groups['compute']
|
||||
- neutron_plugin_agent == "openvswitch"
|
||||
|
||||
- name: Checking neutron-openvswitch-agent container for nova fake node
|
||||
vars:
|
||||
neutron_openvswitch_agent: "{{ neutron_services['neutron-openvswitch-agent'] }}"
|
||||
kolla_docker:
|
||||
action: "compare_container"
|
||||
common_options: "{{ docker_common_options }}"
|
||||
name: "{{ neutron_openvswitch_agent.container_name }}"
|
||||
image: "{{ neutron_openvswitch_agent.image }}"
|
||||
privileged: "{{ neutron_openvswitch_agent.privileged | default(False) }}"
|
||||
volumes: "{{ neutron_openvswitch_agent.volumes }}"
|
||||
register: check_fake_neutron_openvswitch_agent
|
||||
when:
|
||||
- action != "config"
|
||||
- enable_nova_fake | bool
|
||||
- neutron_plugin_agent == "openvswitch"
|
||||
- inventory_hostname in groups["compute"]
|
||||
with_sequence: "start=1 end={{ num_nova_fake_per_node }}"
|
||||
notify:
|
||||
- Restart fake neutron-openvswitch-agent container
|
||||
|
||||
- name: Checking neutron-sfc-agent container for nova fake node
|
||||
vars:
|
||||
neutron_sfc_agent: "{{ neutron_services['neutron-sfc-agent'] }}"
|
||||
kolla_docker:
|
||||
action: "compare_container"
|
||||
common_options: "{{ docker_common_options }}"
|
||||
name: "{{ neutron_sfc_agent.container_name }}"
|
||||
image: "{{ neutron_sfc_agent.image }}"
|
||||
privileged: "{{ neutron_sfc_agent.privileged | default(False) }}"
|
||||
volumes: "{{ neutron_sfc_agent.volumes }}"
|
||||
register: check_fake_neutron_sfc_agent
|
||||
when:
|
||||
- action != "config"
|
||||
- enable_nova_fake | bool
|
||||
- neutron_plugin_agent == "sfc"
|
||||
- inventory_hostname in groups["compute"]
|
||||
with_sequence: "start=1 end={{ num_nova_fake_per_node }}"
|
||||
notify:
|
||||
- Restart fake neutron-sfc-agent container
|
|
@ -0,0 +1,255 @@
|
|||
---
|
||||
- name: Ensuring config directories exist
|
||||
file:
|
||||
path: "{{ node_config_directory }}/{{ item.key }}"
|
||||
state: "directory"
|
||||
recurse: yes
|
||||
when:
|
||||
- item.value.enabled | bool
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over config.json files for services
|
||||
template:
|
||||
src: "{{ item.key }}.json.j2"
|
||||
dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
|
||||
register: neutron_config_jsons
|
||||
when:
|
||||
- item.value.enabled | bool
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over neutron.conf
|
||||
vars:
|
||||
service_name: "{{ item.key }}"
|
||||
services_need_neutron_conf:
|
||||
- "neutron-dhcp-agent"
|
||||
- "neutron-l3-agent"
|
||||
- "neutron-linuxbridge-agent"
|
||||
- "neutron-metadata-agent"
|
||||
- "neutron-openvswitch-agent"
|
||||
- "neutron-server"
|
||||
- "neutron-lbaas-agent"
|
||||
- "neutron-vpnaas-agent"
|
||||
- "neutron-bgp-dragent"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/neutron.conf.j2"
|
||||
- "{{ node_custom_config }}/global.conf"
|
||||
- "{{ node_custom_config }}/database.conf"
|
||||
- "{{ node_custom_config }}/messaging.conf"
|
||||
- "{{ node_custom_config }}/neutron.conf"
|
||||
- "{{ node_custom_config }}/neutron/{{ item.key }}.conf"
|
||||
- "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron.conf"
|
||||
dest: "{{ node_config_directory }}/{{ item.key }}/neutron.conf"
|
||||
register: neutron_confs
|
||||
when:
|
||||
- item.value.enabled | bool
|
||||
|
||||
- item.key in services_need_neutron_conf
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over neutron_lbaas.conf
|
||||
vars:
|
||||
service_name: "{{ item.key }}"
|
||||
services_need_neutron_lbaas_conf:
|
||||
- "neutron-server"
|
||||
- "neutron-lbaas-agent"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/neutron_lbaas.conf.j2"
|
||||
- "{{ node_custom_config }}/neutron/neutron_lbaas.conf"
|
||||
- "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron_lbaas.conf"
|
||||
dest: "{{ node_config_directory }}/{{ item.key }}/neutron_lbaas.conf"
|
||||
register: neutron_lbaas_confs
|
||||
when:
|
||||
- item.value.enabled | bool
|
||||
|
||||
- item.key in services_need_neutron_lbaas_conf
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over neutron_vpnaas.conf
|
||||
vars:
|
||||
service_name: "neutron-server"
|
||||
neutron_server: "{{ neutron_services[service_name] }}"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/neutron_vpnaas.conf.j2"
|
||||
- "{{ node_custom_config }}/neutron/neutron_vpnaas.conf"
|
||||
- "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron_vpnaas.conf"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/neutron_vpnaas.conf"
|
||||
register: neutron_vpnaas_conf
|
||||
when:
|
||||
- neutron_server.enabled | bool
|
||||
|
||||
|
||||
- name: Copying over ml2_conf.ini
|
||||
vars:
|
||||
service_name: "{{ item.key }}"
|
||||
services_need_ml2_conf_ini:
|
||||
- "neutron-dhcp-agent"
|
||||
- "neutron-l3-agent"
|
||||
- "neutron-linuxbridge-agent"
|
||||
- "neutron-lbaas-agent"
|
||||
- "neutron-metadata-agent"
|
||||
- "neutron-openvswitch-agent"
|
||||
- "neutron-server"
|
||||
- "neutron-vpnaas-agent"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/ml2_conf.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/ml2_conf.ini"
|
||||
- "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/ml2_conf.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/ml2_conf.ini"
|
||||
register: neutron_ml2_confs
|
||||
when:
|
||||
- item.key in services_need_ml2_conf_ini
|
||||
- item.value.enabled | bool
|
||||
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over dhcp_agent.ini
|
||||
vars:
|
||||
service_name: "neutron-dhcp-agent"
|
||||
neutron_dhcp_agent: "{{ neutron_services[service_name] }}"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/dhcp_agent.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/dhcp_agent.ini"
|
||||
- "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/dhcp_agent.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/dhcp_agent.ini"
|
||||
register: dhcp_agent_ini
|
||||
when:
|
||||
- neutron_dhcp_agent.enabled | bool
|
||||
|
||||
|
||||
- name: Copying over dnsmasq.conf
|
||||
vars:
|
||||
service_name: "neutron-dhcp-agent"
|
||||
neutron_dhcp_agent: "{{ neutron_services[service_name] }}"
|
||||
template:
|
||||
src: "dnsmasq.conf.j2"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/dnsmasq.conf"
|
||||
register: dnsmasq_conf
|
||||
when:
|
||||
- neutron_dhcp_agent.enabled | bool
|
||||
|
||||
|
||||
- name: Copying over l3_agent.ini
|
||||
vars:
|
||||
service_name: "{{ item.key }}"
|
||||
services_need_l3_agent_ini:
|
||||
- "neutron-l3-agent"
|
||||
- "neutron-vpnaas-agent"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/l3_agent.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/l3_agent.ini"
|
||||
- "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/l3_agent.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/l3_agent.ini"
|
||||
register: neutron_l3_agent_inis
|
||||
when:
|
||||
- item.key in services_need_l3_agent_ini
|
||||
- item.value.enabled | bool
|
||||
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over fwaas_driver.ini
|
||||
vars:
|
||||
service_name: "{{ item.key }}"
|
||||
services_need_fwaas_driver_ini:
|
||||
- "neutron-l3-agent"
|
||||
- "neutron-vpnaas-agent"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/fwaas_driver.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/fwaas_driver.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/fwaas_driver.ini"
|
||||
register: neutron_fwaas_driver_inis
|
||||
when:
|
||||
- item.key in services_need_fwaas_driver_ini
|
||||
- item.value.enabled | bool
|
||||
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
||||
- name: Copying over metadata_agent.ini
|
||||
vars:
|
||||
service_name: "neutron-metadata-agent"
|
||||
neutron_metadata_agent: "{{ neutron_services[service_name] }}"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/metadata_agent.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/metadata_agent.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/metadata_agent.ini"
|
||||
register: neutron_metadata_agent_ini
|
||||
when:
|
||||
- neutron_metadata_agent.enabled | bool
|
||||
|
||||
|
||||
- name: Copying over lbaas_agent.ini
|
||||
vars:
|
||||
service_name: "neutron-lbaas-agent"
|
||||
neutron_lbaas_agent: "{{ neutron_services['neutron-lbaas-agent'] }}"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/lbaas_agent.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/lbaas_agent.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/lbaas_agent.ini"
|
||||
register: neutron_lbaas_agent_ini
|
||||
when:
|
||||
- neutron_lbaas_agent.enabled | bool
|
||||
|
||||
|
||||
- name: Copying over vpnaas_agent.ini
|
||||
vars:
|
||||
service_name: "neutron-vpnaas-agent"
|
||||
neutron_vpnaas_agent: "{{ neutron_services['neutron-vpnaas-agent'] }}"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/vpnaas_agent.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/vpnaas_agent.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/vpnaas_agent.ini"
|
||||
register: neutron_vpnaas_agent_ini
|
||||
when:
|
||||
- neutron_vpnaas_agent.enabled | bool
|
||||
|
||||
|
||||
- name: Copying over bgp_dragent.ini
|
||||
vars:
|
||||
service_name: "neutron-bgp-dragent"
|
||||
neutron_bgp_dragent: "{{ neutron_services['neutron-bgp-dragent'] }}"
|
||||
merge_configs:
|
||||
sources:
|
||||
- "{{ role_path }}/templates/bgp_dragent.ini.j2"
|
||||
- "{{ node_custom_config }}/neutron/bgp_dragent.ini"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/bgp_dragent.ini"
|
||||
register: neutron_bgp_dragent_ini
|
||||
when:
|
||||
- neutron_bgp_dragent.enabled | bool
|
||||
|
||||
|
||||
- name: Check if policies shall be overwritten
|
||||
local_action: stat path="{{ node_custom_config }}/neutron/policy.json"
|
||||
register: neutron_policy
|
||||
|
||||
- name: Copying over existing policy.json
|
||||
vars:
|
||||
service_name: "{{ item.key }}"
|
||||
services_need_policy_json:
|
||||
- "neutron-dhcp-agent"
|
||||
- "neutron-l3-agent"
|
||||
- "neutron-linuxbridge-agent"
|
||||
- "neutron-metadata-agent"
|
||||
- "neutron-openvswitch-agent"
|
||||
- "neutron-server"
|
||||
- "neutron-lbaas-agent"
|
||||
- "neutron-vpnaas-agent"
|
||||
- "neutron-bgp-dragent"
|
||||
template:
|
||||
src: "{{ node_custom_config }}/neutron/policy.json"
|
||||
dest: "{{ node_config_directory }}/{{ service_name }}/policy.json"
|
||||
register: policy_jsons
|
||||
when:
|
||||
- neutron_policy.stat.exists | bool
|
||||
- item.value.enabled | bool
|
||||
|
||||
with_dict: "{{ neutron_services }}"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
- include: "config.yml"
|
|
@ -0,0 +1,3 @@
|
|||
[BGP]
|
||||
bgp_speaker_driver = neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver
|
||||
bgp_router_id = {{ neutron_bgp_router_id }}
|
|
@ -0,0 +1,6 @@
|
|||
# dhcp_agent.ini
|
||||
[DEFAULT]
|
||||
dnsmasq_config_file = /etc/neutron/dnsmasq.conf
|
||||
enable_isolated_metadata = true
|
||||
force_metadata = true
|
||||
dnsmasq_dns_servers = 8.8.8.8,8.8.4.4
|
|
@ -0,0 +1 @@
|
|||
log-facility=/var/log/kolla/neutron/dnsmasq.log
|
|
@ -0,0 +1 @@
|
|||
[fwaas]
|
|
@ -0,0 +1,16 @@
|
|||
#jinja2: trim_blocks: False
|
||||
[DEFAULT]
|
||||
{% if enable_neutron_dvr | bool %}
|
||||
{% if inventory_hostname in groups['network'] %}
|
||||
agent_mode = dvr_snat
|
||||
{% elif inventory_hostname in groups['compute'] %}
|
||||
agent_mode = dvr
|
||||
{% endif %}
|
||||
{% else %}
|
||||
agent_mode = legacy
|
||||
{% endif %}
|
||||
{% if enable_neutron_fwaas | bool %}
|
||||
[fwaas]
|
||||
driver = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver
|
||||
enabled = True
|
||||
{% endif %}
|
|
@ -0,0 +1,6 @@
|
|||
[DEFAULT]
|
||||
debug = {{ neutron_logging_debug }}
|
||||
device_driver = neutron_lbaas.drivers.haproxy.namespace_driver.HaproxyNSDriver
|
||||
|
||||
[haproxy]
|
||||
user_group = haproxy
|
|
@ -0,0 +1,6 @@
|
|||
# metadata_agent.ini
|
||||
[DEFAULT]
|
||||
nova_metadata_ip = {% if orchestration_engine == 'KUBERNETES' %}nova-metadata{% else %}{{ kolla_internal_fqdn }}{% endif %}
|
||||
|
||||
nova_metadata_port = {{ nova_metadata_port }}
|
||||
metadata_proxy_shared_secret = {{ metadata_secret }}
|
|
@ -0,0 +1,72 @@
|
|||
# ml2_conf.ini
|
||||
[ml2]
|
||||
{% if enable_ironic | bool %}
|
||||
tenant_network_types = vxlan, flat
|
||||
mechanism_drivers = openvswitch
|
||||
{% else %}
|
||||
# Changing type_drivers after bootstrap can lead to database inconsistencies
|
||||
type_drivers = flat,vlan,vxlan
|
||||
tenant_network_types = vxlan
|
||||
{% endif %}
|
||||
|
||||
{% if neutron_plugin_agent == "openvswitch" %}
|
||||
mechanism_drivers = openvswitch,l2population
|
||||
{% elif neutron_plugin_agent == "linuxbridge" %}
|
||||
mechanism_drivers = linuxbridge,l2population
|
||||
{% endif %}
|
||||
|
||||
{% if neutron_extension_drivers %}
|
||||
extension_drivers = {{ neutron_extension_drivers|map(attribute='name')|join(',') }}
|
||||
{% endif %}
|
||||
|
||||
[ml2_type_vlan]
|
||||
{% if enable_ironic | bool %}
|
||||
network_vlan_ranges = physnet1
|
||||
{% else %}
|
||||
network_vlan_ranges =
|
||||
{% endif %}
|
||||
|
||||
[ml2_type_flat]
|
||||
{% if enable_ironic | bool %}
|
||||
flat_networks = *
|
||||
{% else %}
|
||||
flat_networks = {% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}{% if not loop.last %},{% endif %}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
[ml2_type_vxlan]
|
||||
vni_ranges = 1:1000
|
||||
vxlan_group = 239.1.1.1
|
||||
|
||||
[securitygroup]
|
||||
{% if neutron_plugin_agent == "openvswitch" %}
|
||||
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
|
||||
{% elif neutron_plugin_agent == "linuxbridge" %}
|
||||
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
|
||||
{% endif %}
|
||||
|
||||
{% if neutron_plugin_agent == "openvswitch" %}
|
||||
[agent]
|
||||
tunnel_types = vxlan
|
||||
l2_population = true
|
||||
arp_responder = true
|
||||
|
||||
{% if enable_neutron_dvr | bool %}
|
||||
enable_distributed_routing = True
|
||||
{% endif %}
|
||||
|
||||
[ovs]
|
||||
bridge_mappings = {% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}:{{ bridge }}{% if not loop.last %},{% endif %}{% endfor %}
|
||||
|
||||
ovsdb_connection = tcp:{{ api_interface_address }}:6640
|
||||
{% if enable_nova_fake | bool %}
|
||||
integration_bridge = br-int-{{ item }}
|
||||
{% endif %}
|
||||
{% elif neutron_plugin_agent == "linuxbridge" %}
|
||||
[linux_bridge]
|
||||
physical_interface_mappings = physnet1:{{ neutron_external_interface }}
|
||||
|
||||
|
||||
[vxlan]
|
||||
l2_population = true
|
||||
{% endif %}
|
||||
local_ip = {{ tunnel_interface_address }}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"command": "neutron-bgp-dragent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/bgp_dragent.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/bgp_dragent.ini",
|
||||
"dest": "/etc/neutron/bgp_dragent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/neutron/kolla",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"command": "neutron-dhcp-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/dhcp_agent.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/dhcp_agent.ini",
|
||||
"dest": "/etc/neutron/dhcp_agent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/dnsmasq.conf",
|
||||
"dest": "/etc/neutron/dnsmasq.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/neutron/kolla",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"command": "neutron-l3-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/l3_agent.ini --config-file /etc/neutron/fwaas_driver.ini --config-file /etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/fwaas_driver.ini",
|
||||
"dest": "/etc/neutron/fwaas_driver.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/l3_agent.ini",
|
||||
"dest": "/etc/neutron/l3_agent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/neutron/kolla",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"command": "neutron-lbaasv2-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/lbaas_agent.ini --config-file /etc/neutron/neutron_lbaas.conf",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/lbaas_agent.ini",
|
||||
"dest": "/etc/neutron/lbaas_agent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron_lbaas.conf",
|
||||
"dest": "/etc/neutron/neutron_lbaas.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/neutron/kolla",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"command": "neutron-linuxbridge-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"command": "neutron-metadata-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/metadata_agent.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/metadata_agent.ini",
|
||||
"dest": "/etc/neutron/metadata_agent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/neutron/kolla",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"command": "neutron-openvswitch-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"command": "neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_lbaas.conf --config-file /etc/neutron/neutron_vpnaas.conf",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron_lbaas.conf",
|
||||
"dest": "/etc/neutron/neutron_lbaas.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron_vpnaas.conf",
|
||||
"dest": "/etc/neutron/neutron_vpnaas.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"command": "neutron-vpn-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/fwaas_driver.ini --config-file /etc/neutron/l3_agent.ini --config-file /etc/neutron/vpnaas_agent.ini --config-file /etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/neutron.conf",
|
||||
"dest": "/etc/neutron/neutron.conf",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/ml2_conf.ini",
|
||||
"dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/fwaas_driver.ini",
|
||||
"dest": "/etc/neutron/fwaas_driver.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/l3_agent.ini",
|
||||
"dest": "/etc/neutron/l3_agent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/vpnaas_agent.ini",
|
||||
"dest": "/etc/neutron/vpnaas_agent.ini",
|
||||
"owner": "neutron",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/policy.json",
|
||||
"dest": "/etc/neutron/policy.json",
|
||||
"owner": "neutron",
|
||||
"perm": "0600",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
{
|
||||
"path": "/var/log/kolla/neutron",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/neutron/kolla",
|
||||
"owner": "neutron:neutron",
|
||||
"recurse": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
# neutron.conf
|
||||
[DEFAULT]
|
||||
debug = {{ neutron_logging_debug }}
|
||||
|
||||
log_dir = /var/log/kolla/neutron
|
||||
|
||||
# NOTE(elemoine): set use_stderr to False or the logs will also be sent to
|
||||
# stderr and collected by Docker
|
||||
use_stderr = False
|
||||
|
||||
bind_host = {{ api_interface_address }}
|
||||
bind_port = {{ neutron_server_port }}
|
||||
|
||||
api_paste_config = /usr/share/neutron/api-paste.ini
|
||||
endpoint_type = internalURL
|
||||
|
||||
api_workers = {{ openstack_service_workers }}
|
||||
metadata_workers = {{ openstack_service_workers }}
|
||||
|
||||
# NOTE(SamYaple): We must specify this value here rather than the metadata conf
|
||||
# because it is used by the l3 and dhcp agents. The reason the path has 'kolla'
|
||||
# in it is because we are sharing this socket in a volume which is it's own dir
|
||||
metadata_proxy_socket = /var/lib/neutron/kolla/metadata_proxy
|
||||
|
||||
{% if neutron_plugin_agent == "openvswitch" %}
|
||||
interface_driver = openvswitch
|
||||
{% elif neutron_plugin_agent == "linuxbridge" %}
|
||||
interface_driver = linuxbridge
|
||||
{% endif %}
|
||||
|
||||
{% if enable_nova_fake | bool %}
|
||||
ovs_integration_bridge = br-int-{{ item }}
|
||||
host = {{ ansible_hostname }}_{{ item }}
|
||||
{% endif %}
|
||||
|
||||
allow_overlapping_ips = true
|
||||
core_plugin = ml2
|
||||
|
||||
service_plugins = {{ neutron_service_plugins|map(attribute='name')|join(',') }}
|
||||
|
||||
{% if enable_neutron_agent_ha | bool %}
|
||||
dhcp_agents_per_network = {{ dhcp_agents_per_network }}
|
||||
l3_ha = true
|
||||
max_l3_agents_per_router = {{ max_l3_agents_per_router }}
|
||||
min_l3_agents_per_router = {{ min_l3_agents_per_router }}
|
||||
{% endif %}
|
||||
|
||||
transport_url = rabbit://{{ rabbitmq_user }}:{{ rabbitmq_password }}@rabbitmq:{{ rabbitmq_port }}
|
||||
|
||||
{% if enable_neutron_dvr | bool %}
|
||||
router_distributed = True
|
||||
{% endif %}
|
||||
|
||||
{% if enable_designate | bool %}
|
||||
dns_domain = {{ designate_ns_record }}.
|
||||
external_dns_driver = designate
|
||||
{% endif %}
|
||||
|
||||
[nova]
|
||||
auth_url = {{ keystone_admin_url }}
|
||||
auth_type = password
|
||||
project_domain_id = default
|
||||
user_domain_id = default
|
||||
region_name = {{ openstack_region_name }}
|
||||
project_name = service
|
||||
username = {{ nova_keystone_user }}
|
||||
password = {{ nova_keystone_password }}
|
||||
endpoint_type = internal
|
||||
|
||||
[oslo_concurrency]
|
||||
lock_path = /var/lib/neutron/tmp
|
||||
|
||||
[agent]
|
||||
root_helper = sudo neutron-rootwrap /etc/neutron/rootwrap.conf
|
||||
|
||||
[database]
|
||||
connection = mysql+pymysql://{{ neutron_database_user }}:{{ neutron_database_password }}@{{ neutron_database_address }}/{{ neutron_database_name }}
|
||||
max_retries = -1
|
||||
|
||||
[keystone_authtoken]
|
||||
auth_uri = {{ keystone_internal_url }}
|
||||
auth_url = {{ keystone_admin_url }}
|
||||
auth_type = password
|
||||
project_domain_id = default
|
||||
user_domain_id = default
|
||||
project_name = service
|
||||
username = {{ neutron_keystone_user }}
|
||||
password = {{ neutron_keystone_password }}
|
||||
|
||||
memcache_security_strategy = ENCRYPT
|
||||
memcache_secret_key = {{ memcache_secret_key }}
|
||||
|
||||
memcache_servers = {{ memcached_servers }}:{{ memcached_port }}
|
||||
|
||||
[oslo_messaging_notifications]
|
||||
{% if enable_ceilometer | bool or enable_searchlight | bool or enable_designate | bool %}
|
||||
driver = messagingv2
|
||||
{% set topics=["notifications" if enable_ceilometer | bool else "", "notifications_designate" if enable_designate | bool else ""] %}
|
||||
topics = {{ topics|reject("equalto", "")|list|join(",") }}
|
||||
{% else %}
|
||||
driver = noop
|
||||
{% endif %}
|
||||
|
||||
{% if neutron_plugin_agent == "sfc" %}
|
||||
[sfc]
|
||||
drivers = ovs
|
||||
[flowclassifier]
|
||||
{% endif %}
|
||||
|
||||
{% if enable_octavia | bool %}
|
||||
[octavia]
|
||||
base_url = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ octavia_api_port }}
|
||||
{% endif %}
|
||||
|
||||
{% if enable_designate | bool %}
|
||||
[designate]
|
||||
url = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ designate_api_port }}/v2
|
||||
auth_uri = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_public_port }}
|
||||
auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
|
||||
auth_type = password
|
||||
project_domain_id = default
|
||||
user_domain_id = default
|
||||
project_name = service
|
||||
username = {{ designate_keystone_user }}
|
||||
password = {{ designate_keystone_password }}
|
||||
allow_reverse_dns_lookup = True
|
||||
ipv4_ptr_zone_prefix_size = 24
|
||||
ipv6_ptr_zone_prefix_size = 116
|
||||
{% endif %}
|
|
@ -0,0 +1,17 @@
|
|||
{% if enable_neutron_lbaas | bool %}
|
||||
[service_providers]
|
||||
{% if enable_octavia | bool %}
|
||||
service_provider = LOADBALANCERV2:Octavia:neutron_lbaas.drivers.octavia.driver.OctaviaDriver:default
|
||||
{% else %}
|
||||
service_provider = LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
|
||||
{% endif %}
|
||||
|
||||
[service_auth]
|
||||
auth_url = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_public_port }}/v2.0
|
||||
admin_tenant_name = service
|
||||
admin_user = neutron
|
||||
admin_password = {{ neutron_keystone_password }}
|
||||
auth_version = 2
|
||||
region = {{ openstack_region_name }}
|
||||
endpoint_type = internal
|
||||
{% endif %}
|
|
@ -0,0 +1,4 @@
|
|||
{% if enable_neutron_vpnaas | bool %}
|
||||
[service_providers]
|
||||
service_provider = VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
|
||||
{% endif %}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"command": "start-ovsdb-server {{ api_interface_address }} {% if orchestration_engine == 'KUBERNETES' %} {{ neutron_bridge_name }} {{ neutron_external_interface }} {% endif %}",
|
||||
"config_files": []
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"command": "/usr/sbin/ovs-vswitchd unix:/run/openvswitch/db.sock -vconsole:emer -vsyslog:err -vfile:info --mlockall --log-file=/var/log/kolla/openvswitch/ovs-vswitchd.log",
|
||||
"config_files": []
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{% set vpn_device_driver = 'neutron_vpnaas.services.vpn.device_drivers.strongswan_ipsec.StrongSwanDriver' if kolla_base_distro in ['ubuntu', 'debian'] else 'neutron_vpnaas.services.vpn.device_drivers.libreswan_ipsec.LibreSwanDriver'%}
|
||||
[DEFAULT]
|
||||
|
||||
[ipsec]
|
||||
enable_detailed_logging = {{ neutron_logging_debug }}
|
||||
|
||||
[service_providers]
|
||||
service_provider = VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
|
||||
|
||||
[vpnagent]
|
||||
vpn_device_driver = {{ vpn_device_driver }}
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: Generate configuration files
|
||||
hosts: localhost
|
||||
connection: local
|
||||
roles:
|
||||
- neutron
|
|
@ -34,6 +34,11 @@ fi
|
|||
kolla-ansible/tools/generate_passwords.py
|
||||
kolla-ansible/tools/kolla-ansible genconfig
|
||||
|
||||
# Testing ansible-in-k8s approach
|
||||
rm -rf /etc/kolla/neutron*
|
||||
ansible-playbook -e ansible_python_interpreter=/usr/bin/python -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla ansible/site.yml
|
||||
ls -la /etc/kolla
|
||||
|
||||
crudini --set /etc/kolla/nova-compute/nova.conf libvirt virt_type qemu
|
||||
crudini --set /etc/kolla/nova-compute/nova.conf libvirt cpu_mode none
|
||||
crudini --set /etc/kolla/nova-compute/nova.conf libvirt rbd_user nova
|
||||
|
|
Loading…
Reference in New Issue