diff --git a/README.rst b/README.rst index f9a42f78cd..42ca35f9d7 100644 --- a/README.rst +++ b/README.rst @@ -69,6 +69,7 @@ Kolla-Ansible deploys containers for the following OpenStack projects: - `Nova `__ - `Octavia `__ - `Panko `__ +- `Qinling `__ - `Rally `__ - `Sahara `__ - `Searchlight `__ diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index 5d63e9d8be..47587084d7 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -375,6 +375,8 @@ prometheus_elasticsearch_exporter_port: "9108" qdrouterd_port: "31459" +qinling_api_port: "7070" + rabbitmq_port: "5672" rabbitmq_management_port: "15672" rabbitmq_cluster_port: "25672" @@ -561,6 +563,7 @@ enable_horizon_murano: "{{ enable_murano | bool }}" enable_horizon_neutron_lbaas: "{{ enable_neutron_lbaas | bool }}" enable_horizon_neutron_vpnaas: "{{ enable_neutron_vpnaas | bool }}" enable_horizon_octavia: "{{ enable_octavia | bool }}" +enable_horizon_qinling: "{{ enable_qinling | bool }}" enable_horizon_sahara: "{{ enable_sahara | bool }}" enable_horizon_searchlight: "{{ enable_searchlight | bool }}" enable_horizon_senlin: "{{ enable_senlin | bool }}" @@ -615,6 +618,7 @@ enable_osprofiler: "no" enable_panko: "no" enable_placement: "{{ enable_nova }}" enable_qdrouterd: "{{ 'yes' if om_rpc_transport == 'amqp' else 'no' }}" +enable_qinling: "no" enable_rally: "no" enable_redis: "no" enable_sahara: "no" @@ -894,6 +898,12 @@ octavia_amp_boot_network_list: octavia_amp_secgroup_list: octavia_amp_flavor_id: +################# +# Qinling options +################# +# Configure qinling-engine certificates to authenticate with Kubernetes cluster. +qinling_kubernetes_certificates: "no" + ################### # Ceph options ################### diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one index 0772ba7948..badb4db5b6 100644 --- a/ansible/inventory/all-in-one +++ b/ansible/inventory/all-in-one @@ -163,6 +163,9 @@ monitoring [magnum:children] control +[qinling:children] +control + [sahara:children] control @@ -508,6 +511,13 @@ magnum [magnum-conductor:children] magnum +# Qinling +[qinling-api:children] +qinling + +[qinling-engine:children] +qinling + # Solum [solum-api:children] solum diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode index 9d07a7d401..4db1174050 100644 --- a/ansible/inventory/multinode +++ b/ansible/inventory/multinode @@ -185,6 +185,9 @@ control [magnum:children] control +[qinling:children] +control + [sahara:children] control @@ -517,6 +520,13 @@ magnum [magnum-conductor:children] magnum +# Qinling +[qinling-api:children] +qinling + +[qinling-engine:children] +qinling + # Sahara [sahara-api:children] sahara diff --git a/ansible/roles/common/tasks/config.yml b/ansible/roles/common/tasks/config.yml index 08b97d36c9..0f6914265f 100644 --- a/ansible/roles/common/tasks/config.yml +++ b/ansible/roles/common/tasks/config.yml @@ -286,6 +286,7 @@ - { name: "opendaylight", enabled: "{{ enable_opendaylight }}" } - { name: "outward-rabbitmq", enabled: "{{ enable_outward_rabbitmq }}" } - { name: "panko", enabled: "{{ enable_panko }}" } + - { name: "qinling", enabled: "{{ enable_qinling }}" } - { name: "rabbitmq", enabled: "{{ enable_rabbitmq }}" } - { name: "rally", enabled: "{{ enable_rally }}" } - { name: "sahara", enabled: "{{ enable_sahara }}" } diff --git a/ansible/roles/common/templates/conf/filter/01-rewrite-0.14.conf.j2 b/ansible/roles/common/templates/conf/filter/01-rewrite-0.14.conf.j2 index 7f0a77ccde..0e03844ff8 100644 --- a/ansible/roles/common/templates/conf/filter/01-rewrite-0.14.conf.j2 +++ b/ansible/roles/common/templates/conf/filter/01-rewrite-0.14.conf.j2 @@ -166,4 +166,9 @@ pattern ^(blazar-api|blazar-manager)$ tag openstack_python + + key programname + pattern ^(qinling-engine|qinling-api)$ + tag openstack_python + diff --git a/ansible/roles/common/templates/conf/input/00-global.conf.j2 b/ansible/roles/common/templates/conf/input/00-global.conf.j2 index 16b70fdb83..639d533cef 100644 --- a/ansible/roles/common/templates/conf/input/00-global.conf.j2 +++ b/ansible/roles/common/templates/conf/input/00-global.conf.j2 @@ -29,6 +29,7 @@ ( 'nova', enable_nova ), ( 'octavia', enable_octavia ), ( 'panko', enable_panko ), + ( 'qinling', enable_qinling ), ( 'rally', enable_rally ), ( 'sahara', enable_sahara ), ( 'searchlight', enable_searchlight ), diff --git a/ansible/roles/common/templates/cron-logrotate-qinling.conf.j2 b/ansible/roles/common/templates/cron-logrotate-qinling.conf.j2 new file mode 100644 index 0000000000..570dfc2760 --- /dev/null +++ b/ansible/roles/common/templates/cron-logrotate-qinling.conf.j2 @@ -0,0 +1,3 @@ +"/var/log/kolla/qinling/*.log" +{ +} diff --git a/ansible/roles/common/templates/cron.json.j2 b/ansible/roles/common/templates/cron.json.j2 index 91134cd5a9..b8517b2452 100644 --- a/ansible/roles/common/templates/cron.json.j2 +++ b/ansible/roles/common/templates/cron.json.j2 @@ -44,6 +44,7 @@ ( 'opendaylight', enable_opendaylight ), ( 'outward-rabbitmq', enable_outward_rabbitmq ), ( 'panko', enable_panko ), + ( 'qinling', enable_qinling ), ( 'rabbitmq', enable_rabbitmq ), ( 'rally', enable_rally ), ( 'sahara', enable_sahara ), diff --git a/ansible/roles/haproxy/tasks/precheck.yml b/ansible/roles/haproxy/tasks/precheck.yml index 41f9c0b063..20b1e1565a 100644 --- a/ansible/roles/haproxy/tasks/precheck.yml +++ b/ansible/roles/haproxy/tasks/precheck.yml @@ -756,6 +756,19 @@ - haproxy_stat.find('panko_api') == -1 - "host_running_haproxy == 'None'" +- name: Checking free port for Qinling API HAProxy + wait_for: + host: "{{ kolla_internal_vip_address }}" + port: "{{ qinling_api_port }}" + connect_timeout: 1 + timeout: 1 + state: stopped + when: + - enable_qinling | bool + - inventory_hostname in groups['haproxy'] + - haproxy_stat.find('qinling_api') == -1 + - "host_running_haproxy == 'None'" + - name: Checking free port for RabbitMQ Management HAProxy wait_for: host: "{{ kolla_internal_vip_address }}" diff --git a/ansible/roles/horizon/defaults/main.yml b/ansible/roles/horizon/defaults/main.yml index 240cfb9207..81c2739d47 100644 --- a/ansible/roles/horizon/defaults/main.yml +++ b/ansible/roles/horizon/defaults/main.yml @@ -24,6 +24,7 @@ horizon_services: ENABLE_NEUTRON_LBAAS: "{{ 'yes' if enable_horizon_neutron_lbaas | bool else 'no' }}" ENABLE_NEUTRON_VPNAAS: "{{ 'yes' if enable_horizon_neutron_vpnaas | bool else 'no' }}" ENABLE_OCTAVIA: "{{ 'yes' if enable_horizon_octavia | bool else 'no' }}" + ENABLE_QINLING: "{{ 'yes' if enable_horizon_qinling | bool else 'no' }}" ENABLE_SAHARA: "{{ 'yes' if enable_horizon_sahara | bool else 'no' }}" ENABLE_SEARCHLIGHT: "{{ 'yes' if enable_horizon_searchlight | bool else 'no' }}" ENABLE_SENLIN: "{{ 'yes' if enable_horizon_senlin | bool else 'no' }}" diff --git a/ansible/roles/horizon/tasks/config.yml b/ansible/roles/horizon/tasks/config.yml index 3545b69498..0ea4b3bfc0 100644 --- a/ansible/roles/horizon/tasks/config.yml +++ b/ansible/roles/horizon/tasks/config.yml @@ -37,6 +37,7 @@ - { name: "murano", enabled: "{{ enable_horizon_murano }}" } - { name: "neutron", enabled: "{{ enable_neutron_horizon_policy_file }}" } - { name: "nova", enabled: "{{ enable_nova_horizon_policy_file }}" } + - { name: "qinling", enabled: "{{ enable_horizon_qinling }}" } - { name: "sahara", enabled: "{{ enable_horizon_sahara }}" } - { name: "searchlight", enabled: "{{ enable_horizon_searchlight }}" } - { name: "senlin", enabled: "{{ enable_horizon_senlin }}" } diff --git a/ansible/roles/horizon/templates/horizon.json.j2 b/ansible/roles/horizon/templates/horizon.json.j2 index 90775ace05..1b302cd815 100644 --- a/ansible/roles/horizon/templates/horizon.json.j2 +++ b/ansible/roles/horizon/templates/horizon.json.j2 @@ -18,6 +18,7 @@ ( 'murano', enable_horizon_murano ), ( 'neutron', enable_neutron ), ( 'nova', enable_nova ), + ( 'qinling', enable_horizon_qinling ), ( 'sahara', enable_horizon_sahara ), ( 'searchlight', enable_horizon_searchlight ), ( 'senlin', enable_horizon_senlin ), diff --git a/ansible/roles/qinling/defaults/main.yml b/ansible/roles/qinling/defaults/main.yml new file mode 100644 index 0000000000..13db9a3bfb --- /dev/null +++ b/ansible/roles/qinling/defaults/main.yml @@ -0,0 +1,88 @@ +--- +project_name: "qinling" + +qinling_services: + qinling-api: + container_name: qinling_api + group: qinling-api + enabled: true + image: "{{ qinling_api_image_full }}" + volumes: + - "{{ node_config_directory }}/qinling-api/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "{{ kolla_dev_repos_directory ~ '/qinling/qinling:/var/lib/kolla/venv/lib/python2.7/site-packages/qinling' if qinling_dev_mode | bool else '' }}" + - "kolla_logs:/var/log/kolla/" + dimensions: "{{ qinling_api_dimensions }}" + haproxy: + qinling_api: + enabled: "{{ enable_qinling }}" + mode: "http" + external: false + port: "{{ qinling_api_port }}" + qinling_api_external: + enabled: "{{ enable_qinling }}" + mode: "http" + external: true + port: "{{ qinling_api_port }}" + qinling-engine: + container_name: qinling_engine + group: qinling-engine + enabled: true + image: "{{ qinling_engine_image_full }}" + environment: "{{ container_proxy }}" + volumes: + - "{{ node_config_directory }}/qinling-engine/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "qinling:/var/lib/qinling/" + - "{{ kolla_dev_repos_directory ~ '/qinling/qinling:/var/lib/kolla/venv/lib/python2.7/site-packages/qinling' if qinling_dev_mode | bool else '' }}" + - "kolla_logs:/var/log/kolla/" + dimensions: "{{ qinling_engine_dimensions }}" + + +#################### +# Database +#################### +qinling_database_name: "qinling" +qinling_database_user: "{% if use_preconfigured_databases | bool and use_common_mariadb_user | bool %}{{ database_user }}{% else %}qinling{% endif %}" +qinling_database_address: "{{ database_address }}:{{ database_port }}" + + +#################### +# Docker +#################### +qinling_install_type: "{{ kolla_install_type }}" +qinling_tag: "{{ openstack_release }}" + +qinling_api_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ qinling_install_type }}-qinling-api" +qinling_api_tag: "{{ qinling_tag }}" +qinling_api_image_full: "{{ qinling_api_image }}:{{ qinling_api_tag }}" + +qinling_engine_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ qinling_install_type }}-qinling-engine" +qinling_engine_tag: "{{ qinling_tag }}" +qinling_engine_image_full: "{{ qinling_engine_image }}:{{ qinling_engine_tag }}" + +qinling_api_dimensions: "{{ default_container_dimensions }}" +qinling_engine_dimensions: "{{ default_container_dimensions }}" + + +#################### +# OpenStack +#################### +qinling_admin_endpoint: "{{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ qinling_api_port }}" +qinling_internal_endpoint: "{{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ qinling_api_port }}" +qinling_public_endpoint: "{{ public_protocol }}://{{ kolla_external_fqdn }}:{{ qinling_api_port }}" + +qinling_logging_debug: "{{ openstack_logging_debug }}" + +qinling_keystone_user: "qinling" + +openstack_qinling_auth: "{{ openstack_auth }}" + + +#################### +# Kolla +#################### +qinling_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}" +qinling_dev_repos_pull: "{{ kolla_dev_repos_pull }}" +qinling_dev_mode: "{{ kolla_dev_mode }}" +qinling_source_version: "{{ kolla_source_version }}" diff --git a/ansible/roles/qinling/handlers/main.yml b/ansible/roles/qinling/handlers/main.yml new file mode 100644 index 0000000000..3963f068d5 --- /dev/null +++ b/ansible/roles/qinling/handlers/main.yml @@ -0,0 +1,52 @@ +--- +- name: Restart qinling-api container + vars: + service_name: "qinling-api" + service: "{{ qinling_services[service_name] }}" + config_json: "{{ qinling_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}" + qinling_conf: "{{ qinling_confs.results|selectattr('item.key', 'equalto', service_name)|first }}" + policy_overwriting: "{{ qinling_policy_overwriting.results|selectattr('item.key', 'equalto', service_name)|first }}" + qinling_api_container: "{{ check_qinling_containers.results|selectattr('item.key', 'equalto', service_name)|first }}" + become: true + kolla_docker: + action: "recreate_or_restart_container" + common_options: "{{ docker_common_options }}" + name: "{{ service.container_name }}" + image: "{{ service.image }}" + volumes: "{{ service.volumes|reject('equalto', '')|list }}" + environment: "{{ service.environment }}" + dimensions: "{{ service.dimensions }}" + when: + - kolla_action != "config" + - inventory_hostname in groups[service.group] + - service.enabled | bool + - config_json.changed | bool + or qinling_conf.changed | bool + or policy_overwriting.changed | bool + or qinling_api_container.changed | bool + +- name: Restart qinling-engine container + vars: + service_name: "qinling-engine" + service: "{{ qinling_services[service_name] }}" + config_json: "{{ qinling_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}" + qinling_conf: "{{ qinling_confs.results|selectattr('item.key', 'equalto', service_name)|first }}" + policy_overwriting: "{{ qinling_policy_overwriting.results|selectattr('item.key', 'equalto', service_name)|first }}" + qinling_engine_container: "{{ check_qinling_containers.results|selectattr('item.key', 'equalto', service_name)|first }}" + become: true + kolla_docker: + action: "recreate_or_restart_container" + common_options: "{{ docker_common_options }}" + name: "{{ service.container_name }}" + image: "{{ service.image }}" + volumes: "{{ service.volumes|reject('equalto', '')|list }}" + environment: "{{ service.environment }}" + dimensions: "{{ service.dimensions }}" + when: + - kolla_action != "config" + - inventory_hostname in groups[service.group] + - service.enabled | bool + - config_json.changed | bool + or qinling_conf.changed | bool + or policy_overwriting.changed | bool + or qinling_engine_container.changed | bool diff --git a/ansible/roles/qinling/meta/main.yml b/ansible/roles/qinling/meta/main.yml new file mode 100644 index 0000000000..6b4fff8fef --- /dev/null +++ b/ansible/roles/qinling/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: common } diff --git a/ansible/roles/qinling/tasks/bootstrap.yml b/ansible/roles/qinling/tasks/bootstrap.yml new file mode 100644 index 0000000000..838d8adbd6 --- /dev/null +++ b/ansible/roles/qinling/tasks/bootstrap.yml @@ -0,0 +1,38 @@ +--- +- name: Creating Qinling database + become: true + kolla_toolbox: + module_name: mysql_db + module_args: + login_host: "{{ database_address }}" + login_port: "{{ database_port }}" + login_user: "{{ database_user }}" + login_password: "{{ database_password }}" + name: "{{ qinling_database_name }}" + register: database + run_once: True + delegate_to: "{{ groups['qinling-api'][0] }}" + when: + - not use_preconfigured_databases | bool + +- name: Creating Qinling database user and setting permissions + become: true + kolla_toolbox: + module_name: mysql_user + module_args: + login_host: "{{ database_address }}" + login_port: "{{ database_port }}" + login_user: "{{ database_user }}" + login_password: "{{ database_password }}" + name: "{{ qinling_database_user }}" + password: "{{ qinling_database_password }}" + host: "%" + priv: "{{ qinling_database_name }}.*:ALL" + append_privs: "yes" + run_once: True + delegate_to: "{{ groups['qinling-api'][0] }}" + when: + - not use_preconfigured_databases | bool + +- include_tasks: bootstrap_service.yml + when: database.changed or use_preconfigured_databases | bool diff --git a/ansible/roles/qinling/tasks/bootstrap_service.yml b/ansible/roles/qinling/tasks/bootstrap_service.yml new file mode 100644 index 0000000000..7428401cd5 --- /dev/null +++ b/ansible/roles/qinling/tasks/bootstrap_service.yml @@ -0,0 +1,20 @@ +--- +- name: Running Qinling bootstrap container + vars: + qinling_api: "{{ qinling_services['qinling-api'] }}" + become: true + kolla_docker: + action: "start_container" + common_options: "{{ docker_common_options }}" + detach: False + environment: + KOLLA_BOOTSTRAP: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + image: "{{ qinling_api.image }}" + labels: + BOOTSTRAP: + name: "bootstrap_qinling" + restart_policy: "never" + volumes: "{{ qinling_api.volumes|reject('equalto', '')|list }}" + run_once: True + delegate_to: "{{ groups[qinling_api.group][0] }}" diff --git a/ansible/roles/qinling/tasks/check.yml b/ansible/roles/qinling/tasks/check.yml new file mode 100644 index 0000000000..ed97d539c0 --- /dev/null +++ b/ansible/roles/qinling/tasks/check.yml @@ -0,0 +1 @@ +--- diff --git a/ansible/roles/qinling/tasks/clone.yml b/ansible/roles/qinling/tasks/clone.yml new file mode 100644 index 0000000000..dc608348b5 --- /dev/null +++ b/ansible/roles/qinling/tasks/clone.yml @@ -0,0 +1,7 @@ +--- +- name: Cloning qinling source repository for development + git: + repo: "{{ qinling_git_repository }}" + dest: "{{ kolla_dev_repos_directory }}/{{ project_name }}" + update: "{{ qinling_dev_repos_pull }}" + version: "{{ qinling_source_version }}" diff --git a/ansible/roles/qinling/tasks/config.yml b/ansible/roles/qinling/tasks/config.yml new file mode 100644 index 0000000000..67c87cde01 --- /dev/null +++ b/ansible/roles/qinling/tasks/config.yml @@ -0,0 +1,104 @@ +--- +- name: Ensuring config directories exist + file: + path: "{{ node_config_directory }}/{{ item.key }}" + state: "directory" + owner: "{{ config_owner_user }}" + group: "{{ config_owner_group }}" + mode: "0770" + become: true + when: + - inventory_hostname in groups[item.value.group] + - item.value.enabled | bool + with_dict: "{{ qinling_services }}" + +- include_tasks: external_kubernetes.yml + when: + - (enable_qinling | bool) and (qinling_kubernetes_certificates | bool) + - inventory_hostname in groups['qinling-engine'] + +- name: Check if policies shall be overwritten + local_action: stat path="{{ item }}" + run_once: True + register: qinling_policy + with_first_found: + - files: "{{ supported_policy_format_list }}" + paths: + - "{{ node_custom_config }}/qinling/" + skip: true + +- name: Set qinling policy file + set_fact: + qinling_policy_file: "{{ qinling_policy.results.0.stat.path | basename }}" + qinling_policy_file_path: "{{ qinling_policy.results.0.stat.path }}" + when: + - qinling_policy.results + +- name: Copying over config.json files for services + template: + src: "{{ item.key }}.json.j2" + dest: "{{ node_config_directory }}/{{ item.key }}/config.json" + mode: "0660" + become: true + register: qinling_config_jsons + when: + - inventory_hostname in groups[item.value.group] + - item.value.enabled | bool + with_dict: "{{ qinling_services }}" + notify: + - Restart {{ item.key }} container + +- name: Copying over qinling.conf + vars: + service_name: "{{ item.key }}" + merge_configs: + sources: + - "{{ role_path }}/templates/qinling.conf.j2" + - "{{ node_custom_config }}/global.conf" + - "{{ node_custom_config }}/qinling.conf" + - "{{ node_custom_config }}/qinling/{{ item.key }}.conf" + - "{{ node_custom_config }}/qinling/{{ inventory_hostname }}/qinling.conf" + dest: "{{ node_config_directory }}/{{ item.key }}/qinling.conf" + mode: "0660" + become: true + register: qinling_confs + when: + - inventory_hostname in groups[item.value.group] + - item.value.enabled | bool + with_dict: "{{ qinling_services }}" + notify: + - Restart {{ item.key }} container + +- name: Copying over existing policy file + template: + src: "{{ qinling_policy_file_path }}" + dest: "{{ node_config_directory }}/{{ item.key }}/{{ qinling_policy_file }}" + mode: "0660" + become: true + register: qinling_policy_overwriting + when: + - qinling_policy_file is defined + - inventory_hostname in groups[item.value.group] + - item.value.enabled | bool + with_dict: "{{ qinling_services }}" + notify: + - Restart {{ item.key }} container + +- name: Check qinling containers + become: true + kolla_docker: + action: "compare_container" + common_options: "{{ docker_common_options }}" + name: "{{ item.value.container_name }}" + image: "{{ item.value.image }}" + volumes: "{{ item.value.volumes|reject('equalto', '')|list }}" + dimensions: "{{ item.value.dimensions }}" + environment: "{{ item.value.environment }}" + register: check_qinling_containers + when: + - kolla_action != "config" + - inventory_hostname in groups[item.value.group] + - item.value.enabled | bool + with_dict: "{{ qinling_services }}" + notify: + - Restart {{ item.key }} container diff --git a/ansible/roles/qinling/tasks/deploy.yml b/ansible/roles/qinling/tasks/deploy.yml new file mode 100644 index 0000000000..471893e058 --- /dev/null +++ b/ansible/roles/qinling/tasks/deploy.yml @@ -0,0 +1,16 @@ +--- +- include_tasks: register.yml + when: inventory_hostname in groups['qinling-api'] + +- include_tasks: config.yml + when: inventory_hostname in groups['qinling-api'] or + inventory_hostname in groups['qinling-engine'] + +- include_tasks: clone.yml + when: qinling_dev_mode | bool + +- include_tasks: bootstrap.yml + when: inventory_hostname in groups['qinling-api'] + +- name: Flush handlers + meta: flush_handlers diff --git a/ansible/roles/qinling/tasks/external_kubernetes.yml b/ansible/roles/qinling/tasks/external_kubernetes.yml new file mode 100644 index 0000000000..0dee19b692 --- /dev/null +++ b/ansible/roles/qinling/tasks/external_kubernetes.yml @@ -0,0 +1,19 @@ +--- +- name: Copy over Kubernetes certificates files for qinling-engine + copy: + src: "{{ item }}" + dest: "{{ node_config_directory }}/qinling-engine/" + mode: "0660" + owner: "{{ config_owner_user }}" + group: "{{ config_owner_group }}" + become: true + register: qinling_engine_kubernetes_files + with_items: + - "{{ node_custom_config }}/qinling/qinling-engine/kubernetes_ca.crt" + - "{{ node_custom_config }}/qinling/qinling-engine/kubernetes.crt" + - "{{ node_custom_config }}/qinling/qinling-engine/kubernetes.key" + when: + - qinling_kubernetes_certificates | bool + - inventory_hostname in groups['qinling-engine'] + notify: + - Restart qinling-engine container diff --git a/ansible/roles/qinling/tasks/loadbalancer.yml b/ansible/roles/qinling/tasks/loadbalancer.yml new file mode 100644 index 0000000000..4b0b6ccbf9 --- /dev/null +++ b/ansible/roles/qinling/tasks/loadbalancer.yml @@ -0,0 +1,7 @@ +--- +- name: "Configure haproxy for {{ project_name }}" + import_role: + role: haproxy-config + vars: + project_services: "{{ qinling_services }}" + tags: always diff --git a/ansible/roles/qinling/tasks/main.yml b/ansible/roles/qinling/tasks/main.yml new file mode 100644 index 0000000000..bc5d1e6257 --- /dev/null +++ b/ansible/roles/qinling/tasks/main.yml @@ -0,0 +1,2 @@ +--- +- include_tasks: "{{ kolla_action }}.yml" diff --git a/ansible/roles/qinling/tasks/precheck.yml b/ansible/roles/qinling/tasks/precheck.yml new file mode 100644 index 0000000000..724fd02977 --- /dev/null +++ b/ansible/roles/qinling/tasks/precheck.yml @@ -0,0 +1,17 @@ +--- +- name: Get container facts + kolla_container_facts: + name: + - qinling_api + register: container_facts + +- name: Checking free port for Qinling API + wait_for: + host: "{{ api_interface_address }}" + port: "{{ qinling_api_port }}" + connect_timeout: 1 + timeout: 1 + state: stopped + when: + - container_facts['qinling_api'] is not defined + - inventory_hostname in groups['qinling-api'] diff --git a/ansible/roles/qinling/tasks/pull.yml b/ansible/roles/qinling/tasks/pull.yml new file mode 100644 index 0000000000..8cd89824e5 --- /dev/null +++ b/ansible/roles/qinling/tasks/pull.yml @@ -0,0 +1,11 @@ +--- +- name: Pulling qinling images + become: true + kolla_docker: + action: "pull_image" + common_options: "{{ docker_common_options }}" + image: "{{ item.value.image }}" + when: + - inventory_hostname in groups[item.value.group] + - item.value.enabled | bool + with_dict: "{{ qinling_services }}" diff --git a/ansible/roles/qinling/tasks/reconfigure.yml b/ansible/roles/qinling/tasks/reconfigure.yml new file mode 100644 index 0000000000..f670a5b78d --- /dev/null +++ b/ansible/roles/qinling/tasks/reconfigure.yml @@ -0,0 +1,2 @@ +--- +- include_tasks: deploy.yml diff --git a/ansible/roles/qinling/tasks/register.yml b/ansible/roles/qinling/tasks/register.yml new file mode 100644 index 0000000000..f1a8914ab2 --- /dev/null +++ b/ansible/roles/qinling/tasks/register.yml @@ -0,0 +1,34 @@ +--- +- name: Creating the Qinling service and endpoint + become: true + kolla_toolbox: + module_name: "kolla_keystone_service" + module_args: + service_name: "qinling" + service_type: "function-engine" + description: "Function Service" + endpoint_region: "{{ openstack_region_name }}" + url: "{{ item.url }}" + interface: "{{ item.interface }}" + region_name: "{{ openstack_region_name }}" + auth: "{{ openstack_qinling_auth }}" + endpoint_type: "{{ openstack_interface }}" + run_once: True + with_items: + - {'interface': 'admin', 'url': '{{ qinling_admin_endpoint }}'} + - {'interface': 'internal', 'url': '{{ qinling_internal_endpoint }}'} + - {'interface': 'public', 'url': '{{ qinling_public_endpoint }}'} + +- name: Creating the Qinling project, user, and role + become: true + kolla_toolbox: + module_name: "kolla_keystone_user" + module_args: + project: "service" + user: "{{ qinling_keystone_user }}" + password: "{{ qinling_keystone_password }}" + role: "admin" + region_name: "{{ openstack_region_name }}" + auth: "{{ openstack_qinling_auth }}" + endpoint_type: "{{ openstack_interface }}" + run_once: True diff --git a/ansible/roles/qinling/tasks/stop.yml b/ansible/roles/qinling/tasks/stop.yml new file mode 100644 index 0000000000..c3a4142ace --- /dev/null +++ b/ansible/roles/qinling/tasks/stop.yml @@ -0,0 +1,6 @@ +--- +- import_role: + role: service-stop + vars: + project_services: "{{ qinling_services }}" + service_name: "{{ project_name }}" diff --git a/ansible/roles/qinling/tasks/upgrade.yml b/ansible/roles/qinling/tasks/upgrade.yml new file mode 100644 index 0000000000..20ccddc8f1 --- /dev/null +++ b/ansible/roles/qinling/tasks/upgrade.yml @@ -0,0 +1,7 @@ +--- +- include_tasks: config.yml + +- include_tasks: bootstrap_service.yml + +- name: Flush handlers + meta: flush_handlers diff --git a/ansible/roles/qinling/templates/qinling-api.json.j2 b/ansible/roles/qinling/templates/qinling-api.json.j2 new file mode 100644 index 0000000000..230219f057 --- /dev/null +++ b/ansible/roles/qinling/templates/qinling-api.json.j2 @@ -0,0 +1,24 @@ +{ + "command": "qinling-api --config-file /etc/qinling/qinling.conf", + "config_files": [ + { + "source": "{{ container_config_directory }}/qinling.conf", + "dest": "/etc/qinling/qinling.conf", + "owner": "qinling", + "perm": "0600" + }{% if qinling_policy_file is defined %}, + { + "source": "{{ container_config_directory }}/{{ qinling_policy_file }}", + "dest": "/etc/qinling/{{ qinling_policy_file }}", + "owner": "qinling", + "perm": "0600" + }{% endif %} + ], + "permissions": [ + { + "path": "/var/log/kolla/qinling", + "owner": "qinling:qinling", + "recurse": true + } + ] +} diff --git a/ansible/roles/qinling/templates/qinling-engine.json.j2 b/ansible/roles/qinling/templates/qinling-engine.json.j2 new file mode 100644 index 0000000000..b1f8bd4c41 --- /dev/null +++ b/ansible/roles/qinling/templates/qinling-engine.json.j2 @@ -0,0 +1,47 @@ +{ + "command": "qinling-engine --config-file /etc/qinling/qinling.conf", + "config_files": [ + { + "source": "{{ container_config_directory }}/qinling.conf", + "dest": "/etc/qinling/qinling.conf", + "owner": "qinling", + "perm": "0600" + }{% if qinling_policy_file is defined %}, + { + "source": "{{ container_config_directory }}/{{ qinling_policy_file }}", + "dest": "/etc/qinling/{{ qinling_policy_file }}", + "owner": "qinling", + "perm": "0600" + }{% endif %}{% if qinling_kubernetes_certificates is defined and qinling_kubernetes_certificates | bool %}, + { + "source": "{{ container_config_directory }}/kubernetes_ca.crt", + "dest": "/etc/qinling/pki/kubernetes/ca.crt", + "owner": "qinling", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/kubernetes.crt", + "dest": "/etc/qinling/pki/kubernetes/qinling.crt", + "owner": "qinling", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/kubernetes.key", + "dest": "/etc/qinling/pki/kubernetes/qinling.key", + "owner": "qinling", + "perm": "0600" + }{% endif %} + ], + "permissions": [ + { + "path": "/var/lib/qinling", + "owner": "qinling:qinling", + "recurse": true + }, + { + "path": "/var/log/kolla/qinling", + "owner": "qinling:qinling", + "recurse": true + } + ] +} diff --git a/ansible/roles/qinling/templates/qinling.conf.j2 b/ansible/roles/qinling/templates/qinling.conf.j2 new file mode 100644 index 0000000000..b7b20c8258 --- /dev/null +++ b/ansible/roles/qinling/templates/qinling.conf.j2 @@ -0,0 +1,62 @@ +[DEFAULT] +debug = {{ qinling_logging_debug }} +log_dir = /var/log/kolla/qinling +transport_url = {{ rpc_transport_url }} + +{% if service_name == 'qinling-api' %} +[api] +port = {{ qinling_api_port }} +host = {{ api_interface_address }} +api_workers = {{ openstack_service_workers }} +{% endif %} + +{% if service_name == 'qinling-engine' %} +[engine] +host = {{ api_interface_address }} +{% endif %} + +[database] +connection = mysql+pymysql://{{ qinling_database_user }}:{{ qinling_database_password }}@{{ qinling_database_address }}/{{ qinling_database_name }} +max_retries = -1 + +[keystone_authtoken] +www_authenticate_uri = {{ keystone_internal_url }}/v3 +auth_url = {{ keystone_admin_url }} +auth_type = password +project_domain_name = {{ default_project_domain_name }} +user_domain_name = {{ default_user_domain_name }} +project_name = service +username = {{ qinling_keystone_user }} +password = {{ qinling_keystone_password }} +region_name = {{ openstack_region_name }} + +memcache_security_strategy = ENCRYPT +memcache_secret_key = {{ memcache_secret_key }} +memcached_servers = {% for host in groups['memcached'] %}{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ memcached_port }}{% if not loop.last %},{% endif %}{% endfor %} + +[storage] +file_system_dir = /var/lib/qinling/package + +[etcd] +{% if enable_etcd | bool %} +host = {{ api_interface_address }} +port = {{ etcd_client_port }} +protocol = {{ internal_protocol }} +{% endif %} + +[oslo_messaging_notifications] +transport_url = {{ notify_transport_url }} +{% if enable_ceilometer | bool %} +driver = messagingv2 +topics = notifications +{% else %} +driver = noop +{% endif %} + +{% if qinling_policy_file is defined %} +[oslo_policy] +policy_file = {{ qinling_policy_file }} +{% endif %} + +[oslo_middleware] +enable_proxy_headers_parsing = True diff --git a/ansible/site.yml b/ansible/site.yml index 595e243837..2f27d6e4e1 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -69,6 +69,7 @@ - enable_placement_{{ enable_placement | bool }} - enable_prometheus_{{ enable_prometheus | bool }} - enable_qdrouterd_{{ enable_qdrouterd | bool }} + - enable_qinling_{{ enable_qinling | bool }} - enable_rabbitmq_{{ enable_rabbitmq | bool }} - enable_rally_{{ enable_rally | bool }} - enable_redis_{{ enable_redis | bool }} @@ -302,6 +303,11 @@ tasks_from: loadbalancer tags: prometheus when: enable_prometheus | bool + - include_role: + role: qinling + tasks_from: loadbalancer + tags: qinling + when: enable_qinling | bool - include_role: role: rabbitmq tasks_from: loadbalancer @@ -863,6 +869,18 @@ tags: mistral, when: enable_mistral | bool } +- name: Apply role qinling + gather_facts: false + hosts: + - qinling-api + - qinling-engine + - '&enable_qinling_True' + serial: '{{ kolla_serial|default("0") }}' + roles: + - { role: qinling, + tags: qinling, + when: enable_qinling | bool } + - name: Apply role sahara gather_facts: false hosts: diff --git a/doc/source/reference/compute/index.rst b/doc/source/reference/compute/index.rst index ba17f64e0e..aa0e86a2bc 100644 --- a/doc/source/reference/compute/index.rst +++ b/doc/source/reference/compute/index.rst @@ -10,6 +10,7 @@ compute services like HyperV, XenServer and so on. hyperv-guide nova-fake-driver + qinling-guide vmware-guide xenserver-guide zun-guide diff --git a/doc/source/reference/compute/qinling-guide.rst b/doc/source/reference/compute/qinling-guide.rst new file mode 100644 index 0000000000..4aaa32e2bd --- /dev/null +++ b/doc/source/reference/compute/qinling-guide.rst @@ -0,0 +1,96 @@ +.. _qinling-guide: + +========================= +Qinling - Function Engine +========================= + +Overview +~~~~~~~~ + +Qinling aims to provide a platform to support serverless functions +(like AWS Lambda). Qinling supports different container orchestration +platforms (Kubernetes/Swarm, etc...) and different function package storage +backends (local/Swift/S3) by nature using plugin mechanism. + +Kolla deploys Qinling API and Qinling Engine containers which are the main +Qinling components but it needs to be connected to an existing container +orchestration platforms. + +Apply custom policies to Qinling API +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Custom policies could be apply by creating ``policy.json`` file under +``/etc/kolla/config/qinling`` directory. + + +Connect to an existing Kubernetes cluster +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Certificates +------------ + +``qinling-engine`` authenticates to Kubernetes by using certificates. + +.. note:: + If the cluster has not been created with OpenStack Magnum then + certificates need to be gathered using different methods that will not + be mentioned here. + +If the Kubernetes cluster has been deployed with OpenStack Magnum then the +OpenStack client should be used to retrieve the certificates. + +.. code-block:: console + + openstack coe cluster config --dir . 687f7476-5604-4b44-8b09-b7a4f3fdbd64 --output-certs + +Where ``687f7476-5604-4b44-8b09-b7a4f3fdbd64`` is the Kubernetes cluster ID +created with Magnum. + +Four files should have been generated: + + - ``ca.pem`` + - ``cert.pem`` + - ``key.pem`` + - ``config`` + +Only ``ca.pem``, ``cert.pem`` and ``key.pem`` will be used, these files have +to be stored in ``/etc/kolla/config/qinling/qinling-engine`` directory under +these file name: + + - ``ca.pem``: ``/etc/kolla/config/qinling/qinling-engine/kubernetes_ca.crt`` + - ``cert.pem``: ``/etc/kolla/config/qinling/qinling-engine/kubernetes.crt`` + - ``key.pem``: ``/etc/kolla/config/qinling/qinling-engine/kubernetes.key`` + + +Declare ``qinling_kubernetes_certificates`` variable in +``/etc/kolla/globals.yml``: + +.. code-block:: yaml + + qinling_kubernetes_certificates: "yes" + +Kubernetes cluster +------------------ + +``qinling-engine`` needs to know where to connect, the information is +provided by options under ``[kubernetes]`` section inside ``qinling.conf`` +configuration file. + +As mentioned above, these settings are only required by ``qinling-engine``, +put the content in ``/etc/kolla/config/qinling/qinling-engine.conf``. + +.. code-block:: ini + + [kubernetes] + kube_host = https://192.168.1.168:6443 + use_api_certificate = True + ssl_ca_cert = /etc/qinling/pki/kubernetes/ca.crt + cert_file = /etc/qinling/pki/kubernetes/qinling.crt + key_file = /etc/qinling/pki/kubernetes/qinling.key + trusted_cidrs = 192.168.1.0/24,10.0.0.53/32 + +``kube_host`` is the the Kubernetes cluster API address, ``https`` protocol +have to be defined. + +``trusted_cidrs`` is a list of CIDR trusted by the Kubernetes cluster defined +by a network policy under the ``qinling`` namespace. diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml index f091b4ca3f..83ae8167ec 100644 --- a/etc/kolla/globals.yml +++ b/etc/kolla/globals.yml @@ -236,6 +236,7 @@ kolla_internal_vip_address: "10.10.10.254" #enable_horizon_neutron_lbaas: "{{ enable_neutron_lbaas | bool }}" #enable_horizon_neutron_vpnaas: "{{ enable_neutron_vpnaas | bool }}" #enable_horizon_octavia: "{{ enable_octavia | bool }}" +#enable_horizon_qinling: "{{ enable_qinling | bool }}" #enable_horizon_sahara: "{{ enable_sahara | bool }}" #enable_horizon_searchlight: "{{ enable_searchlight | bool }}" #enable_horizon_senlin: "{{ enable_senlin | bool }}" @@ -288,6 +289,7 @@ kolla_internal_vip_address: "10.10.10.254" #enable_placement: "{{ enable_nova }}" #enable_prometheus: "no" #enable_qdrouterd: "no" +#enable_qinling: "no" #enable_rally: "no" #enable_redis: "no" #enable_sahara: "no" diff --git a/etc/kolla/passwords.yml b/etc/kolla/passwords.yml index 43f919021a..87204dac10 100644 --- a/etc/kolla/passwords.yml +++ b/etc/kolla/passwords.yml @@ -196,6 +196,9 @@ vitrage_keystone_password: memcache_secret_key: +qinling_database_password: +qinling_keystone_password: + # HMAC secret key osprofiler_secret: diff --git a/releasenotes/notes/add-qinling-role-99d96102837b21f4.yaml b/releasenotes/notes/add-qinling-role-99d96102837b21f4.yaml new file mode 100644 index 0000000000..b2fcdb981c --- /dev/null +++ b/releasenotes/notes/add-qinling-role-99d96102837b21f4.yaml @@ -0,0 +1,5 @@ +--- +features: + - Adds Qinling Ansible role. Qinling is an OpenStack project + to provide "Function as a Service". This project aims to + provide a platform to support serverless functions. diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2 index e3137964a3..2697b405d0 100644 --- a/tests/templates/inventory.j2 +++ b/tests/templates/inventory.j2 @@ -159,6 +159,9 @@ monitoring [magnum:children] control +[qinling:children] +control + [sahara:children] control @@ -457,6 +460,13 @@ magnum [magnum-conductor:children] magnum +# Qinling +[qinling-api:children] +qinling + +[qinling-engine:children] +qinling + # Solum [solum-api:children] solum