Complex custom type?

114 views
Skip to first unread message

Jakov Sosic

unread,
Sep 14, 2012, 12:37:28 PM9/14/12
to puppet...@googlegroups.com
Hi.

I've successfully written and tested three puppet custom types for
managing cobbler so far (distro, repo and profile). So far it has been
interesting week, learning ruby from zero, learning custom types etc.
But I'm really satisfied with the results so far.

Now I'm trying to figure out how to write rather complex provider, so
maybe someone can help with some thoughts or input.

What am I trying to do is write a provider for a command that looks
something like this:

cobbler add system --name=blah \
--profile=someprofile \
--interface=eth0 \
--mac=SOMEMAC \
--interface-type=bond_slave \
--interface-master=bond0 \
--interface=eth1 \
--mac=SOMEMAC \
--interface-type=bond_slave \
--interface-master=bond0 \
--interface-name=bond0 \
--interface-type=bond
--bonding-opts="miimon=300 mode=1 primary=eth0"
--ip-address=MYIP \

As you can see, problem is that I can have multiple interfaces, and
every one of them can have some unique properties (mac, type, etc).

So, for example I don't have a clue how should a resource for something
like this look like? My first thought was:

cobblersystem { 'blah':
profile = 'someprofile',
interfaces = ['eth0','eth1','bond0'],
macs = ['SOMEMAC1','SOMEMAC2']
iface-opts = ['-interface-type=bond_slave
--interface-master=bond0','..','']
...
...
}

But this is just a big mess - both for reading and writing resources
itself, as is for reading and writing provider :(

Another idea was to separate resources for interfaces from the main
system resource, so that I could write something like:


cobblersysiface {'eth0':
...
}
cobblersysiface {'eth1':
...
}
cobblersystem {'eth0':
interfaces = [Cobblersysiface['eth0'], Cobblersysiface['eth1'], ],
}

But I'm still not fully satisfied with this, because provider for
interface should contact the provider for cobblersystem, beacuse it's
that provider that runs the full "cobbler system add/edit" command.

Any ideas on this one?

Or is it too complex and should I just give up and simply use Exec type :-/

Stefan Schulte

unread,
Sep 16, 2012, 10:47:16 AM9/16/12
to puppet...@googlegroups.com
On Fri, Sep 14, 2012 at 06:37:28PM +0200, Jakov Sosic wrote:
> Hi.
>
> I've successfully written and tested three puppet custom types for
> managing cobbler so far (distro, repo and profile). So far it has been
> interesting week, learning ruby from zero, learning custom types etc.
> But I'm really satisfied with the results so far.
>
> Now I'm trying to figure out how to write rather complex provider, so
> maybe someone can help with some thoughts or input.
>
> What am I trying to do is write a provider for a command that looks
> something like this:
>
> cobbler add system --name=blah \
> --profile=someprofile \
> --interface=eth0 \
> --mac=SOMEMAC \
> --interface-type=bond_slave \
> --interface-master=bond0 \
> --interface=eth1 \
> --mac=SOMEMAC \
> --interface-type=bond_slave \
> --interface-master=bond0 \
> --interface-name=bond0 \
> --interface-type=bond
> --bonding-opts="miimon=300 mode=1 primary=eth0"
> --ip-address=MYIP \

As you pointed out you can write different types and the system types
will create the system with no interfaces at all (if that is possible)
and the interface type will add them later on.

The second way I can think of is a delimiter if the interface options
are more or less always the same like

interfaces => [
'eth0:mac=SOME_MAC:type=bond_slave:master=band0',
'eth1:...'
],

or the interface property could accept a hash. I have not tried it
myself but it should work because the puppetlabs f5 type seems to use
it:

https://github.com/puppetlabs/puppetlabs-f5#appendix

-Stefan

Jakov Sosic

unread,
Sep 16, 2012, 3:17:32 PM9/16/12
to puppet...@googlegroups.com
On 09/16/2012 04:47 PM, Stefan Schulte wrote:
> As you pointed out you can write different types and the system types
> will create the system with no interfaces at all (if that is possible)
> and the interface type will add them later on.

It's possible to add interfaces later, I just have to check if it's
possible to create system without one.

My main issue with this approach was how to link those together in
puppet. For example:

cobblersystem{'mysys':
}

cobblersysiface{'eth0':
system => 'mysys',
}

but I didn't know about autoreqire thing, which you've pointed out in
the other thread I've started :) So I guess I will take this approach
into account after I discuss it with the colleague which will administer
Cobbler with this module.

> The second way I can think of is a delimiter if the interface options
> are more or less always the same like
>
> interfaces => [
> 'eth0:mac=SOME_MAC:type=bond_slave:master=band0',
> 'eth1:...'
> ],
>
> or the interface property could accept a hash. I have not tried it
> myself but it should work because the puppetlabs f5 type seems to use
> it:
>
> https://github.com/puppetlabs/puppetlabs-f5#appendix

Delimiter is OK, but requires lots of mangling in the provider, which
could be cumbersome. Approach with subtypes is much cleaner to
implement, although I have no idea what would people prefer to use.


--
Jakov Sosic
www.srce.unizg.hr

Jakov Sosic

unread,
Sep 16, 2012, 5:23:12 PM9/16/12
to puppet...@googlegroups.com
On 09/16/2012 04:47 PM, Stefan Schulte wrote:

> or the interface property could accept a hash. I have not tried it
> myself but it should work because the puppetlabs f5 type seems to use
> it:
>
> https://github.com/puppetlabs/puppetlabs-f5#appendix

Also, if you don't mind to explain it, or to show by example what do you
mean by 'hash'? ty...


--
Jakov Sosic
www.srce.unizg.hr

Nan Liu

unread,
Sep 17, 2012, 1:18:49 PM9/17/12
to puppet...@googlegroups.com
Assuming the following command:
cobbler add system --name=blah \
--profile=someprofile \
--interface=eth0 \
--mac=SOMEMAC \
--interface-type=bond_slave \
--interface-master=bond0 \
--interface=eth1 \
--mac=SOMEMAC \
--interface-type=bond_slave \
--interface-master=bond0 \
...

The example above maps to the following puppet resource:

cobbler_system { 'bla':
profile => 'someprofile',
interface => { 'eth0' => { 'mac' => somemac, 'interface-type' =>
bond_slave, ... },
'eth1' => { 'mac' => ... },
...
}

To support a hash for the interface attribute, make sure you override
insync?, is_to_s, should_to_s and possibly change_to_s in the resource
type. The f5_pool member attribute should provide an example.

Thanks,

Nan

Jakov Sosic

unread,
Sep 21, 2012, 9:55:07 PM9/21/12
to puppet...@googlegroups.com
Thank you for your answer. I've been able to get back to this task only
yesterday and after few hours of battling with hashes and ruby code, and
totally unreadable f5 resource :) - I've finally succeeded to push
through... I've been able to get it work. So far, detecting if the hash
is different in manifest from the state in the real world is working
like a charm.

But there is still some way to go, I have the following problems left:
- detecting and removing items from system if they are removed from hash
- mangling around with unused options
- testing and debugging...


After that, I'll probably upload the module to puppetforge. One thing
that bothers me - since this will be my first module of this complexity,
are there some volunteers to check it out before I upload it? Even just
the code itself, without actually testing if it work's... Any hints if
I've made some mistakes, or if something could be done better would be
of much use to me... because I'm kinda new to ruby, so I guess code
isn't as optimized as it could be, and also maybe puppet
classes/manifests could be organized better.

Thank you guys for all your support so far.


--
Jakov Sosic
www.srce.unizg.hr
Reply all
Reply to author
Forward
0 new messages