diff --git a/roles/rabbitmq/README.md b/roles/rabbitmq/README.md new file mode 100644 index 00000000..6e9ca139 --- /dev/null +++ b/roles/rabbitmq/README.md @@ -0,0 +1,72 @@ +Ansible Role: stackstorm.rabbitmq +================================= + +Installs RabbitMQ. If `rmq_users` is defined, then the guest user is removed, and the provided users are added. + +Requirements +------------ + +No additional requirements. + +Role Variables +-------------- + +These default variables can be set in the inventory's group or host vars, or pass them in as vars in the playbook that +uses this role. An example of passing in some of these vars is shown in an example playbook below. + +* `rabbitmq_plugins`: A list of plugins to install (none by default: `[]`) +* `rabbitmq_vhosts`: A list of vhosts to add (make sure to include all vhosts included in `permissions` of `rabbitmq_users`. (default: `[]`) +* `rabbitmq_absent_vhosts`: A list of vhosts to remove. (default: `[]`) +* `rabbitmq_keep_guest_user`: Whether to keep or delete the guest user (default: `yes`) +* `rabbitmq_users`: A list of users to add (default: `[]`) +* `rabbitmq_absent_users`: A list of users to remove (default: `[]`) +* `rabbitmq_force_user_recreate`: Boolean to force user recreation. This is best set from extra-vars on the command line. + +If you delete the guest (with `rabbitmq_keep_guest_user: no`), then make sure to specify at least one other user in `rabbitmq_users`. Note, you don't need to add the guest user to the `rabbitmq_absent_users` list, just set the `rabbitmq_keep_guest_user` bool to no. + +Dependencies +------------ + +No role dependencies. + +Example Playbook +---------------- + +This playbook installs rabbitmq without adding any users (leaving the default guest user): + + - hosts: localhost + roles: + - role: StackStorm.stackstorm/roles/rabbitmq + + +This playbook installs rabbitmq, removes the guest user, and adds a stackstorm user: + + - hosts: localhost + roles: + - role: StackStorm.stackstorm/roles/mongodb + vars: + rmq_users: + - username: st2rmq + password: stackstorm + tags: policymaker + permissions: + - vhost: 'st2' + configure_priv: .* + read_priv: .* + write_priv: .* + +Note that tags can be zero, one, or more (comma separated) of these: management,policymaker,monitoring,administrator + +WARNING: vhost should not have a leading / or you'd have to remember to encode it in the uri. + +| vhost | URI | +|------------|-------------------------------------------| +| `/myvhost` | `amqp://user:pass@rabbit:5672/%2Fmyvhost` | +| `myvhost` | `amqp://user:pass@rabbit:5672/myvhost` | +| `/` | `amqp://user:pass@rabbit:5672/` | + +License +------- + +Apache 2.0 + diff --git a/roles/rabbitmq/defaults/main.yml b/roles/rabbitmq/defaults/main.yml index ea303445..22ce7fe3 100644 --- a/roles/rabbitmq/defaults/main.yml +++ b/roles/rabbitmq/defaults/main.yml @@ -3,3 +3,29 @@ rabbitmq_plugins: [] # To enable the management plugin (in which case you'd want at least one user tagged with administrator): #rabbitmq_plugins: # - rabbitmq_management + +# Make sure to include an entry for every vhost listed in rabbitmq_users.*.permissions +rabbitmq_vhosts: [] +# - st2 +rabbitmq_absent_vhosts: [] + +# other roles can change the default while allowing the end user to still override the value. +rabbitmq_keep_guest_user_default: yes +rabbitmq_keep_guest_user: "{{ rabbitmq_keep_guest_user_default }}" + +rabbitmq_users: [] +# - user: st2rmq +# password: stackstorm + # tags can be zero, one, or more of (comma separated): management,policymaker,monitoring,administrator +# tags: policymaker +# permissions: +# - vhost: 'st2' +# configure_priv: .* +# read_priv: .* +# write_priv: .* + +# Users (other than guest) that should not be present +rabbitmq_absent_users: [] + +# Set this (probably via extra-vars) to force user recreation +#rabbitmq_force_user_recreate: yes \ No newline at end of file diff --git a/roles/rabbitmq/tasks/main.yml b/roles/rabbitmq/tasks/main.yml index e79d80ed..50050860 100644 --- a/roles/rabbitmq/tasks/main.yml +++ b/roles/rabbitmq/tasks/main.yml @@ -31,3 +31,11 @@ prefix: "{{ rabbitmq_on_el6 | ternary(rabbitmq_el6_prefix, omit) }}" when: rabbitmq_plugins tags: rabbitmq + +- name: Add/Remove RabbitMQ vhosts + when: rabbitmq_vhosts or rabbitmq_absent_vhosts + include: rabbitmq_vhosts.yml + +- name: Add/Remove RabbitMQ users + when: rabbitmq_users or rabbitmq_absent_users + include: rabbitmq_users.yml diff --git a/roles/rabbitmq/tasks/rabbitmq_users.yml b/roles/rabbitmq/tasks/rabbitmq_users.yml new file mode 100644 index 00000000..67e89346 --- /dev/null +++ b/roles/rabbitmq/tasks/rabbitmq_users.yml @@ -0,0 +1,38 @@ +--- +- name: Make sure rabbitmq user options are specified correctly + assert: + that: (rabbitmq_keep_guest_user and 'guest' not in rabbitmq_absent_users) or rabbitmq_users|length > 0 + msg: "If the guest user is deleted, at least one other user needs to be added." + tags: rabbitmq + +- name: Remove the guest user from RabbitMQ + become: yes + rabbitmq_user: + user: guest + state: absent + when: not rabbitmq_keep_guest_user + tags: rabbitmq + +- name: Remove other users from RabbitMQ + become: yes + rabbitmq_user: + user: "{{ _rmq_user }}" + state: absent + with_items: "{{ rabbitmq_absent_users }}" + tags: rabbitmq + +- name: Add RabbitMQ Users + become: yes + rabbitmq_user: + force: "{{ rabbitmq_force_user_recreate|default(omit) }}" + # NOTE: This does not handle erlang nodes other than "rabbit" (when is that even used?) + user: "{{ _rmq_user.user }}" + password: "{{ _rmq_user.password }}" + permissions: "{{ _rmq_user.permissions }}" + tags: "{{ _rmq_user.tags | default(omit) }}" + state: present + loop_control: + loop_var: _rmq_user + label: "{{ _rmq_user.user }}" + with_items: "{{ rabbitmq_users }}" + tags: rabbitmq diff --git a/roles/rabbitmq/tasks/rabbitmq_vhosts.yml b/roles/rabbitmq/tasks/rabbitmq_vhosts.yml new file mode 100644 index 00000000..3619adb3 --- /dev/null +++ b/roles/rabbitmq/tasks/rabbitmq_vhosts.yml @@ -0,0 +1,20 @@ +--- +- name: Remove RabbitMQ vhosts + become: yes + rabbitmq_vhost: + vhost: "{{ _rmq_vhost }}" + state: absent + loop_control: + loop_var: _rmq_vhost + with_items: "{{ rabbitmq_absent_vhosts }}" + tags: rabbitmq + +- name: Add RabbitMQ vhosts + become: yes + rabbitmq_vhost: + vhost: "{{ _rmq_vhost }}" + state: present + loop_control: + loop_var: _rmq_vhost + with_items: "{{ rabbitmq_vhosts }}" + tags: rabbitmq diff --git a/roles/st2/meta/main.yml b/roles/st2/meta/main.yml index 0e8027a7..a9ac0266 100644 --- a/roles/st2/meta/main.yml +++ b/roles/st2/meta/main.yml @@ -4,7 +4,8 @@ galaxy_info: author: armab company: StackStorm license: Apache 2.0 - min_ansible_version: 2.2 + # urlsplit filter in 2.4 used for rabbitmq vhost/user creation + min_ansible_version: 2.4 platforms: - name: Ubuntu versions: diff --git a/roles/st2/tasks/main.yml b/roles/st2/tasks/main.yml index 813c8057..cbef8979 100644 --- a/roles/st2/tasks/main.yml +++ b/roles/st2/tasks/main.yml @@ -68,6 +68,36 @@ when: (st2_config.auth|default({})).enable|default(st2_auth_enable) tags: st2, auth +# If rabbitmq is not running on localhost, then the vhost & user tasks need to be delegated to the appropriate host. +# That is out of scope for this role, and should be handled by the playbook user. +- name: Configure RabbitMQ vhost for st2 + when: '"messaging" in st2_config and "url" in st2_config.messaging and (st2_config.messaging.url | urlsplit("hostname") in ["127.0.0.1", "localhost"])' + include_role: + name: rabbitmq + tasks_from: rabbitmq_vhosts + vars: + rabbitmq_vhosts: + # vhost is either '/' or the encoded version of everything after the '/' + # an empty string != '/' which would need to be encoded as %2F + - '{{ (st2_config.messaging.url | urlsplit("path"))[1:] }}' # [1:] = do not include initial / + - '/' + +- name: Configure RabbitMQ user for st2 + when: '"messaging" in st2_config and "url" in st2_config.messaging and (st2_config.messaging.url | urlsplit("hostname") in ["127.0.0.1", "localhost"])' + include_role: + name: rabbitmq + tasks_from: rabbitmq_users + vars: + rabbitmq_keep_guest_user_default: '{{ st2_config.messaging.url | urlsplit("username") == "guest" }}' + rabbitmq_users: + - user: '{{ st2_config.messaging.url | urlsplit("username") }}' + password: '{{ st2_config.messaging.url | urlsplit("password") }}' + permissions: + - vhost: '{{ (st2_config.messaging.url | urlsplit("path"))[1:] | default("/", true) }}' + configure_priv: .* + read_priv: .* + write_priv: .* + - name: Configure StackStorm st2.conf settings # Ansible nested loop to iterate through a hash of hashes include: config.yml _conf_section_name={{ _conf_section.key }} _conf_options={{ _conf_section.value }}