Kevan Jahanshahi created FELIX-6862:
---------------------------------------
Summary: ConfigInstaller adopts and deletes configuration files
that another ArtifactInstaller handles
Key: FELIX-6862
URL: https://issues.apache.org/jira/browse/FELIX-6862
Project: Felix
Issue Type: Task
Components: File Install
Affects Versions: fileinstall-3.7.4
Reporter: Kevan Jahanshahi
h2. Summary
{{ConfigInstaller}} adopts every configuration that records
{{felix.fileinstall.filename}}, whatever the format of the file. The
{{CM_DELETED}} path then deletes the file that the resulting {{pidToFile}}
entry names. An installer therefore deletes a configuration file that another
{{ArtifactInstaller}} handles.
h2. Where this comes from
FELIX-5832 added a {{canHandle}} filter to the {{CM_UPDATED}} path in 2018, and
the subject of that commit states the rule:
bq. Only handle ConfigurationEvents for config objects managed by us
Three sites read or write {{pidToFile}}, and FELIX-5832 covered one of them.
The other two sites are still unfiltered on {{master}} today.
* {{init()}} puts every configuration that records a file name into
{{pidToFile}}, with no filter.
* The {{CM_DELETED}} path removes the pid from {{pidToFile}} and deletes the
file, with no filter.
h2. Failure scenario
A container runs a second {{ArtifactInstaller}} for another configuration
format. Jahia ships one for {{.yml}} and {{.yaml}}, and that installer records
{{felix.fileinstall.filename}} the same way any installer does.
# The second installer creates a configuration from {{example.yml}} and records
that file name.
# The container restarts, and {{ConfigInstaller.init()}} adopts the pid,
because no filter rejects the format.
# Something deletes that configuration through Configuration Admin.
# {{ConfigInstaller}} deletes {{example.yml}}, although it never handled that
file.
The defect needs a restart, because {{init()}} is the only unfiltered writer of
{{pidToFile}}. The guarded {{CM_UPDATED}} path rejects the foreign format, so a
configuration created while the container runs never enters the map.
A guard in the second installer cannot prevent the deletion. That installer can
decline to delete the file itself, and {{ConfigInstaller}} deletes the file
anyway on the same event.
h2. Proposed fix
Apply the filter FELIX-5832 already wrote, at both remaining sites.
{code:java}
// in init()
if (fileName != null && canHandle(new File(fileName))) {
pidToFile.put(config.getPid(), fileName);
}
// in the CM_DELETED path
if (file != null && file.isFile() && canHandle(file)) {
{code}
The filter at the deletion site matters on its own. Deleting the file is the
act that loses data, and a filter at each writer makes the invariant depend on
every future writer repeating it.
{{init()}} passes {{new File(fileName)}} rather than
{{fromConfigKey(fileName)}}. {{canHandle}} reads the file name only, and
{{fromConfigKey}} calls {{URI.create}}, which throws on a value that is not a
URI. The catch around that loop would then leave {{pidToFile}} half-built.
Behaviour for {{.cfg}} and {{.config}} files is unchanged.
h2. Patch
A pull request follows. It carries two tests, and the first fails when both
filters are removed.
* {{testCmDeletedKeepsAFileOfAnotherInstallersFormat}} asserts that a {{.yml}}
file survives {{CM_DELETED}}.
* {{testCmDeletedStillRemovesAFileOfItsOwnFormat}} asserts that a {{.cfg}} file
is still deleted.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)