diff --git a/crowbar_framework/app/models/node_object.rb b/crowbar_framework/app/models/node_object.rb index 456d04edc0..97b9c4dc8b 100644 --- a/crowbar_framework/app/models/node_object.rb +++ b/crowbar_framework/app/models/node_object.rb @@ -16,6 +16,7 @@ # require "chef/mixin/deep_merge" +require "set" require "timeout" require "open3" @@ -259,6 +260,7 @@ def initialize(node) end # deep clone of @role.default_attributes, used when saving node @attrs_last_saved = @role.default_attributes.deep_dup + @attributes_changed_for_event = Set.new @node = node end @@ -289,7 +291,10 @@ def availability_zone def availability_zone=(value) @node["crowbar_wall"] ||= {} @node["crowbar_wall"]["openstack"] ||= {} - @node["crowbar_wall"]["openstack"]["availability_zone"] = value + if @node["crowbar_wall"]["openstack"]["availability_zone"] != value + @node["crowbar_wall"]["openstack"]["availability_zone"] = value + @attributes_changed_for_event.add("availability_zone") + end end def intended_role @@ -479,6 +484,7 @@ def validate_public_name(value, unique_check = true) def update_public_name(value) unless value.nil? crowbar["crowbar"]["public_name"] = value + @attributes_changed_for_event.add("public_name") end end @@ -835,6 +841,20 @@ def _remove_elements_from_node(old, new, from_node) @attrs_last_saved = @role.default_attributes.deep_dup Rails.logger.debug("Done saving node: #{@node.name} - #{crowbar_revision}") + + unless @attributes_changed_for_event.empty? + Rails.logger.debug("Notifying about saved node: #{@node.name}") + + details = { + node: @node.name, + attributes: @attributes_changed_for_event + } + Crowbar::EventDispatcher.trigger_hooks(:node_changed, details) + + @attributes_changed_for_event = Set.new + + Rails.logger.debug("Done notifying about saved node: #{@node.name}") + end end def destroy diff --git a/crowbar_framework/app/models/service_object.rb b/crowbar_framework/app/models/service_object.rb index 0383ad1522..fc28f74b5f 100644 --- a/crowbar_framework/app/models/service_object.rb +++ b/crowbar_framework/app/models/service_object.rb @@ -1348,6 +1348,13 @@ def apply_role(role, inst, in_queue, bootstrap = false) proposal.save unless roles_to_remove.empty? update_proposal_status(inst, "success", "") + + details = { + barclamp: @bc_name, + instance: inst + } + Crowbar::EventDispatcher.trigger_hooks(:proposal_applied, details) + [200, {}] rescue StandardError => e @logger.fatal("apply_role: Uncaught exception #{e.message} #{e.backtrace.join("\n")}") diff --git a/crowbar_framework/lib/crowbar/event_dispatcher.rb b/crowbar_framework/lib/crowbar/event_dispatcher.rb new file mode 100644 index 0000000000..d38c91d607 --- /dev/null +++ b/crowbar_framework/lib/crowbar/event_dispatcher.rb @@ -0,0 +1,48 @@ +# +# Copyright 2017, SUSE +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module Crowbar + class EventDispatcher + class << self + def trigger_hooks(event, details) + BarclampCatalog.barclamps.keys.each do |barclamp| + begin + cls = ServiceObject.get_service(barclamp) + rescue NameError + # catalog may contain barclamps which don't have services + next + end + + next unless cls.method_defined?(:event_hook) + + service = cls.new(Rails.logger) + + proposals = Proposal.where(barclamp: barclamp) + proposals.each do |proposal| + role = proposal.role + next if role.nil? + begin + service.event_hook(role, event, details) + rescue StandardError => e + raise "Error while executing event hook of #{barclamp} for #{event}: #{e.message}" + end + end + end + end + handle_asynchronously :trigger_hooks + end + end +end