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.
- 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
|