While I have gathered some experience in Ruby scripting, Rails is completely new to me.
The current HEAD can be installed with successful database migrations and Foreman UI integration. After foreman-maintain service restart, existing CNAMEs are shown in the NIC edit form, where new CNAMEs seemingly can be added, too. However, the problem is…
Problem
New or updated CNAMEs from the NIC edit form are not written to the database.
Foreman and Proxy versions
RedHat Satellite 6.13.7, which includes (among others)…
satellite-6.13.7-1.el8sat
katello-4.7.0-1.el8sat
foreman-3.5.1.24-1.el8sat
foreman-proxy-3.5.1-1.el8sat
Distribution and version
My development Foreman instance is running on
Red Hat Enterprise Linux release 8.9 “Ootpa” (4.18.0-513.24.1.el8_9.x86_64)
Other relevant data
I can successfully add new CNAMEs to the database through the Rails console.
This record does show up in the NIC edit form (although ugly formatted, polish comes later ). But as said before, changes to this or newly added CNAMEs are not written to the database. So my plugin is missing something which I could not figure out.
Running Foreman on debug log level, I see that the Deface overrides are applied, but submits of the NIC edit form are not recorded. I’d be thankful for any comments/pointers towards mistakes and/or omissions in the plugin.
Hi again, made one step forward by extending the NIC::Interface parameters (instead of NIC::Base). Now I can see in the log file that a patch was tried and the :host_alias_attributes parameter is not permitted.
logged interface patch
2024-06-11T10:59:11 [I|app|73490761] Started PATCH "/hosts/1937" for 2a00:1398:4:0:65cc:b271:db94:9357 at 2024-06-11 10:59:11 +0200
2024-06-11T10:59:11 [I|app|73490761] Processing by HostsController#update as */*
2024-06-11T10:59:11 [I|app|73490761] Parameters: {
...,
"host" => {
"name" => "satellite-test-01",
"hostgroup_id" => "353",
"managed" => "true",
"overwrite" => "false",
"interfaces_attributes" => {
"0" => {
"_destroy" => "0",
"mac" => "00:50:56:b0:cf:6f",
"identifier" => "ens192",
"name" => "satellite-test-01",
"domain_id" => "1",
"subnet_id" => "63",
"subnet6_id" => "105",
"ip" => "141.52.208.167",
"ip6" => "2a00:1398:100:2::20",
"host_aliases_attributes"=> {
"0" => {
"name" => "test-alias2",
"domains_id" => "2",
"_destroy" => "false",
"id" => "1"
}
},
"managed" => "1",
"primary" => "1",
"provision" => "1",
"execution" => "1",
"tag" => "",
"attached_to" => "",
"id" => "7958"
}
},
...
}
}
2024-06-11T10:59:11 [D|tax|73490761] Current location set to none
2024-06-11T10:59:11 [D|tax|73490761] Current organization set to SCC
2024-06-11T10:59:11 [D|tax|73490761] Current organization set to none
2024-06-11T10:59:11 [D|tax|73490761] Current location set to none
2024-06-11T10:59:11 [D|app|73490761] Unpermitted parameter: :host_aliases_attributes
2024-06-11T10:59:11 [D|app|73490761] Unpermitted parameter: :media_selector
2024-06-11T10:59:11 [W|api|73490761] param host[puppetclass_*] has been deprecated in favor of host[puppet_attributes][puppetclass_*]
2024-06-11T10:59:11 [W|app|73490761] Using TFTP Smart Proxy hostname as the boot server name: satellite-test-01.scc.kit.edu
2024-06-11T10:59:11 [D|tax|73490761] Current organization set to SCC
2024-06-11T10:59:11 [D|tax|73490761] Current location set to CM
2024-06-11T10:59:11 [D|tax|73490761] Current location set to none
2024-06-11T10:59:11 [D|tax|73490761] Current organization set to none
2024-06-11T10:59:12 [I|app|73490761] Redirected to https://satellite-test-01.scc.kit.edu/new/hosts/satellite-test-01.scc.kit.edu
2024-06-11T10:59:12 [D|tax|73490761] Current location set to none
2024-06-11T10:59:12 [D|tax|73490761] Current organization set to SCC
2024-06-11T10:59:12 [I|app|73490761] Completed 302 Found in 1360ms (ActiveRecord: 74.8ms | Allocations: 200316)
Again, I assume the relations between the controllers and models are done correctly, since I can supply :host_aliases_attributes when creating a new Nic::Interface in the Rails console.
My current theory is, that the model is correct. But the parameters controller is not mixed into the interface’s parameter filter. I expected parameter_filter in engine.rb to do that by some opaque magic, but am evidently mistaken.
The old pull request doesn’t have that issue, because it inserts itself right at the NicBase parameter controller. Since my plugin is namespaced, I can’t do that easily (without resorting to monkey patches).
The How-To-Create-a-Plugin briefly explains how to permit attributes on Foreman models by using parameter_filter. Tracing that in the Foreman sources, I get to Foreman::ParameterFiler#permit, where the comment says, it doesn’t work for nested attributes. My options are to either instantiate a new ParameterFilter or to supply a block to parameter_filter, right?
Using a block with parameter_filter I discover that it is executed through Foreman::ParameterFilter::Context. However, none of the variants I’ve tried so far had any impact, :host_aliases_attributes stayed unpermitted.
# ForemanCnames::Engine
Foreman::Plugin.register :foreman_cnames do
requires_foreman '>= 3.5.0'
parameter_filter ::Nic::Interface do |context|
context.permit(host_aliases_attributes: [])
end
end
Just to feel some satisfaction, after spending two weeks on this nut without cracking it, I added {:host_aliases_attributes => [host_alias_params_filter]} to the Foreman::Controller::Parameters::NicBase source and found that now updates to interfaces through the GUI work just fine!
Apparently, I was already very close, though I cannot be sure that this is the sole difference that fixed my issue:
# ForemanCnames::Engine
Foreman::Plugin.register :foreman_cnames do
requires_foreman '>= 3.5.0'
parameter_filter ::Nic::Interface do |context|
context.permit :host_aliases_attributes => {}
end
end
With that, changes in the GUI are propagated to the database!
Next challenge is to find out why these changes are not send to our DNS capsule to add/remove/update the CNAMEs to DNS… If I fail to understand that black magic, I’ll start a new thread.
Just as a new note that might help others googleing for issues with Foreman’s strong parameter filter, this is how you can inspect the current filters for your plugin through the console: