Using Subnet Parameters in templates

Problem:
Probably this is an easy question but I really cannot find the solution. Maybe it’s in the docs and I didn’t read the manual correctly. :slight_smile:

I try to use subnet parameters in foreman templates to make sure certain configuration options are set accordingly. Problem I have, I have no clue how to access them. They do not show up on host_params but I cannot seem to find if they are part of the subnet (e.g. subnet.params[‘parameter’] )

So how can I access the parameters I set in a subnet so I can use it in my provisioning templates.

Foreman and Proxy versions:
1.16 & 1.17

Hi,

you can try to use @host.subnet.mask to access the hosts subnet mask. Otherwise you can also use the @host.interfaces array.

All the available parameters are also documented here:
https://projects.theforeman.org/projects/foreman/wiki/TemplateWriting

Cheers,
Martin

1 Like

Hi Martin,

Thanks for your answer, but it wasn’t exactly what I am looking for.
I am looking for custom subnet parameters (like host parameters). The default I can find and are indeed stated at the URL you gave.
If I add a custom parameter say “route” with value “192.168.1.1/24 via 192.168.2.1 dev eth1” I really have no clue where to find these custom parameters in a template.
I can add them via the webinterface at the given subnet but there the road seems to stop for me.

Cheers,
Maarten

Do you mean this kind of parameters:

They can be accessed by using the @host.params array.

Example:

@host.params[“route”]

Cheers,
Martin

I mean these :slight_smile:

Cheers,
Maarten

Parameters work on a hierarchy, with more specific levels overriding more general ones. These are compiled into a single set of params that are then available to the host, so you’ll find all of them in host_param. As an example, if you have:

Global: foo = bar
Subnet: foo = baz
Host1: foo = quux
Host2: foo not set

Then on Host1 host_param('foo') is quux but on Host2 it’s baz. This allows you to reuse the same templates across many hosts/groups/subnets etc. You can test changes via the template rendering, but also the compiled params should be visible on the YAML page for the Host too.

Hi,

Thanks for explaining, I expected it was like this but for some reason I cannot see the the respective parameter.
The host has an interface(with ip) in this subnet. But for some reason it doesn’t show up at the templates.
I did print out the whole @host.param array but nothing. When using host_param(‘route’) also nothing.
I must say, this subnet is not the primary subnet. So host.subnet will give me another subnet.

So is there anything special I need to do to make sure these subnet params are available?

Ah yes, it might be affected by the primary flag, I haven’t checked that for a while.

Try something like this (the wiki has some other notes that may be useful):

@host.first.interfaces.find_by_identifier('eth0').subnet.parameters.find_by_name('test').value

This is clearly the most awful thing known to man or beast (and probably won’t work in Safe Mode), and if there isn’t a better way, we should write one :slight_smile: - @kgaikwad is there an easier way to get non-primary subnet params?

Ah! That explains a lot :slight_smile:

For me the only things I need to add are:
MTU (should be there in 1.18) and (additional) static routes.

I think static routes should be a default param like netmask, gateway and now MTU.
I am not sure about disabling Safe Mode as I cannot really see what that would imply. I read something about arbitrary code. But not if that might impose a security risk or just that anyone who can alter the templates can inject code.

Worth raising an issue for that, sure.

Anyone with edit-access to a template can state arbitrary code which would be run when the template is next rendered. So yes, it’s not ideal - it strongly depends on who has admin/edit rights on your Foreman.

Can you share more about your intended workflow? I have other potentially hacky solutions in my head that may or may not work depending on usecase :slight_smile:

So this makes it possible to run code on the foreman machine itself? That would be something to think of indeed. While any user able to edit anything will be also admin of the hosts (including foreman) this would not be a security risk perse, but it could lead to unintentional breaking of the foreman server (we all have made the typo).

Usecase is quite simple:
Admin adds or rebuilds a host and (re)installs it, afterwards Ansible takes over to really configure the whole thing.
Foreman is mostly used as a basic installer. Because we use high speed networks (25GE, bonded) we need higher MTU’s. We also have multiple routed ip networks on a single host and not all traffic should pass the default gateway, hence the static route.
We have multiple environments in foreman, that’s why hardcoding routes is not something I’d prefer as this means a whole lot of additional snippets and kickstart templates (but could be a way of doing)

Any dirty trick is fine as long as it works :laughing: but I do prefer default mode of operandi as this will make upgrading easier to manage (hacks tend to break).

Also is there any comprehensive reference for all foreman specific things we can use in the ERB’s as it’s quite hard to see the structure of variables/objects so I cannot really see what is available to me for use in templates. (source code do gives some hints, but not really workable)

No, sorry, I was unclear. It give access equivalent to the Rails console, so you can’t do rm -rf / but you can do Host.all.map(&:destroy) (please don’t run that :stuck_out_tongue:). So yes, there is a risk of typos. One mitigation for that is to store your templates in Git (and all the associated code reviews options that come with that) and then sync them into Foreman using the foreman-templates plugin.

So one option if you only need to set this when a host is (re)built would be to look at foreman-hooks and use a script on-disk on the Foreman server to do the lifting. This could fire when a host is being built, query the API for the subnet params, and set an equivalent param on the host. No need for safemode-off in this case, but it may not be sufficiently flexible.

You could also set params at the Hostgroup or Domain level, but I suspect that’s not going to be flexible enough if you’re already making use of secondary NICs :wink:

Patching the list of permitted SafeMode calls is also an option - this could even be done as a tiny plugin if you want to be safe about not overwriting the change on upgrade. If that interest you, more details can be provided :slight_smile:

It turns out to be quite hard to document too, as it changes rapidly. Since for 90% of users it’s not useful (made up number! but SafeMode is enabled by default, so probably accurate) we don’t even try. The usual route is to use foreman-rake console on your box, and play around in there to see what’s possible. That’s what I did to construct the above, doing things like Host.first.interfaces.methods.sort can show you what can be called…

Thanks for the removal of all hosts… No just kidding :rofl:

This seems the most elegant way of doing. Although I need to think how to proceed as some hosts have even more nics. But I think this will do what I need.
Could you give me some example or url how to use this feature?

Writing a plugin seems a bit of an overkill in this situation but if you have the details on this as well I think we could work out which option to use. Both options seems to be able to do what I need.

Plugin details here (and some examples):

Writing a plugin starts with our template plugin to bootstrap people. Details here:

Thanks!

There is enough reading and trying for now :slight_smile:
I will try one of these and see if we can work out a nice and elegant solution.

Cheers!
Maarten

1 Like