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)

Reply via email to