Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support local async batching #247

Merged
merged 7 commits into from
Feb 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 87 additions & 8 deletions src/main/java/com/suse/salt/netapi/calls/LocalCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.suse.salt.netapi.utils.ClientUtils;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -121,11 +120,37 @@ public Map<String, Object> getPayload() {
* @param client SaltClient instance
* @param target the target for the function
* @param auth authentication credentials to use
* @param batch parameter for enabling and configuring batching
* @return information about the scheduled job
*/
public CompletionStage<LocalAsyncResult<R>> callAsync(final SaltClient client, Target<?> target, AuthMethod auth) {
public CompletionStage<LocalAsyncResult<R>> callAsync(final SaltClient client, Target<?> target, AuthMethod auth,
Batch batch) {
return callAsync(client, target, auth, Optional.of(batch));
}

/**
* Calls a execution module function on the given target asynchronously and
* returns information about the scheduled job that can be used to query the result.
* Authentication is done with the token therefore you have to login prior
* to using this function.
*
* @param client SaltClient instance
* @param target the target for the function
* @param auth authentication credentials to use
* @param batch parameter for enabling and configuring batching
* @return information about the scheduled job
*/
public CompletionStage<LocalAsyncResult<R>> callAsync(final SaltClient client, Target<?> target, AuthMethod auth,
Optional<Batch> batch) {
chiaradiamarcelo marked this conversation as resolved.
Show resolved Hide resolved

Map<String, Object> customArgs = new HashMap<>();
batch.ifPresent(v -> {
customArgs.put("batch", v.getBatch());
v.getDelay().ifPresent(d -> customArgs.put("batch_delay", d));
});

return client.call(
this, Client.LOCAL_ASYNC, Optional.of(target), Collections.emptyMap(),
this, Client.LOCAL_ASYNC, Optional.of(target), customArgs,
new TypeToken<Return<List<LocalAsyncResult<R>>>>(){}, auth)
.thenApply(wrapper -> {
LocalAsyncResult<R> result = wrapper.getResult().get(0);
Expand All @@ -134,6 +159,21 @@ public CompletionStage<LocalAsyncResult<R>> callAsync(final SaltClient client, T
});
}

/**
* Calls a execution module function on the given target asynchronously and
* returns information about the scheduled job that can be used to query the result.
* Authentication is done with the token therefore you have to login prior
* to using this function.
*
* @param client SaltClient instance
* @param target the target for the function
* @param auth authentication credentials to use
* @return information about the scheduled job
*/
public CompletionStage<LocalAsyncResult<R>> callAsync(final SaltClient client, Target<?> target, AuthMethod auth) {
return callAsync(client, target, auth, Optional.empty());
}

/**
* Calls this salt call via the async client and returns the results
* as they come in via the event stream.
Expand All @@ -143,16 +183,40 @@ public CompletionStage<LocalAsyncResult<R>> callAsync(final SaltClient client, T
* @param events the event stream to use
* @param cancel future to cancel the action
* @param auth authentication credentials to use
* @param batch parameter for enabling and configuring batching
* @return a map from minion id to future of the result.
*/
public CompletionStage<Map<String, CompletionStage<Result<R>>>> callAsync(
SaltClient client,
Target<?> target,
AuthMethod auth,
EventStream events,
CompletionStage<GenericError> cancel) {
CompletionStage<GenericError> cancel,
Batch batch) {
return callAsync(client, target, auth, events, cancel, Optional.of(batch));
}

/**
* Calls this salt call via the async client and returns the results
* as they come in via the event stream.
*
* @param client SaltClient instance
* @param target the target for the function
* @param events the event stream to use
* @param cancel future to cancel the action
* @param auth authentication credentials to use
* @param batch parameter for enabling and configuring batching
* @return a map from minion id to future of the result.
*/
public CompletionStage<Map<String, CompletionStage<Result<R>>>> callAsync(
SaltClient client,
Target<?> target,
AuthMethod auth,
EventStream events,
CompletionStage<GenericError> cancel,
Optional<Batch> batch) {
return callAsync(
localCall -> localCall.callAsync(client, target, auth),
localCall -> localCall.callAsync(client, target, auth, batch),
runnerCall -> runnerCall.callAsync(client, auth),
events,
cancel
Expand Down Expand Up @@ -279,7 +343,24 @@ public CompletionStage<Map<String, Result<R>>> callSync(final SaltClient client,
*/
public CompletionStage<List<Map<String, Result<R>>>> callSync(final SaltClient client, Target<?> target,
AuthMethod auth, Batch batch) {
return callSyncHelperNonBlock(client, target, auth, Optional.of(batch));
return callSync(client, target, auth, Optional.of(batch));
}

/**
* Calls a execution module function on the given target with batching and
* synchronously waits for the result. Authentication is done with the token
* therefore you have to login prior to using this function.
*
* @param client SaltClient instance
* @param target the target for the function
* @param auth authentication credentials to use
* @param batch parameter for enabling and configuring batching
* @return A list of maps with each list representing each batch, and maps containing
* the results with the minion names as keys.
*/
public CompletionStage<List<Map<String, Result<R>>>> callSync(final SaltClient client, Target<?> target,
AuthMethod auth, Optional<Batch> batch) {
return callSyncHelperNonBlock(client, target, auth, batch);
}

/**
Expand All @@ -298,8 +379,6 @@ public CompletionStage<List<Map<String, Result<R>>>> callSync(final SaltClient c
private CompletionStage<List<Map<String, Result<R>>>> callSyncHelperNonBlock(
final SaltClient client, Target<?> target, AuthMethod auth, Optional<Batch> batch) {
Map<String, Object> customArgs = new HashMap<>();
customArgs.putAll(getPayload());
customArgs.putAll(target.getProps());
chiaradiamarcelo marked this conversation as resolved.
Show resolved Hide resolved
batch.ifPresent(v -> customArgs.put("batch", v.toString()));

Client clientType = batch.isPresent() ? Client.LOCAL_BATCH : Client.LOCAL;
Expand Down
133 changes: 121 additions & 12 deletions src/main/java/com/suse/salt/netapi/datatypes/Batch.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.suse.salt.netapi.datatypes;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
* A class representing the batch parameter. Salt uses a string for the batch parameter,
* but it accept strings representing both exact numerals and percents, so this class
Expand All @@ -8,28 +12,48 @@
public class Batch {
// The actual batch string
private String batch;
private Optional<Double> delay;
private Optional<Integer> presencePingTimeout;

private Batch(String batch) {
this.batch = batch;
private Batch(BatchBuilder builder) {
this.batch = builder.batch;
this.delay = builder.delay;
this.presencePingTimeout = builder.presencePingTimeout;
}

@Override
public String toString() {
return batch;
}

public String getBatch() {
return batch;
}

public Optional<Double> getDelay() {
return delay;
}

public Optional<Integer> getPresencePingTimeout() {
return presencePingTimeout;
}

public Map<String, Object> getParams() {
Map<String, Object> customArgs = new HashMap<>();
customArgs.put("batch", batch);
delay.ifPresent(d -> {
customArgs.put("batch_delay", d);
});
return customArgs;
}

/**
* Construct a Batch from a value representing a percent
* @param value the percent, which must be greater than 0 and less than or equal to 100
* @return the Batch
*/
public static Batch asPercent(int value) {
if (value <= 0 || value > 100) {
throw new IllegalArgumentException("Expected value greater than 0 and less " +
"than or equal to 100 to make valid batch as a percent.");
}

return new Batch(Integer.toString(value) + "%");
return Batch.custom().withBatchAsPercent(value).build();
}

/**
Expand All @@ -38,11 +62,96 @@ public static Batch asPercent(int value) {
* @return the Batch
*/
public static Batch asAmount(int value) {
if (value <= 0) {
throw new IllegalArgumentException("Expected value greater than 0 to make a " +
"valid batch amount");
return Batch.custom().withBatchAsAmount(value).build();
}

/**
* Returns a BatchBuilder for instantiating a custom Batch.
*
* @return a BatchBuilder instance.
*/
public static BatchBuilder custom() {
return new BatchBuilder();
}

/**
* Helper class for building a Batch.
*/
public static class BatchBuilder {
private String batch;
private Optional<Double> delay;
private Optional<Integer> presencePingTimeout;

/**
* Constructor for BatchBuilder.
*
* @return a BatchBuilder instance.
*/
private BatchBuilder() {
this.delay = Optional.empty();
this.presencePingTimeout = Optional.empty();
}

/**
* Sets the batch value representing an exact amount of items
* @param value the exact amount of items, which must be greater than 0
* @return the Batch
*/
public BatchBuilder withBatchAsAmount(int value) {
if (value <= 0) {
throw new IllegalArgumentException("Expected value greater than 0 to make a " +
"valid batch amount");
}
this.batch = Integer.toString(value);
return this;
}

/**
* Sets the batch value representing a percent
* @param value the percent, which must be greater than 0 and less than or equal to 100
* @return the Batch
*/
public BatchBuilder withBatchAsPercent(int value) {
if (value <= 0 || value > 100) {
throw new IllegalArgumentException("Expected value greater than 0 and less " +
"than or equal to 100 to make valid batch as a percent.");
}
this.batch = Integer.toString(value);
return this;
}

/**
* Batch delay specifies the time for salt to wait for more minions to return a result before
* scheduling the next batch. This helps to avoid single minion batches.
*
* @param delayIn time to wait in seconds.
* @return this BatchBuilder instance with the specified batch delay.
*/
public BatchBuilder withDelay(Double delayIn) {
this.delay = Optional.of(delayIn);
return this;
}

/**
* Batch presence ping timeout specifies the timeout in seconds of the presence ping performed in
* salt minions to determine which minions are available during salt batch calls.
*
* @param presencePingTimeoutIn time to wait in seconds.
* @return this BatchBuilder instance with the specified batch presence ping timeout.
*/
public BatchBuilder withPresencePingTimeout(Integer presencePingTimeoutIn) {
this.presencePingTimeout = Optional.of(presencePingTimeoutIn);
return this;
}

/**
* Returns a Batch with the values of this BatchBuilder instance.
*
* @return a new Batch
*/
public Batch build() {
return new Batch(this);
}

return new Batch(Integer.toString(value));
}
}
Loading