Creating a bunch of types to manage cobbler

30 views
Skip to first unread message

Sven Mueller

unread,
Sep 26, 2008, 5:49:27 AM9/26/08
to puppet...@googlegroups.com
Hi.

I'm trying to create a bunch of types to manage an installation server
via cobbler. However, I don't really understand how to do it.

For example a cobbler repository is actually a record describing a YUM
repository. This could be a local mirror. So there are some
variables/properties describing such a repository:

name, source-URL, architecture, wether to mirror locally

Let's assume I have a few scripts I could use to do various tasks (i.e.
I will use shell scripts for now, to make the cobbler type (and, if
needed, provider(s)) simpler and more easy to understand, but would
implement the logic in ruby later. I have:

repo_update_or_add name url arch local
(updates the repo named or create it if it doesn't yet exist)
repo_exists name
(returns 0 if a repository with the given name exists, 1 otherwise)
repo_up_to_date name url arch local
(returns 0 if the repository exists and is up to date)
repo_delete name
(removes a repository)

Where up to date just means the parameters (i.e. is set to have a local
mirror when this is requested), not necessarily that the local mirror is
in sync with the original source.

Now, how would I write type (and if needed: provider(s)) if my
requirements are that ensure can take:
- present (just make sure the repository is known, not necessarily in
sync with (all) parameters)
- absent (remove repositories which were once installed
- insync (known and in sync with all given parameters)

I did write a preliminary type, but it doesn't seem to work at all (see
below). I put the attached file in
/etc/puppet/modules/puppet/type/cobbler_repo.rb as per
http://reductivelabs.com/trac/puppet/wiki/PluginsInModules, with
effective puppetmasterd configuration containing:
modulepath = /etc/puppet/modules:/usr/share/puppet/modules

But still I get:

err: Could not retrieve catalog: Could not find resource type
cobbler_repo at /etc/puppet/manifests/classes/cobbler.pp:171 on node
op-inst01.wirecard.sys

Could anyone please help me?


regards,
Sven

cobbler_repo.rb

Sven Mueller

unread,
Sep 26, 2008, 6:07:35 AM9/26/08
to puppet...@googlegroups.com
Sven Mueller schrieb:

> I did write a preliminary type, but it doesn't seem to work at all (see
> below). I put the attached file in
> /etc/puppet/modules/puppet/type/cobbler_repo.rb as per
> http://reductivelabs.com/trac/puppet/wiki/PluginsInModules, with
> effective puppetmasterd configuration containing:
> modulepath = /etc/puppet/modules:/usr/share/puppet/modules
>
> But still I get:
>
> err: Could not retrieve catalog: Could not find resource type
> cobbler_repo at /etc/puppet/manifests/classes/cobbler.pp:171 on node
> op-inst01.wirecard.sys

Forget about that. I forgot to enable pluginsync.

Anyway, I now get:

warning: Configuration could not be instantiated: Class cobbler_repo
already has a property named ensure

If I remove the newproperty(:ensure) block, I get:

err: //Node[op-inst01.wirecard.sys]/cobbler/Cobbler_repo[CentOS5]:
Failed to retrieve current state of resource: No ability to determine if
cobbler_repo exists

instead. Now, how do I add that ability (plus the "insync" meaning of
:ensure)?

kind regards,
Sven


puppet...@incase.de

unread,
Sep 26, 2008, 9:17:44 AM9/26/08
to puppet...@googlegroups.com
Another reply to myself.

I also inverstigated using defines like in:
http://reductivelabs.com/trac/puppet/wiki/Recipes/AptKeys

Which resulted in this code:

define cobbler::repo($name, $source, $arch="", $ensure="present",
$local=1) {
case $ensure {
present: {
exec { "ensure_cobbler_repo $name":
command => "cobbler_repo_ensure -n $name -s $source -m $local -a
$arch",
path =>
"/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin",
user => "root",
unless => "cobbler_repo_exists -n $name",
logoutput => on_failure,
notify => Exec["cobbler_repo_sync"],
require => [
File["/usr/local/bin/cobbler_repo_ensure"],
File["/usr/local/bin/cobbler_repo_insync"]
]
}
}
absent: {
exec { "remove_cobbler_repo $name":
command => "cobbler repo remove --name=$name",
path =>
"/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin",
user => "root",
onlyif => "cobbler_repo_exists -n $name",
logoutput => on_failure,
notify => Exec["cobbler_repo_sync"],
require => File["/usr/local/bin/cobbler_repo_exists"]
}
}
insync: {
exec { "ensure_cobbler_repo $name":
command => "cobbler_repo_ensure -n $name -s $source -m $local -a
$arch",
path =>
"/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin",
user => "root",
unless => "cobbler_repo_insync -n $name -s $source -m $local -a
$arch",
logoutput => on_failure,
notify => Exec["cobbler_repo_sync"],
require => [
File["/usr/local/bin/cobbler_repo_ensure"],
File["/usr/local/bin/cobbler_repo_insync"]
]
}
default: {
fail "Invalid 'ensure' value for cobbler::repo: $ensure"
}
}
}


However, I didn't find out how I could require a repository which was
created this way in another define (for a system profile for example).

As before, help would be appreciated.

Regards,
Sven

Andrew Shafer

unread,
Sep 26, 2008, 11:39:41 AM9/26/08
to puppet...@googlegroups.com

You created the type which provides an interface for something that you wish to model.

The 'ensurable' call is going to do something very similar to the ensure definition you defined with a block, but they can't both exists.

ensureable is going to look for an exists? method on the 'provider', and it doesn't look like you have one.

The idea is that types model something at a high level and providers give you portability across platforms. (in this case, you are trying to support something very specific to certain platforms)

Sven Mueller

unread,
Sep 27, 2008, 6:16:35 AM9/27/08
to puppet...@googlegroups.com
Andrew Shafer schrieb:

> You created the type which provides an interface for something that you wish
> to model.

Yes, that much I understood.

> The 'ensurable' call is going to do something very similar to the ensure
> definition you defined with a block, but they can't both exists.

This is also mostly understood. However: if I use "ensurable", can I
extend it to support addional "ensure" states? If not, how do I
implement the ensure interface?

> ensureable is going to look for an exists? method on the 'provider', and it
> doesn't look like you have one.

Well, that much I know, but I don't really understand the relationship
between a type and a provider. I know there are often several providers
for a type (package type has at least dpkg, yum, gem, apt, though there
is only one for parsedfile - as it is the basis for others), I also
understand the "defaultfor:" part. But what a provider really needs in
my case is beyond me.

In other words:
I would really appreciate something like the PracticalTypes page which
goes on to describe "ensurable" and how to write a provider for it.

> The idea is that types model something at a high level and providers give
> you portability across platforms. (in this case, you are trying to support
> something very specific to certain platforms)

Well, yes, but I wanted to implement something like an "installserver"
type collection, which can use cobbler as the backend in an RHEL
environment while using some other backend in other environments. In the
end, even a relatively generic backend directly configuring tftp, dhcp,
dns, repositories (of different types) and webserver would be possible.
So a generic type would be nice, I just started out with the described
relatively simple interface to learn how this has to be done. And I
didn't want to polute the namespace I intended for the later interface.

regards,
Sven

James Turnbull

unread,
Sep 27, 2008, 6:42:26 AM9/27/08
to puppet...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Sven Mueller wrote:
>
> In other words:
> I would really appreciate something like the PracticalTypes page which
> goes on to describe "ensurable" and how to write a provider for it.

Sven

I presume you've read:

http://reductivelabs.com/trac/puppet/wiki/ProviderDevelopment
http://reductivelabs.com/trac/puppet/wiki/CompleteResourceExample

Regards

James Turnbull

- --
Author of:
* Pulling Strings with Puppet
(http://www.amazon.com/gp/product/1590599780/)
* Pro Nagios 2.0
(http://www.amazon.com/gp/product/1590596099/)
* Hardening Linux
(http://www.amazon.com/gp/product/1590594444/)

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFI3g4S9hTGvAxC30ARAlPYAJwKzEYBCRYsCEmubQKuZHgCbxc3QQCgnsTR
FjAjOvvRjz3P2aEKMGAUNEA=
=7zk0
-----END PGP SIGNATURE-----

Sven Mueller

unread,
Sep 29, 2008, 7:38:06 AM9/29/08
to puppet...@googlegroups.com
James Turnbull schrieb:

> Sven Mueller wrote:
>> In other words:
>> I would really appreciate something like the PracticalTypes page which
>> goes on to describe "ensurable" and how to write a provider for it.
>
> Sven
>
> I presume you've read:
>
> http://reductivelabs.com/trac/puppet/wiki/ProviderDevelopment
> http://reductivelabs.com/trac/puppet/wiki/CompleteResourceExample

Thanks, for some odd reason, I completely missed the second one. Now I
should start reading more about writing Ruby code. But shouldn't be too
difficult.

regards,
Sven

Sven Mueller

unread,
Oct 7, 2008, 9:18:29 AM10/7/08
to puppet...@googlegroups.com
I tried writing a type to handle a cobbler repository (because it is the
first thing cobbler wants to see if you start to define a system).
However, I have two problems:

1) (this is a theoretical question for now)

If I understand types (for now without providers) correctly, if I have a
property ensure, it needs a "def retrieve" which returns the current
state of the resource. These returned states should match the "newvalue"
definitions I provide in the source. So if I have

newvalue :present
newvalue :absent
newvalue :insync

with accompanying code, the following should work for retrieve:

def retrieve
ret=`cobbler repo list | \
grep -qE '(^|[[:space:]])#{resource[:name]}([[:space:]]|$)';\
echo $?`
if ( not ret == 0)
:absent
else
if insync?
:insync
else
:present
end
end
end

(As long as I have a working insync? definition)
Is this correct so far? If I defined insync? inside the same newproperty
(:ensure in this case), should I access it as done above, or should I
use "self.insync?" or something else?

2)
I defined retrieve as listed above (full source of the cobbler_repo.rb
is at http://mail.incase.de/cobbler_repo.rb, it surely isn't the best
code I ever wrote, but I can't see why it shouldn't work) and I get:

Tue Oct 07 15:14:02 +0200 2008
//Node[testinst01]/cobbler/Cobbler_repo[CentOS5_i386] (err): Failed to
retrieve current state of resource: wrong number of arguments (1 for 0)


Any hint what I did wrong? What passes one argument to which
function/method and what do I have to do to resolve this. I'm really at
a loss here.

regards,
Sven

Sven Mueller

unread,
Oct 10, 2008, 6:50:16 AM10/10/08
to puppet...@googlegroups.com
Sven Mueller wrote:

I really hate replying to myself when i don't actually have anything to
add. But I'm still at a loss about the solution to the problems below.
Can't anyone help?

Regards,
Sven

Luke Kanies

unread,
Oct 13, 2008, 10:43:30 AM10/13/08
to puppet...@googlegroups.com
On Oct 7, 2008, at 8:18 AM, Sven Mueller wrote:

>
> I tried writing a type to handle a cobbler repository (because it is
> the
> first thing cobbler wants to see if you start to define a system).
> However, I have two problems:
>
> 1) (this is a theoretical question for now)
>
> If I understand types (for now without providers) correctly, if I
> have a
> property ensure, it needs a "def retrieve" which returns the current
> state of the resource. These returned states should match the
> "newvalue"
> definitions I provide in the source.

Essentially, yes. I recommend splitting it into type and provider,
though, in which case your provider needs 'ensure' and 'ensure='
methods, and your type doesn't need any additional code beyond the
newvalue statements.

> So if I have
>
> newvalue :present
> newvalue :absent
> newvalue :insync
>
> with accompanying code, the following should work for retrieve:
>
> def retrieve
> ret=`cobbler repo list | \
> grep -qE '(^|[[:space:]])#{resource[:name]}([[:space:]]|$)';\
> echo $?`
> if ( not ret == 0)
> :absent
> else
> if insync?
> :insync
> else
> :present
> end
> end
> end

You don't call 'insync?' yourself -- Puppet calls it for you.
'retrieve' should just return the current value, which Puppet uses to
determine if your resource is in sync.

This is where the providers are really useful -- you can say
'commands :cobbler', and the providers will 1) provide a 'cobbler'
method, so you can do:

ret = cobbler "repo", "list", ...

and 2) automatically indicate when a provider is non-functional
because the 'cobbler' command is missing.

It's a much better way to separate concerns.

>
> (As long as I have a working insync? definition)
> Is this correct so far? If I defined insync? inside the same
> newproperty
> (:ensure in this case), should I access it as done above, or should I
> use "self.insync?" or something else?
>
> 2)
> I defined retrieve as listed above (full source of the cobbler_repo.rb
> is at http://mail.incase.de/cobbler_repo.rb, it surely isn't the best
> code I ever wrote, but I can't see why it shouldn't work) and I get:
>
> Tue Oct 07 15:14:02 +0200 2008
> //Node[testinst01]/cobbler/Cobbler_repo[CentOS5_i386] (err): Failed to
> retrieve current state of resource: wrong number of arguments (1 for
> 0)
>
>
> Any hint what I did wrong? What passes one argument to which
> function/method and what do I have to do to resolve this. I'm really
> at
> a loss here.

The above should answer it for you, but in general, using --trace is a
good way to get a stack trace, and asking dev questions on puppet-dev
is likely to get faster dev help.

--
Seize opportunity by the beard, for it is bald behind.
-- Bulgarian Proverb
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://madstop.com

Reply all
Reply to author
Forward
0 new messages