/** * 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.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.util.List; import javax.inject.Singleton; import com.google.common.collect.ImmutableList; import com.google.common.io.Files; import com.google.common.util.concurrent.AbstractIdleService; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Module; import com.google.inject.Provider; import com.google.inject.Provides; import com.google.inject.binder.LinkedBindingBuilder; import org.apache.aurora.common.application.ShutdownRegistry; import org.apache.aurora.common.base.MorePreconditions; import org.apache.aurora.common.zookeeper.ZooKeeperUtils; import org.apache.aurora.common.zookeeper.testing.ZooKeeperTestServer; import org.apache.aurora.scheduler.SchedulerServicesModule; import org.apache.zookeeper.data.ACL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.Objects.requireNonNull; /** * Creates a Guice module that binds leader election and leader discovery components. */ public class ServiceDiscoveryModule extends AbstractModule { private static final Logger LOG = LoggerFactory.getLogger(ServiceDiscoveryModule.class); private final ZooKeeperConfig zooKeeperConfig; private final String discoveryPath; /** * Creates a Guice module that will bind a * {@link org.apache.aurora.common.zookeeper.SingletonService} for scheduler leader election and a * {@link org.apache.aurora.scheduler.app.ServiceGroupMonitor} that can be used to find the * leading scheduler. * * @param zooKeeperConfig The ZooKeeper client configuration to use to interact with ZooKeeper. * @param discoveryPath The ZooKeeper path to use to host leader election and service discovery * nodes under. */ public ServiceDiscoveryModule(ZooKeeperConfig zooKeeperConfig, String discoveryPath) { this.zooKeeperConfig = requireNonNull(zooKeeperConfig); this.discoveryPath = MorePreconditions.checkNotBlank(discoveryPath); } @Override protected void configure() { LinkedBindingBuilder<Iterable<InetSocketAddress>> clusterBinder = bind(ServiceDiscoveryBindings.ZOO_KEEPER_CLUSTER_KEY); if (zooKeeperConfig.isInProcess()) { requireBinding(ShutdownRegistry.class); File tempDir = Files.createTempDir(); bind(ZooKeeperTestServer.class).toInstance(new ZooKeeperTestServer(tempDir, tempDir)); SchedulerServicesModule.addAppStartupServiceBinding(binder()).to(TestServerService.class); clusterBinder.toProvider(LocalZooKeeperClusterProvider.class); } else { clusterBinder.toInstance(zooKeeperConfig.getServers()); } install(discoveryModule()); } private Module discoveryModule() { if (zooKeeperConfig.isUseCurator()) { return new CuratorServiceDiscoveryModule(discoveryPath, zooKeeperConfig); } else { return new CommonsServiceDiscoveryModule(discoveryPath, zooKeeperConfig); } } @Provides @Singleton @ServiceDiscoveryBindings.ZooKeeper List<ACL> provideAcls() { if (zooKeeperConfig.getCredentials().isPresent()) { return ZooKeeperUtils.EVERYONE_READ_CREATOR_ALL; } else { LOG.warn("Running without ZooKeeper digest credentials. ZooKeeper ACLs are disabled."); return ZooKeeperUtils.OPEN_ACL_UNSAFE; } } /** * A service to wrap ZooKeeperTestServer. ZooKeeperTestServer is not a service itself because * some tests depend on stop/start routines that do not no-op, like startAsync and stopAsync may. */ private static class TestServerService extends AbstractIdleService { private final ZooKeeperTestServer testServer; @Inject TestServerService(ZooKeeperTestServer testServer) { this.testServer = requireNonNull(testServer); } @Override protected void startUp() { // We actually start the test server on-demand rather than with the normal lifecycle. // This is because a ZooKeeperClient binding is needed before scheduler services are started. } @Override protected void shutDown() { testServer.stop(); } } private static class LocalZooKeeperClusterProvider implements Provider<Iterable<InetSocketAddress>> { private final ZooKeeperTestServer testServer; @Inject LocalZooKeeperClusterProvider(ZooKeeperTestServer testServer) { this.testServer = requireNonNull(testServer); } @Override public Iterable<InetSocketAddress> get() { try { testServer.startNetwork(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); } return ImmutableList.of( InetSocketAddress.createUnresolved("localhost", testServer.getPort())); } } }