Like the other poster, I'm defining an object that takes an array. In
my case, I'm defining gpg keystore, which can contain a number of
keys. (actually part of a larger svn repository object) It would be
called something like:
gpg::keystore{ "/svn/repo/conf/pubring.gpg":
keys => ["XXXXXX", "YYYYYYY"],
}
The obvious way to deal with that array, is to use a require, or to have
the definition directly call the key function.
gpg::addkey{ $keys:
store => $keystore, #as passed in as $name
}
But, this requires that the resources be named with the keyid. Which
fails when I have multiple keystores -- they can't both define
gpg::addkey["XXXXX"].
It's hard to see a nice solution to this. If puppet supported
for loops, I could do something. Or if I could pass some kind of
multidimensional bit in the $name array expansion.
I can get some of it, by inverting the logic. So instead of defining
keystores with key attributes, I instead define keys and the locations
they should get added to. But I find that much harder to maintain, and
it scales differently.
Depending on the details, using inline_template can get part way. But
it's a lot of extra complexity, and I don't think it solves all
problems.
I think I'll probably just rethink my setup, so I only have 1 keystore
per machine, but I'm not very pleased with that. Anyone have any
better suggestion? Any chance at getting better puppet support for
this sort of array handling?
seph
While it may seem clean to you, it doesn't map very well into Puppet.
You can't just have a require hanging out like that in the middle of a
define, just for example. Here's what I'd do (again, not really
understanding the "key" and "keystore" here):
define key($key_arg1, $key_arg2, $keystore) {
# resources to create the key and add it to each keystore.
}
define keystore($keystore_arg1, $path) {
# an exec to create the (empty) keystore
}
key {
"key1":
key_arg1 => value,
key_arg2 => value,
keystore => ["default"],
require => Keystore["default"];
"key2":
key_arg1 => value,
key_arg2 => value,
keystore => ["default", "secure"],
require => Keystore["default", "secure"];
}
keystore {
"default":
keystore_arg1 => value,
path => "/tmp/ks/default";
"secure":
keystore_arg1 => value,
path => "/root/ks/secure";
}
Does that make sense?
--Paul
> While it may seem clean to you, it doesn't map very well into Puppet.
> You can't just have a require hanging out like that in the middle of a
> define, just for example. Here's what I'd do (again, not really
> understanding the "key" and "keystore" here):
[...]
> key {
> "key1":
> key_arg1 => value,
> key_arg2 => value,
> keystore => ["default"],
> require => Keystore["default"];
> "key2":
> key_arg1 => value,
> key_arg2 => value,
> keystore => ["default", "secure"],
> require => Keystore["default", "secure"];
> }
Haven't you just shifted around the problem? You still have an array
that you need to process each element of, only it is now a list of
keystores per key, instead of a list of keys per keystore.
In order to not have any array parameters, you would need to do it
something like this:
keystore { "default": ...; "secure": ...; }
key {
"key1-in-default": key=>"key1", store=>"default", ...;
"key2-in-default": key=>"key2", store=>"default", ...;
"key1-in-secure": key=>"key1", store=>"secure", ...;
"key2-in-secure": key=>"key2", store=>"secure", ...;
}
However, this soon gets pretty tiring, especially if you have many
keys and keystores...
/Bellman
The actual execution is always procedural (either within a custom type
or exec). There is no problem to iterate over all keystores _there_.
> In order to not have any array parameters, you would need to do it
> something like this:
>
> keystore { "default": ...; "secure": ...; }
> key {
> "key1-in-default": key=>"key1", store=>"default", ...;
> "key2-in-default": key=>"key2", store=>"default", ...;
> "key1-in-secure": key=>"key1", store=>"secure", ...;
> "key2-in-secure": key=>"key2", store=>"secure", ...;
> }
>
> However, this soon gets pretty tiring, especially if you have many
> keys and keystores...
I would recommend such a notation only where you want different
parameters for the same key in different keystores. Then I'd go for
something like this:
key {
"/path/to/keystores/storefile1/keyname1": param => foo;
"/path/to/keystores/storefile1/keyname2": param => foo;
"/path/to/keystores/storefile1/keyname3": param => foo;
"/path/to/keystores/storefile2/keyname1": param => bar;
"/path/to/keystores/storefile2/keyname2": param => bar;
"/path/to/keystores/storefile2/keyname3": param => bar;
}
Where Key["/foo/bar"] denotes the key "bar" in the keystore located at
"/foo", with an automatic dependency from Key["/foo/bar"] to
Keystore["/foo"].
Regards, DavidS
> Thomas Bellman wrote:
>> Haven't you just shifted around the problem? You still have an array
>> that you need to process each element of, only it is now a list of
>> keystores per key, instead of a list of keys per keystore.
>
> The actual execution is always procedural (either within a custom type
> or exec). There is no problem to iterate over all keystores _there_.
Yes, but Paul seemed to argue that having array parameters and looping over
them was "un-Puppet-like" and bad design. And then he suggested a variant
that still used array parameters. I happen to disagree with that sentiment.
If you want to use an exec to process the elements of the array, you need
to be able to pass that array to exec someway. The only way I can think
of in standard Puppet is to use inline_template() to create the command;
not exactly pretty...
Custom types are nice, but I think most Puppet users don't want to write
them, and would rather stay within the Puppet language.
That said, there is a way to loop over arrays within Puppet, and that
is by passing it as the name to a helper definition. The OP would do
something like this:
define keystore($keys, ...)
{
keystore_helper {
$keys: ...;
}
...
}
define keystore_helper(...)
{
# Each element of $keys will be available as $name here
# Do something with it here
...
}
This is not unproblematic at the moment, though. Since the name must
be unique for each keystore_helper declaration, that makes it impossible
to have more than one keystore declaration with the same keys parameter.
One would have to preprocess the $keys parameter to prepend the keystore
name to each element, and there's no way to do that in stock 0.24.8.
(I think you will be able to do it in 0.25, by abusing inline_template()
and split(), but that's rather ugly.)
/Bellman
> Yes, but Paul seemed to argue that having array parameters and looping over
> them was "un-Puppet-like" and bad design. And then he suggested a variant
> that still used array parameters. I happen to disagree with that sentiment.
I think this is about where I'm coming from. I don't think I can define
a custom type, and the native puppet support isn't quite enough rope. I
don't think it's a declarative vs. procedural issue.
> That said, there is a way to loop over arrays within Puppet, and that
> is by passing it as the name to a helper definition. The OP would do
> something like this:
>
> define keystore($keys, ...)
> {
> keystore_helper {
> $keys: ...;
> }
> ...
> }
>
> define keystore_helper(...)
> {
> # Each element of $keys will be available as $name here
> # Do something with it here
> ...
> }
>
> This is not unproblematic at the moment, though. Since the name must
> be unique for each keystore_helper declaration, that makes it impossible
> to have more than one keystore declaration with the same keys parameter.
> One would have to preprocess the $keys parameter to prepend the keystore
> name to each element, and there's no way to do that in stock 0.24.8.
> (I think you will be able to do it in 0.25, by abusing inline_template()
> and split(), but that's rather ugly.)
Exactly. I'd love for names to be multidimensional.
seph