flapjack_configurator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +47 -0
  4. data/Dockerfile +11 -0
  5. data/Gemfile +3 -0
  6. data/README.md +139 -0
  7. data/Rakefile +19 -0
  8. data/bin/flapjack_configurator +82 -0
  9. data/example.yml +121 -0
  10. data/flapjack_configurator.gemspec +29 -0
  11. data/lib/flapjack_configurator.rb +32 -0
  12. data/lib/flapjack_configurator/entity_mapper.rb +70 -0
  13. data/lib/flapjack_configurator/flapjack_config.rb +72 -0
  14. data/lib/flapjack_configurator/flapjack_contact.rb +156 -0
  15. data/lib/flapjack_configurator/flapjack_media.rb +23 -0
  16. data/lib/flapjack_configurator/flapjack_notification_rule.rb +39 -0
  17. data/lib/flapjack_configurator/flapjack_object_base.rb +86 -0
  18. data/lib/flapjack_configurator/flapjack_pagerduty.rb +28 -0
  19. data/lib/flapjack_configurator/flapjack_sub_object_base.rb +33 -0
  20. data/lib/flapjack_configurator/user_configuration.rb +107 -0
  21. data/lib/flapjack_configurator/version.rb +6 -0
  22. data/spec/docker_test_wrapper.rb +52 -0
  23. data/spec/functional/all_entity_spec.rb +19 -0
  24. data/spec/functional/config_test_common.rb +58 -0
  25. data/spec/functional/configuration_contact_attributes_spec.rb +18 -0
  26. data/spec/functional/configuration_contact_entities_spec.rb +116 -0
  27. data/spec/functional/configuration_contact_notification_media_spec.rb +73 -0
  28. data/spec/functional/configuration_contact_notification_rules_spec.rb +58 -0
  29. data/spec/functional/configuration_contact_removal_spec.rb +83 -0
  30. data/spec/functional/test_configs/changes/attributes.yaml +24 -0
  31. data/spec/functional/test_configs/changes/notification_media.yaml +155 -0
  32. data/spec/functional/test_configs/changes/notification_rules.yaml +143 -0
  33. data/spec/functional/test_configs/entities.yaml +71 -0
  34. data/spec/functional/test_configs/initial/attributes.yaml +24 -0
  35. data/spec/functional/test_configs/initial/notification_media.yaml +155 -0
  36. data/spec/functional/test_configs/initial/notification_rules.yaml +143 -0
  37. data/spec/functional/test_configs/obj_removal_setup.yaml +106 -0
  38. data/spec/spec_helper.rb +9 -0
  39. metadata +211 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cd6924183c859202d58b0a39d5bd4ef0a90cfbb5
4
+ data.tar.gz: f65b30f3d4ecf257a2e964dfa3c27f51d5fde57e
5
+ SHA512:
6
+ metadata.gz: 05f44c8e5a7c11334478166df466478e905d1a9cacf1346026232834bf2c0251b04b03c3ba4cb965d3e87d3816b104c3df09579d79ee879f8206615c04031f07
7
+ data.tar.gz: 02d11b88c7a9d5b03dd73ed44940e48b80cf2ceb30e30b24b4cd5d57944b03280a79efaeec0716cb38c8000ca3dc97e228e9f95bc0e044e9f42da449c8f823bd
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg/*
2
+ coverage/*
data/.rubocop.yml ADDED
@@ -0,0 +1,47 @@
1
+ # Disable requirement of "encoding" headers on files
2
+ Encoding:
3
+ Enabled: false
4
+
5
+ # Increase line length, we're not on VT220s anymore
6
+ LineLength:
7
+ Max: 180
8
+
9
+ # Increase allowed lines in a method. Short methods are good, but 10 lines
10
+ # is a bit too low.
11
+ MethodLength:
12
+ Max: 40
13
+
14
+ # Favor explicit over implicit code: don't complain of "redundant returns"
15
+ RedundantReturn:
16
+ Enabled: false
17
+
18
+ # Don't complain about if/unless modifiers. The merit of this is debatable
19
+ # and it will likely require building of over-length lines.
20
+ IfUnlessModifier:
21
+ Enabled: false
22
+
23
+ # Raise allowed CyclomaticComplexity to 10.
24
+ CyclomaticComplexity:
25
+ Max: 10
26
+
27
+ # Raise allowed parameter count to 8, 5 is a bit low.
28
+ ParameterLists:
29
+ Max: 8
30
+
31
+ # 123_456 doesn't add value IMO.
32
+ NumericLiterals:
33
+ Enabled: false
34
+
35
+ # Turn up Assignment Branch Condition size
36
+ # This baby's gonna be complicated \m/
37
+ AbcSize:
38
+ Max: 40
39
+
40
+ # Disable the english library substitution cop: What is the value here?
41
+ SpecialGlobalVars:
42
+ Enabled: false
43
+
44
+ # Turn up the class length
45
+ # The contact class is big, and isn't easily pared down.
46
+ ClassLength:
47
+ Max: 250
data/Dockerfile ADDED
@@ -0,0 +1,11 @@
1
+ FROM debian:jessie
2
+ MAINTAINER Tom Noonan II <thomas.noonan@corvisa.com>
3
+
4
+ RUN apt-get update && apt-get install -y ruby bundler git
5
+
6
+ COPY ./ /gem_build
7
+ RUN cd /gem_build; rm -r pkg; bundle install && rake install
8
+
9
+ RUN useradd -m flapjackconf
10
+ USER flapjackconf
11
+ ENTRYPOINT ["/usr/local/bin/flapjack_configurator"]
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,139 @@
1
+ Flapjack Configurator
2
+ =====================
3
+
4
+ This gem provides a idempotent, file based fonfigurator for [Flapjack](http://flapjack.io)
5
+
6
+ Configuration
7
+ -------------
8
+
9
+ The general config form is:
10
+
11
+ ```yaml
12
+ # Example/Demo Flapjack setup file
13
+
14
+ baseline_options:
15
+ notification_media:
16
+ # Baseline Pagerduty creds
17
+ # Pagerduty setup takes the domain, a API token to poll for acks, and a service key unique to the Pagerduty service
18
+ # Define the (common) domain id and API token here
19
+ # Currently only one PD instance is supported to keep the config handling easy. (/lazy)
20
+ pagerduty:
21
+ subdomain: foocorp
22
+ token: PagerDutyAPIToken
23
+
24
+ # Contacts!
25
+ contacts:
26
+ TestUser:
27
+ # Details is a direct map to the Flapjack API arguments (except notification related fields)
28
+ # http://flapjack.io/docs/1.0/jsonapi/#create-contacts
29
+ details:
30
+ first_name: Test
31
+ last_name: User
32
+ # Email is required but is only used here for documentation
33
+ email: test.user@example.com
34
+ timezone: MST7MDT
35
+
36
+ notification_media:
37
+ defaults:
38
+ # Re-notify every 30 minutes
39
+ interval: 1800
40
+ rollup_threshold: 3
41
+
42
+ # Only one of each is allowed in Flapjack 1.x :(
43
+ pagerduty:
44
+ service_key: PagerDutyServiceKey
45
+
46
+ email:
47
+ address: test.user@example.com
48
+
49
+ jabber:
50
+ address: room@conf.hipchat.com
51
+
52
+ notification_rules:
53
+ default:
54
+ warning_media:
55
+ - jabber
56
+ - email
57
+ critical_media:
58
+ - pagerduty
59
+ - jabber
60
+ - email
61
+
62
+ # Entities: A list of entities to associate with the contact
63
+ # Priority ordering is:
64
+ # 1: Exact entities
65
+ # 2: Blacklist entities
66
+ # 3: Blacklist regex
67
+ # 4: Entities regex
68
+ #
69
+ # If entities/default is true the contact will be associated with all entities which would otherwise not be associated with any contact.
70
+ entities:
71
+ default: false
72
+ exact:
73
+ - foo-app-1
74
+ regex:
75
+ - "datagen-[0-9]+"
76
+ entities_blacklist:
77
+ exact:
78
+ - datagen-2
79
+ regex:
80
+ - "datagen-[78]"
81
+ ```
82
+
83
+ Most (but not all) of the options are passed through directly to the API (This is logged at debug level).
84
+ notification_media and notification_rules are merged down with the per contact rule with the highest precidence, contact defaults, and then baseline_options.
85
+ The key must be present in the contact to merge to prevent partial settings from being built off defaults.
86
+ Complete configs at the baseline_option level with automatic inheritance is not currently supported.
87
+
88
+ Use
89
+ ===
90
+
91
+ WARNING: Passwords/API tokens will be logged at debug log level!
92
+
93
+ Command Line
94
+ ------------
95
+
96
+ ```
97
+ $ flapjack_configurator -h
98
+ Usage: flapjack_configurator [options]
99
+
100
+ Specific options:
101
+ -u, --apiurl URL Flapjack API URL
102
+ -v, --verbosity [level] Set Verbosity, level corresponds to Ruby logger levels (0: debug, 3: error)
103
+ -f, --files file1,file2,file3 List of YAML config files to load, increasing precidence
104
+ -h, --help Show this message
105
+ --version Show version
106
+ ```
107
+
108
+ Files is a comma-separated list of yaml files which are merged together to form the configuration.
109
+ API URL should be of the form "http://${hostname}:${port}"
110
+
111
+ Gem
112
+ ---
113
+
114
+ ```
115
+ require 'flapjack_configurator'
116
+
117
+ FlapjackConfigurator.configure_flapjack(config, api_base_url, logger)
118
+ ```
119
+
120
+ ### configure_flapjack method:
121
+
122
+ - Arguments:
123
+ - config (Hash): Configuration hash to apply
124
+ - api_base_url (String)(Default: http://127.0.0.1:3081): Flapjack API URL string to connect to
125
+ - logger (Logger)(Default: Logger.new(STDOUT)): Logger class to log to
126
+ - enable_all_entity (Boolean)(Default: true): Add the ALL magic entity if it doesn't exist
127
+ - Return value: Boolean: true if changes were applied, false otherwise
128
+
129
+ Testing
130
+ =======
131
+
132
+ The Rubocop and Rspec coverage are part of the default rake task.
133
+ Tests spin up a Flapjack container in Docker and interact with its API, no mocks are used.
134
+ As such a running Docker daemon is required for tests.
135
+
136
+ Authors
137
+ =======
138
+
139
+ - Tom Noonan <thomas.noonan@corvisa.com>
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ # https://github.com/bbatsov/rubocop#rake-integration
4
+ begin
5
+ require 'rubocop/rake_task'
6
+ RuboCop::RakeTask.new
7
+ task default: :rubocop
8
+ rescue LoadError
9
+ puts 'WARNING: Rubocop unavailable'
10
+ end
11
+
12
+ # https://www.relishapp.com/rspec/rspec-core/docs/command-line/rake-task
13
+ begin
14
+ require 'rspec/core/rake_task'
15
+ RSpec::Core::RakeTask.new(:spec)
16
+ task default: :spec
17
+ rescue LoadError
18
+ puts 'WARNING: Rspec unavailable'
19
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'flapjack_configurator'
4
+ require 'optparse'
5
+ require 'ostruct'
6
+ require 'logger'
7
+ require 'yaml'
8
+ require 'deep_merge'
9
+
10
+ # Parse the command line arguments
11
+ def parse_arguments(args, logger)
12
+ options = OpenStruct.new
13
+ options.api_url = 'http://127.0.0.1:3081'
14
+ logger.level = Logger::INFO
15
+ options.files = []
16
+
17
+ parser = OptionParser.new do |opts|
18
+ opts.banner = 'Usage: flapjack_configurator [options]'
19
+
20
+ opts.separator ''
21
+ opts.separator 'Specific options:'
22
+
23
+ opts.on('-u', '--apiurl URL', String, 'Flapjack API URL') do |url|
24
+ options.api_url = url
25
+ logger.debug("API URL set to #{url}")
26
+ end
27
+
28
+ opts.on('-v', '--verbosity [level]', Integer, 'Set Verbosity, level corresponds to Ruby logger levels (0: debug, 3: error)') do |level|
29
+ if level
30
+ logger.level = level
31
+ else
32
+ logger.level -= 1 if logger.level > 0
33
+ end
34
+ logger.debug('Log level set to #{logger.level}')
35
+ end
36
+
37
+ opts.on('-f', '--files file1,file2,file3', Array, 'List of YAML config files to load, increasing precidence') do |files|
38
+ options.files += files
39
+ end
40
+
41
+ opts.on_tail('-h', '--help', 'Show this message') do
42
+ puts opts
43
+ exit
44
+ end
45
+
46
+ opts.on_tail('--version', 'Show version') do
47
+ puts "Flapjack Configurator #{Gem.loaded_specs['flapjack_configurator'].version}"
48
+ exit
49
+ end
50
+ end
51
+
52
+ parser.parse!(args)
53
+
54
+ if options.files.length < 1
55
+ logger.fatal('Option --files is required')
56
+ exit
57
+ end
58
+
59
+ return options
60
+ end
61
+
62
+ # Load and merge the configs
63
+ def load_config(file_list, logger)
64
+ config = {}
65
+ file_list.each do |file_name|
66
+ logger.debug("Loading config file #{file_name}")
67
+ config.deep_merge!(YAML.load_file(file_name))
68
+ end
69
+
70
+ return config
71
+ end
72
+
73
+ def main
74
+ logger = Logger.new(STDOUT)
75
+ options = parse_arguments(ARGV, logger)
76
+ config = load_config(options.files, logger)
77
+
78
+ logger.info('Nothing to do') unless FlapjackConfigurator.configure_flapjack(config, options.api_url, logger)
79
+ end
80
+
81
+ # The __FILE__ $0 trick doesn't work when loaded through the gem wrapper
82
+ main
data/example.yml ADDED
@@ -0,0 +1,121 @@
1
+ # Example/Demo Flapjack setup file
2
+
3
+ baseline_options:
4
+ notification_media:
5
+ # Baseline Pagerduty creds
6
+ # Pagerduty setup takes the domain, a API token to poll for acks, and a service key unique to the Pagerduty service
7
+ # Define the (common) domain id and API token here
8
+ # Currently only one PD instance is supported to keep the config handling easy. (/lazy)
9
+ pagerduty:
10
+ subdomain: foocorp
11
+ token: PagerDutyAPIToken
12
+
13
+ # Contacts!
14
+ contacts:
15
+ TestUser:
16
+ # Details is a direct map to the Flapjack API arguments (except notification related fields)
17
+ # http://flapjack.io/docs/1.0/jsonapi/#create-contacts
18
+ details:
19
+ first_name: Test
20
+ last_name: User
21
+ # Email is required but is only used here for documentation
22
+ email: test.user@example.com
23
+ timezone: MST7MDT
24
+
25
+ notification_media:
26
+ defaults:
27
+ # Re-notify every 30 minutes
28
+ interval: 1800
29
+ rollup_threshold: 3
30
+
31
+ # Only one of each is allowed in Flapjack 1.x :(
32
+ pagerduty:
33
+ service_key: PagerDutyServiceKey
34
+
35
+ email:
36
+ address: test.user@example.com
37
+
38
+ jabber:
39
+ address: room@conf.hipchat.com
40
+
41
+ notification_rules:
42
+ default:
43
+ warning_media:
44
+ - jabber
45
+ - email
46
+ critical_media:
47
+ - pagerduty
48
+ - jabber
49
+ - email
50
+
51
+ # Entities: An exact list of entities
52
+ # Priority ordering is:
53
+ # 1: Exact entities
54
+ # 2: Blacklist entities
55
+ # 3: Blacklist regex
56
+ # 4: Entities regex
57
+ entities:
58
+ exact:
59
+ - foo-app-1
60
+ regex:
61
+ - "datagen-[0-9]+"
62
+ entities_blacklist:
63
+ exact:
64
+ - datagen-2
65
+ regex:
66
+ - "datagen-[78]"
67
+
68
+ DefaultUser:
69
+ details:
70
+ first_name: Default
71
+ last_name: User
72
+ email: default.user@example.com
73
+ timezone: MST7MDT
74
+
75
+ notification_media:
76
+ defaults:
77
+ # Re-notify every 30 minutes
78
+ interval: 1800
79
+ rollup_threshold: 3
80
+
81
+ # Only one of each is allowed in Flapjack 1.x :(
82
+ email:
83
+ address: test.user@example.com
84
+
85
+ notification_rules:
86
+ default:
87
+ warning_media:
88
+ - email
89
+ critical_media:
90
+ - email
91
+
92
+ entities:
93
+ default: true
94
+
95
+ Beard:
96
+ details:
97
+ first_name: Beard
98
+ last_name: User
99
+ email: beard.user@example.com
100
+ timezone: CST6CDT
101
+
102
+ notification_media:
103
+ defaults:
104
+ # Re-notify every 30 minutes
105
+ interval: 1800
106
+ rollup_threshold: 3
107
+
108
+ # Only one of each is allowed in Flapjack 1.x :(
109
+ email:
110
+ address: beard.user@example.com
111
+
112
+ notification_rules:
113
+ default:
114
+ warning_media:
115
+ - email
116
+ critical_media:
117
+ - email
118
+
119
+ entities:
120
+ exact:
121
+ - ALL
@@ -0,0 +1,29 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'flapjack_configurator/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ['Tom Noonan II']
7
+ gem.email = 'thomas.noonan@corvisa.com'
8
+ gem.description = 'FlapjackConfigurator loads a user specified config from YAML files and loads them idempotently into Flapjack via the Flapjack API'
9
+ gem.summary = 'Flapjack configuration tool'
10
+ gem.homepage = 'https://github.com/CVTJNII/FlapjackConfigurator'
11
+ gem.license = 'Apache License, Version 2'
12
+
13
+ gem.files = `git ls-files`.split($\) - ['Gemfile.lock']
14
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = 'flapjack_configurator'
17
+ gem.require_paths = ['lib']
18
+ gem.version = FlapjackConfigurator::VERSION
19
+
20
+ gem.add_dependency 'flapjack-diner', '~>1.4'
21
+ gem.add_dependency 'ruby_deep_clone', '~>0.6'
22
+ gem.add_dependency 'deep_merge', '~>1.0'
23
+
24
+ gem.add_development_dependency 'bundler', '~> 1.7'
25
+ gem.add_development_dependency 'rake', '~> 10.0'
26
+ gem.add_development_dependency 'rspec'
27
+ gem.add_development_dependency 'docker-api'
28
+ gem.add_development_dependency 'simplecov'
29
+ end