/** * Reads Json data for the specified config type from zookeeper, * applies the patch from patchData, and writes it back to Zookeeper in a pretty print format. * Patching JSON flattens existing formatting, so this will keep configs readable. * Starts up curatorclient based on zookeeperUrl. * * @param configurationType GLOBAL, PARSER, etc. * @param patchData a JSON patch in the format specified by RFC 6902 * @param zookeeperUrl configs are here */ public static void applyConfigPatchToZookeeper(ConfigurationType configurationType, byte[] patchData, String zookeeperUrl) throws Exception { applyConfigPatchToZookeeper(configurationType, Optional.empty(), patchData, zookeeperUrl); }
/** * Reads Json data for the specified config type and config name (if applicable) from zookeeper, * applies the patch from patchData, and writes it back to Zookeeper in a pretty print format. * Patching JSON flattens existing formatting, so this will keep configs readable. * Starts up curatorclient based on zookeeperUrl. * * @param configurationType GLOBAL, PARSER, etc. * @param configName e.g. bro, yaf, snort * @param patchData a JSON patch in the format specified by RFC 6902 * @param zookeeperUrl configs are here */ public static void applyConfigPatchToZookeeper(ConfigurationType configurationType, Optional<String> configName, byte[] patchData, String zookeeperUrl) throws Exception { try (CuratorFramework client = getClient(zookeeperUrl)) { client.start(); applyConfigPatchToZookeeper(configurationType, configName, patchData, client); } }
private void patch(CuratorFramework client, ConfigurationType configType, Optional<String> configName, Optional<String> patchMode, Optional<String> patchPath, Optional<String> patchKey, Optional<String> patchValue) throws Exception { try { byte[] patchData; if (patchKey.isPresent()) { patchData = buildPatch(patchMode, patchKey, patchValue).getBytes(StandardCharsets.UTF_8); } else { patchData = java.nio.file.Files.readAllBytes(Paths.get(patchPath.get())); } ConfigurationsUtils.applyConfigPatchToZookeeper(configType, configName, patchData, client); } catch (IOException e) { LOG.error("Unable to load patch file '%s'", patchPath, e); throw e; } catch (Exception e) { LOG.error("Unable to apply patch to Zookeeper config", e); throw e; } }
@Test public void patchesParserConfigurationViaPatchJSON() throws Exception { // setup zookeeper with a configuration final ConfigurationType type = ConfigurationType.PARSER; final String parserName = "patched-metron-parser"; byte[] config = JSONUtils.INSTANCE.toJSONPretty(someParserConfig); ConfigurationsUtils.writeConfigToZookeeper(type, Optional.of(parserName), config, zookeeperUrl); // patch the configuration byte[] patch = JSONUtils.INSTANCE.toJSONPretty(patchParserConfig); ConfigurationsUtils.applyConfigPatchToZookeeper(type, Optional.of(parserName), patch, zookeeperUrl); // validate the patched configuration byte[] actual = ConfigurationsUtils.readConfigBytesFromZookeeper(type, Optional.of(parserName), zookeeperUrl); byte[] expected = JSONUtils.INSTANCE.toJSONPretty(modifiedParserConfig); assertThat(actual, equalTo(expected)); }
/** * Note: the current configuration structure mixes abstractions based on the configuration type * and requires testing each type. GLOBAL is a actually representative of the final node name, * whereas the other types, e.g. PARSER, represent a directory/path and not a ZK node where values * are stored. The semantics are similar but slightly different. */ @Test public void patchesGlobalConfigurationViaPatchJSON() throws Exception { // setup zookeeper with a configuration final ConfigurationType type = ConfigurationType.GLOBAL; byte[] config = JSONUtils.INSTANCE.toJSONPretty(someGlobalConfig); ConfigurationsUtils.writeConfigToZookeeper(type, config, zookeeperUrl); // patch the configuration byte[] patch = JSONUtils.INSTANCE.toJSONPretty(patchGlobalConfig); ConfigurationsUtils.applyConfigPatchToZookeeper(type, patch, zookeeperUrl); // validate the patched configuration byte[] actual = ConfigurationsUtils.readConfigBytesFromZookeeper(type, zookeeperUrl); byte[] expected = JSONUtils.INSTANCE.toJSONPretty(modifiedGlobalConfig); assertThat(actual, equalTo(expected)); }