-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Scott Merrill
committed
Oct 21, 2015
0 parents
commit bc66501
Showing
18 changed files
with
1,355 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015 CoverMyMeds | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
puppet-sentry | ||
====== | ||
|
||
[Sentry](https://www.getsentry.com) is "a modern error logging and aggregation platform." This module installs the [on-premise](https://docs.getsentry.com/on-premise/) open source version of Sentry. | ||
|
||
Installation requires RHEL 7, and depends on Python and apache with `mod_wsgi`. These module dependencies are explicitly listed. | ||
Sentry also requires a database (PostgreSQL), memcached, and Redis which are not included in this module. Checkout the modules we use to satify those dependencies below. | ||
|
||
# Usage | ||
Install the latest version of Sentry. The default configuration places all of the dependencies on localhost which is likely only useful for a development scenario. | ||
``` | ||
class { 'sentry': } | ||
``` | ||
|
||
A more realistic use case with roles and profiles might look like this. | ||
``` | ||
**role/manifests/sentry.pp** | ||
class role::sentry { | ||
include profile::sentry | ||
include profile::memcached | ||
} | ||
**profile/manifests/sentry.pp** | ||
class profile::sentry { | ||
include profile::postgresql_client | ||
include ::sentry | ||
Class['profile::postgresql_client'] -> | ||
Class['::sentry'] | ||
} | ||
**hieradata/hosts/sentry.example.com.yaml** | ||
--- | ||
classes: | ||
- role::sentry | ||
sentry::db_host: 'postgresql.example.com' | ||
sentry::db_name: 'sentry' | ||
sentry::db_user: 'sentry' | ||
sentry::db_password: <redacted> | ||
sentry::sentry_vhost: 'sentry.example.com' | ||
sentry::ldap_host: 'ldap.example.com' | ||
sentry::ldap_user: '[email protected]' | ||
sentry::ldap_password: <redacted> | ||
sentry::ldap_domain: 'example' | ||
sentry::ldap_base_ou: 'dc=example,dc=com' | ||
sentry::sentry_group_base: 'OU=Some Group,OU=Some Other Group,DC=example,DC=com' | ||
sentry::sentry_group_dn: 'CN=Sentry_Group,OU=Some Other Group,DC=example,DC=com' | ||
sentry::redis_host: 'redis.example.com' | ||
sentry::smtp_host: 'smtp.example.com' | ||
sentry::admin_email: '[email protected]' | ||
sentry::admin_password: <redacted> | ||
sentry::organization: 'Your Organization Name' | ||
sentry::team: 'Default Team Name' | ||
sentry::secret_key: <some secret key> | ||
sentry::path: '/var/lib/sentry' | ||
sentry::version: '7.7.1' | ||
``` | ||
|
||
## Automation | ||
In addition to the installation of Sentry, this module also provides several useful automation hooks to facilitate the automatic creation of new projects. | ||
|
||
`sentry::source::export` is a defined type that exports a `sentry::source::project` resource. You can use this module in your application manifests. | ||
|
||
The main `sentry` class includes `sentry::server::collect`, which collects all of the exported `sentry::source::project` resources from your app servers. Each collected resource will create a Sentry project if it does not already exist. New projects will be created within your default Sentry organization and team. | ||
|
||
You may optionally also publish each of your projects' DSNs. With a simple custom fact (see the `examples` directory in this repo) your applications can automatically look up their DSN, and you can then embed that DSN wherever may be appropriate for consumption for your apps. | ||
|
||
We use this pattern to ensure that all of our apps automatically report to Sentry. This frees us from the manual task of creating a new Sentry resource for each new application. | ||
|
||
# Modules we use | ||
* [Postgresql](https://github.com/puppetlabs/puppetlabs-postgresql) | ||
* [Redis](https://github.com/covermymeds/puppet-redis) | ||
* [Memcached](https://github.com/saz/puppet-memcached) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# | ||
# sentry_dsn.rb - Set facts for the sentry dsn urls for apps install on the host | ||
# | ||
require 'facter' | ||
require 'net/http' | ||
require 'openssl' | ||
require 'resolv' | ||
require 'timeout' | ||
|
||
# Lookup the Sentry DSN url from cache file or right from Sentry itself | ||
def app_lookup (app_name, sentry_url) | ||
cache_file = "/var/cache/sentry_dsn/#{app_name}" | ||
if File.exists?(cache_file) | ||
Facter.add(:"#{app_name}_sentry_dsn".to_sym) do | ||
setcode do | ||
File.read(cache_file) | ||
end | ||
end | ||
else | ||
begin | ||
uri = URI(sentry_url + app_name) | ||
http = Net::HTTP.new(uri.host, uri.port) | ||
http.use_ssl = true | ||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
request = Net::HTTP::Get.new(uri.request_uri) | ||
response = http.request(request) | ||
if response.code == '200' then | ||
Facter.add(:"#{app_name}_sentry_dsn".to_sym) do | ||
setcode do | ||
response.body | ||
end | ||
end | ||
File.open(cache_file, 'w') { |file| file.write(response.body) } | ||
end | ||
rescue | ||
# It didn't work. Oh well | ||
Facter.debug("Error setting sentry_dsn for #{app_name}") | ||
end | ||
end | ||
end | ||
|
||
# See if the sentry hostname resolves (so this works in Vagrant) | ||
def sentry_resolve (sentry_host) | ||
begin | ||
Resolv::getaddress(sentry_host) | ||
return true | ||
rescue | ||
return false | ||
end | ||
end | ||
|
||
# | ||
# Main | ||
# | ||
if not File.directory("/var/cache/sentry_dsn/") then | ||
Dir.mkdir("/var/cache/sentry_dsn/") | ||
end | ||
app_env = Facter.value(:app_env) | ||
|
||
# | ||
# | ||
# This part is where you'd customize to your environment | ||
# | ||
# | ||
sentry_host = case app_env | ||
when 'production' then 'sentry.example.com' | ||
when 'testing' then 'sentry.testing.example.com' | ||
when 'development' then 'sentry.dev' | ||
end | ||
sentry_url = "https://#{sentry_host}/dsn/" | ||
|
||
if sentry_resolve(sentry_host) | ||
applications = whatever.method.to.get.a.list.of.apps.installed.on.this.server() | ||
applications.each do |app| | ||
begin | ||
expire_time=10 #seconds | ||
Timeout.timeout(expire_time) do | ||
app_lookup(app, sentry_url) | ||
end | ||
rescue Timeout::Error | ||
# Timeout expired, tell debug and stop future app_lookups | ||
Facter.debug("Timeout in app_lookup() for '#{app}'. Skipping remaining apps.") | ||
break | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
# == Class: sentry | ||
# | ||
# Install Sentry from PyPI and configure an Apache mod_wsgi vhost | ||
# | ||
# === Parameters | ||
# | ||
# admin_email: the admin user's email address; also used as login name (root@localhost) | ||
# | ||
# admin_password: the admin user's password (admin) | ||
# | ||
# beacon: whether to share some data upstream with GetSentry's beacon (False) | ||
# | ||
# db_host: the PostgreSQL database host (localhost) | ||
# | ||
# db_name: the name of the PostgreSQL database to use (sentry) | ||
# | ||
# db_password: the DB user's password (sentry) | ||
# | ||
# db_port: the PostgreSQL database port (5432) | ||
# | ||
# db_user: the user account with which to connect to the database (sentry) | ||
# | ||
# group: UNIX group to own virtualenv, and run background workers (sentry) | ||
# | ||
# ldap_*: LDAP connection details used for creating local user accounts from AD users | ||
# | ||
# max_epm: | ||
# | ||
# max_http_body: | ||
# | ||
# max_stacktrace: | ||
# | ||
# memcached_host: name or IP of memcached server (localhost) | ||
# | ||
# memcached_port: port to use for memcached (11211) | ||
# | ||
# organization: default organization to create, and in which to create new users | ||
# | ||
# path: path into which to install Sentry, and create the virtualenv (/srv/sentry) | ||
# | ||
# percent_limit: | ||
# | ||
# redis_host: name or IP of Redis server (localhost) | ||
# | ||
# redis_port: port to use for Redis (6379) | ||
# | ||
# secret_key: string used to hash cookies (fqdn_rand_string(40)) | ||
# | ||
# smtp_host: name or IP of SMTP server (localhost) | ||
# | ||
# ssl_*: Apache SSL controls | ||
# | ||
# team: name of the default team to create and use for new projects | ||
# | ||
# user: UNIX user to own virtualenv, and run background workers (sentry) | ||
# | ||
# version: the Sentry version to install | ||
# | ||
# vhost: the URL at which users will access the Sentry GUI | ||
# | ||
# wsgi_*: mod_wsgi controls | ||
# | ||
# === Authors | ||
# Dan Sajner <[email protected]> | ||
# Scott Merrill <[email protected]> | ||
# | ||
# === Copyright | ||
# Copyright 2014 CoverMyMeds, unless otherwise noted | ||
# | ||
# === License | ||
# Released under the terms of the MIT license. See LICENSE for more details | ||
# | ||
class sentry ( | ||
$admin_email = $sentry::params::admin_email, | ||
$admin_password = $sentry::params::admin_password, | ||
$beacon = $sentry::params::beacon, | ||
$db_host = $sentry::params::db_host, | ||
$db_name = $sentry::params::db_name, | ||
$db_password = $sentry::params::db_password, | ||
$db_port = $sentry::params::db_port, | ||
$db_user = $sentry::params::db_user, | ||
$group = $sentry::params::group, | ||
$ldap_base_ou = $sentry::params::ldap_base_ou, | ||
$ldap_domain = $sentry::params::ldap_domain, | ||
$ldap_group_base = $sentry::params::ldap_group_base, | ||
$ldap_group_dn = $sentry::params::ldap_group_dn, | ||
$ldap_host = $sentry::params::ldap_host, | ||
$ldap_user = $sentry::params::ldap_user, | ||
$ldap_password = $sentry::params::ldap_password, | ||
$max_epm = $sentry::params::max_epm, | ||
$max_http_body = $sentry::params::max_http_body, | ||
$max_stacktrace = $sentry::params::max_stacktrace, | ||
$memcached_host = $sentry::params::memcached_host, | ||
$memcached_port = $sentry::params::memcached_port, | ||
$organization = $sentry::params::organization, | ||
$path = $sentry::params::path, | ||
$percent_limit = $sentry::params::percent_limit, | ||
$project = $sentry::params::project, | ||
$redis_host = $sentry::params::redis_host, | ||
$redis_port = $sentry::params::redis_port, | ||
$secret_key = $sentry::params::secret_key, | ||
$smtp_host = $sentry::params::smtp_host, | ||
$ssl_ca = $sentry::params::ssl_ca, | ||
$ssl_chain = $sentry::params::ssl_chain, | ||
$ssl_cert = $sentry::params::ssl_cert, | ||
$ssl_key = $sentry::params::ssl_key, | ||
$team = $sentry::params::team, | ||
$user = $sentry::params::user, | ||
$version = $sentry::params::version, | ||
$vhost = $sentry::params::vhost, | ||
$wsgi_processes = $sentry::params::wsgi_processes, | ||
$wsgi_threads = $sentry::params::wsgi_threads, | ||
) inherits ::sentry::params { | ||
|
||
# Install Sentry | ||
class { 'sentry::install': | ||
admin_email => $admin_email, | ||
admin_password => $admin_password, | ||
group => $group, | ||
organization => $organization, | ||
path => $path, | ||
project => $project, | ||
team => $team, | ||
user => $user, | ||
version => $version, | ||
} | ||
|
||
file { "${path}/sentry.conf": | ||
ensure => present, | ||
content => template('sentry/sentry.conf.erb'), | ||
notify => Class['sentry::service'], | ||
} | ||
|
||
# set up WSGI | ||
class { 'sentry::wsgi': | ||
path => $path, | ||
ssl_ca => $ssl_ca, | ||
ssl_chain => $ssl_chain, | ||
ssl_cert => $ssl_cert, | ||
ssl_key => $ssl_key, | ||
vhost => $vhost, | ||
wsgi_processes => $wsgi_processes, | ||
wsgi_threads => $wsgi_threads, | ||
subscribe => Class['sentry::install'], | ||
} | ||
|
||
# set up the Sentry background worker(s) | ||
class { 'sentry::service': | ||
user => $user, | ||
group => $group, | ||
path => $path, | ||
subscribe => File["${path}/sentry.conf"], | ||
} | ||
|
||
# Write out a list of "team/project dsn" values to a file. | ||
# Apache will serve this list and Puppet will consume to set | ||
# custom facts for each app installed on a server | ||
file { "${path}/dsn_mapper.py": | ||
ensure => present, | ||
mode => '0755', | ||
content => template('sentry/dsn_mapper.py.erb'), | ||
require => File["${path}/sentry.conf"], | ||
} | ||
|
||
cron { 'dsn_mapper': | ||
command => "${path}/bin/python ${path}/dsn_mapper.py", | ||
user => root, | ||
minute => 5 | ||
} | ||
|
||
# Collect the projects from exported resources | ||
file { "${path}/create_project.py": | ||
ensure => present, | ||
mode => '0755', | ||
content => template('sentry/create_project.py.erb'), | ||
require => File["${path}/sentry.conf"], | ||
} | ||
|
||
include sentry::server::collect | ||
|
||
} |
Oops, something went wrong.