On Mar 22, 10:10 am, Nigel Kersten <[email protected]> wrote:
> On Tue, Mar 22, 2011 at 7:20 AM, jcbollinger <[email protected]> 
> wrote:
>
> > On Mar 21, 8:53 pm, Nigel Kersten <[email protected]> wrote:
> >> The file{} type can do all of the following:
>
> >> * manage single files
> >> * manage directories
> >> * manage symlinks
> >> * manage recursive file copies
>
> >> The intersection of all these bits of functionality makes it difficult
> >> to understand exactly what is going on when you're new to Puppet, and
> >> even experienced users often don't know how combining symlinks/content
> >> management is going to work.
>
> >> How would people feel about at least splitting out these into their own 
> >> types?
>
> >> * symlinks
> >> * recursive file copies
>
> >> The intersection of files and directories isn't that big a deal, but
> >> we could split out directories too if we wanted.
>
> >> Thoughts?
>
> > I agree that File is a mishmash, but I don't think symlinks and
> > recursive copying are the key concepts that would be good to split
> > out.  Instead, I think splitting directories into their own type would
> > be the way to go.
>
> > Consider what would happen if symlinks were made their own type.  What
> > about dependencies?  Right now, I can have
>
> > service { "my_service": require => File["/etc/my_service.conf"] }
>
> > without caring whether File["/etc/my_service.conf"] represents an
> > actual file or a symlink.  I can even change that in the declaration
> > of the file without having to touch anything that depends on it.  If
> > symlinks were modeled via a separate type, however, then I would need
> > everywhere to account for which files were plain and which were
> > symlinks.
>
> That's a really good point. One workaround would be to encapsulate
> such configs into a class and require that.
>
> class foo::service {
>   service { "my_service": require => Class["foo::config"] }
>
> }
>
> class foo::config { ... }
>
> Another would be to flip this around and instead use before instead of
> require, so the service resource wouldn't need to know what kind of
> object is required.


Ok, but the existence of workarounds to the problem doesn't mean there
isn't a problem.  The systems under management draw little distinction
between regular files and symbolic links to files, so at best it would
be quirky for Puppet to draw a substantially larger distinction.  It
is likely that situations would be discovered for which none of the
workarounds is very good.  Instead of solving the problem, you would
merely exchange one set of problems for a different, perhaps smaller,
set.


> > Or look at it from a modelling angle: a symlink to a regular file is
> > much more like a regular file than a directory is like a regular file,
> > so why does it make sense to split out symlinks but not directories?
>
> Because of the clash between defining a symlink and specifying the
> content of a file.
>
> We have edge cases like this:
>
> file { "/tmp/someobject":
>   ensure => present,
>   content => "foo",
>
> }
>
> Now if /tmp/someobject is a symlink (or even a directory), we need to
> special case the code so that we log that the content attribute isn't
> being used.
>
> If it's a file, it will be used.


I'm suggesting that directories get their own type, so they're not
germane here.

I'm also suggesting that the new File type know whether the target is
supposed to be a symlink (which would also trivially be the case if
symlinks were split out), so it would be reasonable for a File
managing a symlink and specifying content to manage the content of the
link target.  That would be pretty natural, in fact.


> It gets worse with the "links" parameter.
>
> file { "/tmp/foo":
>   ensure => present,
>   links => follow,
>   recurse => true,
>   source => "....",
>
> }


No it doesn't, because the File type I'm proposing (like the one you
started with) does not manage directories or, therefore, support
recursion.

Moreover, with no ambiguity about whether the managed object is
expected to be a symlink, the "links" property would be unnecessary.


> This does all sorts of weird things depending upon whether the object
> is a symlink, directory or file.
>
> We've had requests to support sockets in the file type too, which
> complicate things further.


More on that below...


> > Parallel arguments can be made about directories and symlinks to
> > directories.
>
> > As for recursive copying, that's an action, not an observable,
> > manageable artifact, so why would it make sense to create a resource
> > type around it?  It could be recast as something like "directory
> > hierarchy", but that begs the question of why it should be separate
> > from ordinary directories.  If you want to think out of the box, then
> > consider re-implementing recursive directory management via a new
> > (type of) function that dynamically adds all the appropriate Directory
> > and File resources to the catalog.  That's anyway what Puppet already
> > does, right?
>
> We have fundamentally different kinds of parameters on a recursive
> file source than we do on a normal directory.
>
> Think about the clash between source and content. links. purge.
> recurse. recurselimit. ignore.
>
> All those things *only* make sense with a recursive tree, not with a
> single file or a single directory.


I recognize that, but it doesn't change the fact that a directory with
recursively copied contents is still a directory, nor the fact that
the copy *operation* is not a manageable artifact.  As I understand it
-- which is imperfectly -- Puppet currently handles recursive
directories basically by creating resource objects for the whole
hierarchy of files and subdirectories.  I'm suggesting that the Puppet
DSL could provide direct access to that resource generator as an
alternative to having distinct Directory and RecursiveDirectory
types.  That need not be done via a function per se; perhaps there
would be a more general use for such dynamic resource generators,
sufficient to justify adding support for such things to the framework.


> > This, then, is the direction that makes the most sense to me:
>
> > 1) Split out (only) directories into their own type.  Among other
> > things, recursive-tree management would go into the new Directory
> > type.
> > 2) Give File and Directory each a "link_to" property by which these
> > types can be made to manage symbolic links instead of the underlying
> > regular file or directory.
>
> like our existing "target" property?


Umm... yeah.  Sorry, brain fart there.  Still, that property might
admit a more descriptive name if it were the only thing indicating
that the resource represented a symlink.


>   How does it make sense to manage
> a symlink in a Directory type? I'm not seeing it....


It makes sense if the target of the symlink is expected to be a
directory.  (And the target of a File-managed symlink is expected to
be a regular file.)


> > 3) Once (1) and (2) are done, it will be possible and appropriate to
> > limit the allowed values of both types' "ensure" properties to
> > "absent" and "present".
>
> > I recommend seeing how (1) works out before trying to move recursive
> > directory management into its own entity.  If that feature is indeed
> > moved out, however, then I truly don't see how it would make sense to
> > make a resource type out of it.  Making a function out of it instead
> > would be a better fit.
>
> I think you're overlooking the configurable properties for recursive
> copies. A function isn't going to give you all the options that are
> widely used now.


No, I'm not.  The expressive capability of a function call is no less
than that of a resource declaration.  A function might need a dozen
parameters, and might therefore be messy to use, but one *could*
provide all the same facilities.  Maybe the potential mess is good
argument for looking for something new, such as the resource
generators I speculated about above.

On the other hand, perhaps the new thing needed is something
different: what about resource sub-types?  At some levels on which we
might want to manage system configuration, we might not care whether a
file is regular or a directory or a device node, or a symbolic link to
one of the above.  At some other levels, however, those distinctions
can be very important.  So suppose, for example, we have the
alternative of declaring either

plainfile { "/etc/profile.d/foo.sh": source => "..." }

or

filelink { "/etc/profile.d/foo.sh": target => "/opt/foo/foo_env.sh" }

but they are mutually exclusive, and either one satisfies the
requirement in

service { "foo": require => File["/etc/profile.d/foo.sh"] }


Such a framework could be flexible enough to support various sorts of
special files (e.g. device nodes) without making an unmaintainable
shambles out of the File type.  Most importantly, it models the
problem domain better than would addressing plain files and symlinks
via separate, unrelated types.


Best,

John

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-users?hl=en.

Reply via email to