In ACE-230 the problem of targets that are removed is described. Even though you can currently remove a target, via its audit log, that target immediately shows up again as an "unregistered" target. This document analyses the ways in which we can solve this issue and comes up with an initial design for the chosen solution.

Analysis

Let's start by taking a step back to explore how and why targets show up as unregistered. Starting with the why: if some new target polls the server, we have it show up as unregistered so in the client user interface it is easy to see and register it. This covers the use case where you fire up a new target and want to deploy software to it. The alternative is to "preregister" it before it polls. If you do that, you can also already assign software to it. Now to the how: the server currently accepts audit log data from any target, and we use this data to detect that a new target has polled. So any target that polls the server and sends it audit log data will become an unregistered target.

What we want to achieve here is that we can:

  1. Remove an existing, registered target.
  2. If a removed target re-appears, register it again.

As the issue already mentioned, it is not feasible to simply delete the whole audit log to prevent a target from re-appearing. For one, it is historic data that you might want to preserve. Furthermore, if you work with relay servers, they do their best never to loose such data now, so even if you delete data on one server, it might re-appear via another.

One option to explore is to instead mark a target as removed. In that case we keep the TargetObject around, but we mark it as deleted, adding the timestamp at which this has happened. By using this timestamp we can then ignore any event in the audit log that happened before our delete, effectively preventing the target from re-appearing because of old audit log events. At the same time, if the target does re-appear in the future, we can again show it as unregistered. However, in a scenario where targets come and go quickly, there is one big downside: since we no longer delete a target, but mark it as deleted instead, over time lots of "deleted" targets will be present in the repository. That does not scale well. It would be much better not to have them in the target repository at all.

That takes us back to why unregistered targets show up at all. As explained above, this is done for convenience and use cases where you really want to discover "new" targets that show up. During development and simple demonstrations, this is nice. It might also be nice in other, specific scenarios. It is questionable if this is always nice though, so let's explore if a better solution would be to make this behaviour optional.

Since unregistered targets show up in the client, we could make it a configuration option to never show unregistered targets. It not always makes sense to show them:

  • You might want to explicitly register them at all times anyway.
  • You might have partitioned your world using different customer repositories. If you do so, unknown targets might show up in all of them (because with just an audit log, you have no clue which customer the target belongs to, furthermore, if it is registered with one customer, it is still unknown with another, all of which is potentially solvable if you add a customer ID when an unknown target polls, but the question is if you want to have to solve it at all).

Another thing we could do, is to add a configuration option that will never allow audit log data of targets that are unknown. This might actually be tricky, as we would have to scan all repositories to see if a target is known. For that reason, I would probably not want to add such a feature. If you really only want to talk to "known" targets, it probably makes more sense to use authentication to identify them first.

Also, if you need some kind of discovery mechanism, there are many ways to potentially do that. For one you can always query the audit log store yourself and compare the targets you find there to the target repository (which is how the current discovery mechanism works, which subsequently creates stateful targets for each "unregistered" target). You can also rely on some other means of discovery. Your targets might be manufactured and pre-configured with some ID that is known. If you keep a list of those IDs you can also discover, or even pre-register such targets. You might also have an authentication mechanism, so using the list of authorized targets might also be a way to implement discovery.

Conclusion

I think we should implement an option in the client to not show "unregistered" targets at all. This can be a configuration we either persist (a default) or allow users to specify when they start a new session (to override the default).

If you then still want to show unregistered targets and mark them as deleted, we could consider implementing the code to mark such targets as deleted, but right now I'm not yet convinced it has much real-world use so I would propose to postpone that for now. Furthermore, this is something you can always implement yourself by adding such a property and doing the filtering logic yourself. Whilst not desirable in the generic case, it might be a good solution to your particular problem.

Design

Configuring a default to show unregistered targets or not is something that belongs to the client repository. It does not yet have a configuration, so we'd have to make it a ManagedService. The configuration can be optional, and the default when no configuration is specified is to show unregistered targets (like we do now) to remain backward compatible with the current implementation.

Overriding the default is something that could be done when creating a new session. This happens in the SessionFactory of the client repository, so we could add a parameter to that method to override the default.

The StatefulTargetRepositoryImpl contains a "populate()" method which explicitly creates stateful targets for both targets that have a target object and ones that have an audit log. The latter can then be optional. This repository instance is created when the session is created, so the configured option can be passed along there.

  • No labels