@Override public LoadedInstanceConfig storeConfig(ConfigCollection config, long compareVersion) throws Exception { Long currentVersion = loadProperties().getVersion(); if (currentVersion != compareVersion) { return null; } KeyValueClient kv = consul.keyValueClient(); PropertyBasedInstanceConfig instanceConfig = new PropertyBasedInstanceConfig(config); StringWriter writer = new StringWriter(); instanceConfig.getProperties().store(writer, "Auto-generated by Exhibitor"); lock.acquireLock(lockTimeoutMs, TimeUnit.MILLISECONDS); try { kv.putValue(propertiesPath, writer.toString()); kv.putValue(versionPath, String.valueOf(currentVersion + 1)); } finally { lock.releaseLock(); } return new LoadedInstanceConfig(instanceConfig, currentVersion + 1); }
public boolean acquireLock(long maxWait, TimeUnit unit) { KeyValueClient kv = consul.keyValueClient(); sessionId = createSession(); Optional<Value> value = kv.getValue(path); if (kv.acquireLock(path, sessionId)) { return true; } BigInteger index = BigInteger.valueOf(value.get().getModifyIndex()); kv.getValue(path, QueryOptions.blockMinutes((int) unit.toMinutes(maxWait), index).build()); if (!kv.acquireLock(path, sessionId)) { destroySession(); return false; } else { return true; } }
private String getString(String path) { return consul.keyValueClient().getValueAsString(path).orNull(); }
public void releaseLock() { try { KeyValueClient kv = consul.keyValueClient(); Optional<Value> value = kv.getValue(path); if (value.isPresent()) { Optional<String> session = value.get().getSession(); if (session.isPresent()) { kv.releaseLock(path, session.get()); } } } finally { destroySession(); } } }
/** * Retrieves a {@link com.orbitz.consul.model.kv.Value} for a specific key * from the key/value store. * * GET /v1/kv/{key} * * @param key The key to retrieve. * @return An {@link Optional} containing the value or {@link Optional#empty()()} */ public Optional<Value> getValue(String key) { return getValue(key, QueryOptions.BLANK); }
private void register(String key, String defaultValue, String valueType, String description, ConfigurationScope configurationScope, boolean isPassword) { Optional<String> i = kvClient.getValueAsString(addSn(key)); ConfigItem configItem = prepareConfigItem(valueType, description, configurationScope, isPassword); // TODO this check does not work if (!i.isPresent()) { // Set the value of environment variable as default String envVariable = System.getenv(key); if (envVariable != null) { configItem.setValue(envVariable); kvClient.putValue(addSn(key), toJson(configItem)); } else { configItem.setValue(defaultValue); kvClient.putValue(addSn(key), toJson(configItem)); } } if (configProps != null) { configProps.put(key, getString(key)); } }
public void put(String key, Object object) { // Substitute $ character in key key = key.replaceAll("\\$", "/"); // create session to avoid conflicts // (not sure if that is safe enough, again) SessionClient sessionClient = consul.sessionClient(); String sessionName = "session_" + UUID.randomUUID().toString(); SessionCreatedResponse response = sessionClient .createSession(ImmutableSession.builder().name(sessionName).build()); String sessionId = response.getId(); kvClient = consul.keyValueClient(); String lockKey = "lock_" + key; kvClient.acquireLock(lockKey, sessionName, sessionId); // Allow only unique keys, last one wins if (lookupByName(key) != null) { remove(key); } Object clone = ConsulRegistryUtils.clone((Serializable) object); byte[] serializedObject = ConsulRegistryUtils.serialize((Serializable) clone); // pre-encode due native encoding issues String value = ConsulRegistryUtils.encodeBase64(serializedObject); // store the actual class kvClient.putValue(key, value); // store just as a bookmark kvClient.putValue(object.getClass().getName().replaceAll("\\$", "/") + "/" + key, "1"); kvClient.releaseLock(lockKey, sessionId); }
@InvokeOnHeader(ConsulKeyValueActions.GET_VALUE) protected void getValue(Message message) throws Exception { Object result; Boolean asString = message.getHeader(ConsulConstants.CONSUL_VALUE_AS_STRING, getConfiguration().isValueAsString(), Boolean.class); if (asString) { result = getClient().getValueAsString( getMandatoryHeader(message, ConsulConstants.CONSUL_KEY, getConfiguration().getKey(), String.class) ).orElse(null); } else { result = getClient().getValue( getMandatoryHeader(message, ConsulConstants.CONSUL_KEY, getConfiguration().getKey(), String.class), message.getHeader(ConsulConstants.CONSUL_OPTIONS, QueryOptions.BLANK, QueryOptions.class) ).orElse(null); } setBodyAndResult(message, result); }
@Override protected void commitInternal(ConfigChangeContext context) { for(HostAndPort hostAndPort: ConsulBackends.getConsulBackends()){ try{ Consul consul = Consul.builder().withHostAndPort(hostAndPort).build(); KeyValueClient kvClient = consul.keyValueClient(); for(String k: context.getRemovedProperties()){ try{ kvClient.deleteKey(k); } catch(Exception e){ LOG.info("Failed to remove key from consul: " + k); } } for(Map.Entry<String,String> en:context.getAddedProperties().entrySet()){ String key = en.getKey(); try{ kvClient.putValue(key,en.getValue()); }catch(Exception e) { LOG.info("Failed to add key to consul: " + en.getKey() + "=" + en.getValue()); } } // success: stop here break; } catch(Exception e){ LOG.log(Level.FINE, "consul access failed on " + hostAndPort + ", trying next...", e); } } } }
/** * Aquire a lock for a given key. * * PUT /v1/kv/{key}?acquire={session} * * @param key The key to acquire the lock. * @param session The session to acquire lock. * @return true if the lock is acquired successfully, false otherwise. */ public boolean acquireLock(final String key, final String session) { return acquireLock(key, "", session); }
public void remove(String key) { // create session to avoid conflicts (not sure if that is safe enough) SessionClient sessionClient = consul.sessionClient(); String sessionName = "session_" + UUID.randomUUID().toString(); SessionCreatedResponse response = sessionClient .createSession(ImmutableSession.builder().name(sessionName).build()); String sessionId = response.getId(); kvClient = consul.keyValueClient(); String lockKey = "lock_" + key; kvClient.acquireLock(lockKey, sessionName, sessionId); Object object = lookupByName(key); if (object == null) { String msg = "Bean with key '" + key + "' did not exist in Consul Registry."; throw new NoSuchBeanException(msg); } kvClient.deleteKey(key); kvClient.deleteKey(object.getClass().getName() + "/" + key); kvClient.releaseLock(lockKey, sessionId); }
private static void atomicUpdate(KeyValueClient kv, String key, Function<String, String> mutator) throws IOException { while (true) { final ConsulResponse<Value> r = kv.getConsulResponseWithValue(key).orElse(null); if (r == null) { // Don't automatically create the document, because it might need to be associated with another node's session. // For example, an RPC endpoint doc is updated by both client and server, but is tied to the server session. throw new IOException("Can't update non-existent document: " + key); } final BigInteger index = r.getIndex(); final String oldValue = r.getResponse().getValueAsString(UTF_8).orElse(missingDocumentValue); final String newValue = mutator.apply(oldValue); if (Objects.equals(newValue, oldValue)) { return; } final PutOptions options = ImmutablePutOptions.builder().cas(index.longValue()).build(); boolean success = kv.putValue(key, newValue, 0, options, UTF_8); if (success) { return; } // todo truncated exponential backoff, please! Die if timeout! //MILLISECONDS.sleep(100); } }
/** * Retrieves a list of {@link com.orbitz.consul.model.kv.Value} objects for a specific key * from the key/value store. * * GET /v1/kv/{key}?recurse * * @param key The key to retrieve. * @return A list of zero to many {@link com.orbitz.consul.model.kv.Value} objects. */ public List<Value> getValues(String key) { return getValues(key, QueryOptions.BLANK); }
/** * Deletes a specified key. * * DELETE /v1/kv/{key} * * @param key The key to delete. */ public void deleteKey(String key) { deleteKey(key, DeleteOptions.BLANK); }
/** * Retrieves a list of matching keys for the given key. * * GET /v1/kv/{key}?keys * * @param key The key to retrieve. * @return A list of zero to many keys. */ public List<String> getKeys(String key) { return getKeys(key, QueryOptions.BLANK); }
private void bind() throws InterruptedException, EndpointAlreadyInUseException { while (!closed()) { LOGGER.info("Attempting to binding to RPC endpoint document {}", endpointKey); final boolean acquired = kv.acquireLock(endpointKey, "{}", sessionId); if (acquired) { LOGGER.info("Successfully bound to RPC endpoint document {}", endpointKey); return; } final Optional<ConsulResponse<Value>> existing = kv.getConsulResponseWithValue(endpointKey); if (existing.isPresent()) { // somebody else has acquired the lock final String lockSession = existing.get().getResponse().getSession().orElse(null); throw new EndpointAlreadyInUseException( "Failed to lock RPC endpoint document " + endpointKey + " ; already locked by session " + lockSession); } LOGGER.info("Endpoint lock acquisition failed; will retry after delay."); SECONDS.sleep(1); } } }
public static KVCache newCache( final KeyValueClient kvClient, final String rootPath, final int watchSeconds, final QueryOptions queryOptions) { final String keyPath = prepareRootPath(rootPath); final Function<Value, String> keyExtractor = getKeyExtractorFunction(keyPath); final ConsulCache.CallbackConsumer<Value> callbackConsumer = (index, callback) -> { QueryOptions params = watchParams(index, watchSeconds, queryOptions); kvClient.getValues(keyPath, params, callback); }; CacheDescriptor cacheDescriptor = new CacheDescriptor("keyvalue", rootPath); return new KVCache(keyExtractor, callbackConsumer, kvClient.getConfig().getCacheConfig(), kvClient.getEventHandler(), cacheDescriptor); }
@InvokeOnHeader(ConsulKeyValueActions.GET_VALUES) protected void getValues(Message message) throws Exception { Object result; Boolean asString = message.getHeader(ConsulConstants.CONSUL_VALUE_AS_STRING, getConfiguration().isValueAsString(), Boolean.class); if (asString) { result = getClient().getValuesAsString( getMandatoryHeader(message, ConsulConstants.CONSUL_KEY, getConfiguration().getKey(), String.class) ); } else { result = getClient().getValues( getMandatoryHeader(message, ConsulConstants.CONSUL_KEY, getConfiguration().getKey(), String.class), message.getHeader(ConsulConstants.CONSUL_OPTIONS, QueryOptions.BLANK, QueryOptions.class) ); } setBodyAndResult(message, result); }
@Override protected void doStop() throws Exception { if (sessionId.get() != null) { if (keyValueClient.releaseLock(this.path, sessionId.get())) { LOGGER.debug("Successfully released lock on path '{}' with id '{}'", path, sessionId.get()); } synchronized (sessionId) { sessionClient.destroySession(sessionId.getAndSet(null)); localMember.setMaster(false); } } }
/** * Retrieves a session string for a specific key from the key/value store. * * GET /v1/kv/{key} * * @param key The key to retrieve. * @return An {@link Optional} containing the value as a string or * {@link Optional#empty()} */ public Optional<String> getSession(String key) { return getValue(key).flatMap(Value::getSession); }