[
https://issues.apache.org/jira/browse/BROOKLYN-286?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15312260#comment-15312260
]
ASF GitHub Bot commented on BROOKLYN-286:
-----------------------------------------
Github user neykov commented on a diff in the pull request:
https://github.com/apache/brooklyn-server/pull/173#discussion_r65534125
--- Diff:
camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
---
@@ -257,37 +261,63 @@ private void configureEntityConfig(EntitySpec<?>
spec, Set<String> encounteredRe
// attrs will contain only brooklyn.xxx properties when coming
from BrooklynEntityMatcher.
// Any top-level flags will go into "brooklyn.flags". When
resolving a spec from $brooklyn:entitySpec
// top level flags remain in place. Have to support both cases.
-
+ //
+ // For config values inherited from the super-type (be that the
Java type or another catalog item
+ // being extended), we lookup the config key to find out if the
values should be merged, overridden or
+ // cleared.
+
ConfigBag bag = ConfigBag.newInstance((Map<Object, Object>)
attrs.getStringKey(BrooklynCampReservedKeys.BROOKLYN_CONFIG));
ConfigBag bagFlags = ConfigBag.newInstanceCopying(attrs);
if (attrs.containsKey(BrooklynCampReservedKeys.BROOKLYN_FLAGS)) {
bagFlags.putAll((Map<String, Object>)
attrs.getStringKey(BrooklynCampReservedKeys.BROOKLYN_FLAGS));
}
- Collection<FlagConfigKeyAndValueRecord> topLevelApparentConfig =
findAllFlagsAndConfigKeys(spec, bagFlags);
+ Collection<FlagConfigKeyAndValueRecord> topLevelApparentConfig =
findAllFlagsAndConfigKeyValues(spec, bagFlags);
for (FlagConfigKeyAndValueRecord r: topLevelApparentConfig) {
if (r.getConfigKeyMaybeValue().isPresent())
bag.putIfAbsent((ConfigKey)r.getConfigKey(),
r.getConfigKeyMaybeValue().get());
if (r.getFlagMaybeValue().isPresent())
bag.putAsStringKeyIfAbsent(r.getFlagName(),
r.getFlagMaybeValue().get());
}
+
// now set configuration for all the items in the bag
- Collection<FlagConfigKeyAndValueRecord> records =
findAllFlagsAndConfigKeys(spec, bag);
+ Map<String, ConfigKey<?>> entityConfigKeys =
findAllConfigKeys(spec);
+
+ Collection<FlagConfigKeyAndValueRecord> records =
findAllFlagsAndConfigKeyValues(spec, bag);
Set<String> keyNamesUsed = new LinkedHashSet<String>();
for (FlagConfigKeyAndValueRecord r: records) {
if (r.getFlagMaybeValue().isPresent()) {
- Object transformed = new SpecialFlagsTransformer(loader,
encounteredRegisteredTypeIds).apply(r.getFlagMaybeValue().get());
- spec.configure(r.getFlagName(), transformed);
- keyNamesUsed.add(r.getFlagName());
+ String flag = r.getFlagName();
+ Object ownVal = new SpecialFlagsTransformer(loader,
encounteredRegisteredTypeIds).apply(r.getFlagMaybeValue().get());
+ Maybe<?> superVal = spec.getFlags().containsKey(flag) ?
Maybe.of(spec.getFlags().get(flag)) : Maybe.absent();
+ Object combinedVal =
combineValues(entityConfigKeys.get(flag), spec, Maybe.of(ownVal),
superVal).get();
+ spec.configure(flag, combinedVal);
+ keyNamesUsed.add(flag);
}
if (r.getConfigKeyMaybeValue().isPresent()) {
- Object transformed = new SpecialFlagsTransformer(loader,
encounteredRegisteredTypeIds).apply(r.getConfigKeyMaybeValue().get());
- spec.configure((ConfigKey<Object>)r.getConfigKey(),
transformed);
- keyNamesUsed.add(r.getConfigKey().getName());
+ ConfigKey<Object> key = (ConfigKey<Object>)
r.getConfigKey();
+ Object ownVal = new SpecialFlagsTransformer(loader,
encounteredRegisteredTypeIds).apply(r.getConfigKeyMaybeValue().get());
+ Maybe<?> superVal = spec.getConfig().containsKey(key) ?
Maybe.of(spec.getConfig().get(key)) : Maybe.absent();
+ Object combinedVal =
combineValues(entityConfigKeys.get(key.getName()), spec, Maybe.of(ownVal),
superVal).get();
+ spec.configure(key, combinedVal);
+ keyNamesUsed.add(key.getName());
}
}
+ // For anything that should not be inherited, clear if from the
spec
+ for (Map.Entry<String, ConfigKey<?>> entry :
entityConfigKeys.entrySet()) {
+ if (keyNamesUsed.contains(entry.getKey())) {
+ continue;
+ }
+ ConfigKey<?> key = entry.getValue();
+ InheritanceMode mode = getInheritanceMode(key, spec);
+ if (mode == InheritanceMode.NONE) {
+ spec.removeConfig(key);
+ spec.removeFlag(key.getName());
+ }
+ }
+
--- End diff --
Should do analogous merging for locations?
> merge config keys map values, where appropriate
> -----------------------------------------------
>
> Key: BROOKLYN-286
> URL: https://issues.apache.org/jira/browse/BROOKLYN-286
> Project: Brooklyn
> Issue Type: New Feature
> Affects Versions: 0.9.0
> Reporter: Aled Sage
>
> See the email discussion on [email protected], subject "[PROPOSAL]
> merging config keys", initially kicked off 25/05/2016, 12:12.
> Below is a copy of that initial proposal, which has then been further
> discussed on the mailing list.
> TL;DR: we should merge config when overriding entities/locations, where it's
> obvious that such behaviour is desired. For example, where an entity type
> defines shell.env, then a new entity extending this type should inherit and
> add to those values.
> _*REQUIREMENTS*_
> _*shell.env in entities*_
> When extending an existing entity type in YAML, it is not possible to extend
> the set of environment variables. Instead, if the sub-type declares shell.env
> it will override the inherited values.
> For example, consider the catalog items below:
> # Catalog
> brooklyn.catalog:
> items:
> - id: machine-with-env
> item:
> type:
> org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess
> brooklyn.config:
> shell.env:
> ENV1: myEnv1
> # Blueprint
> location: ...
> services:
> - type: machine-with-env
> brooklyn.config:
> shell.env:
> ENV2: myEnv2
> launch.command: echo "ENV1=$ENV1, ENV2=$ENV2"
> A user might well expect the launch.command to have myEnv1 and myEnv2.
> However, it does not get the ENV1 environment variable. This is a real pain
> when trying to customize stock blueprints.
> We propose that the shell.env map should be *merged*.
> _*provisioning.properties*_
> An entity can be configured with provisioning.properties. These are passed to
> the location when obtaining a new machine. They supplement and override the
> values configured on the location. However, for templateOptions the
> expected/desired behaviour would be to merge the options.
> Consider the blueprint below:_*
> *_
> location:
> minCores: 1
> templateOptions:
> networks: myNetwork
> services:
> - type: org.apache.brooklyn.entity.machine.MachineEntity
> brooklyn.config:
> provisioning.properties:
> minRam: 2G
> templateOptions:
> tags: myTag
> A user might well expect the VM to be created with the given networks and
> tags. However, currently the templateOptions in provisoining.properties will
> override the existing value, rather than being merged with it.
> We propose that the templateOptions map should be *merged*.
> Valentin made a start to fix this in
> https://github.com/apache/brooklyn-server/pull/151.
> _*_*provisioning.properties in sub-entities*_
> *_
> A similar argument holds for when extending an entity-type in YAML.
> If the super-type declares template options, then any additional
> provisioning.properties declared on the entity sub-type should be *merged*
> (including merging the templateOptions map contained within it).
> _*files.preinstall, templates.preinstall, etc*_
> The same applies for the map config for: files.preinstall,
> templates.preinstall, files.install, templates.install, files.runtime and
> templates.runtime.
> We propose that these maps get *merged* with the value defined in the
> super-type.
> _*Overriding default values*_
> For default values in the super-type, we propose that this value *does* get
> overridden, rather than merged.
> For example, in the blueprint below we suggest that the launch-command in the
> sub-type should have ENV2 but not ENV_IN_DEFAULT.
> brooklyn.catalog:
> items:
> - id: machine-with-env
> version: 1.0.0
> item:
> type:
> org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess
> brooklyn.parameters:
> - name: shell.env
> default:
> ENV_IN_DEFAULT: myEnvInDefault
> - id: machine-with-env-2
> version: 1.0.0
> item:
> type: machine-with-env
> brooklyn.config:
> shell.env:
> ENV2: myEnv2
> launch.command: echo "ENV_IN_DEFAULT=$ENV_IN_DEFAULT,
> ENV2=$ENV2"
> (Interestingly, the current behaviour of machine-with-env is that it gets the
> value for ENV_IN_DEFAULT but not for ENV2, so sometime strange is going on
> with re-defining the shell.env config key!)
> _*Extending commands: deferred*_
> Another scenario is where a super-type declares a value for
> `install.command`, and the sub-type wants to augment this by adding
> additional commands. Currently that is not possible. Instead the sub-type
> needs to use pre.install.command and/or post.install.command. But that leads
> to the same problem if a super-type also has a value defined for that key.
> Svet suggested we could perhaps introduce something like $brooklyn:super().
> Unless we can generalise that approach to also solve the merging of
> `shell.env` etc, then I suggest we defer the `install.command` use-case. That
> can be proposed and discussed in a different thread.
> However, if we can solve these problems with clever explicit use of
> $brooklyn:super(), then that could provide an elegant solution to all of
> these problems!
> _*Inheritance from parent entities*_
> Things are made yet more complicated by the fact we inherit config from
> parent entities, in the entity hierarchy.
> We propose that this behaviour is also configurable for the config key, but
> that the defaults stay as they are. The existing logic is applied to find the
> config value that applies to the given entity. That value is then merged with
> its super-type, as appropriate.
> For example, in the blueprint below... machine1 would get ENV1 and ENV2 (i.e.
> the ENV1 definition overrides the ENV_IN_APP definition). However, machine2
> would get ENV1 and ENV_IN_APP (i.e. it inherits ENV_IN_APP from the parent,
> and this is meged with the super-type).
> services:
> - type: org.apache.brooklyn.entity.stock.BasicApplication
> brooklyn.config:
> shell.env:
> ENV_IN_APP: myEnvInApp
> brooklyn.children:
> - type: machine-with-env
> id: machine1
> brooklyn.config:
> shell.env:
> ENV2: myEnv2
> - type: machine-with-env
> id: machine2
> The reasoning behind this is to figure out the inheritance/override rules
> incrementally. We leave the parent-inheritance as-is, and just focus on the
> sub-typing inheritance.
> Note that there is already a ConfigInheritance defined on ConfigKey for
> controlling this kind of inheritance from the parent. The legal values for
> ConfigInheritance are currently just ALWAYS and NONE.
> _*IMPLEMENTATION*_
> Clearly we do not want to implement this piecemeal. We'll add a way to
> declare that a config key should be merged with that value from the
> super-type.
> We'll change the Java ConfigKey code to be:
> public interface ConfigKey {
> /**
> * @since 0.10.0
> */
> @Nullable ConfigInheritance getParentInheritance();
> /**
> * @since 0.10.0
> */
> @Nullable ConfigInheritance getTypeInheritance();
> /**
> * @deprecated since 0.10.0; instead use {@link
> #getParentInheritance()}
> */
> @Nullable ConfigInheritance getInheritance();
> }
> We'll add to ConfigInheritance support for MERGE. We'll change the name
> "ALWAYS" to OVERRIDE (deprecating the old value).
> We'll change EntityConfigMap.getConfig to handle this new merge behaviour.
> And same for locations, policies and enrichers.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)