aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject [1/2] aurora git commit: Add webhook code that can POST events to an endpoint
Date Mon, 06 Jun 2016 22:50:17 GMT
Repository: aurora
Updated Branches:
  refs/heads/master d64e179ed -> 2e7b317be


Add webhook code that can POST events to an endpoint

Bugs closed: AURORA-1683

Reviewed at https://reviews.apache.org/r/47440/


Project: http://git-wip-us.apache.org/repos/asf/aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/33295fa7
Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/33295fa7
Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/33295fa7

Branch: refs/heads/master
Commit: 33295fa795cb3b8b39ea52f96fe76a1351283aa2
Parents: d64e179
Author: Dmitriy Shirchenko <caldima@gmail.com>
Authored: Tue Jun 7 00:41:47 2016 +0200
Committer: Stephan Erb <stephan@dev.static-void.de>
Committed: Tue Jun 7 00:41:47 2016 +0200

----------------------------------------------------------------------
 RELEASE-NOTES.md                                |   1 +
 docs/README.md                                  |   1 +
 docs/features/webhooks.md                       |  79 +++++++++++++
 docs/reference/scheduler-configuration.md       |   2 +
 .../aurora/scheduler/app/SchedulerMain.java     |   5 +-
 .../aurora/scheduler/events/PubsubEvent.java    |   6 +
 .../apache/aurora/scheduler/events/Webhook.java | 110 +++++++++++++++++++
 .../aurora/scheduler/events/WebhookInfo.java    |  82 ++++++++++++++
 .../aurora/scheduler/events/WebhookModule.java  |  98 +++++++++++++++++
 .../org/apache/aurora/scheduler/webhook.json    |   8 ++
 .../aurora/scheduler/events/WebhookTest.java    |  80 ++++++++++++++
 11 files changed, 471 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/RELEASE-NOTES.md
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 7d47cf6..65f4191 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -39,6 +39,7 @@
     `-job_update_history_pruning_threshold=1mins` and `-job_update_history_per_job_threshold=0`
   5. Ensure a new snapshot is created by running `aurora_admin scheduler_snapshot <cluster>`
   6. Rollback to previous version
+- Adding a webhook feature which POSTs all task state changes to a user defined endpoint.
 
 ### Deprecations and removals:
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/docs/README.md
----------------------------------------------------------------------
diff --git a/docs/README.md b/docs/README.md
index aea8518..7cea18f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -27,6 +27,7 @@ Description of important Aurora features.
  * [Services](features/services.md)
  * [Service Discovery](features/service-discovery.md)
  * [SLA Metrics](features/sla-metrics.md)
+ * [Webhooks](features/webhooks.md)
 
 ## Operators
 For those that wish to manage and fine-tune an Aurora cluster.

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/docs/features/webhooks.md
----------------------------------------------------------------------
diff --git a/docs/features/webhooks.md b/docs/features/webhooks.md
new file mode 100644
index 0000000..2ca342f
--- /dev/null
+++ b/docs/features/webhooks.md
@@ -0,0 +1,79 @@
+Webhooks
+==================
+
+Aurora has an optional feature which allows operator to specify a file to configure a HTTP
webhook to receive task state
+ change events. It can be enabled with a scheduler flag eg
+ -webhook_config=/path/to/webhook.json
+
+ Below is a sample configuration:
+
+ ```json
+{
+  "headers": {
+    "Content-Type": "application/vnd.kafka.json.v1+json",
+    "Producer-Type": "reliable"
+  },
+  "targetURL": "http://localhost:5000/",
+  "timeoutMsec": 5
+}
+```
+
+And an example of a response that you will get back:
+```json
+{
+    "task":
+    {
+        "cachedHashCode":0,
+        "assignedTask": {
+            "cachedHashCode":0,
+            "taskId":"vagrant-test-http_example-8-a6cf7ec5-d793-49c7-b10f-0e14ab80bfff",
+            "task": {
+                "cachedHashCode":-1819348376,
+                "job": {
+                    "cachedHashCode":803049425,
+                    "role":"vagrant",
+                    "environment":"test",
+                    "name":"http_example"
+                    },
+                "owner": {
+                    "cachedHashCode":226895216,
+                    "user":"vagrant"
+                    },
+                "isService":true,
+                "numCpus":0.1,
+                "ramMb":16,
+                "diskMb":8,
+                "priority":0,
+                "maxTaskFailures":1,
+                "production":false,
+                "resources":[
+                    {"cachedHashCode":729800451,"setField":"NUM_CPUS","value":0.1},
+                    {"cachedHashCode":552899914,"setField":"RAM_MB","value":16},
+                    {"cachedHashCode":-1547868317,"setField":"DISK_MB","value":8},
+                    {"cachedHashCode":1957328227,"setField":"NAMED_PORT","value":"http"},
+                    {"cachedHashCode":1954229436,"setField":"NAMED_PORT","value":"tcp"}
+                    ],
+                "constraints":[],
+                "requestedPorts":["http","tcp"],
+                "taskLinks":{"http":"http://%host%:%port:http%"},
+                "contactEmail":"vagrant@localhost",
+                "executorConfig": {
+                    "cachedHashCode":-1194797325,
+                    "name":"AuroraExecutor",
+                    "data": "{\"environment\": \"test\", \"health_check_config\": {\"initial_interval_secs\":
5.0, \"health_checker\": { \"http\": {\"expected_response_code\": 0, \"endpoint\": \"/health\",
\"expected_response\": \"ok\"}}, \"max_consecutive_failures\": 0, \"timeout_secs\": 1.0, \"interval_secs\":
1.0}, \"name\": \"http_example\", \"service\": true, \"max_task_failures\": 1, \"cron_collision_policy\":
\"KILL_EXISTING\", \"enable_hooks\": false, \"cluster\": \"devcluster\", \"task\": {\"processes\":
[{\"daemon\": false, \"name\": \"echo_ports\", \"ephemeral\": false, \"max_failures\": 1,
\"min_duration\": 5, \"cmdline\": \"echo \\\"tcp port: {{thermos.ports[tcp]}}; http port:
{{thermos.ports[http]}}; alias: {{thermos.ports[alias]}}\\\"\", \"final\": false}, {\"daemon\":
false, \"name\": \"stage_server\", \"ephemeral\": false, \"max_failures\": 1, \"min_duration\":
5, \"cmdline\": \"cp /vagrant/src/test/sh/org/apache/aurora/e2e/http_example.py .\", \"final\":
false}, {\
 "daemon\": false, \"name\": \"run_server\", \"ephemeral\": false, \"max_failures\": 1, \"min_duration\":
5, \"cmdline\": \"python http_example.py {{thermos.ports[http]}}\", \"final\": false}], \"name\":
\"http_example\", \"finalization_wait\": 30, \"max_failures\": 1, \"max_concurrency\": 0,
\"resources\": {\"disk\": 8388608, \"ram\": 16777216, \"cpu\": 0.1}, \"constraints\": [{\"order\":
[\"echo_ports\", \"stage_server\", \"run_server\"]}]}, \"production\": false, \"role\": \"vagrant\",
\"contact\": \"vagrant@localhost\", \"announce\": {\"primary_port\": \"http\", \"portmap\":
{\"alias\": \"http\"}}, \"lifecycle\": {\"http\": {\"graceful_shutdown_endpoint\": \"/quitquitquit\",
\"port\": \"health\", \"shutdown_endpoint\": \"/abortabortabort\"}}, \"priority\": 0}"},
+                    "metadata":[],
+                    "container":{
+                        "cachedHashCode":-1955376216,
+                        "setField":"MESOS",
+                        "value":{"cachedHashCode":31}}
+                    },
+                    "assignedPorts":{},
+                    "instanceId":8
+        },
+        "status":"PENDING",
+        "failureCount":0,
+        "taskEvents":[
+            {"cachedHashCode":0,"timestamp":1464992060258,"status":"PENDING","scheduler":"aurora"}]
+        },
+        "oldState":{}}
+```
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/docs/reference/scheduler-configuration.md
----------------------------------------------------------------------
diff --git a/docs/reference/scheduler-configuration.md b/docs/reference/scheduler-configuration.md
index f7d676d..c0c3944 100644
--- a/docs/reference/scheduler-configuration.md
+++ b/docs/reference/scheduler-configuration.md
@@ -218,6 +218,8 @@ Optional flags:
 	Whether to use the experimental database-backed task store.
 -viz_job_url_prefix (default )
 	URL prefix for job container stats.
+-webhook_config [file must be readable]
+    File to configure a HTTP webhook to receive task state change events.
 -zk_chroot_path
 	chroot path to use for the ZooKeeper connections
 -zk_digest_credentials

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
index 9ebfe23..8fe2b79 100644
--- a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
+++ b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
@@ -52,6 +52,7 @@ import org.apache.aurora.scheduler.configuration.executor.ExecutorModule;
 import org.apache.aurora.scheduler.cron.quartz.CronModule;
 import org.apache.aurora.scheduler.discovery.FlaggedZooKeeperConfig;
 import org.apache.aurora.scheduler.discovery.ServiceDiscoveryModule;
+import org.apache.aurora.scheduler.events.WebhookModule;
 import org.apache.aurora.scheduler.http.HttpService;
 import org.apache.aurora.scheduler.log.mesos.MesosLogStreamModule;
 import org.apache.aurora.scheduler.mesos.CommandLineDriverSettingsModule;
@@ -198,7 +199,9 @@ public class SchedulerMain {
             new LibMesosLoadingModule(),
             new MesosLogStreamModule(FlaggedZooKeeperConfig.create()),
             new LogStorageModule(),
-            new TierModule())
+            new TierModule(),
+            new WebhookModule()
+        )
         .build();
     flagConfiguredMain(Modules.combine(modules));
   }

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/main/java/org/apache/aurora/scheduler/events/PubsubEvent.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/events/PubsubEvent.java b/src/main/java/org/apache/aurora/scheduler/events/PubsubEvent.java
index 2a4c066..70b5470 100644
--- a/src/main/java/org/apache/aurora/scheduler/events/PubsubEvent.java
+++ b/src/main/java/org/apache/aurora/scheduler/events/PubsubEvent.java
@@ -18,6 +18,7 @@ import java.util.Set;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Optional;
+import com.google.gson.Gson;
 
 import org.apache.aurora.gen.ScheduleStatus;
 import org.apache.aurora.scheduler.base.TaskGroupKey;
@@ -157,6 +158,11 @@ public interface PubsubEvent {
           .add("newState", getNewState())
           .toString();
     }
+
+    public String toJson() {
+      return new Gson().toJson(this);
+    }
+
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/main/java/org/apache/aurora/scheduler/events/Webhook.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/events/Webhook.java b/src/main/java/org/apache/aurora/scheduler/events/Webhook.java
new file mode 100644
index 0000000..e54aa19
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/events/Webhook.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.events;
+
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.time.Instant;
+
+import com.google.common.eventbus.Subscribe;
+
+import com.google.inject.Inject;
+
+import org.apache.aurora.scheduler.events.PubsubEvent.EventSubscriber;
+import org.apache.aurora.scheduler.events.PubsubEvent.TaskStateChange;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Watches TaskStateChanges and send events to configured endpoint.
+ */
+public class Webhook implements EventSubscriber {
+
+  private static final Logger LOG = LoggerFactory.getLogger(Webhook.class);
+
+  private static final String CALL_METHOD = "POST";
+  private final WebhookInfo webhookInfo;
+
+  @Inject
+  Webhook(WebhookInfo webhookInfo) {
+    this.webhookInfo = webhookInfo;
+    LOG.debug("Webhook enabled with info" + this.webhookInfo);
+  }
+
+  private HttpURLConnection initializeConnection() {
+    try {
+      final HttpURLConnection connection = (HttpURLConnection) new URL(
+          this.webhookInfo.getTargetURL()).openConnection();
+      connection.setRequestMethod(CALL_METHOD);
+      connection.setConnectTimeout(this.webhookInfo.getConnectonTimeout());
+
+      webhookInfo.getHeaders().entrySet().forEach(
+          e -> connection.setRequestProperty(e.getKey(), e.getValue()));
+      connection.setRequestProperty("TimeStamp", Long.toString(Instant.now().toEpochMilli()));
+      connection.setDoOutput(true);
+      return connection;
+    } catch (Exception e) {
+      // Do nothing since we are just doing best-effort here.
+      LOG.error("Exception trying to initialize a connection:", e);
+      return null;
+    }
+  }
+
+  /**
+   * Calls a specified endpoint with the provided string representing an internal event.
+   *
+   * @param eventJson String represenation of task state change.
+   */
+  public void callEndpoint(String eventJson) {
+    HttpURLConnection connection = this.initializeConnection();
+    if (connection == null) {
+      LOG.error("Received a null object when trying to initialize an HTTP connection");
+    } else {
+      try {
+        try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
+          wr.writeBytes(eventJson);
+          LOG.debug("Sending message " + eventJson
+              + " with connection info " + connection.toString()
+              + " with WebhookInfo " + this.webhookInfo.toString());
+        } catch (Exception e) {
+          InputStream errorStream = connection.getErrorStream();
+          if (errorStream != null) {
+            errorStream.close();
+          }
+          LOG.error("Exception writing via HTTP connection", e);
+        }
+        // Don't care about reading input so just performing basic close() operation.
+        connection.getInputStream().close();
+      } catch (Exception e) {
+        LOG.error("Exception when sending a task change event", e);
+      }
+    }
+    LOG.debug("Done with Webhook call");
+  }
+
+  /**
+   * Watches all TaskStateChanges and send them best effort to a configured endpoint.
+   * <p>
+   * This is used to expose an external event bus.
+   *
+   * @param stateChange State change notification.
+   */
+  @Subscribe
+  public void taskChangedState(TaskStateChange stateChange) {
+    String eventJson = stateChange.toJson();
+    callEndpoint(eventJson);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/main/java/org/apache/aurora/scheduler/events/WebhookInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/events/WebhookInfo.java b/src/main/java/org/apache/aurora/scheduler/events/WebhookInfo.java
new file mode 100644
index 0000000..e4193f7
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/events/WebhookInfo.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.events;
+
+import java.util.Map;
+
+import com.google.common.base.MoreObjects;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Defines configuration for Webhook.
+ */
+public class WebhookInfo {
+  private final Integer connectTimeout;
+  private final Map<String, String> headers;
+  private final String targetURL;
+
+  /**
+   * Return key:value pairs of headers to set for every connection.
+   *
+   * @return Map
+   */
+  public Map<String, String> getHeaders() {
+    return this.headers;
+  }
+
+  /**
+   * Returns URL to post events to.
+   *
+   * @return String
+   */
+  public String getTargetURL() {
+    return this.targetURL;
+  }
+
+  /**
+   * Returns connection timeout to set when POSTing an event.
+   *
+   * @return Integer value.
+   */
+  public Integer getConnectonTimeout() {
+    return this.connectTimeout;
+  }
+
+  @JsonCreator
+  public WebhookInfo(
+       @JsonProperty("headers") Map<String, String> headers,
+       @JsonProperty("targetURL") String targetURL,
+       @JsonProperty("timeoutMsec") Integer timeout) {
+
+    requireNonNull(targetURL);
+    this.headers = ImmutableMap.copyOf(headers);
+    this.targetURL = requireNonNull(targetURL);
+    this.connectTimeout = requireNonNull(timeout);
+  }
+
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+      .add("headers", headers.toString())
+      .add("targetURL", targetURL)
+      .add("connectTimeout", connectTimeout)
+      .toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/main/java/org/apache/aurora/scheduler/events/WebhookModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/events/WebhookModule.java b/src/main/java/org/apache/aurora/scheduler/events/WebhookModule.java
new file mode 100644
index 0000000..eaa7053
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/events/WebhookModule.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.events;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.common.base.Throwables;
+import com.google.common.io.Files;
+import com.google.common.io.Resources;
+import com.google.inject.AbstractModule;
+
+import com.google.inject.Singleton;
+
+import org.apache.aurora.common.args.Arg;
+import org.apache.aurora.common.args.CmdLine;
+import org.apache.aurora.common.args.constraints.CanRead;
+import org.apache.aurora.common.args.constraints.Exists;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Binding module for webhook management.
+ */
+public class WebhookModule extends AbstractModule {
+
+  private static final Logger LOG = LoggerFactory.getLogger(WebhookModule.class);
+
+  @VisibleForTesting
+  static final String WEBHOOK_CONFIG_PATH = "org/apache/aurora/scheduler/webhook.json";
+
+  @CmdLine(name = "webhook_config", help = "Path to webhook configuration file.")
+  @Exists
+  @CanRead
+  private static final Arg<File> WEBHOOK_CONFIG_FILE = Arg.create();
+
+  private final boolean enableWebhook;
+
+  public WebhookModule() {
+    this(WEBHOOK_CONFIG_FILE.hasAppliedValue());
+  }
+
+  @VisibleForTesting
+  private WebhookModule(boolean enableWebhook) {
+    this.enableWebhook = enableWebhook;
+  }
+
+  @Override
+  protected void configure() {
+    if (enableWebhook) {
+      bind(WebhookInfo.class).toInstance(parseWebhookConfig(readWebhookFile()));
+      PubsubEventModule.bindSubscriber(binder(), Webhook.class);
+      bind(Webhook.class).in(Singleton.class);
+    }
+  }
+
+  @VisibleForTesting
+  static String readWebhookFile() {
+    try {
+      return WEBHOOK_CONFIG_FILE.hasAppliedValue()
+          ? Files.toString(WEBHOOK_CONFIG_FILE.get(), StandardCharsets.UTF_8)
+          : Resources.toString(
+              Webhook.class.getClassLoader().getResource(WEBHOOK_CONFIG_PATH),
+              StandardCharsets.UTF_8);
+    } catch (IOException e) {
+      LOG.error("Error loading webhook configuration file.");
+      throw Throwables.propagate(e);
+    }
+  }
+
+  @VisibleForTesting
+  static WebhookInfo parseWebhookConfig(String config) {
+    checkArgument(!Strings.isNullOrEmpty(config), "Webhook configuration cannot be empty");
+    try {
+      return new ObjectMapper().readValue(config, WebhookInfo.class);
+    } catch (IOException e) {
+      LOG.error("Error parsing Webhook configuration file.");
+      throw Throwables.propagate(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/main/resources/org/apache/aurora/scheduler/webhook.json
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/aurora/scheduler/webhook.json b/src/main/resources/org/apache/aurora/scheduler/webhook.json
new file mode 100644
index 0000000..0078798
--- /dev/null
+++ b/src/main/resources/org/apache/aurora/scheduler/webhook.json
@@ -0,0 +1,8 @@
+{
+  "headers": {
+    "Content-Type": "application/vnd.kafka.json.v1+json",
+    "Producer-Type": "reliable"
+  },
+  "targetURL": "http://localhost:5000/",
+  "timeoutMsec": 5
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/33295fa7/src/test/java/org/apache/aurora/scheduler/events/WebhookTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/events/WebhookTest.java b/src/test/java/org/apache/aurora/scheduler/events/WebhookTest.java
new file mode 100644
index 0000000..488eefd
--- /dev/null
+++ b/src/test/java/org/apache/aurora/scheduler/events/WebhookTest.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.events;
+
+import com.google.common.eventbus.EventBus;
+
+import org.apache.aurora.common.testing.easymock.EasyMockTest;
+
+import org.apache.aurora.scheduler.base.TaskTestUtil;
+import org.apache.aurora.scheduler.events.PubsubEvent.TaskStateChange;
+import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class WebhookTest extends EasyMockTest {
+  private static final IScheduledTask TASK = TaskTestUtil.makeTask("id", TaskTestUtil.JOB);
+  private Webhook realWebhook;
+  private Webhook webhook;
+  private EventBus eventBus;
+
+  @Before
+  public void setUp() {
+    webhook = createMock(Webhook.class);
+    eventBus = new EventBus();
+    eventBus.register(webhook);
+    WebhookInfo webhookInfo = WebhookModule.parseWebhookConfig(
+        "{\"headers\": {\"Producer-Type\": \"reliable\","
+            + " \"Content-Type\": \"application/vnd.kafka.json.v1+json\"},"
+            + " \"timeoutMsec\": 1,"
+            + " \"targetURL\": \"http://localhost:5000/\"}"
+    );
+    realWebhook = new Webhook(webhookInfo);
+  }
+
+  private final TaskStateChange change = TaskStateChange.initialized(TASK);
+  private final String changeJson = TaskStateChange.initialized(TASK).toJson();
+
+  @Test
+  public void testTaskChangedState() {
+    webhook.taskChangedState(change);
+
+    control.replay();
+
+    eventBus.post(change);
+  }
+
+  @Test
+  public void testCallEndpoint() {
+    control.replay();
+
+    realWebhook.callEndpoint(changeJson);
+  }
+
+  @Test
+  public void testWebhookInfo() {
+    WebhookInfo webhookInfo = WebhookModule.parseWebhookConfig(WebhookModule.readWebhookFile());
+    assertEquals(webhookInfo.toString(),
+        "WebhookInfo{headers={"
+            + "Content-Type=application/vnd.kafka.json.v1+json, "
+            + "Producer-Type=reliable"
+            + "}, "
+            + "targetURL=http://localhost:5000/, "
+            + "connectTimeout=5"
+            + "}");
+    control.replay();
+  }
+}


Mime
View raw message