Browse Source

Merge branch 'ubuntu'

cmacrae 9 years ago
parent
commit
7de221bd23

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 site
+tests/.vagrant

+ 95 - 48
README.md

@@ -1,4 +1,4 @@
-# Sensu [![Ansible Galaxy](https://img.shields.io/badge/galaxy-cmacrae.sensu-660198.svg?style=flat)](https://galaxy.ansible.com/list#/roles/3802)
+# Sensu [![Ansible Galaxy](https://img.shields.io/badge/galaxy-cmacrae.sensu-660198.svg?style=flat)](https://galaxy.ansible.com/cmacrae/sensu/)
 
 [![Join the chat at https://gitter.im/cmacrae/ansible-sensu](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cmacrae/ansible-sensu?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
@@ -7,6 +7,7 @@ This role deploys a full [Sensu](https://sensuapp.org) stack, a modern, open sou
 ## Features
 - Deploy a full [Sensu](https://sensuapp.org) stack, including RabbitMQ, Redis, and the [Uchiwa dashboard](https://uchiwa.io/#/)
 - Tight integration with the Ansible inventory - deployment of monitoring checks based on role defined in your inventory
+- Fine grained control over dynamic client configurations
 - Automatic generation and dynamic deployment of SSL certs for secure communication between your clients and servers
 - Highly configurable
 
@@ -22,73 +23,119 @@ So... watch this space!
 [Read the full documentation](http://rtfm.cmacr.ae/) for a comprehensive overview of this role and its powerful features.
 
 ## Supported Platforms
-In this initial release [SmartOS](https://smartos.org) will be the only supported platform.
-However, I am dedicating a lot of time to this role and will be adding support for all major BSD & Linux platforms.
-
 ### Current Release
-- [SmartOS - base-64 15.1.0](https://docs.joyent.com/images/smartos/base#base-15.1.0)
+- [SmartOS - base-64 15.x.x](https://docs.joyent.com/images/smartos/base#version-15xx)
+- [Ubuntu - 15.04 (Vivid Vervet)](http://releases.ubuntu.com/15.04/)
 
 ### Future Releases
 - OpenBSD
 - FreeBSD
 - NetBSD
-- EL
-- Ubuntu / Debian
+- EL (RHEL/CentOS)
+- Debian
 
 ## Role Variables
 All variables have sensible defaults, which can be found in `defaults/main.yml`.
 The current version includes the following variables:
 
-### RabbitMQ Server Properties - [Sensu RabbitMQ documentation](https://sensuapp.org/docs/0.18/rabbitmq)
+## Defaults
+
+### [RabbitMQ Server Properties](https://sensuapp.org/docs/0.21/rabbitmq)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `rabbitmq_config_path` | `/etc/rabbitmq` | Path to the RabbitMQ configuration directory |
+| `rabbitmq_config_template` | `rabbitmq.config.j2` | The template to use for the RabbitMQ service configuration |
+|` rabbitmq_host` | `"{{ groups\['rabbitmq_servers']\[0] }}"` | The hostname/IP address of the RabbitMQ node |
+| `rabbitmq_port` | 5671 | The transmission port for RabbitMQ communications |
+| `rabbitmq_pkg_state` | present | The state of the RabbitMQ package (should be set to `present` or `latest`) |
+| `rabbitmq_server` | `false` | Determines whether to include the deployment of RabbitMQ |
+| `rabbitmq_service_name` | rabbitmq-server | The name of the RabbitMQ service |
+| `rabbitmq_sensu_user_name` | sensu | Username for authentication with the RabbitMQ vhost |
+| `rabbitmq_sensu_password` | sensu | Password for authentication with the RabbitMQ vhost |
+| `rabbitmq_sensu_vhost` | `/sensu` | Name of the RabbitMQ Sensu vhost |
+
+### [Redis Server Properties](https://sensuapp.org/docs/0.21/redis)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `redis_host` | `"{{ groups['redis_servers'][0] }}"` | Hostname/IP address of the Redis node |
+| `redis_server` | `false` | Determines whether to include the deployment of Redis |
+| `redis_pkg_repo` | _undefined_ |  The PPA to use for installing Redis from (specific to Debian flavored systems) |
+| `redis_pkg_state` | present | The state of the Redis package (should be set to `present` or `latest`) |
+| `redis_port` | 6379 | The transmission port for Redis communications |
+
+### [Sensu Properties](https://sensuapp.org/docs/0.21/install-sensu)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `sensu_api_host` | `"{{ groups['sensu_masters'][0] }}"` | Hostname/IP address of the node running the Sensu API |
+| `sensu_api_port` | 4567 | Transmission port for Sensu API communications |
+| `sensu_api_ssl` | "false" | Determines whether to use SSL for Sensu API communications |
+| `sensu_api_user_name` | admin | Username for authentication with the Sensu API |
+| `sensu_api_password` | secret | Password for authentication with the Sensu API |
+| `sensu_api_uchiwa_path` | `''` | Path to append to the Sensu API URI for Uchiwa communications |
+| `sensu_api_timeout` | 5000 | Value to set for the Sensu API timeout |
+| `sensu_client_config` | `client.json.j2` | Jinja2 template to use for node configuration of the Sensu Client service |
+| `sensu_config_path` | `/etc/sensu` | Path to the Sensu configuration directory |
+| `sensu_gem_state` | present | State of the Sensu gem - can be set to `latest` to keep Sensu updated |
+| `sensu_plugin_gem_state` | present | State of the Sensu Plugins gem - can be set to `latest` to keep Sensu Plugins updated |
+| `sensu_group_name` | sensu | The name of the Sensu service user's primary group |
+| `sensu_include_plugins` | `true` | Determines whether to include the `sensu-plugins` gem |
+| `sensu_include_dashboard` | `false` | Determines whether to deploy the Uchiwa dashboard |
+| `sensu_master` | `false` | Determines if a node is to act as the Sensu "master" node |
+| `sensu_user_name`| sensu | The name of the Sensu service user |
+
+### Sensu/RabbitMQ SSL certificate properties
+``` yaml
+sensu_ssl_gen_certs: true
+sensu_ssl_client_cert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/client/cert.pem"
+sensu_ssl_client_key: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/client/key.pem"
+sensu_ssl_server_cacert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/sensu_ca/cacert.pem"
+sensu_ssl_server_cert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server/cert.pem"
+sensu_ssl_server_key: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server/key.pem"
+```
+
+### [Uchiwa Properties](http://docs.uchiwa.io/en/latest/)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| rabbitmq\_config\_path| /opt/local/etc/rabbitmq | Path to the RabbitMQ configuration directory |
-| rabbitmq\_host| "{{ groups\['rabbitmq\_servers']\[0] }}" | The hostname/IP address of the RabbitMQ node |
-| rabbitmq\_port| 5671 | The transmission port for RabbitMQ communications |
-| rabbitmq\_server| false | Determines whether to include the deployment of RabbitMQ |
-| rabbitmq\_sensu\_user\_name| sensu | Username for authentication with the RabbitMQ vhost |
-| rabbitmq\_sensu\_password| sensu | Password for authentication with the RabbitMQ vhost |
-| rabbitmq\_sensu\_vhost| /sensu | Name of the RabbitMQ Sensu vhost |
-
-### Redis Server Properties - [Sensu Redis documentation](https://sensuapp.org/docs/0.18/redis)
+| `uchiwa_dc_name` | _undefined_ | Datacenter name for Uchiwa instance |
+| `uchiwa_path` | `/opt/uchiwa` | Path to the Uchiwa configuration directory |
+| `uchiwa_redis_use_ssl` | `false` | Determines whether to use SSL for Redis communication |
+| `uchiwa_user_name`| admin | The user-name to log into Uchiwa |
+| `uchiwa_password` | admin | The password to log into Uchiwa |
+| `uchiwa_port` | 3000 | The TCP port to bind the Uchiwa web service to |
+| `uchiwa_refresh` | 5 | The interval to pull the Sensu APIs in seconds |
+| `uchiwa_pkg_download_sha256sum` | _undefined_ | The SHA256 hash sum to use for verification of the Uchiwa package being fetched (specific to Linux systems) |
+| `uchiwa_pkg_download_path` | _undefined_ | The path to fetch the Uchiwa package to (specific to Linux systems) |
+| `uchiwa_pkg_version` | _undefined_ | The version of the Uchiwa package to fetch (specific to Linux systems) |
+| `uchiwa_pkg_download_url` | _undefined_ | The URL of the Uchiwa package to fetch (specific to Linux systems) |
+
+## Ubuntu
+### [Redis Server Properties](https://sensuapp.org/docs/0.21/redis)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| redis\_host| "{{ groups['redis_servers'][0] }}" | Hostname/IP address of the Redis node |
-| redis\_server| false | Determines whether to include the deployment of Redis |
-| redis_port| 6379 | The transmission port for Redis communications |
+| `redis_pkg_repo`   | `'ppa:rwky/redis'` | The PPA to use for installing Redis from |
 
-### Sensu Properties - [Sensu services documentation](https://sensuapp.org/docs/0.18/install-sensu)
+
+### [Sensu Properties](https://sensuapp.org/docs/0.21/install-sensu)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `sensu_user_name`    | root        | The name of the Sensu service user |
+| `sensu_group_name`   | root        | The name of the Sensu service user's primary group |
+| `uchiwa_pkg_download_sha256sum` | _See `vars/Ubuntu.yml`_ | The SHA256 hash sum to use for verification of the Uchiwa package being fetched |
+| `uchiwa_pkg_download_path` | `/root/uchiwa_latest.deb` | The path to fetch the Uchiwa package to |
+| `uchiwa_pkg_version` | _See `vars/Ubuntu.yml`_ | The version of the Uchiwa package to fetch (specific to Linux systems) |
+| `uchiwa_pkg_download_url`  | _See `vars/Ubuntu.yml`_ | The URL of the Uchiwa package to fetch |
+
+## SmartOS
+### [RabbitMQ Server Properties](https://sensuapp.org/docs/0.21/rabbitmq)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| sensu\_api\_host| "{{ groups['sensu_masters'][0] }}" | Hostname/IP address of the node running the Sensu API |
-| sensu\_api\_port| 4567 | Transmission port for Sensu API communications |
-| sensu\_api\_ssl| "false" | Determines whether to use SSL for Sensu API communications |
-| sensu\_api\_user\_name| admin | Username for authentication with the Sensu API |
-| sensu\_api\_password| secret | Password for authentication with the Sensu API |
-| sensu\_api\_uchiwa\_path| '' | Path to append to the Sensu API URI for Uchiwa communications |
-| sensu\_api\_timeout| 5000 | Value to set for the Sensu API timeout |
-| sensu\_client\_config| client.json.j2 | Jinja2 template to use for node configuration of the Sensu Client service |
-| sensu\_config\_path| /opt/local/etc/sensu | Path to the Sensu configuration directory |
-| sensu\_gem\_state| present | State of the Sensu gem - can be set to `latest` to keep Sensu updated |
-| sensu\_plugin\_gem\_state| present | State of the Sensu Plugins gem - can be set to `latest` to keep Sensu Plugins updated |
-| sensu\_group\_name| sensu | The name of the Sensu service user's primary group |
-| sensu\_include\_plugins| true | Determines whether to include the `sensu-plugins` gem |
-| sensu\_include\_dashboard| false | Determines whether to deploy the Uchiwa dashboard |
-| sensu\_master| false | Determines if a node is to act as the Sensu "master" node |
-| sensu\_user\_name| sensu | The name of the Sensu service user |
-
-### Uchiwa Properties - [Uchiwa documentation](http://docs.uchiwa.io/en/latest/)
+| `rabbitmq_config_path` | `/opt/local/etc/rabbitmq` | Path to the RabbitMQ configuration directory |
+| `rabbitmq_service_name` | rabbitmq | The name of the RabbitMQ service |
+
+### [Sensu Properties](https://sensuapp.org/docs/0.21/install-sensu)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| uchiwa\_dc\_name| _undefined_ | Datacenter name for Uchiwa instance |
-| uchiwa\_path| /opt/uchiwa | Path to the Uchiwa configuration directory |
-| uchiwa\_redis\_use\_ssl| false | Determines whether to use SSL for Redis communication |
-| uchiwa\_user\_name| admin | The user-name to log into Uchiwa |
-| uchiwa\_password| admin | The password to log into Uchiwa |
-| uchiwa\_port| 3000 | The TCP port to bind the Uchiwa web service to |
-| uchiwa\_refresh| 5 | The interval to pull the Sensu APIs in seconds |
-
-_Note_: _A few of these defaults will be moving to_`vars`_in the near future due to the addition of other OS support_
+| `sensu_config_path` | `/opt/local/etc/sensu` | Path to the Sensu configuration directory |
 
 ## Example Playbook
 

+ 20 - 2
defaults/main.yml

@@ -1,10 +1,13 @@
 ---
 
 # RabbitMQ server properties
-rabbitmq_config_path: /opt/local/etc/rabbitmq
+rabbitmq_config_path: /etc/rabbitmq
+rabbitmq_config_template: rabbitmq.config.j2
 rabbitmq_host: "{{ groups['rabbitmq_servers'][0] }}"
 rabbitmq_port: 5671
+rabbitmq_pkg_state: present
 rabbitmq_server: false
+rabbitmq_service_name: rabbitmq-server
 rabbitmq_sensu_user_name: sensu
 rabbitmq_sensu_password: sensu
 rabbitmq_sensu_vhost: /sensu
@@ -12,6 +15,8 @@ rabbitmq_sensu_vhost: /sensu
 # Redis server properties
 redis_host: "{{ groups['redis_servers'][0] }}"
 redis_server: false
+redis_pkg_repo: ~
+redis_pkg_state: present
 redis_port: 6379
 
 # Sensu/Uchiwa user/group/service properties
@@ -23,7 +28,8 @@ sensu_api_password: secret
 sensu_api_uchiwa_path: ''
 sensu_api_timeout: 5000
 sensu_client_config: client.json.j2
-sensu_config_path: /opt/local/etc/sensu
+sensu_config_path: /etc/sensu
+sensu_pkg_state: present
 sensu_gem_state: present
 sensu_plugin_gem_state: present
 sensu_group_name: sensu
@@ -32,6 +38,14 @@ sensu_include_dashboard: false
 sensu_master: false
 sensu_user_name: sensu
 
+# Sensu/RabbitMQ SSL certificate properties
+sensu_ssl_gen_certs: true
+sensu_ssl_client_cert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/client/cert.pem"
+sensu_ssl_client_key: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/client/key.pem"
+sensu_ssl_server_cacert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/sensu_ca/cacert.pem"
+sensu_ssl_server_cert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server/cert.pem"
+sensu_ssl_server_key: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server/key.pem"
+  
 # Uchiwa properties
 uchiwa_dc_name: ~
 uchiwa_path: /opt/uchiwa
@@ -40,3 +54,7 @@ uchiwa_user_name: admin
 uchiwa_password: admin
 uchiwa_port: 3000
 uchiwa_refresh: 5
+uchiwa_pkg_download_sha256sum: ~
+uchiwa_pkg_download_path: ~
+uchiwa_pkg_version: ~
+uchiwa_pkg_download_url: ~

+ 9 - 12
docs/afewwords.md

@@ -1,7 +1,7 @@
 # A few words from the author
 Well, thanks for bothering to even visit this page!
 
-This role was born out of my own passion for the absolutely excellent projects that it uses.
+This role was born out of my own passion for the absolutely excellent projects that it uses.  
 I figure I have to list them, in no particular order, here they are. __Make sure to check them all out!__
 
 - [Ansible](http://ansible.com/home)
@@ -12,26 +12,23 @@ I figure I have to list them, in no particular order, here they are. __Make sure
 - [Redis](http://redis.io/)
 
 ## What about support for other operating systems?
-It's planned! I've done development for this role entirely on [SmartOS](https://smartos.org/).
-It makes development fast, easy, and cheap! Just a few reasons it really is the perfect operating system ;)
-
-I've already started support for OpenBSD, other BSDs and some Linuxes will follow, notably:
+It's planned!
 
+Coming in the near future:
+- OpenBSD
 - FreeBSD
 - NetBSD
 - EL
-- Ubuntu/Debian
+- Debian
 
 I'd be happy to add any others to the list if high demand shows.
 
 ## About updates
-This is a personal project of mine that I work on in my own free time.
-Most of the real "meat" is there, I just need to restructure and implement conditional includes based on facts.
-
-That said, I'm a busy man! And when I do get time, all development takes place on [a little HP microserver](http://drentheweer.nl/img/hpn54l.png)... which, when straying from [Zones](https://wiki.smartos.org/display/DOC/Zones), can get a little sluggish.
+This is a personal project of mine that I work on in my own free time.  
+Most of the real "meat" is there, I just need to restructure and implement conditional includes based on facts.  
 
-So please, [bear with me](http://i.imgur.com/bGhY7oX.jpg). I'll happily accept any contributions, both in [additions to the code](https://github.com/cmacrae/ansible-sensu/pulls), and any [bug reports](https://github.com/cmacrae/ansible-sensu/issues) :)
+That said, I'm a busy man! So please, [bear with me](http://i.imgur.com/bGhY7oX.jpg). I'll happily accept any contributions, both in [additions to the code](https://github.com/cmacrae/ansible-sensu/pulls), and any [bug reports](https://github.com/cmacrae/ansible-sensu/issues) :)  
 
 ## If you like it
-Share it! Get it out there; link it all over the place!
+Share it! Get it out there; link it all over the place!  
 It's not just about awesome deployment, it's about exposing people to excellent open source software!

+ 25 - 15
docs/deploy_plugins.md

@@ -63,33 +63,43 @@ Finally, we have the actual handler script [`pushover.rb`](https://github.com/se
 
 
 These are all deployed when the role runs through the `tasks/plugins.yml` playbook, in particular these plays:
-```
+``` yaml
   - name: Deploy handler plugins
-    copy: src={{ static_data_store }}/sensu/handlers/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/handlers/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     notify: restart sensu-client service
 
   - name: Deploy filter plugins
-    copy: src={{ static_data_store }}/sensu/filters/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/filters/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     notify: restart sensu-client service
 
   - name: Deploy mutator plugins
-    copy: src={{ static_data_store }}/sensu/mutators/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/mutators/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     notify: restart sensu-client service
 
   - name: Deploy check/handler/filter/mutator definitions to the master
-    template: src={{ static_data_store }}/sensu/definitions/{{ item }}.j2
-          dest={{ sensu_config_path }}/conf.d/{{ item }}
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    template:
+      src: "{{ static_data_store }}/sensu/definitions/{{ item }}.j2"
+      dest: "{{ sensu_config_path }}/conf.d/{{ item }}"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     when: sensu_master
     with_lines:
-      - ls {{ static_data_store }}/sensu/definitions | cut -d. --fields=1,2
+      - ls {{ static_data_store }}/sensu/definitions | sed 's/\.j2//'
     notify: restart sensu-api service
-
 ```
 Quite straight forward and repetitive. If you skim this code, it may become clear that failures could be introduced if the source directories don't exist within your static data store. That's correct. You may have noticed that the example output `tree` shows both the `filters` & `mutators` directories are empty. It's expected that such features will be used, but if you don't wish to use filters or mutators, you still need to ensure these directories exist.

+ 7 - 4
docs/dynamic_checks.md

@@ -78,12 +78,15 @@ With this pair of plays, in the `tasks/plugins.yml` playbook:
   - name: Register available checks
     local_action: command ls {{ static_data_store }}/sensu/checks
     register: sensu_available_checks
-    changed_when: False
+    changed_when: false
 
   - name: Deploy check plugins
-    copy: src={{ static_data_store }}/sensu/checks/{{ item }}/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/checks/{{ item }}/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     when: sensu_available_checks.stdout.find('{{ item }}') != -1
     with_flattened:
       - group_names

+ 17 - 13
docs/dynamic_data.md

@@ -51,30 +51,34 @@ data/dynamic/
 As you can see, it resembles the file tree from the node it fetched the data from. This is configurable behavior, and can be set otherwise if you find this inconvenient/unsightly. See [ the `fetch` documentation](http://docs.ansible.com/fetch_module.html) for more information.
 
 ## Deployment of the data fetched to the dynamic data store
-Next up is this rather unsightly play (still from the `tasks/ssl.yml` playbook):
+Next up is this nifty little play (still from the `tasks/ssl.yml` playbook):
 ``` yaml
   - name: Deploy the Sensu client SSL cert/key
-    copy: src={{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/ssl_certs/client/{{ item }}
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-          dest={{ sensu_config_path }}/ssl
+    copy:
+      src: "{{ item }}"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      dest: "{{ sensu_config_path }}/ssl"
     with_items:
-      - cert.pem
-      - key.pem
-
+      - "{{ sensu_ssl_client_cert }}"
+      - "{{ sensu_ssl_client_key }}"
+    notify: restart sensu-client service
 ```
-Blegh! Pretty ugly, right? Well, it may not be so great looking, but it's pretty nifty.
 It takes care of distributing the SSL certificates to the client systems so they can interact with the Sensu API.
 
 The same method is used for node communication with RabbitMQ:
 `tasks/rabbitmq.yml`
 ``` yaml
   - name: Ensure RabbitMQ SSL certs/keys are in place
-    copy: src={{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/ssl_certs/{{ item }}
-          dest={{ rabbitmq_config_path }}/ssl
+    copy: src={{ item }} dest={{ rabbitmq_config_path }}/ssl
     with_items:
-      - sensu_ca/cacert.pem
-      - server/cert.pem
-      - server/key.pem
+      - "{{ sensu_ssl_server_cacert }}"
+      - "{{ sensu_ssl_server_cert }}"
+      - "{{ sensu_ssl_server_key }}"
+    notify:
+      - restart rabbitmq service
+      - restart sensu-api service
+      - restart sensu-server service
 ```
 
 ## So, what do I need to do?

+ 6 - 1
docs/example_infra.md

@@ -57,8 +57,13 @@ You can see I decided I want the Uchiwa dashboard to be deployed also, so I set
 The above code could also be set straight in the node's `host_vars` file: `host_vars/sensu.cmacr.ae.yml` or set straight in a playbook intended just for the `sensu_masters` node:
 ``` yaml
   - hosts: sensu_masters
+
+    vars:
+	  sensu_master: true
+	  sensu_include_dashboard: true
+
     roles:
-	  - { role: cmacrae.sensu, sensu_master: true, sensu_include_dashboard: true  }
+	  - cmacrae.sensu
 ```
 
 ### RabbitMQ/Redis variables

+ 5 - 7
docs/index.md

@@ -1,4 +1,4 @@
-# Ansible Sensu [![Ansible Galaxy](https://img.shields.io/badge/galaxy-cmacrae.sensu-660198.svg?style=flat)](https://galaxy.ansible.com/list#/roles/3802)
+# Ansible Sensu [![Ansible Galaxy](https://img.shields.io/badge/galaxy-cmacrae.sensu-660198.svg?style=flat)](https://galaxy.ansible.com/cmacrae/sensu/)
 An [Ansible](https://ansible.com) role that deploys a full [Sensu](https://sensuapp.org) stack, a modern, open source monitoring framework.
 
 [![Join the chat at https://gitter.im/cmacrae/ansible-sensu](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cmacrae/ansible-sensu?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -11,18 +11,16 @@ An [Ansible](https://ansible.com) role that deploys a full [Sensu](https://sensu
 - Highly configurable
 
 ## Supported Platforms
-In this initial release [SmartOS](https://smartos.org) will be the only supported platform.
-However, I am dedicating a lot of time to this role and will be adding support for all major BSD & Linux platforms.
-
 ### Current Release
-- [SmartOS - base-64 15.1.0](https://docs.joyent.com/images/smartos/base#base-15.1.0)
+- [SmartOS - base-64 15.x.x](https://docs.joyent.com/images/smartos/base#version-15xx)
+- [Ubuntu - 15.04 (Vivid Vervet)](http://releases.ubuntu.com/15.04/)
 
 ### Future Releases
 - OpenBSD
 - FreeBSD
 - NetBSD
-- EL
-- Ubuntu / Debian
+- EL (RHEL/CentOS)
+- Debian
 
 ## Role Variables
 All variables have sensible defaults, which can be found in `defaults/main.yml`.  

+ 85 - 38
docs/role_variables.md

@@ -1,52 +1,99 @@
 # Role Variables
+## Defaults
 
-### RabbitMQ Server Properties - [Sensu RabbitMQ documentation](https://sensuapp.org/docs/0.18/rabbitmq)
+### [RabbitMQ Server Properties](https://sensuapp.org/docs/0.21/rabbitmq)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| rabbitmq\_config\_path| /opt/local/etc/rabbitmq | Path to the RabbitMQ configuration directory |
-| rabbitmq\_host| "{{ groups\['rabbitmq\_servers']\[0] }}" | The hostname/IP address of the RabbitMQ node |
-| rabbitmq\_port| 5671 | The transmission port for RabbitMQ communications |
-| rabbitmq\_server| false | Determines whether to include the deployment of RabbitMQ |
-| rabbitmq\_sensu\_user\_name| sensu | Username for authentication with the RabbitMQ vhost |
-| rabbitmq\_sensu\_password| sensu | Password for authentication with the RabbitMQ vhost |
-| rabbitmq\_sensu\_vhost| /sensu | Name of the RabbitMQ Sensu vhost |
+| `rabbitmq_config_path` | `/etc/rabbitmq` | Path to the RabbitMQ configuration directory |
+| `rabbitmq_config_template` | `rabbitmq.config.j2` | The template to use for the RabbitMQ service configuration |
+|` rabbitmq_host` | `"{{ groups\['rabbitmq_servers']\[0] }}"` | The hostname/IP address of the RabbitMQ node |
+| `rabbitmq_port` | 5671 | The transmission port for RabbitMQ communications |
+| `rabbitmq_pkg_state` | present | The state of the RabbitMQ package (should be set to `present` or `latest`) |
+| `rabbitmq_server` | `false` | Determines whether to include the deployment of RabbitMQ |
+| `rabbitmq_service_name` | rabbitmq-server | The name of the RabbitMQ service |
+| `rabbitmq_sensu_user_name` | sensu | Username for authentication with the RabbitMQ vhost |
+| `rabbitmq_sensu_password` | sensu | Password for authentication with the RabbitMQ vhost |
+| `rabbitmq_sensu_vhost` | `/sensu` | Name of the RabbitMQ Sensu vhost |
 
-### Redis Server Properties - [Sensu Redis documentation](https://sensuapp.org/docs/0.18/redis)
+### [Redis Server Properties](https://sensuapp.org/docs/0.21/redis)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| redis\_host| "{{ groups['redis_servers'][0] }}" | Hostname/IP address of the Redis node |
-| redis\_server| false | Determines whether to include the deployment of Redis |
-| redis_port| 6379 | The transmission port for Redis communications |
+| `redis_host` | `"{{ groups['redis_servers'][0] }}"` | Hostname/IP address of the Redis node |
+| `redis_server` | `false` | Determines whether to include the deployment of Redis |
+| `redis_pkg_repo` | _undefined_ |  The PPA to use for installing Redis from (specific to Debian flavored systems) |
+| `redis_pkg_state` | present | The state of the Redis package (should be set to `present` or `latest`) |
+| `redis_port` | 6379 | The transmission port for Redis communications |
 
-### Sensu Properties - [Sensu services documentation](https://sensuapp.org/docs/0.18/install-sensu)
+### [Sensu Properties](https://sensuapp.org/docs/0.21/install-sensu)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| sensu\_api\_host| "{{ groups['sensu_masters'][0] }}" | Hostname/IP address of the node running the Sensu API |
-| sensu\_api\_port| 4567 | Transmission port for Sensu API communications |
-| sensu\_api\_ssl| "false" | Determines whether to use SSL for Sensu API communications |
-| sensu\_api\_user\_name| admin | Username for authentication with the Sensu API |
-| sensu\_api\_password| secret | Password for authentication with the Sensu API |
-| sensu\_api\_uchiwa\_path| '' | Path to append to the Sensu API URI for Uchiwa communications |
-| sensu\_api\_timeout| 5000 | Value to set for the Sensu API timeout |
-| sensu\_client\_config| client.json.j2 | Jinja2 template to use for node configuration of the Sensu Client service |
-| sensu\_config\_path| /opt/local/etc/sensu | Path to the Sensu configuration directory |
-| sensu\_gem\_state| present | State of the Sensu gem - can be set to `latest` to keep Sensu updated |
-| sensu\_plugin\_gem\_state| present | State of the Sensu Plugins gem - can be set to `latest` to keep Sensu Plugins updated |
-| sensu\_group\_name| sensu | The name of the Sensu service user's primary group |
-| sensu\_include\_plugins| true | Determines whether to include the `sensu-plugins` gem |
-| sensu\_include\_dashboard| false | Determines whether to deploy the Uchiwa dashboard |
-| sensu\_master| false | Determines if a node is to act as the Sensu "master" node |
-| sensu\_user\_name| sensu | The name of the Sensu service user |
+| `sensu_api_host` | `"{{ groups['sensu_masters'][0] }}"` | Hostname/IP address of the node running the Sensu API |
+| `sensu_api_port` | 4567 | Transmission port for Sensu API communications |
+| `sensu_api_ssl` | "false" | Determines whether to use SSL for Sensu API communications |
+| `sensu_api_user_name` | admin | Username for authentication with the Sensu API |
+| `sensu_api_password` | secret | Password for authentication with the Sensu API |
+| `sensu_api_uchiwa_path` | `''` | Path to append to the Sensu API URI for Uchiwa communications |
+| `sensu_api_timeout` | 5000 | Value to set for the Sensu API timeout |
+| `sensu_client_config` | `client.json.j2` | Jinja2 template to use for node configuration of the Sensu Client service |
+| `sensu_config_path` | `/etc/sensu` | Path to the Sensu configuration directory |
+| `sensu_gem_state` | present | State of the Sensu gem - can be set to `latest` to keep Sensu updated |
+| `sensu_plugin_gem_state` | present | State of the Sensu Plugins gem - can be set to `latest` to keep Sensu Plugins updated |
+| `sensu_group_name` | sensu | The name of the Sensu service user's primary group |
+| `sensu_include_plugins` | `true` | Determines whether to include the `sensu-plugins` gem |
+| `sensu_include_dashboard` | `false` | Determines whether to deploy the Uchiwa dashboard |
+| `sensu_master` | `false` | Determines if a node is to act as the Sensu "master" node |
+| `sensu_user_name`| sensu | The name of the Sensu service user |
 
-### Uchiwa Properties - [Uchiwa documentation](http://docs.uchiwa.io/en/latest/)
+### Sensu/RabbitMQ SSL certificate properties
+``` yaml
+sensu_ssl_gen_certs: true
+sensu_ssl_client_cert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/client/cert.pem"
+sensu_ssl_client_key: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/client/key.pem"
+sensu_ssl_server_cacert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/sensu_ca/cacert.pem"
+sensu_ssl_server_cert: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server/cert.pem"
+sensu_ssl_server_key: "{{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server/key.pem"
+```
+
+### [Uchiwa Properties](http://docs.uchiwa.io/en/latest/)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `uchiwa_dc_name` | _undefined_ | Datacenter name for Uchiwa instance |
+| `uchiwa_path` | `/opt/uchiwa` | Path to the Uchiwa configuration directory |
+| `uchiwa_redis_use_ssl` | `false` | Determines whether to use SSL for Redis communication |
+| `uchiwa_user_name`| admin | The user-name to log into Uchiwa |
+| `uchiwa_password` | admin | The password to log into Uchiwa |
+| `uchiwa_port` | 3000 | The TCP port to bind the Uchiwa web service to |
+| `uchiwa_refresh` | 5 | The interval to pull the Sensu APIs in seconds |
+| `uchiwa_pkg_download_sha256sum` | _undefined_ | The SHA256 hash sum to use for verification of the Uchiwa package being fetched (specific to Linux systems) |
+| `uchiwa_pkg_download_path` | _undefined_ | The path to fetch the Uchiwa package to (specific to Linux systems) |
+| `uchiwa_pkg_version` | _undefined_ | The version of the Uchiwa package to fetch (specific to Linux systems) |
+| `uchiwa_pkg_download_url` | _undefined_ | The URL of the Uchiwa package to fetch (specific to Linux systems) |
+
+## Ubuntu
+### [Redis Server Properties](https://sensuapp.org/docs/0.21/redis)
 | Name               | Default Value | Description                  |
 |--------------------|---------------|------------------------------|
-| uchiwa\_dc\_name| _undefined_ | Datacenter name for Uchiwa instance |
-| uchiwa\_path| /opt/uchiwa | Path to the Uchiwa configuration directory |
-| uchiwa\_redis\_use\_ssl| false | Determines whether to use SSL for Redis communication |
-| uchiwa\_user\_name| admin | The user-name to log into Uchiwa |
-| uchiwa\_password| admin | The password to log into Uchiwa |
-| uchiwa\_port| 3000 | The TCP port to bind the Uchiwa web service to |
-| uchiwa\_refresh| 5 | The interval to pull the Sensu APIs in seconds |
+| `redis_pkg_repo`   | `'ppa:rwky/redis'` | The PPA to use for installing Redis from |
 
-_Note_: _A few of these defaults will be moving to_`vars`_in the near future due to the addition of other OS support_
+
+### [Sensu Properties](https://sensuapp.org/docs/0.21/install-sensu)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `sensu_user_name`    | root        | The name of the Sensu service user |
+| `sensu_group_name`   | root        | The name of the Sensu service user's primary group |
+| `uchiwa_pkg_download_sha256sum` | _See `vars/Ubuntu.yml`_ | The SHA256 hash sum to use for verification of the Uchiwa package being fetched |
+| `uchiwa_pkg_download_path` | `/root/uchiwa_latest.deb` | The path to fetch the Uchiwa package to |
+| `uchiwa_pkg_version` | _See `vars/Ubuntu.yml`_ | The version of the Uchiwa package to fetch (specific to Linux systems) |
+| `uchiwa_pkg_download_url`  | _See `vars/Ubuntu.yml`_ | The URL of the Uchiwa package to fetch |
+
+## SmartOS
+### [RabbitMQ Server Properties](https://sensuapp.org/docs/0.21/rabbitmq)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `rabbitmq_config_path` | `/opt/local/etc/rabbitmq` | Path to the RabbitMQ configuration directory |
+| `rabbitmq_service_name` | rabbitmq | The name of the RabbitMQ service |
+
+### [Sensu Properties](https://sensuapp.org/docs/0.21/install-sensu)
+| Name               | Default Value | Description                  |
+|--------------------|---------------|------------------------------|
+| `sensu_config_path` | `/opt/local/etc/sensu` | Path to the Sensu configuration directory |

+ 20 - 0
docs/testing.md

@@ -0,0 +1,20 @@
+# Testing
+A small testing framework is provided with this role using [Vagrant](https://vagrantup.com/).  
+
+To test this role locally, once you've set up Vagrant, simply `cd` to `tests` and run `vagrant up`, after which you can visit the following URLs in your browser for the associated deployments:  
+- Ubuntu 15.04: `http://localhost:3000`
+
+_Note: Right now, there is only an Ubuntu 15.04 system available in the testing framework. To test SmartOS, please simply roll out a base64 zone_  
+
+To log in, use `admin` as both the username & password.  
+
+
+As support for other operating systems/distributions is written, they will be added as options for testing.
+
+## Caveats
+It is expected that the following two handlers, triggered at the end of the test run will fail:  
+- `restart sensu-server service`  
+- `restart sensu-api service`  
+
+Both these handlers use the `delegate_to` directive, which does not play nice with Vagrant.  
+This __is__ expected to work in real deployments.

+ 15 - 0
files/ubuntu_redis_systemd.service

@@ -0,0 +1,15 @@
+[Unit]
+Description=Redis Datastore Server
+After=network.target
+
+[Service]
+Type=forking
+PIDFile=/var/run/redis/redis.pid
+ExecStartPre=/bin/mkdir -p /var/run/redis
+ExecStartPre=/bin/chown redis:redis /var/run/redis
+
+ExecStart=/sbin/start-stop-daemon --start --chuid redis:redis --pidfile /var/run/redis/redis.pid --umask 007 --exec /usr/bin/redis-server -- /etc/redis/redis.conf
+ExecReload=/bin/kill -USR2 $MAINPID
+
+[Install]
+WantedBy=multi-user.target

+ 11 - 2
handlers/main.yml

@@ -1,20 +1,23 @@
 ---
 
   - name: restart rabbitmq service
-    service: name=rabbitmq state=restarted
+    service: name={{ rabbitmq_service_name }} state=restarted
   
   - name: restart uchiwa service
     service: name=uchiwa state=restarted
 
   - name: restart sensu-server service
     service: name=sensu-server state=restarted
+    delegate_to: "{{ sensu_api_host }}"
 
   - name: restart sensu-api service
     service: name=sensu-api state=restarted
+    delegate_to: "{{ sensu_api_host }}"
 
   - name: restart sensu-client service
     service: name=sensu-client state=restarted
 
+  # Joyent SmartOS specific handlers
   - name: import sensu-server service
     command: /usr/sbin/svccfg import /opt/local/lib/svc/manifest/sensu-server.xml
   
@@ -26,4 +29,10 @@
   
   - name: import uchiwa service
     command: /usr/sbin/svccfg import /opt/local/lib/svc/manifest/uchiwa.xml
-  
+
+  - name: Build and deploy Uchiwa
+    shell: npm install --production
+    args:
+      chdir: "{{ uchiwa_path }}/go/src/github.com/sensu/uchiwa"
+    become: true
+    become_user: "{{ sensu_user_name }}"

+ 44 - 44
meta/main.yml

@@ -1,22 +1,8 @@
----
 galaxy_info:
   author: Calum MacRae
-  description: Roll out a full Sensu stack, including the Uchiwa dashboard
-  #company: your company (optional)
-  # Some suggested licenses:
-  # - BSD (default)
-  # - MIT
-  # - GPLv2
-  # - GPLv3
-  # - Apache
-  # - CC-BY
+  description: Deploy a full Sensu monitoring stack; including Redis, RabbitMQ & the Uchiwa dashboard
   license: MIT
-  min_ansible_version: 1.4
-  #
-  # Below are all platforms currently available. Just uncomment
-  # the ones that apply to your role. If you don't see your 
-  # platform on this list, let us know and we'll get it added!
-  #
+  min_ansible_version: 2.0
   platforms:
   #- name: EL
   #  versions:
@@ -28,6 +14,14 @@ galaxy_info:
   #  versions:
   #  - all
   #  - any
+  #- name: Solaris
+  #  versions:
+  #  - all
+  #  - 10
+  #  - 11.0
+  #  - 11.1
+  #  - 11.2
+  #  - 11.3
   #- name: Fedora
   #  versions:
   #  - all
@@ -36,10 +30,18 @@ galaxy_info:
   #  - 18
   #  - 19
   #  - 20
-  #- name: SmartOS
+  #  - 21
+  #  - 22
+  #  - 23
+  #- name: Windows
   #  versions:
   #  - all
+  #  - 2012R2
+  - name: SmartOS
+    versions:
+  #  - all
   #  - any
+     - 15.x.x
   #- name: opensuse
   #  versions:
   #  - all
@@ -60,6 +62,9 @@ galaxy_info:
   #- name: FreeBSD
   #  versions:
   #  - all
+  #  - 10.0
+  #  - 10.1
+  #  - 10.2
   #  - 8.0
   #  - 8.1
   #  - 8.2
@@ -69,8 +74,9 @@ galaxy_info:
   #  - 9.1
   #  - 9.1
   #  - 9.2
-  #- name: Ubuntu
-  #  versions:
+  #  - 9.3
+  - name: Ubuntu
+    versions:
   #  - all
   #  - lucid
   #  - maverick
@@ -81,6 +87,9 @@ galaxy_info:
   #  - raring
   #  - saucy
   #  - trusty
+  #  - utopic
+    - vivid
+  #  - wily
   #- name: SLES
   #  versions:
   #  - all
@@ -98,34 +107,25 @@ galaxy_info:
   #  versions:
   #  - all
   #  - etch
+  #  - jessie
   #  - lenny
   #  - squeeze
   #  - wheezy
-  - name: SmartOS
-    versions:
-    - 15.1.0
-  #
-  # Below are all categories currently available. Just as with
-  # the platforms above, uncomment those that apply to your role.
-  #
-  categories:
-  - cloud
-  #- cloud:ec2
-  #- cloud:gce
-  #- cloud:rax
-  #- clustering
-  #- database
-  #- database:nosql
-  #- database:sql
-  #- development
-  - monitoring
-  #- networking
-  #- packaging
-  - system
-  - web
+  
+  galaxy_tags:
+    - cloud
+    - monitoring
+    - system
+    - web
+    - sensu
+    - rabbitmq
+    - redis
+    - metrics
+    - amqp
+    - alerting
+    - stack
+    - dashboard
 dependencies: []
-  # List your role dependencies here, one per line. Only
-  # dependencies available via galaxy should be listed here.
+  # List your role dependencies here, one per line.
   # Be sure to remove the '[]' above if you add dependencies
   # to this list.
-  

+ 1 - 0
mkdocs.yml

@@ -13,6 +13,7 @@ pages:
   - [ 'custom_client_config.md', 'Usage', 'Custom client configuration' ]
   - [ 'deploy_plugins.md', 'Usage', 'Deployment of handlers/filters/mutators' ]
   - [ 'sensitive_info.md', 'Usage', 'Sensitive information in version control' ]
+  - [ 'testing.md', 'Usage', 'Testing' ]
   - [ 'dynamic_data.md','Conventions','Dynamic data store' ]
   - [ 'dynamic_checks.md','Conventions','Dynamic check deployment' ]
   - [ 'afewwords.md','About','A few words from the author' ]

+ 18 - 0
tasks/SmartOS/client.yml

@@ -0,0 +1,18 @@
+---
+# tasks/SmartOS/client.yml: Deploy various client-side configurations for Sensu
+# Specific to Joyent SmartOS
+  
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Deploy Sensu client service manifest
+    template:
+      dest: /opt/local/lib/svc/manifest/sensu-client.xml
+      src: sensu-client.smartos_smf_manifest.xml.j2
+      owner: root
+      group: root
+      mode: 644
+    notify:
+      - import sensu-client service
+      - restart sensu-client service
+
+  - meta: flush_handlers

+ 82 - 0
tasks/SmartOS/dashboard.yml

@@ -0,0 +1,82 @@
+---
+# tasks/SmartOS/dashboard.yml: Deployment of the Uchiwa dashboard
+# Specific to Joyent SmartOS
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Ensure Uchiwa (dashboard) dependencies are installed
+    pkgin: name=go state=present
+
+  - name: Ensure Uchiwa directory exists
+    file:
+      dest: "{{ uchiwa_path }}"
+      state: directory
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      recurse: true
+
+  - name: Ensure Uchiwa Go/config directory exists
+    file:
+      dest: "{{ uchiwa_path }}/{{ item }}"
+      state: directory
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      recurse: true
+    with_items:
+      - etc
+      - go
+
+  - name: Ensure Uchiwa GOPATH exists
+    file:
+      dest: "{{ uchiwa_path }}/go/{{ item }}"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      state: directory
+      recurse: true
+    with_items:
+      - bin
+      - pkg
+      - src
+
+  - name: Fetch Uchiwa from GitHub
+    command: go get github.com/sensu/uchiwa
+    environment:
+      GOPATH: "{{ uchiwa_path }}/go"
+    args:
+      creates: "{{ uchiwa_path }}/go/src/github.com/sensu/uchiwa"
+    notify: Build and deploy Uchiwa
+    become: true
+    become_user: "{{ sensu_user_name }}"
+
+  - meta: flush_handlers
+
+  - name: Deploy Uchiwa config
+    template:
+      src: uchiwa_config.json.j2
+      dest: "{{ uchiwa_path }}/etc/config.json"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+    notify: restart uchiwa service
+
+  - name: Deploy Uchiwa service script
+    template:
+      src: uchiwa.sh.j2
+      dest: /opt/local/lib/svc/method/uchiwa
+      owner: root
+      group: root
+      mode: 0755
+    notify: restart uchiwa service
+
+  - name: Deploy Uchiwa service manifest
+    template:
+      dest: /opt/local/lib/svc/manifest/uchiwa.xml
+      src: uchiwa.smartos_smf_manifest.xml.j2
+      owner: root
+      group: root
+      mode: 644
+    notify: import uchiwa service
+
+  - meta: flush_handlers
+
+  - name: Ensure Uchiwa server service is running
+    service: name=uchiwa state=started enabled=yes

+ 36 - 0
tasks/SmartOS/main.yml

@@ -0,0 +1,36 @@
+---
+# tasks/SmartOS/main.yml: "Set-up" playbook for cmacrae.sensu role
+# This takes care of base prerequisites for Joyent SmartOS
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Ensure the Sensu group is present
+    group: name={{ sensu_group_name }} state=present
+             
+  - name: Ensure the Sensu user is present
+    user:
+      name: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      shell: /bin/false
+      home: "{{ sensu_config_path }}"
+      createhome: true
+      state: present
+
+  - name: Ensure the Sensu config directory is present
+    file:
+      dest: "{{ sensu_config_path }}/conf.d"
+      state: directory
+      recurse: true
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+
+  - name: Ensure Sensu dependencies are installed
+    pkgin: name=build-essential,ruby21-base state=present
+
+  - name: Ensure Sensu is installed
+    gem: name=sensu state={{ sensu_gem_state }} user_install=no
+    notify:
+      - restart sensu-client service
+    
+  - name: Ensure Sensu 'plugins' gem is installed
+    gem: name=sensu-plugin state={{ sensu_plugin_gem_state }} user_install=no

+ 12 - 0
tasks/SmartOS/rabbit.yml

@@ -0,0 +1,12 @@
+---
+# tasks/SmartOS/rabbit.yml: Deploy RabbitMQ
+# Specific to Joyent SmartOS
+
+  - name: Ensure RabbitMQ is installed
+    pkgin: name=rabbitmq state=present
+  
+  - name: Ensure EPMD is running
+    service:
+      name: epmd
+      state: started
+      enabled: true

+ 8 - 0
tasks/SmartOS/redis.yml

@@ -0,0 +1,8 @@
+---
+# tasks/SmartOS/redis.yml: Deploy Redis
+# Specific to Ubuntu
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Ensure Redis is installed
+    pkgin: name=redis state={{ redis_pkg_state }}

+ 26 - 0
tasks/SmartOS/server.yml

@@ -0,0 +1,26 @@
+---
+# tasks/SmartOS/server.yml: Deploy the necessary configuration for
+# a Sensu 'master' node.
+# Specific to SmartOS
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Deploy Sensu server service manifest
+    template:
+      dest: /opt/local/lib/svc/manifest/sensu-server.xml
+      src: sensu-server.smartos_smf_manifest.xml.j2
+      owner: root
+      group: root
+      mode: 644
+    notify: import sensu-server service
+
+  - name: Deploy Sensu API service manifest
+    template:
+      dest: /opt/local/lib/svc/manifest/sensu-api.xml
+      src: sensu-api.smartos_smf_manifest.xml.j2
+      owner: root
+      group: root
+      mode: 644
+    notify: import sensu-api service
+ 
+  - meta: flush_handlers

+ 20 - 0
tasks/Ubuntu/dashboard.yml

@@ -0,0 +1,20 @@
+---
+# tasks/Ubuntu/dashboard.yml: Deployment of the Uchiwa dashboard
+# Specific to Ubuntu
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Retrieve the Uchiwa deb package
+    get_url:
+      url: "{{ uchiwa_pkg_download_url }}"
+      dest: "{{ uchiwa_pkg_download_path }}"
+      sha256sum: "{{ uchiwa_pkg_download_sha256sum }}"
+
+  - name: Install Uchiwa from the retrieved deb package
+    apt: deb={{ uchiwa_pkg_download_path }} 
+
+  - name: Deploy Uchiwa config
+    template:
+      src: uchiwa_config.json.j2
+      dest: "{{ sensu_config_path }}/uchiwa.json"
+    notify: restart uchiwa service

+ 19 - 0
tasks/Ubuntu/main.yml

@@ -0,0 +1,19 @@
+---
+# tasks/Ubuntu/main.yml: Ubuntu specific set-up
+# This takes care of base prerequisites for Ubuntu
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Ensure the Sensu APT repo GPG key is present
+    apt_key:
+      url: http://repositories.sensuapp.org/apt/pubkey.gpg
+      state: present
+
+  - name: Ensure the Sensu Core APT repo is present
+    apt_repository:
+      repo: 'deb     http://repositories.sensuapp.org/apt sensu main'
+      state: present
+      update_cache: true
+
+  - name: Ensure Sensu is installed
+    apt: name=sensu state={{ sensu_pkg_state }}

+ 22 - 0
tasks/Ubuntu/rabbit.yml

@@ -0,0 +1,22 @@
+---
+# tasks/Ubuntu/rabbit.yml: Deploy RabbitMQ
+# Specific to Ubuntu
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Ensure the RabbitMQ APT repo GPG key is present
+    apt_key:
+      url: https://www.rabbitmq.com/rabbitmq-signing-key-public.asc
+      state: present
+
+  - name: Ensure the RabbitMQ APT repo is present
+    apt_repository:
+      repo: 'deb http://www.rabbitmq.com/debian/ testing main'
+      state: present
+      update_cache: true
+
+  - name: Ensure RabbitMQ is installed
+    apt:
+      name: rabbitmq-server
+      state: "{{ rabbitmq_pkg_state }}"
+      update_cache: true

+ 22 - 0
tasks/Ubuntu/redis.yml

@@ -0,0 +1,22 @@
+---
+# tasks/Ubuntu/redis.yml: Deploy Redis
+# Specific to Ubuntu
+
+  - include_vars: "{{ ansible_distribution }}.yml"
+
+  - name: Ensure the Redis APT repo is present
+    apt_repository:
+      repo: "{{ redis_pkg_repo }}"
+      state: present
+      update_cache: true
+
+  - name: Ensure Redis is installed
+    apt:
+      name: redis-server
+      state: "{{ redis_pkg_state }}"
+      update_cache: true
+
+  - name: Deploy Redis systemd service manifest
+    copy:
+      src: ubuntu_redis_systemd.service
+      dest: /etc/systemd/system/redis.service

+ 25 - 16
tasks/client.yml

@@ -1,27 +1,36 @@
 ---
+# tasks/client.yml: Deploy various client-side configurations for Sensu
+  
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
+
+  - name: Ensure the Sensu config directory is present
+    file:
+      dest: "{{ sensu_config_path }}/conf.d"
+      state: directory
+      recurse: true
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
 
   - name: Deploy Sensu client RabbitMQ configuration
-    template: dest="{{ sensu_config_path }}/conf.d/rabbitmq.json"
-              owner={{ sensu_user_name }} group={{ sensu_group_name }}
-              src=rabbitmq.json.j2
+    template:
+      dest: "{{ sensu_config_path }}/conf.d/rabbitmq.json"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      src: rabbitmq.json.j2
     notify: restart sensu-client service
 
   - name: Deploy Sensu client service configuration
-    template: dest="{{ sensu_config_path }}/conf.d/client.json"
-              owner={{ sensu_user_name }} group={{ sensu_group_name }}
-              src={{ sensu_client_config  }}
+    template:
+      dest: "{{ sensu_config_path }}/conf.d/client.json"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      src: "{{ sensu_client_config  }}"
     notify: restart sensu-client service
 
-  - name: Deploy Sensu client service manifest
-    template: dest=/opt/local/lib/svc/manifest/sensu-client.xml
-              src=sensu-client.smartos_smf_manifest.xml.j2
-              owner=root group=root mode=644
-    notify: import sensu-client service
-              
-  - name: Initial import of Sensu client service
-    command: /usr/sbin/svccfg import /opt/local/lib/svc/manifest/sensu-client.xml
-    args:
-      creates: "/var/svc/log/application-sensu-client:default.log"
+  - include: SmartOS/client.yml
+    when: ansible_distribution == "SmartOS"
 
   - name: Ensure Sensu client service is running
     service: name=sensu-client state=started enabled=yes

+ 5 - 62
tasks/dashboard.yml

@@ -1,67 +1,10 @@
 ---
+# tasks/dashboard.yml: Deployment of the Uchiwa dashboard
+  - include: SmartOS/dashboard.yml
+    when: ansible_distribution == "SmartOS"
 
-  - name: Ensure Uchiwa directory exists
-    file: dest={{ uchiwa_path }} state=directory
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-          recurse=yes
-
-  - name: Ensure Uchiwa config directory exists
-    file: dest={{ uchiwa_path }}/etc state=directory
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-          recurse=yes
-
-  - name: Ensure Uchiwa Go directory exists
-    file: dest={{ uchiwa_path }}/go state=directory
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-          recurse=yes
-
-  - name: Ensure Uchiwa GOPATH exists
-    file: dest={{ uchiwa_path }}/go/{{ item }}
-          owner={{ sensu_user_name }}
-          group={{ sensu_group_name }}
-          state=directory recurse=yes
-    with_items:
-      - bin
-      - pkg
-      - src
-
-  - name: Fetch Uchiwa from GitHub
-    command: go get github.com/sensu/uchiwa
-    environment:
-      GOPATH: "{{ uchiwa_path }}/go"
-    sudo: yes
-    sudo_user: "{{ sensu_user_name }}"
-    args:
-      creates: "{{ uchiwa_path }}/go/src/github.com/sensu/uchiwa"
-
-  - name: Build and deploy Uchiwa
-    shell: npm install --production chdir={{ uchiwa_path }}/go/src/github.com/sensu/uchiwa
-    args:
-      creates: "{{ uchiwa_path }}/go/src/github.com/sensu/uchiwa/public/bower_components"
-    sudo: yes
-    sudo_user: "{{ sensu_user_name }}"
-
-  - name: Deploy Uchiwa config
-    template: src=uchiwa_config.json.j2 dest={{ uchiwa_path }}/etc/config.json
-              owner={{ sensu_user_name }} group={{ sensu_group_name }}
-    notify: restart uchiwa service
-
-  - name: Deploy Uchiwa service script
-    template: src=uchiwa.sh.j2
-              dest=/opt/local/lib/svc/method/uchiwa
-              owner=root group=root mode=755
-    notify: restart uchiwa service
-
-  - name: Deploy Uchiwa service manifest
-    template: dest=/opt/local/lib/svc/manifest/uchiwa.xml
-              src=uchiwa.smartos_smf_manifest.xml.j2
-              owner=root group=root mode=644
-    notify: import uchiwa service
-
-  - name: Initial import of Uchiwa server service
-    command: /usr/sbin/svccfg import /opt/local/lib/svc/manifest/uchiwa.xml
-    args:
-      creates: "/var/svc/log/application-uchiwa:default.log"
+  - include: Ubuntu/dashboard.yml
+    when: ansible_distribution == "Ubuntu"
 
   - name: Ensure Uchiwa server service is running
     service: name=uchiwa state=started enabled=yes

+ 9 - 29
tasks/main.yml

@@ -1,36 +1,16 @@
 ---
+# tasks/main.yml: "Master" playbook for the cmacrae.sensu role
 
-  - name: Ensure the Sensu group is present
-    group: name={{ sensu_group_name }}
-             state=present
-             
-  - name: Ensure the Sensu user is present
-    user: name={{ sensu_user_name }}
-          group={{ sensu_group_name }}
-          shell=/bin/false
-          home={{ sensu_config_path }}
-          createhome=yes
-          state=present
-
-  - name: Ensure the Sensu config directory is present
-    file: dest={{ sensu_config_path }}/conf.d state=directory recurse=yes
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-
-  - name: Ensure Sensu dependencies are installed
-    pkgin: name=build-essential,ruby21-base state=present
-
-  - name: Ensure Uchiwa (dashboard) dependencies are installed
-    pkgin: name=go state=present
-    when: sensu_include_dashboard
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
 
-  - name: Ensure Sensu is installed
-    gem: name=sensu state={{ sensu_gem_state }} user_install=no
-    notify:
-      - restart sensu-client service
-    
-  - name: Ensure Sensu 'plugins' gem is installed
-    gem: name=sensu-plugin state={{ sensu_plugin_gem_state }} user_install=no
+  - include: SmartOS/main.yml tags=setup
+    when: ansible_distribution == "SmartOS"
 
+  - include: Ubuntu/main.yml tags=setup
+    when: ansible_distribution == "Ubuntu"
+      
   - include: ssl.yml tags=ssl
 
   - include: rabbit.yml tags=rabbitmq

+ 41 - 19
tasks/plugins.yml

@@ -1,46 +1,68 @@
 ---
+# tasks/plugins.yml: Deploy available checks/plugins/handlers/filters/mutators
+
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
 
   - name: Ensure Sensu plugin directory exists
-    file: dest={{ sensu_config_path }}/plugins state=directory
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    file:
+      dest: "{{ sensu_config_path }}/plugins"
+      state: directory
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
 
   - name: Register available checks
     local_action: command ls {{ static_data_store }}/sensu/checks
     register: sensu_available_checks
-    changed_when: False
+    changed_when: false
 
   - name: Deploy check plugins
-    copy: src={{ static_data_store }}/sensu/checks/{{ item }}/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/checks/{{ item }}/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     when: sensu_available_checks.stdout.find('{{ item }}') != -1
     with_flattened:
       - group_names
     notify: restart sensu-client service
 
   - name: Deploy handler plugins
-    copy: src={{ static_data_store }}/sensu/handlers/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/handlers/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     notify: restart sensu-client service
 
   - name: Deploy filter plugins
-    copy: src={{ static_data_store }}/sensu/filters/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/filters/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     notify: restart sensu-client service
 
   - name: Deploy mutator plugins
-    copy: src={{ static_data_store }}/sensu/mutators/
-          dest={{ sensu_config_path }}/plugins/ mode=755
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    copy:
+      src: "{{ static_data_store }}/sensu/mutators/"
+      dest: "{{ sensu_config_path }}/plugins/"
+      mode: 0755
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     notify: restart sensu-client service
 
   - name: Deploy check/handler/filter/mutator definitions to the master
-    template: src={{ static_data_store }}/sensu/definitions/{{ item }}.j2
-          dest={{ sensu_config_path }}/conf.d/{{ item }}
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+    template:
+      src: "{{ static_data_store }}/sensu/definitions/{{ item }}.j2"
+      dest: "{{ sensu_config_path }}/conf.d/{{ item }}"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
     when: sensu_master
     with_lines:
-      - ls {{ static_data_store }}/sensu/definitions | cut -d. --fields=1,2
+      - ls {{ static_data_store }}/sensu/definitions | sed 's/\.j2//'
     notify: restart sensu-api service

+ 43 - 29
tasks/rabbit.yml

@@ -1,46 +1,60 @@
 ---
+# tasks/rabbit.yml: Deploy RabbitMQ and set-up vhost for Sensu messaging
 
-  - name: Ensure RabbitMQ is installed
-    pkgin: name=rabbitmq state=present
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
+
+  - include: SmartOS/rabbit.yml
+    when: ansible_distribution == "SmartOS"
+
+  - include: Ubuntu/rabbit.yml
+    when: ansible_distribution == "Ubuntu"
 
   - name: Ensure RabbitMQ SSL directory exists
     file: dest={{ rabbitmq_config_path }}/ssl state=directory
 
   - name: Ensure RabbitMQ SSL certs/keys are in place
-    copy: src={{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/ssl_certs/{{ item }}
-          dest={{ rabbitmq_config_path }}/ssl
+    copy: src={{ item }} dest={{ rabbitmq_config_path }}/ssl
     with_items:
-      - sensu_ca/cacert.pem
-      - server/cert.pem
-      - server/key.pem
+      - "{{ sensu_ssl_server_cacert }}"
+      - "{{ sensu_ssl_server_cert }}"
+      - "{{ sensu_ssl_server_key }}"
+    notify:
+      - restart rabbitmq service
+      - restart sensu-api service
+      - restart sensu-server service
 
   - name: Deploy RabbitMQ config
-    template: dest={{ rabbitmq_config_path }}/rabbitmq.config
-              src=rabbitmq.config.j2
-              owner=root group=root mode=644
+    template:
+      dest: "{{ rabbitmq_config_path }}/rabbitmq.config"
+      src: "{{ rabbitmq_config_template }}"
+      owner: root
+      group: root
+      mode: 644
     notify: restart rabbitmq service
 
   - name: Ensure RabbitMQ is running
-    service: name={{ item }} state=started enabled=true
-    with_items:
-      - epmd
-      - rabbitmq
+    service:
+      name: "{{ rabbitmq_service_name }}"
+      state: started
+      enabled: true
 
   - name: Wait for RabbitMQ to be up and running before asking to create a vhost
     pause: seconds=3
 
-  - name: Ensure Sensu RabbitMQ vhost exists
-    rabbitmq_vhost: name={{ rabbitmq_sensu_vhost }} state=present
-    sudo: yes
-    sudo_user: rabbitmq
-
-  - name: Ensure Sensu RabbitMQ user has access to the Sensu vhost
-    rabbitmq_user: user={{ rabbitmq_sensu_user_name }}
-                   password={{ rabbitmq_sensu_password }}
-                   vhost={{ rabbitmq_sensu_vhost }}
-                   configure_priv=.*
-                   read_priv=.*
-                   write_priv=.*
-                   state=present
-    sudo: yes
-    sudo_user: rabbitmq
+  - block:
+    - name: Ensure Sensu RabbitMQ vhost exists
+      rabbitmq_vhost: name={{ rabbitmq_sensu_vhost }} state=present
+
+    - name: Ensure Sensu RabbitMQ user has access to the Sensu vhost
+      rabbitmq_user:
+        user: "{{ rabbitmq_sensu_user_name }}"
+        password: "{{ rabbitmq_sensu_password }}"
+        vhost: "{{ rabbitmq_sensu_vhost }}"
+        configure_priv: .*
+        read_priv: .*
+        write_priv: .*
+        state: present
+    become: true
+    become_user: rabbitmq

+ 6 - 2
tasks/redis.yml

@@ -1,7 +1,11 @@
 ---
+# tasks/redis.yml: Deploy Redis
 
-  - name: Ensure Redis is installed
-    pkgin: name=redis state=present
+  - include: SmartOS/redis.yml
+    when: ansible_distribution == "SmartOS"
+
+  - include: Ubuntu/redis.yml
+    when: ansible_distribution == "Ubuntu"
 
   - name: Ensure Redis is running
     service: name=redis state=started enabled=true

+ 25 - 27
tasks/server.yml

@@ -1,38 +1,36 @@
 ---
+# tasks/server.yml: Deploy Sensu Server/API
+
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
+
+  - name: Ensure the Sensu config directory is present
+    file:
+      dest: "{{ sensu_config_path }}/conf.d"
+      state: directory
+      recurse: true
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
 
   - name: Deploy Sensu server API configuration
-    template: dest={{ sensu_config_path }}/conf.d/api.json
-              owner={{ sensu_user_name }} group={{ sensu_group_name }}
-              src=sensu-api.json.j2
+    template:
+      dest: "{{ sensu_config_path }}/conf.d/api.json"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      src: sensu-api.json.j2
     notify: restart sensu-api service
 
   - name: Deploy Sensu Redis configuration
-    template: dest={{ sensu_config_path }}/conf.d/redis.json
-              owner={{ sensu_user_name }} group={{ sensu_group_name }}
-              src=sensu-redis.json.j2
+    template:
+      dest: "{{ sensu_config_path }}/conf.d/redis.json"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      src: sensu-redis.json.j2
     notify: restart sensu-api service
 
-  - name: Deploy Sensu server service manifest
-    template: dest=/opt/local/lib/svc/manifest/sensu-server.xml
-              src=sensu-server.smartos_smf_manifest.xml.j2
-              owner=root group=root mode=644
-    notify: import sensu-server service
-
-  - name: Deploy Sensu API service manifest
-    template: dest=/opt/local/lib/svc/manifest/sensu-api.xml
-              src=sensu-api.smartos_smf_manifest.xml.j2
-              owner=root group=root mode=644
-    notify: import sensu-api service
- 
-  - name: Initial import of Sensu server service
-    command: /usr/sbin/svccfg import /opt/local/lib/svc/manifest/sensu-server.xml
-    args:
-      creates: "/var/svc/log/application-sensu-server:default.log"
-        
-  - name: Initial import of Sensu API service
-    command: /usr/sbin/svccfg import /opt/local/lib/svc/manifest/sensu-api.xml
-    args:
-      creates: "/var/svc/log/application-sensu-api:default.log"
+  - include: SmartOS/server.yml
+    when: ansible_distribution == "SmartOS"
 
   - name: Ensure Sensu server service is running
     service: name=sensu-server state=started enabled=yes

+ 14 - 46
tasks/ssl.yml

@@ -1,52 +1,20 @@
 ---
+# tasks/ssl.yml: Deploy the client SSL cert/key to client systems
 
-  - name: Ensure Sensu SSL directory exists
-    file: dest={{ sensu_config_path }}/ssl state=directory
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
 
-  - name: Ensure SSL generation directory exists
-    file: dest={{ sensu_config_path }}/ssl_generation state=directory
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-    when: sensu_master
-
-  - name: Fetch the ssl_certs tarball from sensuapp.org
-    get_url: url=http://sensuapp.org/docs/0.16/tools/ssl_certs.tar
-             dest={{ sensu_config_path }}/ssl_generation/ssl_certs.tar
-    when: sensu_master
-    sudo: yes
-    sudo_user: "{{ sensu_user_name }}"
-
-  - name: Untar the ssl_certs tarball from sensuapp.org
-    shell: tar xf ssl_certs.tar chdir={{ sensu_config_path }}/ssl_generation
-    args:
-      creates: "{{ sensu_config_path }}/ssl_generation/ssl_certs"
-    when: sensu_master
-    sudo: yes
-    sudo_user: "{{ sensu_user_name }}"
-
-  - name: Generate SSL certs
-    shell: ./ssl_certs.sh generate chdir={{ sensu_config_path }}/ssl_generation/ssl_certs
-    args:
-      creates: "{{ sensu_config_path }}/ssl_generation/ssl_certs/server"
-    when: sensu_master
-    sudo: yes
-    sudo_user: "{{ sensu_user_name }}"
-
-  - name: Stash the Sensu SSL certs/keys
-    fetch: src={{ sensu_config_path }}/ssl_generation/ssl_certs/{{ item }}
-           dest={{ dynamic_data_store }}
-    when: sensu_master
-    with_items:
-      - sensu_ca/cacert.pem
-      - server/cert.pem
-      - server/key.pem
-      - client/cert.pem
-      - client/key.pem
+  - include: ssl_generate.yml
+    when: sensu_ssl_gen_certs
 
   - name: Deploy the Sensu client SSL cert/key
-    copy: src={{ dynamic_data_store }}/{{ groups['sensu_masters'][0] }}/{{ sensu_config_path }}/ssl_generation/ssl_certs/client/{{ item }}
-          owner={{ sensu_user_name }} group={{ sensu_group_name }}
-          dest={{ sensu_config_path }}/ssl
+    copy:
+      src: "{{ item }}"
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+      dest: "{{ sensu_config_path }}/ssl"
     with_items:
-      - cert.pem
-      - key.pem
+      - "{{ sensu_ssl_client_cert }}"
+      - "{{ sensu_ssl_client_key }}"
+    notify: restart sensu-client service

+ 57 - 0
tasks/ssl_generate.yml

@@ -0,0 +1,57 @@
+---
+# tasks/ssl_generate.yml: Generate SSL data and stash to dynamic
+# data store for deployment to clients
+
+  - include_vars: "{{ item }}"
+    with_first_found:
+      - "{{ ansible_distribution }}.yml"
+
+  - name: Ensure Sensu SSL directory exists
+    file:
+      dest: "{{ sensu_config_path }}/ssl"
+      state: directory
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+
+  - name: Ensure SSL generation directory exists
+    file:
+      dest: "{{ sensu_config_path }}/ssl_generation"
+      state: directory
+      owner: "{{ sensu_user_name }}"
+      group: "{{ sensu_group_name }}"
+    when: sensu_master
+
+  - block:
+
+    - name: Fetch the ssl_certs tarball from sensuapp.org
+      get_url:
+        url: http://sensuapp.org/docs/0.21/files/sensu_ssl_tool.tar
+        dest: "{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool.tar"
+  
+    - name: Untar the ssl_certs tarball from sensuapp.org
+      shell: tar xf sensu_ssl_tool.tar
+      args:
+        chdir: "{{ sensu_config_path }}/ssl_generation"
+        creates: "{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool"
+  
+    - name: Generate SSL certs
+      shell: ./ssl_certs.sh generate
+      args:
+        chdir: "{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool"
+        creates: "{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/server"
+
+    when: sensu_master|bool
+    become: true
+    become_user: "{{ sensu_user_name }}"
+
+  - name: Stash the Sensu SSL certs/keys
+    fetch:
+      src: "{{ sensu_config_path }}/ssl_generation/sensu_ssl_tool/{{ item }}"
+      dest: "{{ dynamic_data_store }}"
+    when: sensu_master
+    with_items:
+      - sensu_ca/cacert.pem
+      - server/cert.pem
+      - server/key.pem
+      - client/cert.pem
+      - client/key.pem

+ 4 - 0
tests/Vagrantfile

@@ -0,0 +1,4 @@
+vagrantfiles = %w[vms/Vagrantfile.ubuntu15]
+vagrantfiles.each do |vagrantfile|
+  load File.expand_path(vagrantfile) if File.exists?(vagrantfile)
+end

+ 5 - 0
tests/provision.yml

@@ -0,0 +1,5 @@
+---
+- hosts: all
+
+  roles:
+    - ../../cmacrae.sensu

+ 46 - 0
tests/vms/Vagrantfile.ubuntu15

@@ -0,0 +1,46 @@
+################
+# Ubuntu 15.04 #
+################
+Vagrant.configure(2) do | config |
+  config.ssh.insert_key = false
+  config.ssh.username = 'vagrant'
+  config.vm.provider :virtualbox do |vb|
+    vb.customize ["modifyvm", :id, "--memory", "2048"]
+  end
+
+   config.vm.define "ubuntu15" do |ubuntu15|
+    ubuntu15.vm.hostname = "ubuntu15.dev"
+    ubuntu15.vm.box = "ubuntu/vivid64"
+    ubuntu15.vm.network :private_network, ip: "192.168.40.2"
+    ubuntu15.vm.network "forwarded_port", guest: 3000, host: 3000
+  end
+
+  # Ansible
+  config.vm.provision "ansible" do |ansible|
+    ansible.groups = {
+      "sensu_masters" => ["ubuntu15"],
+      "rabbitmq_servers" => ["ubuntu15"],
+      "redis_servers" => ["ubuntu15"],
+    }
+
+    ansible.extra_vars = {
+      dynamic_data_store: "data/dynamic",
+      rabbitmq_host: "192.168.40.2",
+      rabbitmq_server: true,
+      redis_host: "192.168.40.2",
+      redis_server: true,
+      sensu_api_host: "192.168.40.2",
+      sensu_api_user_name: "admin",
+      sensu_api_password: "admin",
+      sensu_include_plugins: false,
+      sensu_include_dashboard: true,
+      sensu_master: true,
+      uchiwa_dc_name: "vagrant",
+      uchiwa_user_name: "admin",
+      uchiwa_password: "admin",
+    }
+
+    ansible.sudo = true
+    ansible.playbook = "provision.yml"
+  end
+end

+ 10 - 0
vars/SmartOS.yml

@@ -0,0 +1,10 @@
+---
+# vars/SmartOS.yml: Variables for Joyent SmartOS
+# Defaults are defined in vars/default.yml
+
+# RabbitMQ server properties
+rabbitmq_service_name: rabbitmq
+rabbitmq_config_path: /opt/local/etc/rabbitmq
+
+# Sensu/Uchiwa user/group/service properties
+sensu_config_path: /opt/local/etc/sensu

+ 14 - 0
vars/Ubuntu.yml

@@ -0,0 +1,14 @@
+---
+# vars/Ubuntu.yml: Variables for Ubuntu
+# Defaults are defined in vars/default.yml
+
+# Redis server properties
+redis_pkg_repo: 'ppa:rwky/redis'
+
+# Sensu/Uchiwa user/group/service properties
+sensu_user_name: root
+sensu_group_name: root
+uchiwa_pkg_download_sha256sum: 04d830e84159cc82b297ec9eb4333b8038b58ab77b12464163d7c5291bdda21d
+uchiwa_pkg_download_path: /root/uchiwa_latest.deb
+uchiwa_pkg_version: 0.14.2-1
+uchiwa_pkg_download_url: http://dl.bintray.com/palourde/uchiwa/uchiwa_{{ uchiwa_pkg_version }}_amd64.deb