diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index 88d6de0..20cb241 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -28,6 +28,9 @@ nova_api_port: "8774" # Cinder cinder_api_port: "8776" +# Senlin +senlin_api_port: "8778" + # Trove trove_api_port: "8779" diff --git a/ansible/passwords.yml b/ansible/passwords.yml index 6ae778f..9ed98b4 100644 --- a/ansible/passwords.yml +++ b/ansible/passwords.yml @@ -1,2 +1,4 @@ trove_database_password: trove_keystone_password: +senlin_database_password: +senlin_keystone_password: diff --git a/ansible/roles/fuel/defaults/main.yml b/ansible/roles/fuel/defaults/main.yml index 50f4865..06530e9 100644 --- a/ansible/roles/fuel/defaults/main.yml +++ b/ansible/roles/fuel/defaults/main.yml @@ -25,6 +25,10 @@ eayunstack_docker_images: image_name: "{{ eayunstack_docker_prefix }}/trove-db-sync" file_name: "eayunstack_trove_db_sync.latest" push: "True" + senlin_base: + image_name: "{{ eayunstack_docker_prefix }}/senlin-base" + file_name: "eayunstack_senlin_base.latest" + push: "True" eayunstack_registry_diretory: "/var/lib/eayunstack-registry" eayunstack_registry_port: "5010" diff --git a/ansible/roles/haproxy/defaults/main.yml b/ansible/roles/haproxy/defaults/main.yml index d9ab424..5a49508 100644 --- a/ansible/roles/haproxy/defaults/main.yml +++ b/ansible/roles/haproxy/defaults/main.yml @@ -1,2 +1,3 @@ --- +senlin_haproxy_order: "299" trove_haproxy_order: "300" diff --git a/ansible/roles/haproxy/tasks/main.yml b/ansible/roles/haproxy/tasks/main.yml index f7804c0..11c9d87 100644 --- a/ansible/roles/haproxy/tasks/main.yml +++ b/ansible/roles/haproxy/tasks/main.yml @@ -1,4 +1,10 @@ --- +- name: Copying over senlin haproxy conf files + template: + src: "senlin-api-haproxy.conf.j2" + dest: "{{ haproxy_config_base }}/{{ senlin_haproxy_order }}-senlin-api.cfg" + notify: Reload HAProxy + - name: Copying over trove haproxy conf files template: src: "trove-api-haproxy.conf.j2" diff --git a/ansible/roles/haproxy/templates/senlin-api-haproxy.conf.j2 b/ansible/roles/haproxy/templates/senlin-api-haproxy.conf.j2 new file mode 100644 index 0000000..14a1d43 --- /dev/null +++ b/ansible/roles/haproxy/templates/senlin-api-haproxy.conf.j2 @@ -0,0 +1,10 @@ +listen senlin-api + bind {{ management_vip }}:{{ senlin_api_port }} + bind {{ public_vip }}:{{ senlin_api_port }} + mode http + option httpchk + option httplog + option httpclose +{% for host in groups['controller'] %} + server {{hostvars[host]['ansible_hostname']}} {{ hostvars[host]['ansible_' + hostvars[host]['network_scheme']['roles']['management']|replace('-', '_')]['ipv4']['address'] }}:{{senlin_api_port}} check inter 10s fastinter 2s downinter 3s rise 3 fall 3 +{% endfor %} diff --git a/ansible/roles/senlin/defaults/main.yml b/ansible/roles/senlin/defaults/main.yml new file mode 100644 index 0000000..785cb99 --- /dev/null +++ b/ansible/roles/senlin/defaults/main.yml @@ -0,0 +1,53 @@ +--- +project_name: senlin + +senlin_sys_uid: 970 +senlin_sys_gid: 970 +senlin_sys_homedir: "/var/lib/senlin" + +senlin_database_name: "senlin" + +senlin_services: + senlin-api: + container_name: senlin_api + image: "{{ senlin_base_image }}" + volumes: + - "{{ senlin_sys_homedir }}:{{ senlin_sys_homedir }}" + - "{{ eayunstack_config_base }}/{{ project_name }}:{{ senlin_config_diretory }}:ro" + - "{{ timezone_path }}:/etc/localtime:ro" + - "{{ eayunstack_log_base }}/{{ project_name }}:{{ senlin_log_directory }}" + senlin-engine: + container_name: senlin_engine + image: "{{ senlin_base_image }}" + volumes: + - "{{ senlin_sys_homedir }}:{{ senlin_sys_homedir }}" + - "{{ eayunstack_config_base }}/{{ project_name }}:{{ senlin_config_diretory }}:ro" + - "{{ timezone_path }}:/etc/localtime:ro" + - "{{ eayunstack_log_base }}/{{ project_name }}:{{ senlin_log_directory }}" + +senlin_config_diretory: /etc/senlin +senlin_config_files: + senlin.conf: + handlers: + - Restart senlin-api container + - Restart senlin-engine container + +senlin_public_endpoint: "http://{{ public_vip }}:{{ senlin_api_port }}" +senlin_internal_endpoint: "http://{{ management_vip }}:{{ senlin_api_port }}" +senlin_admin_endpoint: "http://{{ management_vip }}:{{ senlin_api_port }}" + +senlin_endpoints: + publicurl: "{{ senlin_public_endpoint }}" + internalurl: "{{ senlin_internal_endpoint }}" + adminurl: "{{ senlin_admin_endpoint }}" + +senlin_log_directory: "/var/log/{{ project_name }}" +senlin_logging_debug: "True" +check_interval_max: "300" +default_action_timeout: "300" + +senlin_base_image: "{{ docker_registry }}/{{ eayunstack_docker_prefix }}/senlin-base" + +senlin_logrotate_conf: + rotate: "4" + minsize: "30M" diff --git a/ansible/roles/senlin/files/api-paste.ini b/ansible/roles/senlin/files/api-paste.ini new file mode 100644 index 0000000..4ddfefd --- /dev/null +++ b/ansible/roles/senlin/files/api-paste.ini @@ -0,0 +1,39 @@ + +# senlin-api pipeline +[pipeline:senlin-api] +pipeline = request_id faultwrap ssl versionnegotiation webhook authtoken context trust apiv1app + +[app:apiv1app] +paste.app_factory = senlin.api.common.wsgi:app_factory +senlin.app_factory = senlin.api.openstack.v1.router:API + +# Middleware to set x-openstack-request-id in http response header +[filter:request_id] +paste.filter_factory = oslo_middleware.request_id:RequestId.factory + +[filter:faultwrap] +paste.filter_factory = senlin.api.common.wsgi:filter_factory +senlin.filter_factory = senlin.api.middleware:fault_filter + +[filter:context] +paste.filter_factory = senlin.api.common.wsgi:filter_factory +senlin.filter_factory = senlin.api.middleware:context_filter + +[filter:ssl] +paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory + +[filter:versionnegotiation] +paste.filter_factory = senlin.api.common.wsgi:filter_factory +senlin.filter_factory = senlin.api.middleware:version_filter + +[filter:trust] +paste.filter_factory = senlin.api.common.wsgi:filter_factory +senlin.filter_factory = senlin.api.middleware:trust_filter + +[filter:webhook] +paste.filter_factory = senlin.api.common.wsgi:filter_factory +senlin.filter_factory = senlin.api.middleware:webhook_filter + +# Auth middleware that validates token against keystone +[filter:authtoken] +paste.filter_factory = keystonemiddleware.auth_token:filter_factory diff --git a/ansible/roles/senlin/files/policy.json b/ansible/roles/senlin/files/policy.json new file mode 100644 index 0000000..f0c4d9d --- /dev/null +++ b/ansible/roles/senlin/files/policy.json @@ -0,0 +1,51 @@ +{ + "context_is_admin": "role:admin", + "deny_everybody": "!", + + "build_info:build_info": "", + "profile_types:index": "", + "profile_types:get": "", + "policy_types:index": "", + "policy_types:get": "", + "clusters:index": "", + "clusters:create": "", + "clusters:delete": "", + "clusters:get": "", + "clusters:action": "", + "clusters:update": "", + "clusters:collect": "", + "profiles:index": "", + "profiles:create": "", + "profiles:get": "", + "profiles:delete": "", + "profiles:update": "", + "profiles:validate": "", + "nodes:index": "", + "nodes:create": "", + "nodes:get": "", + "nodes:action": "", + "nodes:update": "", + "nodes:delete": "", + "policies:index": "", + "policies:create": "", + "policies:get": "", + "policies:update": "", + "policies:delete": "", + "policies:validate": "", + "cluster_policies:index": "", + "cluster_policies:attach": "", + "cluster_policies:detach": "", + "cluster_policies:update": "", + "cluster_policies:get": "", + "receivers:index": "", + "receivers:create": "", + "receivers:get": "", + "receivers:update": "", + "receivers:delete": "", + "actions:index": "", + "actions:get": "", + "events:index": "", + "events:get": "", + "webhooks:trigger": "", + "services:index": "role:admin" +} diff --git a/ansible/roles/senlin/handlers/main.yml b/ansible/roles/senlin/handlers/main.yml new file mode 100644 index 0000000..c9d29ef --- /dev/null +++ b/ansible/roles/senlin/handlers/main.yml @@ -0,0 +1,36 @@ +--- +- name: Restart senlin-api container + vars: + service_name: "senlin-api" + service: "{{ senlin_services[service_name] }}" + senlin_conf: "{{ senlin_confs.results|selectattr('item.key', 'match', 'senlin.conf')|first }}" + senlin_api_container: "{{ check_senlin_containers.results|selectattr('item.key', 'match', service_name)|first }}" + kolla_docker: + action: "recreate_or_restart_container" + name: "{{ service.container_name }}" + image: "{{ service.image }}" + volumes: "{{ service.volumes }}" + environment: + DAEMON: "senlin-api" + restart_policy: "{{ docker_restart_policy }}" + when: senlin_conf.changed | bool + or senlin_api_container.changed | bool + or (senlin_database_migrate is defined and senlin_database_migrate.changed | bool) + +- name: Restart senlin-engine container + vars: + service_name: "senlin-engine" + service: "{{ senlin_services[service_name] }}" + senlin_conf: "{{ senlin_confs.results|selectattr('item.key', 'match', 'senlin.conf')|first }}" + senlin_engine_container: "{{ check_senlin_containers.results|selectattr('item.key', 'match', service_name)|first }}" + kolla_docker: + action: "recreate_or_restart_container" + name: "{{ service.container_name }}" + image: "{{ service.image }}" + volumes: "{{ service.volumes }}" + environment: + DAEMON: "senlin-engine" + restart_policy: "{{ docker_restart_policy }}" + when: senlin_conf.changed | bool + or senlin_engine_container.changed | bool + or (senlin_database_migrate is defined and senlin_database_migrate.changed | bool) diff --git a/ansible/roles/senlin/tasks/config.yml b/ansible/roles/senlin/tasks/config.yml new file mode 100644 index 0000000..d032878 --- /dev/null +++ b/ansible/roles/senlin/tasks/config.yml @@ -0,0 +1,74 @@ +--- +- name: Ensuring system group exist + group: + name: senlin + gid: "{{ senlin_sys_gid }}" + +- name: Ensuring system user exist + user: + name: senlin + comment: "senlin Daemons" + uid: "{{ senlin_sys_uid }}" + group: senlin + groups: senlin + home: "{{ senlin_sys_homedir }}" + shell: "/sbin/nologin" + +- name: Ensuring config directory exist + file: + path: "{{ eayunstack_config_base }}/{{ project_name }}" + state: "directory" + recurse: yes + +- name: Ensuring log directory exist + file: + path: "{{ eayunstack_log_base }}/{{ project_name }}" + state: "directory" + owner: senlin + +- name: Copy api-paste.ini + copy: + src: api-paste.ini + dest: "{{ eayunstack_config_base }}/{{ project_name }}/" + +- name: Copy policy.json + copy: + src: policy.json + dest: "{{ eayunstack_config_base }}/{{ project_name }}/" + +- name: Copy senlin-logrotate config + template: + src: senlin-logrotate.conf.j2 + dest: "/etc/logrotate.d/eayunstack-docker-{{ project_name }}" + +- name: Copying over senlin conf files + vars: + service_name: "{{ item.key }}" + template: + src: "{{ item.key }}.j2" + dest: "{{ eayunstack_config_base }}/{{ project_name }}/{{ item.key }}" + register: senlin_confs + with_dict: "{{ senlin_config_files }}" + notify: "{{ item.value.handlers | default([]) }}" + +- name: Check senlin containers + kolla_docker: + action: "compare_container" + name: "{{ item.value.container_name }}" + image: "{{ item.value.image }}" + volumes: "{{ item.value.volumes }}" + restart_policy: "{{ docker_restart_policy }}" + with_dict: "{{ senlin_services }}" + register: check_senlin_containers + notify: + - "Restart {{ item.key }} container" + +- name: Ensuring iptables for senlin + iptables: + action: insert + chain: INPUT + protocol: tcp + match: multiport + destination_port: "{{ senlin_api_port }}" + jump: ACCEPT + notify: "Save iptables rules" diff --git a/ansible/roles/senlin/tasks/database_migrate.yml b/ansible/roles/senlin/tasks/database_migrate.yml new file mode 100644 index 0000000..86cfc3e --- /dev/null +++ b/ansible/roles/senlin/tasks/database_migrate.yml @@ -0,0 +1,21 @@ +--- +- name: Migrating senlin database + vars: + senlin_api_container: "{{ check_senlin_containers.results|selectattr('item.key', 'match', 'senlin-api')|first }}" + kolla_docker: + action: "start_container" + detach: False + name: "senlin_database_migrate" + image: "{{ senlin_base_image }}" + volumes: "{{ senlin_services['senlin-api']['volumes'] }}" + environment: + DAEMON: "senlin-manage" + restart_policy: "never" + register: senlin_database_migrate + when: senlin_database.changed | bool + or senlin_api_container.changed | bool + run_once: True + delegate_to: "{{ groups['controller'][0] }}" + notify: + - Restart senlin-api container + - Restart senlin-engine container diff --git a/ansible/roles/senlin/tasks/main.yml b/ansible/roles/senlin/tasks/main.yml new file mode 100644 index 0000000..27b5775 --- /dev/null +++ b/ansible/roles/senlin/tasks/main.yml @@ -0,0 +1,54 @@ +- name: ensure senlin user, service + run_once: True + keystone: + region_name: "{{ keystone_region }}" + endpoint: "{{ keystone_admin_endpoint_v3 }}" + token: "{{ keystone.admin_token }}" + command: "{{ item.command }}" + user_name: "senlin" + password: "{{ senlin_keystone_password }}" + project_name: "{{ item.tenant | default(None) }}" + role_name: "{{ item.role | default(None) }}" + service_name: "{{ item.service_name | default(None) }}" + service_type: "{{ item.service_type | default(None) }}" + description: "{{ item.description | default(None) }}" + with_items: + - { command: 'ensure_user' } + - { command: 'ensure_user_role', tenant: 'services', role: 'admin' } + - { command: 'ensure_service', service_name: 'senlin', service_type: 'clustering', description: 'Senlin Clustering Service V1' } + +- name: ensure senlin endpoint + run_once: True + keystone_v2_endpoint: + region_name: "{{ keystone_region }}" + endpoint: "{{ keystone_admin_endpoint_v2 }}" + token: "{{ keystone.admin_token }}" + service_name: "senlin" + service_type: "clustering" + endpoint_dict: "{{ senlin_endpoints }}" + +- name: Creating senlin database + mysql_db: + config_file: "{{ mysql_conf_file }}" + name: "{{ senlin_database_name }}" + register: senlin_database + run_once: True + delegate_to: "{{ groups['controller'][0] }}" + +- name: Creating senlin database user and setting permissions + mysql_user: + config_file: "{{ mysql_conf_file }}" + name: "{{ senlin_database_name }}" + password: "{{ senlin_database_password }}" + host: "%" + priv: "{{ senlin_database_name }}.*:ALL" + append_privs: "yes" + run_once: True + delegate_to: "{{ groups['controller'][0] }}" + +- include: pull.yml + +- include: config.yml + +- include: database_migrate.yml + diff --git a/ansible/roles/senlin/tasks/pull.yml b/ansible/roles/senlin/tasks/pull.yml new file mode 100644 index 0000000..adc3f68 --- /dev/null +++ b/ansible/roles/senlin/tasks/pull.yml @@ -0,0 +1,5 @@ +--- +- name: Pulling senlin images + kolla_docker: + action: "pull_image" + image: "{{ senlin_base_image }}" diff --git a/ansible/roles/senlin/templates/senlin-api-haproxy.conf.j2 b/ansible/roles/senlin/templates/senlin-api-haproxy.conf.j2 new file mode 100644 index 0000000..14a1d43 --- /dev/null +++ b/ansible/roles/senlin/templates/senlin-api-haproxy.conf.j2 @@ -0,0 +1,10 @@ +listen senlin-api + bind {{ management_vip }}:{{ senlin_api_port }} + bind {{ public_vip }}:{{ senlin_api_port }} + mode http + option httpchk + option httplog + option httpclose +{% for host in groups['controller'] %} + server {{hostvars[host]['ansible_hostname']}} {{ hostvars[host]['ansible_' + hostvars[host]['network_scheme']['roles']['management']|replace('-', '_')]['ipv4']['address'] }}:{{senlin_api_port}} check inter 10s fastinter 2s downinter 3s rise 3 fall 3 +{% endfor %} diff --git a/ansible/roles/senlin/templates/senlin-logrotate.conf.j2 b/ansible/roles/senlin/templates/senlin-logrotate.conf.j2 new file mode 100644 index 0000000..0adf32f --- /dev/null +++ b/ansible/roles/senlin/templates/senlin-logrotate.conf.j2 @@ -0,0 +1,8 @@ +{{ eayunstack_log_base }}/{{ project_name}}/*.log { + weekly + rotate {{ senlin_logrotate_conf.rotate }} + minsize {{ senlin_logrotate_conf.minsize }} + compress + missingok + notifempty +} diff --git a/ansible/roles/senlin/templates/senlin.conf.j2 b/ansible/roles/senlin/templates/senlin.conf.j2 new file mode 100644 index 0000000..feca61f --- /dev/null +++ b/ansible/roles/senlin/templates/senlin.conf.j2 @@ -0,0 +1,37 @@ +[DEFAULT] +debug = {{ senlin_logging_debug }} + +log_dir = /var/log/senlin + +check_interval_max = {{ check_interval_max }} +default_action_timeout = {{ default_action_timeout }} + +[senlin_api] +bind_port = {{ senlin_api_port }} +bind_host = 0.0.0.0 + +[authentication] +auth_url = http://{{ management_vip }}:{{ keystone_api_port }}/v3 +service_username = senlin +service_password = {{ senlin_keystone_password }} +service_project_name = services + +[database] +connection = mysql://senlin:{{ senlin_database_password }}@{{ management_vip }}/senlin?&charset=utf8 + +[oslo_messaging_rabbit] +rabbit_hosts = 127.0.0.1:{{ rabbit_port}},{% for host in groups['controller']|difference([inventory_hostname]) %}{{ hostvars[host]['ansible_' + hostvars[host]['network_scheme']['roles']['management']|replace('-', '_')]['ipv4']['address'] }}:{{ rabbit_port }}{% if not loop.last %},{% endif %}{% endfor %} + +rabbit_userid = nova +rabbit_password = {{ rabbit.password }} + +[keystone_authtoken] +auth_uri = http://{{ management_vip }}:{{ keystone_api_port }}/v3 +identity_uri = http://{{ management_vip }}:{{ keystone_admin_port }} +auth_version = 3 +admin_user = senlin +admin_password = {{ senlin_keystone_password }} +admin_tenant_name = services + +[oslo_messaging_notifications] +driver = messaging diff --git a/ansible/site.yml b/ansible/site.yml index 04ba229..b668fea 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -18,6 +18,7 @@ gather_facts: false roles: - trove + - senlin - haproxy handlers: - name: Save iptables rules