flapjack_configurator 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +47 -0
- data/Dockerfile +11 -0
- data/Gemfile +3 -0
- data/README.md +139 -0
- data/Rakefile +19 -0
- data/bin/flapjack_configurator +82 -0
- data/example.yml +121 -0
- data/flapjack_configurator.gemspec +29 -0
- data/lib/flapjack_configurator.rb +32 -0
- data/lib/flapjack_configurator/entity_mapper.rb +70 -0
- data/lib/flapjack_configurator/flapjack_config.rb +72 -0
- data/lib/flapjack_configurator/flapjack_contact.rb +156 -0
- data/lib/flapjack_configurator/flapjack_media.rb +23 -0
- data/lib/flapjack_configurator/flapjack_notification_rule.rb +39 -0
- data/lib/flapjack_configurator/flapjack_object_base.rb +86 -0
- data/lib/flapjack_configurator/flapjack_pagerduty.rb +28 -0
- data/lib/flapjack_configurator/flapjack_sub_object_base.rb +33 -0
- data/lib/flapjack_configurator/user_configuration.rb +107 -0
- data/lib/flapjack_configurator/version.rb +6 -0
- data/spec/docker_test_wrapper.rb +52 -0
- data/spec/functional/all_entity_spec.rb +19 -0
- data/spec/functional/config_test_common.rb +58 -0
- data/spec/functional/configuration_contact_attributes_spec.rb +18 -0
- data/spec/functional/configuration_contact_entities_spec.rb +116 -0
- data/spec/functional/configuration_contact_notification_media_spec.rb +73 -0
- data/spec/functional/configuration_contact_notification_rules_spec.rb +58 -0
- data/spec/functional/configuration_contact_removal_spec.rb +83 -0
- data/spec/functional/test_configs/changes/attributes.yaml +24 -0
- data/spec/functional/test_configs/changes/notification_media.yaml +155 -0
- data/spec/functional/test_configs/changes/notification_rules.yaml +143 -0
- data/spec/functional/test_configs/entities.yaml +71 -0
- data/spec/functional/test_configs/initial/attributes.yaml +24 -0
- data/spec/functional/test_configs/initial/notification_media.yaml +155 -0
- data/spec/functional/test_configs/initial/notification_rules.yaml +143 -0
- data/spec/functional/test_configs/obj_removal_setup.yaml +106 -0
- data/spec/spec_helper.rb +9 -0
- metadata +211 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'flapjack-diner'
|
4
|
+
require 'logger'
|
5
|
+
require 'flapjack_configurator/flapjack_config'
|
6
|
+
require 'flapjack_configurator/version'
|
7
|
+
|
8
|
+
# Flapjack Configuration Module
|
9
|
+
module FlapjackConfigurator
|
10
|
+
# Method to configure flapjack
|
11
|
+
def self.configure_flapjack(config, api_base_url = 'http://127.0.0.1:3081', logger = Logger.new(STDOUT), enable_all_entity = true)
|
12
|
+
ret_val = false
|
13
|
+
Flapjack::Diner.base_uri(api_base_url)
|
14
|
+
|
15
|
+
# The underlying classes treat the Flapjack::Diner module as if it is a class.
|
16
|
+
# This was done as it was fairly natural and will allow Flapjack::Diner to be
|
17
|
+
# replaced or wrapped very easily in the future.
|
18
|
+
config_obj = FlapjackConfig.new(config, Flapjack::Diner, logger)
|
19
|
+
|
20
|
+
if enable_all_entity
|
21
|
+
# Ensure the ALL entity is present
|
22
|
+
ret_val = true if config_obj.add_all_entity
|
23
|
+
end
|
24
|
+
|
25
|
+
# Update the contacts
|
26
|
+
# This will update media, PD creds, notification rules, and entity associations
|
27
|
+
# as they're associated to the contact.
|
28
|
+
ret_val = true if config_obj.update_contacts
|
29
|
+
|
30
|
+
return ret_val
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'deep_clone'
|
3
|
+
|
4
|
+
module FlapjackConfigurator
|
5
|
+
# Walk though the entities and build the map of entities to contacts
|
6
|
+
# Built as a class for future proofing and because this is expected to
|
7
|
+
# be an expensive operation: so instantiate it once and pass it around.
|
8
|
+
class EntityMapper
|
9
|
+
attr_reader :entity_map
|
10
|
+
|
11
|
+
def initialize(config_obj, diner)
|
12
|
+
@entity_map = {}.tap { |em| config_obj.contact_ids.each { |cn| em[cn.to_sym] = [] } }
|
13
|
+
default_contacts = config_obj.default_contacts
|
14
|
+
|
15
|
+
# Walk the entities and compare each individually so that the whitelisting/blacklisting can be easily enforced
|
16
|
+
# This probably will need some optimization
|
17
|
+
diner.entities.each do |entity|
|
18
|
+
contact_defined = false
|
19
|
+
config_obj.contact_ids.each do |contact_id|
|
20
|
+
match_id = _check_entity(entity, config_obj.contact_config(contact_id))
|
21
|
+
if match_id
|
22
|
+
@entity_map[contact_id.to_sym].push(entity[:id])
|
23
|
+
contact_defined = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# ALL is a special case entity, don't associate the default to it.
|
28
|
+
# Using next if per Rubocop :)
|
29
|
+
next if contact_defined || entity[:id] == 'ALL'
|
30
|
+
# No contacts match this entity, add it to the defaults
|
31
|
+
default_contacts.each do |contact_id|
|
32
|
+
@entity_map[contact_id.to_sym].push(entity[:id])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
return @entity_map
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check if entity should be included in contact
|
40
|
+
# Helper for _build_entity_map
|
41
|
+
# Returns the entity ID on match or nil on no match
|
42
|
+
def _check_entity(entity, contact)
|
43
|
+
# Priority 1: Exact Entries
|
44
|
+
return true if contact['entities']['exact'].include? entity[:name]
|
45
|
+
|
46
|
+
# Priority 2: Exact blacklist
|
47
|
+
return false if contact['entities_blacklist']['exact'].include? entity[:name]
|
48
|
+
|
49
|
+
# Priority 3: Regex blacklist
|
50
|
+
contact['entities_blacklist']['regex'].each do |bl_regex|
|
51
|
+
return false if /#{bl_regex}/.match(entity[:name])
|
52
|
+
end
|
53
|
+
|
54
|
+
# Priority 4: Match regex
|
55
|
+
contact['entities']['regex'].each do |m_regex|
|
56
|
+
return true if /#{m_regex}/.match(entity[:name])
|
57
|
+
end
|
58
|
+
|
59
|
+
# Fallthrough
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return the entities for the given contact
|
64
|
+
# Returns a clone so the returned object is modifyable
|
65
|
+
def entities_for_contact(id)
|
66
|
+
fail("ID #{id} not in entity map") unless @entity_map.key? id.to_sym
|
67
|
+
return DeepClone.clone @entity_map[id.to_sym]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'user_configuration.rb'
|
4
|
+
require_relative 'flapjack_media.rb'
|
5
|
+
require_relative 'flapjack_pagerduty.rb'
|
6
|
+
require_relative 'flapjack_notification_rule.rb'
|
7
|
+
require_relative 'flapjack_contact.rb'
|
8
|
+
|
9
|
+
module FlapjackConfigurator
|
10
|
+
# Class representing the overall Flapjack config
|
11
|
+
class FlapjackConfig
|
12
|
+
attr_reader :config_obj, :contacts
|
13
|
+
|
14
|
+
def initialize(config, diner, logger)
|
15
|
+
@config_obj = UserConfiguration.new(config, diner, logger)
|
16
|
+
@diner = diner
|
17
|
+
@logger = logger
|
18
|
+
|
19
|
+
# Media will be tied in via the contacts, however pregenerate objects off a single API call for speed.
|
20
|
+
media = @diner.media.map { |api_media| FlapjackMedia.new(api_media, @diner, logger) }
|
21
|
+
# Also add PagerDuty creds into media. PD creds are handled separately by the API but can be grouped thanks to our class handling.
|
22
|
+
media += @diner.pagerduty_credentials.map { |api_pd| FlapjackPagerduty.new(api_pd, @diner, logger) }
|
23
|
+
|
24
|
+
# Prebuild notification rules for the same reason
|
25
|
+
notification_rules = @diner.notification_rules.map { |api_nr| FlapjackNotificationRule.new(nil, api_nr, @diner, logger) }
|
26
|
+
|
27
|
+
@contacts = {}.tap { |ce| @diner.contacts.map { |api_contact| ce[api_contact[:id]] = FlapjackContact.new(nil, api_contact, @diner, logger, media, notification_rules) } }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Loop over the contacts and call update/create/remove methods as needed
|
31
|
+
# Builds the @contacts hash
|
32
|
+
def update_contacts
|
33
|
+
config_contact_ids = @config_obj.contact_ids
|
34
|
+
ret_val = false
|
35
|
+
|
36
|
+
# Iterate over a list of keys to avoid the iterator being impacted by deletes
|
37
|
+
@contacts.keys.each do |id|
|
38
|
+
if config_contact_ids.include? id
|
39
|
+
ret_val = true if @contacts[id].update(@config_obj)
|
40
|
+
|
41
|
+
# Delete the ID from the id array
|
42
|
+
# This will result in config_contact_ids being a list of IDs that need to be created at the end of the loop
|
43
|
+
config_contact_ids.delete(id)
|
44
|
+
else
|
45
|
+
# Delete contact from Flapjack
|
46
|
+
@contacts[id].delete
|
47
|
+
@contacts.delete(id)
|
48
|
+
ret_val = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add new contacts to Flapjack
|
53
|
+
config_contact_ids.each do |new_id|
|
54
|
+
contact_obj = FlapjackContact.new(new_id, nil, @diner, @logger)
|
55
|
+
contact_obj.update(@config_obj)
|
56
|
+
@contacts[new_id] = contact_obj
|
57
|
+
end
|
58
|
+
|
59
|
+
# Return true if changes made
|
60
|
+
return ret_val || config_contact_ids.length > 0
|
61
|
+
end
|
62
|
+
|
63
|
+
# Ensure the ALL entity is present
|
64
|
+
# http://flapjack.io/docs/1.0/usage/Howto-Dynamic-Entity-Contact-Linking/
|
65
|
+
def add_all_entity
|
66
|
+
return false if @diner.entities('ALL')
|
67
|
+
@logger.info('Creating the ALL magic entity')
|
68
|
+
fail('Failed to create ALL entity') unless @diner.create_entities(id: 'ALL', name: 'ALL')
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'flapjack_object_base.rb'
|
4
|
+
require_relative 'flapjack_media.rb'
|
5
|
+
require_relative 'flapjack_pagerduty.rb'
|
6
|
+
require_relative 'flapjack_notification_rule.rb'
|
7
|
+
|
8
|
+
module FlapjackConfigurator
|
9
|
+
# Class representing a Flapjack contact
|
10
|
+
class FlapjackContact < FlapjackObjectBase
|
11
|
+
attr_reader :media
|
12
|
+
|
13
|
+
def initialize(my_id, current_config, diner, logger, current_media = [], current_notification_rules = [])
|
14
|
+
@diner = diner
|
15
|
+
@logger = logger
|
16
|
+
super(my_id, current_config, diner.method(:contacts), diner.method(:create_contacts), diner.method(:update_contacts), diner.method(:delete_contacts), logger, 'contact')
|
17
|
+
|
18
|
+
# Select our media out from a premade hash of all media built from a single API call
|
19
|
+
@media = current_media.select { |m| m.config[:links][:contacts].include? id }
|
20
|
+
|
21
|
+
# Select notification rules the same way.
|
22
|
+
@notification_rules = current_notification_rules.select { |m| m.config[:links][:contacts].include? id }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Update all the things
|
26
|
+
def update(config_obj)
|
27
|
+
ret_val = false
|
28
|
+
ret_val = true if update_attributes(config_obj)
|
29
|
+
ret_val = true if update_entities(config_obj)
|
30
|
+
ret_val = true if update_media(config_obj)
|
31
|
+
ret_val = true if update_notification_rules(config_obj)
|
32
|
+
return ret_val
|
33
|
+
end
|
34
|
+
|
35
|
+
# Define our own _create as it doesn't use an ID
|
36
|
+
def _create(config)
|
37
|
+
fail("Object #{id} exists") if @obj_exists
|
38
|
+
# AFAIK there is not an easy way to convert hash keys to symbols outside of Rails
|
39
|
+
config.each { |k, v| @config[k.to_sym] = v }
|
40
|
+
@logger.info("Creating contact #{id} with config #{@config}")
|
41
|
+
fail "Failed to create contact #{id}" unless @create_method.call([@config])
|
42
|
+
_reload_config
|
43
|
+
|
44
|
+
# Creating an entity auto generates notification rules
|
45
|
+
# Regenerate the notification rules
|
46
|
+
@notification_rules = []
|
47
|
+
@config[:links][:notification_rules].each do |nr_id|
|
48
|
+
@notification_rules << FlapjackNotificationRule.new(nr_id, nil, @diner, @logger)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Update attributes from the config, creating the contact if needed
|
53
|
+
# (Chef definition of "update")
|
54
|
+
# Does not handle entites or notifications
|
55
|
+
def update_attributes(config_obj)
|
56
|
+
@logger.debug("Updating attributes for contact #{id}")
|
57
|
+
if @obj_exists
|
58
|
+
return _update(config_obj.contact_config(id)['details'])
|
59
|
+
else
|
60
|
+
_create(config_obj.contact_config(id)['details'])
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Update entities for the contact, creating or removing as needed
|
66
|
+
def update_entities(config_obj)
|
67
|
+
fail("Contact #{id} doesn't exist yet") unless @obj_exists
|
68
|
+
@logger.debug("Updating entities for contact #{id}")
|
69
|
+
|
70
|
+
wanted_entities = config_obj.entity_map.entities_for_contact(id)
|
71
|
+
current_entities = @config[:links][:entities]
|
72
|
+
ret_val = false
|
73
|
+
|
74
|
+
(wanted_entities - current_entities).each do |entity_id|
|
75
|
+
@logger.info("Associating entity #{entity_id} to contact #{id}")
|
76
|
+
fail("Failed to add entity #{entity_id} to contact #{id}") unless @diner.update_contacts(id, add_entity: entity_id)
|
77
|
+
ret_val = true
|
78
|
+
end
|
79
|
+
|
80
|
+
(current_entities - wanted_entities).each do |entity_id|
|
81
|
+
@logger.info("Removing entity #{entity_id} from contact #{id}")
|
82
|
+
fail("Failed to remove entity #{entity_id} from contact #{id}") unless @diner.update_contacts(id, remove_entity: entity_id)
|
83
|
+
ret_val = true
|
84
|
+
end
|
85
|
+
|
86
|
+
_reload_config
|
87
|
+
return ret_val
|
88
|
+
end
|
89
|
+
|
90
|
+
# Update the media for the contact
|
91
|
+
def update_media(config_obj)
|
92
|
+
@logger.debug("Updating media for contact #{id}")
|
93
|
+
media_config = config_obj.media(id)
|
94
|
+
ret_val = false
|
95
|
+
|
96
|
+
media_config_types = media_config.keys
|
97
|
+
@media.each do |media_obj|
|
98
|
+
if media_config_types.include? media_obj.type
|
99
|
+
ret_val = true if media_obj.update(media_config[media_obj.type])
|
100
|
+
# Delete the ID from the type array. This will result in media_config_types being a list of types that need to be created at the end of the loop
|
101
|
+
media_config_types.delete(media_obj.type)
|
102
|
+
else
|
103
|
+
media_obj.delete
|
104
|
+
ret_val = true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Delete outside the loop as deleting inside the loop messes up the each iterator
|
109
|
+
@media.delete_if { |obj| !obj.obj_exists }
|
110
|
+
|
111
|
+
media_config_types.each do |type|
|
112
|
+
# Pagerduty special case again
|
113
|
+
# TODO: Push this back up so that the if isn't done here
|
114
|
+
if type == 'pagerduty'
|
115
|
+
media_obj = FlapjackPagerduty.new(nil, @diner, @logger)
|
116
|
+
media_obj.create(id, media_config[type])
|
117
|
+
else
|
118
|
+
media_obj = FlapjackMedia.new(nil, @diner, @logger)
|
119
|
+
media_obj.create(id, type, media_config[type])
|
120
|
+
end
|
121
|
+
@media << media_obj
|
122
|
+
end
|
123
|
+
|
124
|
+
return ret_val || media_config_types.length > 0
|
125
|
+
end
|
126
|
+
|
127
|
+
def update_notification_rules(config_obj)
|
128
|
+
@logger.debug("Updating notification rules for contact #{id}")
|
129
|
+
nr_config = config_obj.notification_rules(id)
|
130
|
+
nr_config_ids = nr_config.keys
|
131
|
+
ret_val = false
|
132
|
+
|
133
|
+
@notification_rules.each do |nr_obj|
|
134
|
+
if nr_config_ids.include? nr_obj.id
|
135
|
+
ret_val = true if nr_obj.update(nr_config[nr_obj.id])
|
136
|
+
# Delete the ID from the type array. This will result in nr_config_ids being a list of types that need to be created at the end of the loop
|
137
|
+
nr_config_ids.delete(nr_obj.id)
|
138
|
+
else
|
139
|
+
nr_obj.delete
|
140
|
+
ret_val = true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Delete outside the loop as deleting inside the loop messes up the each iterator
|
145
|
+
@notification_rules.delete_if { |obj| !obj.obj_exists }
|
146
|
+
|
147
|
+
nr_config_ids.each do |nr_id|
|
148
|
+
nr_obj = FlapjackNotificationRule.new(nr_id, nil, @diner, @logger)
|
149
|
+
nr_obj.create(id, nr_config[nr_id])
|
150
|
+
@notification_rules << (nr_obj)
|
151
|
+
end
|
152
|
+
|
153
|
+
return ret_val || nr_config_ids.length > 0
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'flapjack_sub_object_base.rb'
|
4
|
+
|
5
|
+
module FlapjackConfigurator
|
6
|
+
# Class representing Flapjack media
|
7
|
+
class FlapjackMedia < FlapjackSubObjectBase
|
8
|
+
def initialize(current_config, diner, logger)
|
9
|
+
super(nil, current_config, diner.method(:media), diner.method(:create_contact_media), diner.method(:update_media), diner.method(:delete_media), logger, 'media')
|
10
|
+
@allowed_config_keys = [:address, :interval, :rollup_threshold]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Create a new entry
|
14
|
+
def create(contact_id, type, config)
|
15
|
+
_create(contact_id, _filter_config(config).merge(type: type))
|
16
|
+
end
|
17
|
+
|
18
|
+
# Helper to return the type
|
19
|
+
def type
|
20
|
+
return @config[:type]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'flapjack_sub_object_base.rb'
|
4
|
+
|
5
|
+
module FlapjackConfigurator
|
6
|
+
# Class representing notification rules
|
7
|
+
class FlapjackNotificationRule < FlapjackSubObjectBase
|
8
|
+
def initialize(conf_id, current_config, diner, logger)
|
9
|
+
super(conf_id, current_config, diner.method(:notification_rules), diner.method(:create_contact_notification_rules), diner.method(:update_notification_rules),
|
10
|
+
diner.method(:delete_notification_rules), logger, 'notification rule')
|
11
|
+
end
|
12
|
+
|
13
|
+
def create(contact_id, config)
|
14
|
+
# Flapjack will let you create a notification rule object with no attributes, but that sets nils whereas
|
15
|
+
# the default it creates has empty arrays.
|
16
|
+
# Set up a baseline config that matches what Flapjack creates by default
|
17
|
+
full_config = {
|
18
|
+
id: id,
|
19
|
+
tags: [],
|
20
|
+
regex_tags: [],
|
21
|
+
entities: [],
|
22
|
+
regex_entities: [],
|
23
|
+
time_restrictions: [],
|
24
|
+
warning_media: nil,
|
25
|
+
critical_media: nil,
|
26
|
+
unknown_media: nil,
|
27
|
+
unknown_blackhole: false,
|
28
|
+
warning_blackhole: false,
|
29
|
+
critical_blackhole: false
|
30
|
+
}.merge(config)
|
31
|
+
|
32
|
+
_create(contact_id, full_config)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update(config)
|
36
|
+
return _update(config)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module FlapjackConfigurator
|
4
|
+
# Baseline class representing a Flapjack object
|
5
|
+
class FlapjackObjectBase
|
6
|
+
attr_reader :config, :obj_exists
|
7
|
+
|
8
|
+
def initialize(my_id, current_config, getter_method, create_method, update_method, delete_method, logger, log_name)
|
9
|
+
@config = {}
|
10
|
+
@logger = logger
|
11
|
+
@log_name = log_name # A user friendly name for log entries
|
12
|
+
|
13
|
+
@getter_method = getter_method
|
14
|
+
@create_method = create_method
|
15
|
+
@update_method = update_method
|
16
|
+
@delete_method = delete_method
|
17
|
+
|
18
|
+
# Load the object from the API if needed
|
19
|
+
# The current config from Flapjack is passable to avoid polling the API for each individual contact
|
20
|
+
if my_id
|
21
|
+
@config[:id] = my_id
|
22
|
+
current_config = _load_from_api(my_id) unless current_config
|
23
|
+
end
|
24
|
+
|
25
|
+
if current_config
|
26
|
+
@config.merge! current_config
|
27
|
+
@obj_exists = true
|
28
|
+
else
|
29
|
+
@obj_exists = false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Load the config from the API
|
34
|
+
def _load_from_api(my_id)
|
35
|
+
api_data = @getter_method.call(my_id)
|
36
|
+
return nil unless api_data
|
37
|
+
|
38
|
+
fail "Unexpected number of responses for #{@log_name} #{my_id}" unless api_data.length == 1
|
39
|
+
return api_data[0]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Simple helper to return the ID
|
43
|
+
def id
|
44
|
+
return @config[:id]
|
45
|
+
end
|
46
|
+
|
47
|
+
def _reload_config
|
48
|
+
my_id = id
|
49
|
+
api_obj = @getter_method.call(my_id)
|
50
|
+
fail "Config reload failed for config ID #{my_id}: not found" unless api_obj
|
51
|
+
@config = api_obj[0]
|
52
|
+
fail "Config reload failed for config ID #{my_id}: parse error" unless @config
|
53
|
+
@obj_exists = true
|
54
|
+
end
|
55
|
+
|
56
|
+
# No base create object as the method arguments differ too much.
|
57
|
+
|
58
|
+
# Update the object
|
59
|
+
def _update(config)
|
60
|
+
fail("Object #{id} doesn't exist") unless @obj_exists
|
61
|
+
change_list = {}
|
62
|
+
config.each do |k, v|
|
63
|
+
k_sym = k.to_sym
|
64
|
+
if @config[k_sym] != v
|
65
|
+
change_list[k_sym] = v
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return false if change_list.empty?
|
70
|
+
|
71
|
+
@logger.info("Updating #{@log_name} #{id}")
|
72
|
+
@logger.debug("#{@log_name} #{id} changes: #{change_list}")
|
73
|
+
fail "Failed to update #{id}" unless @update_method.call(id, change_list)
|
74
|
+
_reload_config
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
|
78
|
+
# Delete the object
|
79
|
+
def delete
|
80
|
+
fail("Object #{id} doesn't exist") unless @obj_exists
|
81
|
+
@logger.info("Deleting #{@log_name} #{id}")
|
82
|
+
fail "Failed to delete #{id}" unless @delete_method.call(id)
|
83
|
+
@obj_exists = false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|