[PATCH conductor] #3391 Represent the relationships between instances

Jan Provaznik jprovazn at redhat.com
Mon Jul 23 09:57:15 UTC 2012


On 07/13/2012 09:14 PM, Dan Radez wrote:
> On 07/13/2012 02:22 PM, Jan Provazník wrote:
>> On 07/04/2012 06:03 PM, jzigmund at redhat.com wrote:
>>> From: Jozef Zigmund <jzigmund at redhat.com>
>>>
>>> ---
>>>    src/Gemfile.in                                     |    1 +
>>>    src/app/controllers/deployables_controller.rb      |   13 +++++++
>>>    src/app/models/deployable.rb                       |    1 +
>>>    src/app/util/deployable_xml.rb                     |   35
>>> ++++++++++++++++++++
>>>    .../deployables/service_dependencies.html.haml     |   11 ++++++
>>>    src/app/views/deployables/show.html.haml           |    1 +
>>>    src/config/initializers/mime_types.rb              |    1 +
>>>    src/config/locales/en.yml                          |    1 +
>>>    src/config/routes.rb                               |    1 +
>>>    9 files changed, 65 insertions(+), 0 deletions(-)
>>>    create mode 100644
>>> src/app/views/deployables/service_dependencies.html.haml
>>>
>>> diff --git a/src/Gemfile.in b/src/Gemfile.in
>>> index 1d90a91..7bb3704 100644
>>> --- a/src/Gemfile.in
>>> +++ b/src/Gemfile.in
>>> @@ -23,6 +23,7 @@ gem 'compass'
>>>    gem 'compass-960-plugin', :require=> 'ninesixty'
>>>    gem 'delayed_job', '~> 2.1.4'
>>>    gem 'paranoia'
>>> +gem 'graphviz'
>>>
>>>    platforms :ruby_18 do
>>>      gem 'fastercsv'
>>> diff --git a/src/app/controllers/deployables_controller.rb
>>> b/src/app/controllers/deployables_controller.rb
>>> index 3e3b76a..e4d3f91 100644
>>> --- a/src/app/controllers/deployables_controller.rb
>>> +++ b/src/app/controllers/deployables_controller.rb
>>> @@ -283,6 +283,19 @@ class DeployablesController < ApplicationController
>>>        redirect_to_original({"deployables_preset_filter" =>
>>> params[:deployables_preset_filter], "deployables_search" =>
>>> params[:deployables_search]})
>>>      end
>>>
>>> +  def service_dependencies
>>> +    deployable = Deployable.find(params[:id])
>>> +    deployable_xml = DeployableXML.new(deployable.xml)
>>> +    respond_to do |format|
>>> +      format.html do
>>> +        render :locals => {:deployable => deployable}
>>> +      end
>>> +      format.png do
>>> +        render :text => deployable_xml.display_digraph
>>> +      end
>>> +    end
>>> +  end
>>> +
>>>      private
>>>
>>>      def set_header
>>> diff --git a/src/app/models/deployable.rb b/src/app/models/deployable.rb
>>> index 9c6aff9..b052b44 100644
>>> --- a/src/app/models/deployable.rb
>>> +++ b/src/app/models/deployable.rb
>>> @@ -15,6 +15,7 @@
>>>    #
>>>
>>>    require 'util/conductor'
>>> +require 'util/deployable_xml'
>>>
>>>    class Deployable < ActiveRecord::Base
>>>      class << self
>>> diff --git a/src/app/util/deployable_xml.rb
>>> b/src/app/util/deployable_xml.rb
>>> index cdbbc39..ab46251 100644
>>> --- a/src/app/util/deployable_xml.rb
>>> +++ b/src/app/util/deployable_xml.rb
>>> @@ -17,6 +17,7 @@
>>>    =begin
>>>    XML Wrapper objects for the deployable XML format
>>>    =end
>>> +require "graphviz"
>>>
>>>    class ValidationError < RuntimeError; end
>>>
>>> @@ -100,6 +101,8 @@ end
>>>
>>>    class AssemblyXML
>>>
>>> +  attr_accessor :root
>>> +
>>>      def initialize(xmlstr_or_node = "")
>>>        if xmlstr_or_node.is_a? Nokogiri::XML::Node
>>>          @root = xmlstr_or_node
>>> @@ -202,6 +205,38 @@ class DeployableXML
>>>        @relax_file =
>>> "#{File.dirname(File.expand_path(__FILE__))}/deployable-rng.xml"
>>>      end
>>>
>>> +  def display_digraph
>>> +    graph = GraphViz.new(:G, :type => :digraph)
>>> +    if has_reference?
>>> +      draw_nodes(graph)
>>> +      draw_edges(graph)
>>> +    else
>>> +      draw_nodes(graph)
>>> +    end
>>> +    graph.output :png => String
>>> +  end
>>> +
>>> +  def draw_nodes(graph)
>>> +    assemblies.each do |assembly|
>>> +      graph.add_node(assembly.name)
>>> +    end
>>> +  end
>>> +
>>> +  def draw_edges(graph)
>>> +    assemblies.each do |assembly|
>>> +      references = assembly.root.xpath(".//reference")
>>> +      unless references.empty?
>>> +        references.each do |reference|
>>> +          graph.add_edge(assembly.name,
>>> reference.attributes['assembly'].value)
>>> +        end
>>> +      end
>>> +    end
>>> +  end
>>> +
>>> +  def has_reference?
>>> +     not @root.xpath("//reference").empty?
>>> +  end
>>> +
>>>      def name
>>>        @root["name"] if @root
>>>      end
>>> diff --git a/src/app/views/deployables/service_dependencies.html.haml
>>> b/src/app/views/deployables/service_dependencies.html.haml
>>> new file mode 100644
>>> index 0000000..075de04
>>> --- /dev/null
>>> +++ b/src/app/views/deployables/service_dependencies.html.haml
>>> @@ -0,0 +1,11 @@
>>> += render :partial => 'layouts/admin_nav'
>>> +%header.page-header
>>> +  .obj_actions
>>> +    .button-group
>>> +      - if check_privilege(Privilege::MODIFY, deployable)
>>> +        = link_to t('deployables.show.edit'),
>>> edit_polymorphic_path([@catalog, deployable]), :class => 'button', :id
>>> => 'edit_button'
>>> +        = link_to t('deployables.show.edit_xml'),
>>> edit_polymorphic_path([@catalog, deployable], :edit_xml => true),
>>> :class => 'button', :id => 'edit_xml_button'
>>> +        = button_to t('delete'), polymorphic_path([@catalog,
>>> deployable]), :method => 'delete', :confirm =>
>>> "#{t'catalog_entries.show.confirm_delete'}", :class => 'button
>>> danger', :id => 'delete'
>>> +  %h1.catalog_entries= deployable.name
>>> +%p
>>> +  = image_tag(service_dependencies_deployable_path(deployable,
>>> :format => :png))
>>> \ No newline at end of file
>>> diff --git a/src/app/views/deployables/show.html.haml
>>> b/src/app/views/deployables/show.html.haml
>>> index a7ee021..d28db60 100644
>>> --- a/src/app/views/deployables/show.html.haml
>>> +++ b/src/app/views/deployables/show.html.haml
>>> @@ -3,6 +3,7 @@
>>>      .obj_actions
>>>        .button-group
>>>          - if check_privilege(Privilege::MODIFY, @deployable)
>>> +        = link_to t(".dependencies_diagram"),
>>> service_dependencies_deployable_path(@deployable, :catalog_id =>
>>> @catalog, :pushed_count => @pushed_count), :class => 'button'
>>>            = link_to t('.edit'), edit_polymorphic_path([@catalog,
>>> @deployable]), :class => 'button', :id => 'edit_button'
>>>            = link_to t('.edit_xml'), edit_polymorphic_path([@catalog,
>>> @deployable], :edit_xml => true), :class => 'button', :id =>
>>> 'edit_xml_button'
>>>            = button_to t('.delete'), polymorphic_path([@catalog,
>>> @deployable]), :method => 'delete', :confirm =>
>>> "#{t'catalog_entries.show.confirm_delete'}", :class => 'button
>>> danger', :id => 'delete'
>>> diff --git a/src/config/initializers/mime_types.rb
>>> b/src/config/initializers/mime_types.rb
>>> index 18ecf33..bd77cce 100644
>>> --- a/src/config/initializers/mime_types.rb
>>> +++ b/src/config/initializers/mime_types.rb
>>> @@ -20,3 +20,4 @@
>>>    # Mime::Type.register "text/richtext", :rtf
>>>    # Mime::Type.register_alias "text/html", :iphone
>>>    Mime::Type.register "image/svg+xml", :svg
>>> +Mime::Type.register "image/png", :png
>>> diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
>>> index 9295373..1684721 100644
>>> --- a/src/config/locales/en.yml
>>> +++ b/src/config/locales/en.yml
>>> @@ -1036,6 +1036,7 @@ en:
>>>          n_a: "N/A"
>>>          uuids: "UUIDs"
>>>          show_hide_uuids: "Show/Hide"
>>> +      dependencies_diagram: Dependencies Diagram
>>>        form:
>>>          choose_xml: Choose Deployable XML file
>>>          catalog: Catalog
>>> diff --git a/src/config/routes.rb b/src/config/routes.rb
>>> index e7f26c5..18ed7f2 100644
>>> --- a/src/config/routes.rb
>>> +++ b/src/config/routes.rb
>>> @@ -237,6 +237,7 @@ Conductor::Application.routes.draw do
>>>        end
>>>        member do
>>>          get :definition
>>> +      get :service_dependencies
>>>        end
>>>      end
>>>
>>>
>>
>> Hi Jozef,
>> I didn't have time to do a proper review yet, but have a few findings
>> about this so far:
>> - graphviz has many pkg dependencies (it added 41 new pkgs). Maybe it
>> could be optional - if graphviz is not installed, one some warning about
>> missing graphviz would be displayed.
>> - there is also already packaged graphviz-ruby gem - couldn't this be
>> used? I didn't check this, maybe it's not sufficient, but it could save
>> us some packaging
>> - it seems that this code generates dependencies between assemblies,
>> what we need are dependencies between services: so nodes would be
>> services, edges would represent param references, assembly would be
>> represented by a frame around services belonging to this assembly.
>>
>> I checked deployable xml schema and what confuses me is that it seems
>> that a service param can reference a service _or_ an assembly (according
>> to param definition in app/util/deployable-rng.xml). If a param
>> references assembly, then we can't resolve dependencies between
>> services. Dan, you are most familiar with this - what do you think about
>> it? As I understand it, referencing whole assemblies should be disabled.
>>
>> Jan
>
> Services can depend on other services with in the same assembly. We
> don't have code that allows cross assembly references. If you are going
> to represent relationships do it service to service within an assembly.
>
> There was talk to allow cross assembly relationships, but I doubt it
> will ever come to fruition.
>

Hm, from what I know, Audrey now waits with launching services of an 
assembly until all params for all services of the assembly are gathered. 
So if assembly1 references assembly2, assembly2 can't reference 
(directly or indirectly) assembly1 because of deadlock. Isn't it too big 
limitation?

Anyway, in current situation, conductor should make sure that:
- there is no deadlock between services in an assembly
- there is no deadlock between whole assemblies
Right?

> Visual representation of the relationships is a cool idea.
>
> Dan
>



More information about the aeolus-devel mailing list