damian.folwell@gmail.com
2013-Mar-07 16:47 UTC
[Puppet Users] Custom type and provider development
Hi, I''m very new to Ruby, and pretty new to Puppet so apologies if this is a bit Puppet custom type development 101. We currently have a whole bunch of Windows services that are written in .Net. They are really simple and so we don''t bother creating MSI installs for them and just use InstallUtil.exe called from a script. I''m looking at creating a simple Puppet type and provider that will allow me to install the service (via InstallUtil) if it doesn''t already exist (as opposed to using an exec resource in which it is hard to determine if the service exists as a conditional). Now, there are many different flavours of .Net in use, and some are 32bit, some 64 bit. This means that I need to be able to specify what version of installutil.exe to use. Currently the type has a bunch of parameters (not properties) to specify this. E.g. dotnetwinservice {''MyService'': ensure => present, dotnetversion => ''4.0.30319'', sixtyfourbit => false, path => ''c:\program files(x86)\myapp\myapp.exe'', } My question is, in the provider code what is the best way to dynamically determine the installutil path? All of the examples i can find setting a command are not dynamic (i.e. the full command path is known without looking at parameter values). My provider code looks like the below... The INSTALLUTIL value is currently hard coded. I''d like to do something like the commented out code but it doesn''t appear as though either @property_hash or @resource have values at the time of execution (I get undefined method [] for nil:nilClass error). Puppet::Type.type(:dotnetwinservice).provide(:dotnetwinservice) do desc "DotNet Windows Service" confine :operatingsystem => :windows defaultfor :operatingsystem => :windows #dotnetframeworkversion = @resource[:sixtyfourbit] ? ''Framework64'' : ''Framework'' #installutilpath = "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\#{@resource[:dotnetversion]}\\InstallUtil.exe" #INSTALLUTIL = # if File.exists?(installutilpath) # installutilpath # else # raise Puppet::Error.new("Cannot find installutil.exe for dotnetversion #{@property_hash[:dotnetversion]} at #{installutilpath} " ) # end INSTALLUTIL = "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe" commands :installutil => INSTALLUTIL def create installutil("/unattended", @resource[:path]) end def destroy installutil("/u", "/unattended", @resource[:path]) end def exists? Win32::Service.exists?( @resource[:name] ) end end -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
On 03/07/2013 05:47 PM, damian.folwell@gmail.com wrote:> My question is, in the provider code what is the best way to dynamically > determine the installutil path? All of the examples i can find setting > a command are not dynamic (i.e. the full command path is known without > looking at parameter values).Really interesting question... I don''t know the answer but am looking forward to hearing :) Maybe Nan Liu can help? -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
On Thu, Mar 7, 2013 at 8:47 AM, <damian.folwell@gmail.com> wrote:> > Hi, > > I''m very new to Ruby, and pretty new to Puppet so apologies if this is a > bit Puppet custom type development 101. > > We currently have a whole bunch of Windows services that are written in > .Net. They are really simple and so we don''t bother creating MSI installs > for them and just use InstallUtil.exe called from a script. > I''m looking at creating a simple Puppet type and provider that will allow > me to install the service (via InstallUtil) if it doesn''t already exist (as > opposed to using an exec resource in which it is hard to determine if the > service exists as a conditional). > > Now, there are many different flavours of .Net in use, and some are 32bit, > some 64 bit. This means that I need to be able to specify what version of > installutil.exe to use. > Currently the type has a bunch of parameters (not properties) to specify > this. E.g. > dotnetwinservice {''MyService'': > ensure => present, > dotnetversion => ''4.0.30319'', > sixtyfourbit => false, > path => ''c:\program files(x86)\myapp\myapp.exe'', > } > > My question is, in the provider code what is the best way to dynamically > determine the installutil path? All of the examples i can find setting a > command are not dynamic (i.e. the full command path is known without > looking at parameter values). > > My provider code looks like the below... > The INSTALLUTIL value is currently hard coded. I''d like to do something > like the commented out code but it doesn''t appear as though either > @property_hash or @resource have values at the time of execution (I get > undefined method [] for nil:nilClass error). > > Puppet::Type.type(:dotnetwinservice).provide(:dotnetwinservice) do > desc "DotNet Windows Service" > > confine :operatingsystem => :windows > defaultfor :operatingsystem => :windows > > #dotnetframeworkversion = @resource[:sixtyfourbit] ? ''Framework64'' : > ''Framework'' > #installutilpath > "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\#{@resource[:dotnetversion]}\\InstallUtil.exe" > > #INSTALLUTIL > # if File.exists?(installutilpath) > # installutilpath > # else > # raise Puppet::Error.new("Cannot find installutil.exe for > dotnetversion #{@property_hash[:dotnetversion]} at #{installutilpath} " ) > # end > > INSTALLUTIL > "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe" > > commands :installutil => INSTALLUTIL > > > def create > installutil("/unattended", @resource[:path]) > end > > def destroy > installutil("/u", "/unattended", @resource[:path]) > end > > def exists? > Win32::Service.exists?( @resource[:name] ) > end > > endSee example here, you should be able to do something similar: https://github.com/puppetlabs/puppetlabs-dism/blob/master/lib/puppet/provider/dism/dism.rb#L7-L13 HTH, Nan -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
On Thu, Mar 7, 2013 at 1:38 PM, Nan Liu <nan.liu@gmail.com> wrote:> On Thu, Mar 7, 2013 at 8:47 AM, <damian.folwell@gmail.com> wrote: > >> >> Hi, >> >> I''m very new to Ruby, and pretty new to Puppet so apologies if this is a >> bit Puppet custom type development 101. >> >> We currently have a whole bunch of Windows services that are written in >> .Net. They are really simple and so we don''t bother creating MSI installs >> for them and just use InstallUtil.exe called from a script. >> I''m looking at creating a simple Puppet type and provider that will allow >> me to install the service (via InstallUtil) if it doesn''t already exist (as >> opposed to using an exec resource in which it is hard to determine if the >> service exists as a conditional). >> >> Now, there are many different flavours of .Net in use, and some are >> 32bit, some 64 bit. This means that I need to be able to specify what >> version of installutil.exe to use. >> Currently the type has a bunch of parameters (not properties) to specify >> this. E.g. >> dotnetwinservice {''MyService'': >> ensure => present, >> dotnetversion => ''4.0.30319'', >> sixtyfourbit => false, >> path => ''c:\program files(x86)\myapp\myapp.exe'', >> } >> >> My question is, in the provider code what is the best way to dynamically >> determine the installutil path? All of the examples i can find setting a >> command are not dynamic (i.e. the full command path is known without >> looking at parameter values). >> >> My provider code looks like the below... >> The INSTALLUTIL value is currently hard coded. I''d like to do something >> like the commented out code but it doesn''t appear as though either >> @property_hash or @resource have values at the time of execution (I get >> undefined method [] for nil:nilClass error). >> >> Puppet::Type.type(:dotnetwinservice).provide(:dotnetwinservice) do >> desc "DotNet Windows Service" >> >> confine :operatingsystem => :windows >> defaultfor :operatingsystem => :windows >> >> #dotnetframeworkversion = @resource[:sixtyfourbit] ? ''Framework64'' : >> ''Framework'' >> #installutilpath >> "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\#{@resource[:dotnetversion]}\\InstallUtil.exe" >> >> #INSTALLUTIL >> # if File.exists?(installutilpath) >> # installutilpath >> # else >> # raise Puppet::Error.new("Cannot find installutil.exe for >> dotnetversion #{@property_hash[:dotnetversion]} at #{installutilpath} " ) >> # end >> >> INSTALLUTIL >> "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe" >> >> commands :installutil => INSTALLUTIL >> >> >> def create >> installutil("/unattended", @resource[:path]) >> end >> >> def destroy >> installutil("/u", "/unattended", @resource[:path]) >> end >> >> def exists? >> Win32::Service.exists?( @resource[:name] ) >> end >> >> end > > > See example here, you should be able to do something similar: > > https://github.com/puppetlabs/puppetlabs-dism/blob/master/lib/puppet/provider/dism/dism.rb#L7-L13 > >Rethinking a bit more since you need access to a provider parameter, you may need to do something closer to this: commands :default_installutil => INSTALLUTIL def installutil(*args) if @resource[:dotnetversion] args.unshift "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\#{@ resource[:dotnetversion]}\\InstallUtil.exe" Puppet.debug("Executing ''#{args.inspect}''") execute(args, :failonfail => true) else default_installutil *args end end def create installutil("/unattended", @resource[:path]) end HTH, Nan -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
On Thu, Mar 7, 2013 at 6:42 PM, Nan Liu <nan.liu@gmail.com> wrote:> On Thu, Mar 7, 2013 at 1:38 PM, Nan Liu <nan.liu@gmail.com> wrote: > >> On Thu, Mar 7, 2013 at 8:47 AM, <damian.folwell@gmail.com> wrote: >> >>> >>> Hi, >>> >>> I''m very new to Ruby, and pretty new to Puppet so apologies if this is a >>> bit Puppet custom type development 101. >>> >>> We currently have a whole bunch of Windows services that are written in >>> .Net. They are really simple and so we don''t bother creating MSI installs >>> for them and just use InstallUtil.exe called from a script. >>> I''m looking at creating a simple Puppet type and provider that will >>> allow me to install the service (via InstallUtil) if it doesn''t already >>> exist (as opposed to using an exec resource in which it is hard to >>> determine if the service exists as a conditional). >>> >>> Now, there are many different flavours of .Net in use, and some are >>> 32bit, some 64 bit. This means that I need to be able to specify what >>> version of installutil.exe to use. >>> Currently the type has a bunch of parameters (not properties) to specify >>> this. E.g. >>> dotnetwinservice {''MyService'': >>> ensure => present, >>> dotnetversion => ''4.0.30319'', >>> sixtyfourbit => false, >>> path => ''c:\program files(x86)\myapp\myapp.exe'', >>> } >>> >>> My question is, in the provider code what is the best way to dynamically >>> determine the installutil path? All of the examples i can find setting a >>> command are not dynamic (i.e. the full command path is known without >>> looking at parameter values). >>> >>> My provider code looks like the below... >>> The INSTALLUTIL value is currently hard coded. I''d like to do something >>> like the commented out code but it doesn''t appear as though either >>> @property_hash or @resource have values at the time of execution (I get >>> undefined method [] for nil:nilClass error). >>> >>> Puppet::Type.type(:dotnetwinservice).provide(:dotnetwinservice) do >>> desc "DotNet Windows Service" >>> >>> confine :operatingsystem => :windows >>> defaultfor :operatingsystem => :windows >>> >>> #dotnetframeworkversion = @resource[:sixtyfourbit] ? ''Framework64'' : >>> ''Framework'' >>> #installutilpath >>> "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\#{@resource[:dotnetversion]}\\InstallUtil.exe" >>> >>> #INSTALLUTIL >>> # if File.exists?(installutilpath) >>> # installutilpath >>> # else >>> # raise Puppet::Error.new("Cannot find installutil.exe for >>> dotnetversion #{@property_hash[:dotnetversion]} at #{installutilpath} " ) >>> # end >>> >>> INSTALLUTIL >>> "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe" >>> >>> commands :installutil => INSTALLUTIL >>> >>> >>> def create >>> installutil("/unattended", @resource[:path]) >>> end >>> >>> def destroy >>> installutil("/u", "/unattended", @resource[:path]) >>> end >>> >>> def exists? >>> Win32::Service.exists?( @resource[:name] ) >>> end >>> >>> end >> >> >> See example here, you should be able to do something similar: >> >> https://github.com/puppetlabs/puppetlabs-dism/blob/master/lib/puppet/provider/dism/dism.rb#L7-L13 >> >> > Rethinking a bit more since you need access to a provider parameter, you > may need to do something closer to this: > > commands :default_installutil => INSTALLUTIL > > def installutil(*args) > if @resource[:dotnetversion] > args.unshift "#{ENV[''SYSTEMROOT'']}\\Microsoft.NET\\Framework\\#{@ > resource[:dotnetversion]}\\InstallUtil.exe" > Puppet.debug("Executing ''#{args.inspect}''") > execute(args, :failonfail => true) > else > default_installutil *args > end > end > > def create > installutil("/unattended", @resource[:path]) > end > > HTH, > > Nan > > -- > You received this message because you are subscribed to the Google Groups > "Puppet Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to puppet-users+unsubscribe@googlegroups.com. > To post to this group, send email to puppet-users@googlegroups.com. > Visit this group at http://groups.google.com/group/puppet-users?hl=en. > For more options, visit https://groups.google.com/groups/opt_out. > > >Some background on why this is necessary. When you declare: Puppet::Type.type(:dotnetwinservice).provide(:dotnetwinservice) Puppet uses metaprogramming to define a new class named Puppet::Type::Dotnetwinservice::ProviderDotnetwinservice, and it adds instance methods to the class, e.g. `def create`. Within the body of an instance method, you have access to instance variables, e.g. @resource, and methods, e.g. Puppet::Provider#set, #get, #resource, etc. However, statements that are not within an instance method such as: dotnetframeworkversion = @resource[:sixtyfourbit] ? ''Framework64'' : ''Framework'' are being evaluated in the context of your class, not an instance of your class. So you don''t have access to instance variables like @resource, and that''s why you need to create a helper method like Nan suggested. Unfortunately, you as a provider author have to know in which context your code is being evaluated, as that will determine what methods and variables you have access to. HTH, Josh -- Josh Cooper Developer, Puppet Labs -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
damian.folwell@gmail.com
2013-Mar-08 21:56 UTC
Re: [Puppet Users] Custom type and provider development
Thanks Nan and Josh. Your help is much appreciated. Once I''ve finished first draft I''ll upload to GitHub / Forge and ask for comments! -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Klavs Klavsen
2013-Mar-21 08:41 UTC
[Puppet Users] Re: Custom type and provider development
Did you get any further with the installutil provider? It sounds really interesting - I myself is trying to automate install of PerfTab (a .net application).. -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
damian.folwell@gmail.com
2013-Apr-05 21:32 UTC
[Puppet Users] Re: Custom type and provider development
I''ve finally got round to loading what i''ve done so far onto GitHub. My efforts can be found at https://github.com/damo-se/puppet-dotnetwinservice. This is very untested (only tried on a 32bit .Net 4.0 windows service so far) and doesn''t have any rspec tests yet. Also the code isn''t documented very well. I''d be grateful for feedback. (For info, I notice that since i started somebody else has also created a similar module at https://github.com/rismoney/puppet-winsvc although that looks limited to .Net 4 only). -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
That''s mine :). I haven''t followed up on it. Don''t even know if it works... :( when I start doing svc mgmt I am going to need it and like you, will need the multi version capabilities. It was more of a copy paste initial idea at this point... On a side note, off topic but windows relevant: I have a bunch of providers at various stages of dev but need to round them all up into fully functional in the next few months. I have a few more on deck, including AD, both building it and managing it. The ones I need bad are file ACL and a reboot handler :( In other news, I am about to mark functional the baremetal build. I managed to inject puppet/facter into WinPE and can take a host through a fully unattended install of win2008r2 including manage unattend.xml as a file template. On a vm where ive tested it takes 10 minutes and fully bootstraps itself 2x. The best part is I scripted the pe build, uses only native supported tooling so anyone who clones the repo can build the iso in 15 min themselves. I think it could be a game changer with some refinement, and could lure a lot of people away from massive sccm, wds, altiris or other commercial tooling. One tool. One module. Automated. Puppet ftw -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ringo De Smet
2013-Oct-14 09:59 UTC
[Puppet Users] Re: Custom type and provider development
Rich, On Sunday, 7 April 2013 08:04:52 UTC+2, Rich Siegel wrote:> > In other news, I am about to mark functional the baremetal build. I > managed to inject puppet/facter into WinPE and can take a host through a > fully unattended install of win2008r2 including manage unattend.xml as a > file template. On a vm where ive tested it takes 10 minutes and fully > bootstraps itself 2x. The best part is I scripted the pe build, uses only > native supported tooling so anyone who clones the repo can build the iso in > 15 min themselves. I think it could be a game changer with some > refinement, and could lure a lot of people away from massive sccm, wds, > altiris or other commercial tooling. One tool. One module. Automated. > Puppet ftw >What is the status of this? This is something I could definitely use for my current customer, and within these working hours also contribute to. However, a guiding hand will be needed as I''m still in my uphill battle to get to know Puppet. Ringo -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users. For more options, visit https://groups.google.com/groups/opt_out.