Hi Marc,
> Hello together,
> currently I'm looking into the plugin concept of foreman.
> I took a look at the hubot_notify plugin and the isratrade /
> foreman_plugin_template.
>
> I was even successful to write a plugin that would execute a given
> command when a system was provisioned.
>
> As far as I understand it the concept is based on the RAILS 3
> ActiveSupport/Concern pattern.
>
> Now I tried to imagine how it would be if one would want to provide two
> plugins that hook in the same functionality.
>
> Like for example:
> After provisioning of a host I'd like to both execute a given command
> and for example update a provision ticket in either Jira or Redmine (or
> what ever).
>
> So I'll end up with two different plugins both extending the same
> Module/Class UnattendedController.
>
> Background is that my idea was to have modular plugins that can be
> combined if need be.
>
> Let's say one would like to change a Redmine ticket instead of a JIRA
> one but would still like to execute the given command.
> That means using two plugins that extend the same module/class.
>
> Has anybody any idea on how to do that without having to write the same
> code multiple times and being quite flexible? I couldn't find any
> directions on this.
I wrote a plugin recently called foreman_hooks that might solve this for
you. It's a generic plugin that can then call all scripts in a
directory based on any event in Foreman, so you can then easily add
multiple scripts for different tasks.
You're right though, if you're writing it as actual plugins, there will
be a small duplication in extending or observing a particular class, but
it should be relatively small. The bulk of the work I think is in
having separate projects, gems etc for each individual hook, so having
one plugin for this would help.
Anyway, foreman_hooks is here:
It runs hooks both on model events in Rails (e.g. after_save,
before_destroy) plus can extend the host orchestration framework in
Foreman, which is probably the most useful feature.
You'd create a script such as:
~foreman/config/hooks/host/create/50_register_system.sh
Then the script gets called with two parameters. The first is either
"create", "update" or "destroy", which you should use to handle your
event (note that Foreman orchestration will roll back if there's a
subsequent failure, so you might get a "create" followed by "destroy").
The second is the name of the object, e.g. the hostname.
A task for tomorrow is to write this up in a blog post with an example,
maybe a small screencast too. I'd be interested in your feedback!
···
On 04/04/13 10:21, Marc Grimme wrote:
–
Dominic Cleal
Red Hat Engineering
Hi Dominic,
this pretty much looks like what I had in mind for the script execution.
The only thing that I don't "like" is the limited information inside the
scripts.
I decided to either pass the host as yaml to stdin of the script or use
some kind of self parsed command line (still under construction).
Means:
cmd=SETTINGS[:pluginExecCmd][params['action']] ||
SETTINGS[:pluginExecCmd][:cmd] || "cat"
logger.debug "Executing cmd #{cmd}"
if ! SETTINGS[:pluginExecCmd][params['action']+"_aspipe"] && !
SETTINGS[:pluginExecCmd][:cmd_aspipe] then
#{cmd}
else
IO.popen("#{cmd}", mode="r+") do |io|
io.write @host.to_yaml
io.close_write
puts io.read
end
end
end
The background is that I'd need more information then just the hostname to
be created.
But I think this could be easily added to your gem.
At least more or less like above.
And back to the plugins problem:
Let's say you have one plugin that would add the VMware guest's notes to
the host summary or the host edit pages (cause this is something only
needed by few people) and there is another plugin that adds some data to
the host collected from some kind of CMDB (or the like). I wouldn't want to
have both functionalities in the same plugin. As for the modularisation of
both.
So that would also be a use case where the combination of two plugins
overwriting the same functionality could be handy.
And that's why I think this is a real cool solution if this combination is
possible.
What do you think?
Regards Marc.
···
On Thursday, April 4, 2013 11:58:10 AM UTC+2, Dominic Cleal wrote:
>
> Hi Marc,
>
> On 04/04/13 10:21, Marc Grimme wrote:
> > Hello together,
> > currently I'm looking into the plugin concept of foreman.
> > I took a look at the hubot_notify plugin and the isratrade /
> > foreman_plugin_template.
> >
> > I was even successful to write a plugin that would execute a given
> > command when a system was provisioned.
> >
> > As far as I understand it the concept is based on the RAILS 3
> > ActiveSupport/Concern pattern.
> >
> > Now I tried to imagine how it would be if one would want to provide two
> > plugins that hook in the same functionality.
> >
> > Like for example:
> > After provisioning of a host I'd like to both execute a given command
> > and for example update a provision ticket in either Jira or Redmine (or
> > what ever).
> >
> > So I'll end up with two different plugins both extending the same
> > Module/Class UnattendedController.
> >
> > Background is that my idea was to have modular plugins that can be
> > combined if need be.
> >
> > Let's say one would like to change a Redmine ticket instead of a JIRA
> > one but would still like to execute the given command.
> > That means using two plugins that extend the same module/class.
> >
> > Has anybody any idea on how to do that without having to write the same
> > code multiple times and being quite flexible? I couldn't find any
> > directions on this.
>
> I wrote a plugin recently called foreman_hooks that might solve this for
> you. It's a generic plugin that can then call all scripts in a
> directory based on any event in Foreman, so you can then easily add
> multiple scripts for different tasks.
>
> You're right though, if you're writing it as actual plugins, there will
> be a small duplication in extending or observing a particular class, but
> it should be relatively small. The bulk of the work I think is in
> having separate projects, gems etc for each individual hook, so having
> one plugin for this would help.
>
> Anyway, foreman_hooks is here:
> https://github.com/domcleal/foreman_hooks
>
> It runs hooks both on model events in Rails (e.g. after_save,
> before_destroy) plus can extend the host orchestration framework in
> Foreman, which is probably the most useful feature.
>
> You'd create a script such as:
> ~foreman/config/hooks/host/create/50_register_system.sh
>
> Then the script gets called with two parameters. The first is either
> "create", "update" or "destroy", which you should use to handle your
> event (note that Foreman orchestration will roll back if there's a
> subsequent failure, so you might get a "create" followed by "destroy").
> The second is the name of the object, e.g. the hostname.
>
> A task for tomorrow is to write this up in a blog post with an example,
> maybe a small screencast too. I'd be interested in your feedback!
>
> --
> Dominic Cleal
> Red Hat Engineering
>
> Hi Marc,
>
>> Hello together,
>> currently I'm looking into the plugin concept of foreman.
>> I took a look at the hubot_notify plugin and the isratrade /
>> foreman_plugin_template.
>>
>> I was even successful to write a plugin that would execute a given
>> command when a system was provisioned.
>>
>> As far as I understand it the concept is based on the RAILS 3
>> ActiveSupport/Concern pattern.
>>
>> Now I tried to imagine how it would be if one would want to provide two
>> plugins that hook in the same functionality.
>>
>> Like for example:
>> After provisioning of a host I'd like to both execute a given command
>> and for example update a provision ticket in either Jira or Redmine (or
>> what ever).
>>
>> So I'll end up with two different plugins both extending the same
>> Module/Class UnattendedController.
>>
>> Background is that my idea was to have modular plugins that can be
>> combined if need be.
>>
>> Let's say one would like to change a Redmine ticket instead of a JIRA
>> one but would still like to execute the given command.
>> That means using two plugins that extend the same module/class.
>>
>> Has anybody any idea on how to do that without having to write the same
>> code multiple times and being quite flexible? I couldn't find any
>> directions on this.
>
> I wrote a plugin recently called foreman_hooks that might solve this for
> you. It's a generic plugin that can then call all scripts in a
> directory based on any event in Foreman, so you can then easily add
> multiple scripts for different tasks.
>
> You're right though, if you're writing it as actual plugins, there will
> be a small duplication in extending or observing a particular class, but
> it should be relatively small. The bulk of the work I think is in
> having separate projects, gems etc for each individual hook, so having
> one plugin for this would help.
>
> Anyway, foreman_hooks is here:
> https://github.com/domcleal/foreman_hooks
>
> It runs hooks both on model events in Rails (e.g. after_save,
> before_destroy) plus can extend the host orchestration framework in
> Foreman, which is probably the most useful feature.
Did you include the after/before provisioning hooks (e.g. when a node
enable / disable build?)
Ohad
···
On Thu, Apr 4, 2013 at 12:58 PM, Dominic Cleal wrote:
> On 04/04/13 10:21, Marc Grimme wrote:
>
> You'd create a script such as:
> ~foreman/config/hooks/host/create/50_register_system.sh
>
> Then the script gets called with two parameters. The first is either
> "create", "update" or "destroy", which you should use to handle your
> event (note that Foreman orchestration will roll back if there's a
> subsequent failure, so you might get a "create" followed by "destroy").
> The second is the name of the object, e.g. the hostname.
>
> A task for tomorrow is to write this up in a blog post with an example,
> maybe a small screencast too. I'd be interested in your feedback!
>
> --
> Dominic Cleal
> Red Hat Engineering
>
> --
> You received this message because you are subscribed to the Google Groups "Foreman users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to foreman-users+unsubscribe@googlegroups.com.
> To post to this group, send email to foreman-users@googlegroups.com.
> Visit this group at http://groups.google.com/group/foreman-users?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
> Hi Dominic,
> this pretty much looks like what I had in mind for the script execution.
> The only thing that I don't "like" is the limited information inside the
> scripts.
> I decided to either pass the host as yaml to stdin of the script or use
> some kind of self parsed command line (still under construction).
> Means:
>
> cmd=SETTINGS[:pluginExecCmd][params['action']] ||
> SETTINGS[:pluginExecCmd][:cmd] || "cat"
> logger.debug "Executing cmd #{cmd}"
> if ! SETTINGS[:pluginExecCmd][params['action']+"_aspipe"] && !
> SETTINGS[:pluginExecCmd][:cmd_aspipe] then
> #{cmd}
> else
> IO.popen("#{cmd}", mode="r+") do |io|
> io.write @host.to_yaml
> io.close_write
> puts io.read
> end
> end
> end
>
> The background is that I'd need more information then just the hostname
> to be created.
> But I think this could be easily added to your gem.
> At least more or less like above.
Exactly. I have a branch in progress to pass in the JSON representation
via stdin, then you can use jgrep (or a small shell wrapper provided) to
get access to the data.
> And back to the plugins problem:
> Let's say you have one plugin that would add the VMware guest's notes to
> the host summary or the host edit pages (cause this is something only
> needed by few people) and there is another plugin that adds some data to
> the host collected from some kind of CMDB (or the like). I wouldn't want
> to have both functionalities in the same plugin. As for the
> modularisation of both.
>
> So that would also be a use case where the combination of two plugins
> overwriting the same functionality could be handy.
> And that's why I think this is a real cool solution if this combination
> is possible.
>
> What do you think?
I guess the key here is to push helpers into the core Foreman codebase
if we can, then adapt core code to use them. It would be great if not
every plugin had to rewrite how to add a button to a page from scratch.
···
On 04/04/13 14:46, Marc Grimme wrote:
–
Dominic Cleal
Red Hat Engineering
> Hi Dominic,
> this pretty much looks like what I had in mind for the script execution.
> The only thing that I don't "like" is the limited information inside the
> scripts.
> I decided to either pass the host as yaml to stdin of the script or use some
> kind of self parsed command line (still under construction).
> Means:
>
> cmd=SETTINGS[:pluginExecCmd][params['action']] ||
> SETTINGS[:pluginExecCmd][:cmd] || "cat"
> logger.debug "Executing cmd #{cmd}"
> if ! SETTINGS[:pluginExecCmd][params['action']+"_aspipe"] && !
> SETTINGS[:pluginExecCmd][:cmd_aspipe] then
> #{cmd}
> else
> IO.popen("#{cmd}", mode="r+") do |io|
> io.write @host.to_yaml
> io.close_write
> puts io.read
> end
> end
> end
>
> The background is that I'd need more information then just the hostname to
> be created.
> But I think this could be easily added to your gem.
> At least more or less like above.
>
> And back to the plugins problem:
> Let's say you have one plugin that would add the VMware guest's notes to the
> host summary or the host edit pages (cause this is something only needed by
> few people) and there is another plugin that adds some data to the host
> collected from some kind of CMDB (or the like). I wouldn't want to have both
> functionalities in the same plugin. As for the modularisation of both.
>
> So that would also be a use case where the combination of two plugins
> overwriting the same functionality could be handy.
> And that's why I think this is a real cool solution if this combination is
> possible.
>
> What do you think?
this makes a whole lot of sense, we could think of:
- expose JSON representing the host in ENV variable?
- consider calling the API during the event (that might introduce
some potential problems if you are using before statements when the db
transaction is not done yet).
Ohad
···
On Thu, Apr 4, 2013 at 4:46 PM, Marc Grimme wrote:
> Regards Marc.
>
> On Thursday, April 4, 2013 11:58:10 AM UTC+2, Dominic Cleal wrote:
>>
>> Hi Marc,
>>
>> On 04/04/13 10:21, Marc Grimme wrote:
>> > Hello together,
>> > currently I'm looking into the plugin concept of foreman.
>> > I took a look at the hubot_notify plugin and the isratrade /
>> > foreman_plugin_template.
>> >
>> > I was even successful to write a plugin that would execute a given
>> > command when a system was provisioned.
>> >
>> > As far as I understand it the concept is based on the RAILS 3
>> > ActiveSupport/Concern pattern.
>> >
>> > Now I tried to imagine how it would be if one would want to provide two
>> > plugins that hook in the same functionality.
>> >
>> > Like for example:
>> > After provisioning of a host I'd like to both execute a given command
>> > and for example update a provision ticket in either Jira or Redmine (or
>> > what ever).
>> >
>> > So I'll end up with two different plugins both extending the same
>> > Module/Class UnattendedController.
>> >
>> > Background is that my idea was to have modular plugins that can be
>> > combined if need be.
>> >
>> > Let's say one would like to change a Redmine ticket instead of a JIRA
>> > one but would still like to execute the given command.
>> > That means using two plugins that extend the same module/class.
>> >
>> > Has anybody any idea on how to do that without having to write the same
>> > code multiple times and being quite flexible? I couldn't find any
>> > directions on this.
>>
>> I wrote a plugin recently called foreman_hooks that might solve this for
>> you. It's a generic plugin that can then call all scripts in a
>> directory based on any event in Foreman, so you can then easily add
>> multiple scripts for different tasks.
>>
>> You're right though, if you're writing it as actual plugins, there will
>> be a small duplication in extending or observing a particular class, but
>> it should be relatively small. The bulk of the work I think is in
>> having separate projects, gems etc for each individual hook, so having
>> one plugin for this would help.
>>
>> Anyway, foreman_hooks is here:
>> https://github.com/domcleal/foreman_hooks
>>
>> It runs hooks both on model events in Rails (e.g. after_save,
>> before_destroy) plus can extend the host orchestration framework in
>> Foreman, which is probably the most useful feature.
>>
>> You'd create a script such as:
>> ~foreman/config/hooks/host/create/50_register_system.sh
>>
>> Then the script gets called with two parameters. The first is either
>> "create", "update" or "destroy", which you should use to handle your
>> event (note that Foreman orchestration will roll back if there's a
>> subsequent failure, so you might get a "create" followed by "destroy").
>> The second is the name of the object, e.g. the hostname.
>>
>> A task for tomorrow is to write this up in a blog post with an example,
>> maybe a small screencast too. I'd be interested in your feedback!
>>
>> --
>> Dominic Cleal
>> Red Hat Engineering
>
> --
> You received this message because you are subscribed to the Google Groups
> "Foreman users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to foreman-users+unsubscribe@googlegroups.com.
> To post to this group, send email to foreman-users@googlegroups.com.
> Visit this group at http://groups.google.com/group/foreman-users?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
> > The background is that I'd need more information then just the hostname
> > to be created.
> > But I think this could be easily added to your gem.
> > At least more or less like above.
>
> Exactly. I have a branch in progress to pass in the JSON representation
> via stdin, then you can use jgrep (or a small shell wrapper provided) to
> get access to the data.
>
Let me know when the branch has been moved from "in progress" state to
"ready for testing and being pushed"

Then I wont need to work on my plugin any further.
> >
> > So that would also be a use case where the combination of two plugins
> > overwriting the same functionality could be handy.
> > And that's why I think this is a real cool solution if this combination
> > is possible.
>
> I guess the key here is to push helpers into the core Foreman codebase
> if we can, then adapt core code to use them. It would be great if not
> every plugin had to rewrite how to add a button to a page from scratch.
>
Besides from the helper functions and back to the ActionSupport/Concern
approach.
I'm not - yet - that deep into Rails but is this not a Rails feature. And
shouldn't there already be a a solution in place for that kind of problems?
Or am I completely mistaken?
>
> –
> Dominic Cleal
> Red Hat Engineering
>
Marc.
···
On Thursday, April 4, 2013 5:29:45 PM UTC+2, Dominic Cleal wrote:
> On 04/04/13 14:46, Marc Grimme wrote:
It's not a hard coded list, it'll just add an observer to models in
config/hooks and then if a method's called on the observer and a hook
exists, then it will get run.
So yes, it should in theory. Haven't tested it (and need to figure out
how to test this actually).
···
On 04/04/13 11:32, Ohad Levy wrote:
> On Thu, Apr 4, 2013 at 12:58 PM, Dominic Cleal wrote:
>> Hi Marc,
>>
>> On 04/04/13 10:21, Marc Grimme wrote:
>>> Hello together,
>>> currently I'm looking into the plugin concept of foreman.
>>> I took a look at the hubot_notify plugin and the isratrade /
>>> foreman_plugin_template.
>>>
>>> I was even successful to write a plugin that would execute a given
>>> command when a system was provisioned.
>>>
>>> As far as I understand it the concept is based on the RAILS 3
>>> ActiveSupport/Concern pattern.
>>>
>>> Now I tried to imagine how it would be if one would want to provide two
>>> plugins that hook in the same functionality.
>>>
>>> Like for example:
>>> After provisioning of a host I'd like to both execute a given command
>>> and for example update a provision ticket in either Jira or Redmine (or
>>> what ever).
>>>
>>> So I'll end up with two different plugins both extending the same
>>> Module/Class UnattendedController.
>>>
>>> Background is that my idea was to have modular plugins that can be
>>> combined if need be.
>>>
>>> Let's say one would like to change a Redmine ticket instead of a JIRA
>>> one but would still like to execute the given command.
>>> That means using two plugins that extend the same module/class.
>>>
>>> Has anybody any idea on how to do that without having to write the same
>>> code multiple times and being quite flexible? I couldn't find any
>>> directions on this.
>>
>> I wrote a plugin recently called foreman_hooks that might solve this for
>> you. It's a generic plugin that can then call all scripts in a
>> directory based on any event in Foreman, so you can then easily add
>> multiple scripts for different tasks.
>>
>> You're right though, if you're writing it as actual plugins, there will
>> be a small duplication in extending or observing a particular class, but
>> it should be relatively small. The bulk of the work I think is in
>> having separate projects, gems etc for each individual hook, so having
>> one plugin for this would help.
>>
>> Anyway, foreman_hooks is here:
>> https://github.com/domcleal/foreman_hooks
>>
>> It runs hooks both on model events in Rails (e.g. after_save,
>> before_destroy) plus can extend the host orchestration framework in
>> Foreman, which is probably the most useful feature.
>
> Did you include the after/before provisioning hooks (e.g. when a node
> enable / disable build?)
–
Dominic Cleal
Red Hat Engineering
>> Hi Dominic,
>> this pretty much looks like what I had in mind for the script execution.
>> The only thing that I don't "like" is the limited information inside the
>> scripts.
>> I decided to either pass the host as yaml to stdin of the script or use some
>> kind of self parsed command line (still under construction).
>> Means:
>>
>> cmd=SETTINGS[:pluginExecCmd][params['action']] ||
>> SETTINGS[:pluginExecCmd][:cmd] || "cat"
>> logger.debug "Executing cmd #{cmd}"
>> if ! SETTINGS[:pluginExecCmd][params['action']+"_aspipe"] && !
>> SETTINGS[:pluginExecCmd][:cmd_aspipe] then
>> #{cmd}
>> else
>> IO.popen("#{cmd}", mode="r+") do |io|
>> io.write @host.to_yaml
>> io.close_write
>> puts io.read
>> end
>> end
>> end
>>
>> The background is that I'd need more information then just the hostname to
>> be created.
>> But I think this could be easily added to your gem.
>> At least more or less like above.
>>
>> And back to the plugins problem:
>> Let's say you have one plugin that would add the VMware guest's notes to the
>> host summary or the host edit pages (cause this is something only needed by
>> few people) and there is another plugin that adds some data to the host
>> collected from some kind of CMDB (or the like). I wouldn't want to have both
>> functionalities in the same plugin. As for the modularisation of both.
>>
>> So that would also be a use case where the combination of two plugins
>> overwriting the same functionality could be handy.
>> And that's why I think this is a real cool solution if this combination is
>> possible.
>>
>> What do you think?
>
> this makes a whole lot of sense, we could think of:
>
> 1. expose JSON representing the host in ENV variable?
Yeah, I was implementing stdin, then to provide a small helper script
you can source to access it.
> 2. consider calling the API during the event (that might introduce
> some potential problems if you are using before statements when the db
> transaction is not done yet).
I was thinking of foreman_hooks setting up temporary OAuth immediately
before running the hook, passing the info through environment variables
and then revoking it after it terminates. Then scripts could use the
foreman CLI tools, which could again be set up by a helper.
···
On 04/04/13 14:50, Ohad Levy wrote:
> On Thu, Apr 4, 2013 at 4:46 PM, Marc Grimme wrote:
–
Dominic Cleal
Red Hat Engineering
Oops, sorry, I forgot to post back here.
I released v0.3 which does the JSON stuff we talked about and wrote an
article about it:
http://m0dlx.com/blog/Extending_Foreman_quickly_with_hook_scripts.html
···
On 04/04/13 16:50, Marc Grimme wrote:
> On Thursday, April 4, 2013 5:29:45 PM UTC+2, Dominic Cleal wrote:
>
> On 04/04/13 14:46, Marc Grimme wrote:
> > The background is that I'd need more information then just the
> hostname
> > to be created.
> > But I think this could be easily added to your gem.
> > At least more or less like above.
>
> Exactly. I have a branch in progress to pass in the JSON
> representation
> via stdin, then you can use jgrep (or a small shell wrapper
> provided) to
> get access to the data.
>
> Let me know when the branch has been moved from "in progress" state to
> "ready for testing and being pushed"
> ;-)
> Then I wont need to work on my plugin any further.
–
Dominic Cleal
Red Hat Engineering
I already saw it.
And like it very much.
I'm currently testing it.
First thing I'm not sure about is error handling.
Right now nothing really happens (except from a warning in the log) if a
hook fails.
How about passing the exception up to the foreman GUI somehow (if possible).
Did you think about that already?
Nevertheless thanks for the work and the very good blog article.
Marc.
···
On Tuesday, April 9, 2013 4:52:44 PM UTC+2, Dominic Cleal wrote:
>
> On 04/04/13 16:50, Marc Grimme wrote:
> > On Thursday, April 4, 2013 5:29:45 PM UTC+2, Dominic Cleal wrote:
> >
> > On 04/04/13 14:46, Marc Grimme wrote:
> > > The background is that I'd need more information then just the
> > hostname
> > > to be created.
> > > But I think this could be easily added to your gem.
> > > At least more or less like above.
> >
> > Exactly. I have a branch in progress to pass in the JSON
> > representation
> > via stdin, then you can use jgrep (or a small shell wrapper
> > provided) to
> > get access to the data.
> >
> > Let me know when the branch has been moved from "in progress" state to
> > "ready for testing and being pushed"
> > ;-)
> > Then I wont need to work on my plugin any further.
>
> Oops, sorry, I forgot to post back here.
>
> I released v0.3 which does the JSON stuff we talked about and wrote an
> article about it:
> http://m0dlx.com/blog/Extending_Foreman_quickly_with_hook_scripts.html
>
> --
> Dominic Cleal
> Red Hat Engineering
>
> I already saw it.
And like it very much.
> I'm currently testing it.
Ah, great!
> First thing I'm not sure about is error handling.
> Right now nothing really happens (except from a warning in the log) if a
> hook fails.
> How about passing the exception up to the foreman GUI somehow (if possible).
> Did you think about that already?
>
> Nevertheless thanks for the work and the very good blog article.
I haven't thought about it much for the activerecord hooks, but I'm sure
something could be done there such as throwing an exception when the
hook has a bad exit code.
For hooks in orchestration (create/update/destroy), it fits neatly into
the existing GUI display of tasks and handles failure and rollback. If
one of these hooks returns a non-zero exit code, it'll register the task
as failed and then roll back previous tasks.
···
On 09/04/13 16:16, Marc Grimme wrote:
–
Dominic Cleal
Red Hat Engineering