[PATCH/puppet 1/1] Fixed #2820 - Install QuickLook plugins in Darwin

8 views
Skip to first unread message

James Turnbull

unread,
Nov 14, 2009, 8:06:38 AM11/14/09
to puppe...@googlegroups.com

Signed-off-by: James Turnbull <ja...@lovedthanlost.net>
---
lib/puppet/provider/package/quicklookdmg.rb | 148 +++++++++++++++++++++++++++
1 files changed, 148 insertions(+), 0 deletions(-)
create mode 100644 lib/puppet/provider/package/quicklookdmg.rb

diff --git a/lib/puppet/provider/package/quicklookdmg.rb b/lib/puppet/provider/package/quicklookdmg.rb
new file mode 100644
index 0000000..a059724
--- /dev/null
+++ b/lib/puppet/provider/package/quicklookdmg.rb
@@ -0,0 +1,148 @@
+# Udo Waechter <udo.wa...@uni-osnabrueck.de>
+# Mac OS X QuickLook package provider to (un)install quicklook plugins
+#
+# Motivation: DMG files provide a true HFS file system
+# and are easier to manage.
+#
+# Note: the 'apple' Provider checks for the package name
+# in /L/Receipts. Since we possibly install multiple plugins from
+# a single source, we treat the source .dmg file as the package name.
+# As a result, we store installed .dmg file names
+# in /var/db/.puppet_quicklookdmg_installed_<name>
+
+require 'puppet/provider/package'
+require 'yaml'
+require "FileUtils"
+
+Puppet::Type.type(:package).provide(:quicklookdmg, :parent => Puppet::Provider::Package) do
+ desc "Package management which copies application bundles to a target."
+ $quicklookdmg_target = "/Library/QuickLook"
+ confine :operatingsystem => :darwin
+
+ commands :hdiutil => "/usr/bin/hdiutil"
+ commands :curl => "/usr/bin/curl"
+ commands :ditto => "/usr/bin/ditto"
+ commands :qlmanage => "/usr/bin/qlmanage"
+ # Save information about installed plugins in /var/db
+ def self.instances_by_name
+ Dir.entries("/var/db").find_all { |f|
+ f =~ /^\.puppet_quicklook_installed_/
+ }.collect do |f|
+ name = f.sub(/^\.puppet_quicklook_installed_/, '')
+ yield name if block_given?
+ name
+ end
+ end
+
+ def self.instances
+ instances_by_name.collect do |name|
+ new(:name => name, :provider => :quicklookdmg, :ensure => :installed)
+ end
+ end
+
+ def self.installapp(source, name, orig_source)
+ appname = File.basename(source);
+ ditto "--rsrc", source, "#{$quicklookdmg_target}/#{appname}"
+ dbfile = "/var/db/.puppet_quicklook_installed_#{name}.yaml"
+ receipthash = {}
+ receipthash["files"] = []
+ if File.exist?(dbfile)
+ receipthash = YAML::load_file(dbfile)
+ end
+ receipthash["name"] = name
+ receipthash["source"] = orig_source
+ receipthash["files"].include?(appname) or receipthash["files"].push(appname)
+ f = File.open(dbfile,"w")
+ f.print receipthash.to_yaml
+ f.close
+ # refresh plugins
+ qlmanage "-r"
+ end
+
+ def self.uninstallquicklookdmg(name)
+ dbfile = "/var/db/.puppet_quicklook_installed_#{name}.yaml"
+ unless File.exist?(dbfile)
+ raise Puppet::Error.new("QuickLook DMG Package #{name} not installed.")
+ end
+ receipthash = YAML::load_file(dbfile)
+ receipthash["files"].each do |appname|
+ FileUtils.remove_entry_secure("#{$quicklookdmg_target}/#{appname}")
+ unless $? == 0
+ raise Puppet::Error.new("QuickLook DMG could not remove \"#{$quicklookdmg_target}/#{appname}\"")
+ end
+ end
+ File.unlink(dbfile)
+ qlmanage "-r"
+ end
+
+ def self.installquicklookdmg(source, name)
+ unless source =~ /\.dmg$/i
+ raise Puppet::Error.new("Mac OS X QuickLook DMG's must specificy a source string ending in .dmg")
+ end
+ require 'open-uri'
+ require 'facter/util/plist'
+ cached_source = source
+ if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
+ cached_source = "/tmp/#{name}"
+ begin
+ curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source
+ Puppet.debug "Success: curl transfered [#{name}]"
+ rescue Puppet::ExecutionFailure
+ Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods."
+ cached_source = source
+ end
+ end
+
+ begin
+ open(cached_source) do |dmg|
+ xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-mountrandom", "/tmp", dmg.path
+ ptable = Plist::parse_xml xml_str
+ # JJM Filter out all mount-paths into a single array, discard the rest.
+ mounts = ptable['system-entities'].collect { |entity|
+ entity['mount-point']
+ }.select { |mountloc|; mountloc }
+ begin
+ mounts.each do |fspath|
+ Dir.entries(fspath).select { |f|
+ f =~ /\.qlgenerator$/i
+ }.each do |app|
+ installapp("#{fspath}/#{app}", name, source)
+ end
+ end # mounts.each do
+ ensure
+ hdiutil "eject", mounts[0]
+ end # begin
+ end # open() do
+ ensure
+ # JJM Remove the file if open-uri didn't already do so.
+ File.unlink(cached_source) if File.exist?(cached_source)
+ end # begin
+ end # def self.installquicklookdmg
+
+ def query
+ if FileTest.exists?("/var/db/.puppet_quicklook_installed_#{@resource[:name]}.yaml")
+ return {:name => @resource[:name], :ensure => :present}
+ else
+ return nil
+ end
+ end
+
+ def install
+ source = nil
+ unless source = @resource[:source]
+ raise Puppet::Error.new("Mac OS X quicklook DMG's must specify a package source.")
+ end
+ unless name = @resource[:name]
+ raise Puppet::Error.new("Mac OS X quicklook DMG's must specify a package name.")
+ end
+ self.class.installquicklookdmg(source,name)
+ end
+
+ def uninstall
+ unless name = @resource[:name]
+ raise Puppet::Error.new("Mac OS X QuickLook DMG's must specify a package name.")
+ end
+ self.class.uninstallquicklookdmg(name)
+ end
+end
+
--
1.6.0.6

Nigel Kersten

unread,
Nov 14, 2009, 9:51:51 PM11/14/09
to puppe...@googlegroups.com
Was this really necessary to create a whole new provider?

Can't we just subclass the app/pkg dmg provider instead? There looks to be a lot of duplicated code here...


--
nigel

Markus Roberts

unread,
Nov 14, 2009, 10:25:29 PM11/14/09
to puppe...@googlegroups.com
> Was this really necessary to create a whole new provider?

Can't we just subclass the app/pkg dmg provider instead? There looks to be a lot of duplicated code here...

To get optimum code reuse we'd probably want to parametrize a few things (e.g. "/var/db/.
puppet_quicklook_installed_..." vs. "/var/db/.puppet_appdmg_installed_..." to something like "/var/db/.puppet_#{provider}_installed_...", some messages, etc.

-- Markus

Nigel Kersten

unread,
Nov 14, 2009, 11:00:13 PM11/14/09
to puppe...@googlegroups.com
I'm so unhappy that we do our Mac pkg tracking this way. :( but I just can't see a way around it.

The more I think about it, I can't quite see that this really justifies a whole provider.

Isn't this simply installing the package just like pkgdmg does but running [qlmanage "-r"] after each install?

This seems best suited to the postflight of the package itself don't you think? How many QuickLook plugins are you really managing?

Does qlmanage run happily when run as root via puppet when no-one is logged in btw?


 


--
nigel

Udo Waechter

unread,
Nov 16, 2009, 9:23:20 AM11/16/09
to puppe...@googlegroups.com
Yes, appdmg, pkgdmg and now quicklookdmg share a lot of functionality in common. As soon as the time comes, I will try to make those shorter.
udo.
--
:: udo waechter - ro...@zoide.net :: N 52º16'30.5" E 8º3'10.1"
:: genuine input for your ears: http://auriculabovinari.de
:: your eyes: http://ezag.zoide.net
:: your brain: http://zoide.net




Udo Waechter

unread,
Nov 16, 2009, 9:29:46 AM11/16/09
to puppe...@googlegroups.com
Hi,

On 15.11.2009, at 05:00, Nigel Kersten wrote:

> I'm so unhappy that we do our Mac pkg tracking this way. :( but I just can't see a way around it.
>

nope, as long as the apple-people do not come up with a proper package-management (apt would be great ;)).

> The more I think about it, I can't quite see that this really justifies a whole provider.
>
> Isn't this simply installing the package just like pkgdmg does but running [qlmanage "-r"] after each install?
>

In principle yes, but in fact no:
- The appdmg and quicklookdmg provider use ditto to copy .app or .ql<whatever> files to their appropriate places.

> This seems best suited to the postflight of the package itself don't you think? How many QuickLook plugins are you really managing?
>

Well, I like the appdmg provider, since not all .dmgs come with installer-packages inside. That would then mean that one has to create a package first, then put it in a .dmg
For us, this really is a lot of work. Thus we mostly use appdmg.

We are currently trying to figure out how to get all the files that were installed from .pkgs Then we could implement uninstall caps for pkgdmg also.

> Does qlmanage run happily when run as root via puppet when no-one is logged in btw?

Did not try it out, I hope it does.

udo.

Nigel Kersten

unread,
Nov 16, 2009, 8:51:08 PM11/16/09
to puppe...@googlegroups.com
On Mon, Nov 16, 2009 at 8:29 AM, Udo Waechter <udo.wa...@uni-osnabrueck.de> wrote:

Hi,

On 15.11.2009, at 05:00, Nigel Kersten wrote:

> I'm so unhappy that we do our Mac pkg tracking this way. :( but I just can't see a way around it.
>
nope, as long as the apple-people do not come up with a proper package-management (apt would be great ;)).

> The more I think about it, I can't quite see that this really justifies a whole provider.
>
> Isn't this simply installing the package just like pkgdmg does but running [qlmanage "-r"] after each install?
>
In principle yes, but in fact no:
- The appdmg and quicklookdmg provider use ditto to copy .app or .ql<whatever> files to their appropriate places.

> This seems best suited to the postflight of the package itself don't you think? How many QuickLook plugins are you really managing?
>
Well, I like the appdmg provider, since not all .dmgs come with installer-packages inside. That would then mean that one has to create a package first, then put it in a .dmg
For us, this really is a lot of work. Thus we mostly use appdmg.

You really should fix this. It's not difficult to create packages, and they're much easier to audit.

We use a version of this as it was initially developed here, and it's since been open sourced.


I'm going to say it again. If you don't have a workflow that makes it simple to create packages from a single .app bundle, you should fix that.

If you like Makefiles, the system above lets you create automatically dated/versioned packages in no more than a handful of lines.

We create all our packages using this kind of method, primarily because it allows for peer review and version control, allowing us to go back and rebuild any version of any of our packages that has ever been deployed on a client.

Copying an .app bundle into a dmg gives you none of this.
 

We are currently trying to figure out how to get all the files that were installed from .pkgs Then we could implement uninstall caps for pkgdmg also.

> Does qlmanage run happily when run as root via puppet when no-one is logged in btw?
Did not try it out, I hope it does.

Hope is not a strategy for config management :)
 

udo.
--
:: udo waechter - ro...@zoide.net :: N 52º16'30.5" E 8º3'10.1"
:: genuine input for your ears: http://auriculabovinari.de
::                          your eyes: http://ezag.zoide.net
::                          your brain: http://zoide.net









--
nigel

Udo Waechter

unread,
Nov 21, 2009, 7:50:12 AM11/21/09
to puppe...@googlegroups.com
Hi.
On 17.11.2009, at 02:51, Nigel Kersten wrote:

>
>
> On Mon, Nov 16, 2009 at 8:29 AM, Udo Waechter <udo.wa...@uni-osnabrueck.de> wrote:
>
> Hi,
>
> On 15.11.2009, at 05:00, Nigel Kersten wrote:
>
> > The more I think about it, I can't quite see that this really justifies a whole provider.
Well, it must not be to have a whole provider. But it gives the freedom to choose.
> >
> > Isn't this simply installing the package just like pkgdmg does but running [qlmanage "-r"] after each install?
> >
> In principle yes, but in fact no:
> - The appdmg and quicklookdmg provider use ditto to copy .app or .ql<whatever> files to their appropriate places.
>
> > This seems best suited to the postflight of the package itself don't you think? How many QuickLook plugins are you really managing?
> >
> Well, I like the appdmg provider, since not all .dmgs come with installer-packages inside. That would then mean that one has to create a package first, then put it in a .dmg
> For us, this really is a lot of work. Thus we mostly use appdmg.
>
> You really should fix this. It's not difficult to create packages, and they're much easier to audit.
>
I'm sorry to say, but for us it is a lot of work to create these packages. I really do not want to invest the time in this stuff right now. Our environment is controlled by some few people, thus we can say that using appdmg is pretty handy for us.


> We use a version of this as it was initially developed here, and it's since been open sourced.
> http://luggage.apesseekingknowledge.net/
hmmm, fetched that. Had to fix a lot of stuff to get it installed. But, it really does not work at all.

>
> I'm going to say it again. If you don't have a workflow that makes it simple to create packages from a single .app bundle, you should fix that.
>
Can we agree that it is left to the personal or team-taste how applications are deployed? At least puppet gives us the freedom to choose how to do stuff, thats what makes it so great. If Apple has so many ways of installing stuff, why teach puppet to use those.

> We create all our packages using this kind of method, primarily because it allows for peer review and version control, allowing us to go back and rebuild any version of any of our packages that has ever been deployed on a client.
>
> Copying an .app bundle into a dmg gives you none of this.
Hmm, it can uninstall stuff now (if my patches are accepted). This gives it an advantage over pkgdmg I would say ;)

>
> > Does qlmanage run happily when run as root via puppet when no-one is logged in btw?
No, it exits with an error. This error can be ignored though, since the quicklook-deamon is started (and thus updated) when someone logs in. Patch follows.

Have a nice day.
udo.

>
> --
> :: udo waechter - ro...@zoide.net :: N 52º16'30.5" E 8º3'10.1"
> :: genuine input for your ears: http://auriculabovinari.de
> :: your eyes: http://ezag.zoide.net
> :: your brain: http://zoide.net
>
>
>
>
>
>
>
>
>
> --
> nigel
>
> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
> To post to this group, send email to puppe...@googlegroups.com
> To unsubscribe from this group, send email to puppet-dev+...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en
> -~----------~----~----~----~------~----~------~--~---

Nigel Kersten

unread,
Nov 21, 2009, 7:38:15 PM11/21/09
to puppe...@googlegroups.com
On Sat, Nov 21, 2009 at 6:50 AM, Udo Waechter
<udo.wa...@uni-osnabrueck.de> wrote:
> Hi.
> On 17.11.2009, at 02:51, Nigel Kersten wrote:
>
>>
>>
>> On Mon, Nov 16, 2009 at 8:29 AM, Udo Waechter <udo.wa...@uni-osnabrueck.de> wrote:
>>
>> Hi,
>>
>> On 15.11.2009, at 05:00, Nigel Kersten wrote:
>>
>> > The more I think about it, I can't quite see that this really justifies a whole provider.
> Well, it must not be to have a whole provider. But it gives the freedom to choose.
>> >
>> > Isn't this simply installing the package just like pkgdmg does but running [qlmanage "-r"] after each install?
>> >
>> In principle yes, but in fact no:
>> - The appdmg and quicklookdmg provider use ditto to copy .app or .ql<whatever> files to their appropriate places.
>>
>> > This seems best suited to the postflight of the package itself don't you think? How many QuickLook plugins are you really managing?
>> >
>> Well, I like the appdmg provider, since not all .dmgs come with installer-packages inside. That would then mean that one has to create a package first, then put it in a .dmg
>> For us, this really is a lot of work. Thus we mostly use appdmg.
>>
>> You really should fix this. It's not difficult to create packages, and they're much easier to audit.
>>
> I'm sorry to say, but for us it is a lot of work to create these packages. I really do not want to invest the time in this stuff right now. Our environment is controlled by some few people, thus we can say that using appdmg is pretty handy for us
>
>
>> We use a version of this as it was initially developed here, and it's since been open sourced.
>> http://luggage.apesseekingknowledge.net/
> hmmm, fetched that. Had to fix a lot of stuff to get it installed. But, it really does not work at all.

I have many hundreds of packages created this way, and many tens of
versions of those packages, and we're not the only company building
packages this way, so it at least works in some cases :)

>
>>
>> I'm going to say it again. If you don't have a workflow that makes it simple to create packages from a single .app bundle, you should fix that.
>>
> Can we agree that it is left to the personal or team-taste how applications are deployed? At least puppet gives us the freedom to choose how to do stuff, thats what makes it so great. If Apple has so many ways of installing stuff, why teach puppet to use those.

People are always free not to follow best practice :) Are you saying
you're not using packages to customize your base images either? You're
not using SIU or InstaDMG?

>
>> We create all our packages using this kind of method, primarily because it allows for peer review and version control, allowing us to go back and rebuild any version of any of our packages that has ever been deployed on a client.
>>
>> Copying an .app bundle into a dmg gives you none of this.
> Hmm, it can uninstall stuff now (if my patches are accepted). This gives it an advantage over pkgdmg I would say ;)

In the long run that's a minor benefit compared to peer review and
version control of the payloads themselves, something you cannot do
sanely with .app bundles.

There is a reason that the vast majority of enterprise platforms
involve packages.

>
>>
>> > Does qlmanage run happily when run as root via puppet when no-one is logged in btw?
> No, it exits with an error. This error can be ignored though, since the quicklook-deamon is started (and thus updated) when someone logs in. Patch follows.

So when no-one logs in, this resource fails? Or it succeeds and
produces spurious errors?

Are you going to be refactoring the existing providers so we're not
duplicating code?

I'm not at convinced there is enough general utility here to
distribute this as part of the puppet core distribution, particularly
given how simple it is to distribute plugins these days, but I don't
think we should even have that discussion until the providers are
refactored.

I'm really not trying to be discouraging here, no matter how we
obviously disagree above about the best practices for managing Mac
clients.

I would love it if I wasn't doing most of the Mac-specific provider
work at the moment, and welcome patches. I would however like us to
follow reasonable coding principles, and welcome discussion as to
whether this sort of provider belongs in the core puppet distribution.
Reply all
Reply to author
Forward
0 new messages