You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by js...@apache.org on 2016/04/07 04:46:06 UTC

aurora git commit: Factor out a discovery package.

Repository: aurora
Updated Branches:
  refs/heads/master ce40eaa71 -> 14f975a4a


Factor out a discovery package.

This will be the home for the Curator implementations.

In the process, lift the `ServerSetMonitor` to a top-level class and add
a test. Also tighten up the `ServiceDiscoveryModule` and make
requirements and exports clear.

Bugs closed: AURORA-1468

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


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

Branch: refs/heads/master
Commit: 14f975a4a31758cf9d664497bc4dbf72824d6830
Parents: ce40eaa
Author: John Sirois <js...@apache.org>
Authored: Wed Apr 6 20:46:04 2016 -0600
Committer: John Sirois <jo...@gmail.com>
Committed: Wed Apr 6 20:46:04 2016 -0600

----------------------------------------------------------------------
 .../aurora/scheduler/app/SchedulerMain.java     |   1 +
 .../scheduler/app/ServiceDiscoveryModule.java   | 124 -----------------
 .../discovery/CommonsServerGroupMonitor.java    |  59 ++++++++
 .../discovery/ServiceDiscoveryModule.java       |  99 ++++++++++++++
 .../aurora/scheduler/app/SchedulerIT.java       |   1 +
 .../CommonsServerGroupMonitorTest.java          | 137 +++++++++++++++++++
 6 files changed, 297 insertions(+), 124 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/14f975a4/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 11f6ad1..ecdaa7e 100644
--- a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
+++ b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java
@@ -50,6 +50,7 @@ import org.apache.aurora.scheduler.SchedulerLifecycle;
 import org.apache.aurora.scheduler.TierModule;
 import org.apache.aurora.scheduler.configuration.executor.ExecutorModule;
 import org.apache.aurora.scheduler.cron.quartz.CronModule;
+import org.apache.aurora.scheduler.discovery.ServiceDiscoveryModule;
 import org.apache.aurora.scheduler.http.HttpService;
 import org.apache.aurora.scheduler.log.mesos.MesosLogStreamModule;
 import org.apache.aurora.scheduler.mesos.CommandLineDriverSettingsModule;

http://git-wip-us.apache.org/repos/asf/aurora/blob/14f975a4/src/main/java/org/apache/aurora/scheduler/app/ServiceDiscoveryModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/app/ServiceDiscoveryModule.java b/src/main/java/org/apache/aurora/scheduler/app/ServiceDiscoveryModule.java
deleted file mode 100644
index 73695cd..0000000
--- a/src/main/java/org/apache/aurora/scheduler/app/ServiceDiscoveryModule.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * 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.app;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-
-import org.apache.aurora.common.base.Command;
-import org.apache.aurora.common.net.pool.DynamicHostSet;
-import org.apache.aurora.common.thrift.ServiceInstance;
-import org.apache.aurora.common.zookeeper.ServerSetImpl;
-import org.apache.aurora.common.zookeeper.SingletonService;
-import org.apache.aurora.common.zookeeper.SingletonServiceImpl;
-import org.apache.aurora.common.zookeeper.ZooKeeperClient;
-import org.apache.aurora.common.zookeeper.ZooKeeperClient.Credentials;
-import org.apache.aurora.common.zookeeper.ZooKeeperUtils;
-import org.apache.zookeeper.data.ACL;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * Binding module for utilities to advertise the network presence of the scheduler.
- */
-class ServiceDiscoveryModule extends AbstractModule {
-
-  private static class ServerSetMonitor implements ServiceGroupMonitor {
-    private Optional<Command> closeCommand = Optional.empty();
-    private final DynamicHostSet<ServiceInstance> serverSet;
-    private final AtomicReference<ImmutableSet<ServiceInstance>> services =
-        new AtomicReference<>(ImmutableSet.of());
-
-    // NB: We only take a ServerSetImpl instead of a DynamicHostSet<ServiceInstance> here to
-    // simplify binding.
-    @Inject
-    ServerSetMonitor(ServerSetImpl serverSet) {
-      this.serverSet = requireNonNull(serverSet);
-    }
-
-    @Override
-    public void start() throws MonitorException {
-      try {
-        closeCommand = Optional.of(serverSet.watch(services::set));
-      } catch (DynamicHostSet.MonitorException e) {
-        throw new MonitorException("Unable to watch scheduler host set.", e);
-      }
-    }
-
-    @Override
-    public void close() {
-      closeCommand.ifPresent(Command::execute);
-    }
-
-    @Override
-    public ImmutableSet<ServiceInstance> get() {
-      return services.get();
-    }
-  }
-
-  private static final Logger LOG = LoggerFactory.getLogger(ServiceDiscoveryModule.class);
-
-  private final String serverSetPath;
-  private final Credentials zkCredentials;
-
-  ServiceDiscoveryModule(String serverSetPath, Credentials zkCredentials) {
-    this.serverSetPath = requireNonNull(serverSetPath);
-    this.zkCredentials = requireNonNull(zkCredentials);
-  }
-
-  @Override
-  protected void configure() {
-    bind(ServiceGroupMonitor.class).to(ServerSetMonitor.class).in(Singleton.class);
-  }
-
-  @Provides
-  @Singleton
-  List<ACL> provideAcls() {
-    if (zkCredentials == Credentials.NONE) {
-      LOG.warn("Running without ZooKeeper digest credentials. ZooKeeper ACLs are disabled.");
-      return ZooKeeperUtils.OPEN_ACL_UNSAFE;
-    } else {
-      return ZooKeeperUtils.EVERYONE_READ_CREATOR_ALL;
-    }
-  }
-
-  @Provides
-  @Singleton
-  ServerSetImpl provideServerSet(ZooKeeperClient client, List<ACL> zooKeeperAcls) {
-    return new ServerSetImpl(client, zooKeeperAcls, serverSetPath);
-  }
-
-  // NB: We only take a ServerSetImpl instead of a ServerSet here to simplify binding.
-  @Provides
-  @Singleton
-  SingletonService provideSingletonService(
-      ZooKeeperClient client,
-      ServerSetImpl serverSet,
-      List<ACL> zookeeperAcls) {
-
-    return new SingletonServiceImpl(
-        serverSet,
-        SingletonServiceImpl.createSingletonCandidate(client, serverSetPath, zookeeperAcls));
-  }
-}

http://git-wip-us.apache.org/repos/asf/aurora/blob/14f975a4/src/main/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitor.java b/src/main/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitor.java
new file mode 100644
index 0000000..3336c87
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitor.java
@@ -0,0 +1,59 @@
+/**
+ * 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.discovery;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.inject.Inject;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.apache.aurora.common.base.Command;
+import org.apache.aurora.common.net.pool.DynamicHostSet;
+import org.apache.aurora.common.thrift.ServiceInstance;
+import org.apache.aurora.scheduler.app.ServiceGroupMonitor;
+
+import static java.util.Objects.requireNonNull;
+
+class CommonsServerGroupMonitor implements ServiceGroupMonitor {
+  private Optional<Command> closeCommand = Optional.empty();
+  private final DynamicHostSet<ServiceInstance> serverSet;
+  private final AtomicReference<ImmutableSet<ServiceInstance>> services =
+      new AtomicReference<>(ImmutableSet.of());
+
+  @Inject
+  CommonsServerGroupMonitor(DynamicHostSet<ServiceInstance> serverSet) {
+    this.serverSet = requireNonNull(serverSet);
+  }
+
+  @Override
+  public void start() throws MonitorException {
+    try {
+      closeCommand = Optional.of(serverSet.watch(services::set));
+    } catch (DynamicHostSet.MonitorException e) {
+      throw new MonitorException("Unable to watch scheduler host set.", e);
+    }
+  }
+
+  @Override
+  public void close() {
+    closeCommand.ifPresent(Command::execute);
+  }
+
+  @Override
+  public ImmutableSet<ServiceInstance> get() {
+    return services.get();
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/14f975a4/src/main/java/org/apache/aurora/scheduler/discovery/ServiceDiscoveryModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/discovery/ServiceDiscoveryModule.java b/src/main/java/org/apache/aurora/scheduler/discovery/ServiceDiscoveryModule.java
new file mode 100644
index 0000000..c14162f
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/discovery/ServiceDiscoveryModule.java
@@ -0,0 +1,99 @@
+/**
+ * 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.discovery;
+
+import java.util.List;
+
+import javax.inject.Singleton;
+
+import com.google.inject.Exposed;
+import com.google.inject.PrivateModule;
+import com.google.inject.Provides;
+
+import org.apache.aurora.common.net.pool.DynamicHostSet;
+import org.apache.aurora.common.thrift.ServiceInstance;
+import org.apache.aurora.common.zookeeper.ServerSetImpl;
+import org.apache.aurora.common.zookeeper.SingletonService;
+import org.apache.aurora.common.zookeeper.SingletonServiceImpl;
+import org.apache.aurora.common.zookeeper.ZooKeeperClient;
+import org.apache.aurora.common.zookeeper.ZooKeeperClient.Credentials;
+import org.apache.aurora.common.zookeeper.ZooKeeperUtils;
+import org.apache.aurora.scheduler.app.ServiceGroupMonitor;
+import org.apache.zookeeper.data.ACL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Binding module for utilities to advertise the network presence of the scheduler.
+ */
+public class ServiceDiscoveryModule extends PrivateModule {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ServiceDiscoveryModule.class);
+
+  private final String serverSetPath;
+  private final Credentials zkCredentials;
+
+  public ServiceDiscoveryModule(String serverSetPath, Credentials zkCredentials) {
+    this.serverSetPath = requireNonNull(serverSetPath);
+    this.zkCredentials = requireNonNull(zkCredentials);
+  }
+
+  @Override
+  protected void configure() {
+    requireBinding(ZooKeeperClient.class);
+
+    bind(ServiceGroupMonitor.class).to(CommonsServerGroupMonitor.class).in(Singleton.class);
+    expose(ServiceGroupMonitor.class);
+  }
+
+  @Provides
+  @Singleton
+  List<ACL> provideAcls() {
+    if (zkCredentials == Credentials.NONE) {
+      LOG.warn("Running without ZooKeeper digest credentials. ZooKeeper ACLs are disabled.");
+      return ZooKeeperUtils.OPEN_ACL_UNSAFE;
+    } else {
+      return ZooKeeperUtils.EVERYONE_READ_CREATOR_ALL;
+    }
+  }
+
+  @Provides
+  @Singleton
+  ServerSetImpl provideServerSet(ZooKeeperClient client, List<ACL> zooKeeperAcls) {
+    return new ServerSetImpl(client, zooKeeperAcls, serverSetPath);
+  }
+
+  @Provides
+  @Singleton
+  DynamicHostSet<ServiceInstance> provideServerSet(ServerSetImpl serverSet) {
+    // Used for a type re-binding of the server set.
+    return serverSet;
+  }
+
+  // NB: We only take a ServerSetImpl instead of a ServerSet here to simplify binding.
+  @Provides
+  @Singleton
+  @Exposed
+  SingletonService provideSingletonService(
+      ZooKeeperClient client,
+      ServerSetImpl serverSet,
+      List<ACL> zookeeperAcls) {
+
+    return new SingletonServiceImpl(
+        serverSet,
+        SingletonServiceImpl.createSingletonCandidate(client, serverSetPath, zookeeperAcls));
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/14f975a4/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java b/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
index 5b77750..b449827 100644
--- a/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
+++ b/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
@@ -63,6 +63,7 @@ import org.apache.aurora.scheduler.ResourceSlot;
 import org.apache.aurora.scheduler.TierModule;
 import org.apache.aurora.scheduler.base.TaskTestUtil;
 import org.apache.aurora.scheduler.configuration.executor.ExecutorSettings;
+import org.apache.aurora.scheduler.discovery.ServiceDiscoveryModule;
 import org.apache.aurora.scheduler.log.Log;
 import org.apache.aurora.scheduler.log.Log.Entry;
 import org.apache.aurora.scheduler.log.Log.Position;

http://git-wip-us.apache.org/repos/asf/aurora/blob/14f975a4/src/test/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitorTest.java b/src/test/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitorTest.java
new file mode 100644
index 0000000..b584780
--- /dev/null
+++ b/src/test/java/org/apache/aurora/scheduler/discovery/CommonsServerGroupMonitorTest.java
@@ -0,0 +1,137 @@
+/**
+ * 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.discovery;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import org.apache.aurora.common.base.Command;
+import org.apache.aurora.common.net.pool.DynamicHostSet;
+import org.apache.aurora.common.net.pool.DynamicHostSet.HostChangeMonitor;
+import org.apache.aurora.common.testing.easymock.EasyMockTest;
+import org.apache.aurora.common.thrift.Endpoint;
+import org.apache.aurora.common.thrift.ServiceInstance;
+import org.apache.aurora.common.thrift.Status;
+import org.apache.aurora.scheduler.app.ServiceGroupMonitor;
+import org.easymock.Capture;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class CommonsServerGroupMonitorTest extends EasyMockTest {
+
+  private DynamicHostSet<ServiceInstance> serverSet;
+  private Capture<HostChangeMonitor<ServiceInstance>> hostChangeMonitorCapture;
+  private Command stopCommand;
+
+  @Before
+  public void setUp() throws Exception {
+    serverSet = createMock(new Clazz<DynamicHostSet<ServiceInstance>>() { });
+    hostChangeMonitorCapture = createCapture();
+    stopCommand = createMock(Command.class);
+  }
+
+  private void expectSuccessfulWatch() throws Exception {
+    expect(serverSet.watch(capture(hostChangeMonitorCapture))).andReturn(stopCommand);
+  }
+
+  private void expectFailedWatch() throws Exception {
+    DynamicHostSet.MonitorException watchError =
+        new DynamicHostSet.MonitorException(
+            "Problem watching service group",
+            new RuntimeException());
+    expect(serverSet.watch(capture(hostChangeMonitorCapture))).andThrow(watchError);
+  }
+
+  @Test
+  public void testNominalLifecycle() throws Exception {
+    expectSuccessfulWatch();
+
+    stopCommand.execute();
+    expectLastCall();
+
+    control.replay();
+
+    CommonsServerGroupMonitor groupMonitor = new CommonsServerGroupMonitor(serverSet);
+    groupMonitor.start();
+    groupMonitor.close();
+  }
+
+  @Test
+  public void testExceptionalLifecycle() throws Exception {
+    expectFailedWatch();
+    control.replay();
+
+    CommonsServerGroupMonitor groupMonitor = new CommonsServerGroupMonitor(serverSet);
+    try {
+      groupMonitor.start();
+      fail();
+    } catch (ServiceGroupMonitor.MonitorException e) {
+      // expected
+    }
+
+    // Close on a non-started monitor should be allowed.
+    groupMonitor.close();
+  }
+
+  @Test
+  public void testNoHosts() throws Exception {
+    expectSuccessfulWatch();
+    control.replay();
+
+    CommonsServerGroupMonitor groupMonitor = new CommonsServerGroupMonitor(serverSet);
+    assertEquals(ImmutableSet.of(), groupMonitor.get());
+
+    groupMonitor.start();
+    assertEquals(ImmutableSet.of(), groupMonitor.get());
+
+    hostChangeMonitorCapture.getValue().onChange(ImmutableSet.of());
+    assertEquals(ImmutableSet.of(), groupMonitor.get());
+  }
+
+  @Test
+  public void testHostUpdates() throws Exception {
+    expectSuccessfulWatch();
+    control.replay();
+
+    CommonsServerGroupMonitor groupMonitor = new CommonsServerGroupMonitor(serverSet);
+    groupMonitor.start();
+
+    ImmutableSet<ServiceInstance> twoHosts =
+        ImmutableSet.of(serviceInstance("one"), serviceInstance("two"));
+    hostChangeMonitorCapture.getValue().onChange(twoHosts);
+    assertEquals(twoHosts, groupMonitor.get());
+
+    ImmutableSet<ServiceInstance> oneHost = ImmutableSet.of(serviceInstance("one"));
+    hostChangeMonitorCapture.getValue().onChange(oneHost);
+    assertEquals(oneHost, groupMonitor.get());
+
+    ImmutableSet<ServiceInstance> anotherHost = ImmutableSet.of(serviceInstance("three"));
+    hostChangeMonitorCapture.getValue().onChange(anotherHost);
+    assertEquals(anotherHost, groupMonitor.get());
+
+    ImmutableSet<ServiceInstance> noHosts = ImmutableSet.of();
+    hostChangeMonitorCapture.getValue().onChange(noHosts);
+    assertEquals(noHosts, groupMonitor.get());
+  }
+
+  private ServiceInstance serviceInstance(String hostName) {
+    return new ServiceInstance(new Endpoint(hostName, 42), ImmutableMap.of(), Status.ALIVE);
+  }
+}