/** * Returns whether or not service1 depends on service2 in some way for runtime actions, either directly or indirectly. * * @param service1 Service to check dependency for. * @param service2 Service to check dependency on. * @return True if service 1 depends on service 2 directly or indirectly, false if not. */ public boolean runtimeDependsOn(String service1, String service2) { return doesDependOn(service1, service2, runtimeServiceDependencies); }
public ServiceDependencyResolver(Actions actions, Map<String, Service> clusterServices) { this.clusterServices = ImmutableMap.copyOf(clusterServices); this.providesIndex = ImmutableSetMultimap.copyOf(getProvidesIndex()); this.installServiceDependencies = minimizeDependencies( new Function<Service, Set<String>>() { @Override this.runtimeServiceDependencies = minimizeDependencies( new Function<Service, Set<String>>() { @Override this.reversedInstallServiceDependencies = reverseDependencies(installServiceDependencies); this.reversedRuntimeServiceDependencies = reverseDependencies(runtimeServiceDependencies); this.clusterDependencies = HashMultimap.create(); Set<Actions.Dependency> serviceActionDependencies = actions.getActionDependencies(); getDirectActionDependencies(service, actionDependency));
private Set<String> expandStopServices(Set<String> services) { Set<String> expandedServices = Sets.newHashSet(services); // if svc A depends on svc B and we're asked to restart svc B, we actually need to restart both svc A and svc B. // similarly, if svc A depends on svc B and we're asked to stop svc B, we actually need to stop both svc A and B. Set<String> additionalServicesToStop = Sets.newHashSet(); do { additionalServicesToStop.clear(); for (String otherService : Sets.difference(serviceMap.keySet(), expandedServices)) { for (String expandedService : expandedServices) { // if the other service depends on the expanded service, we need to add it to the list of services to stop. // ex: otherService=A and expandedService=B, A depends on B, and B is being stopped/restarted if (dependencyResolver.runtimeDependsOn(otherService, expandedService)) { additionalServicesToStop.add(otherService); } } } expandedServices.addAll(additionalServicesToStop); } while (!additionalServicesToStop.isEmpty()); return expandedServices; }
@Test public void testServiceUsesDependency() { ServiceAction sAction = new ServiceAction("shell", TestHelper.actionMapOf(null, null)); Map<ProvisionerAction, ServiceAction> installActions = ImmutableMap.of(ProvisionerAction.INSTALL, sAction); Service s1 = Service.builder().setName("s1").setProvisionerActions(installActions).build(); Service s2 = Service.builder() .setName("s2") .setDependencies( ServiceDependencies.builder().setInstallDependencies( new ServiceStageDependencies(null, ImmutableSet.<String>of("s1", "s3"))).build()) .setProvisionerActions(installActions) .build(); Map<String, Service> serviceMap = Maps.newHashMap(); serviceMap.put(s1.getName(), s1); serviceMap.put(s2.getName(), s2); SetMultimap<ActionOnService, ActionOnService> expected = HashMultimap.create(); // s2 depends on s1 expected.put(new ActionOnService(ProvisionerAction.INSTALL, "s2"), new ActionOnService(ProvisionerAction.INSTALL, "s1")); ServiceDependencyResolver resolver = new ServiceDependencyResolver(Actions.getInstance(), serviceMap); SetMultimap<ActionOnService, ActionOnService> actual = resolver.getClusterDependencies(); Assert.assertEquals(expected, actual); } }
expected.put("s5", "s3"); expected.put("s5", "s4"); ServiceDependencyResolver resolver = new ServiceDependencyResolver(Actions.getInstance(), serviceMap); SetMultimap<String, String> actual = resolver.getRuntimeServiceDependencies(); Assert.assertEquals(expected, actual); Assert.assertTrue(actual.get("base").isEmpty());
public JobPlanner(ClusterJob job, Set<Node> clusterNodes) { this.clusterAction = job.getClusterAction(); this.nodesToPlan = job.getPlannedNodes(); this.serviceNodeMap = ArrayListMultimap.create(); this.serviceMap = Maps.newHashMap(); this.nodeMap = Maps.newHashMap(); for (Node node : clusterNodes) { for (Service service : node.getServices()) { serviceNodeMap.put(service.getName(), node); serviceMap.put(service.getName(), service); } nodeMap.put(node.getId(), node); } this.dependencyResolver = new ServiceDependencyResolver(actions, serviceMap); if (job.getPlannedServices() != null) { this.servicesToPlan = ImmutableSet.copyOf(expandServices(job.getPlannedServices(), clusterAction)); } else { this.servicesToPlan = null; } }
dependencyResolver.getDirectDependentActions(service.getName(), task)) {
new ActionOnService(ProvisionerAction.START, "s5")); ServiceDependencyResolver resolver = new ServiceDependencyResolver(Actions.getInstance(), serviceMap); SetMultimap<ActionOnService, ActionOnService> actual = resolver.getClusterDependencies(); Assert.assertEquals(expected, actual);
expected.put("s3", "s2-v1"); expected.put("s3", "s2-v2"); ServiceDependencyResolver resolver = new ServiceDependencyResolver(Actions.getInstance(), serviceMap); SetMultimap<String, String> actual = resolver.getRuntimeServiceDependencies(); Assert.assertEquals(expected, actual); Assert.assertTrue(actual.get("base").isEmpty());
new ActionOnService(ProvisionerAction.INSTALL, "s5")); ServiceDependencyResolver resolver = new ServiceDependencyResolver(Actions.getInstance(), serviceMap); SetMultimap<ActionOnService, ActionOnService> actual = resolver.getClusterDependencies(); Assert.assertEquals(expected, actual);
if (doesDependOn(directDependency1.getService(), directDependency2.getService(), serviceDependencies)) { toRemove.add(directDependency2);
private Set<String> expandStartServices(Set<String> services) { Set<String> expandedServices = Sets.newHashSet(services); // if svc A depends on svc B and we're asked to start svc A, we need to start svc B first. Set<String> additionalServicesToStart = Sets.newHashSet(); do { additionalServicesToStart.clear(); for (String otherService : Sets.difference(serviceMap.keySet(), expandedServices)) { for (String expandedService : expandedServices) { // if the other service is one the expanded service depends on, // we need to add it to the list of services to start. // ex: other=A, expanded=B, A depends on B, and A is being started if (dependencyResolver.runtimeDependsOn(expandedService, otherService)) { additionalServicesToStart.add(otherService); } } } expandedServices.addAll(additionalServicesToStart); } while (!additionalServicesToStart.isEmpty()); return expandedServices; } }
for (String service2 : serviceDeps.keySet()) { Assert.assertEquals(serviceDeps.get(service1).contains(service2), ServiceDependencyResolver.doesDependOn(service1, service2, dependencies));