use of com.mesosphere.sdk.storage.PersisterException in project dcos-commons by mesosphere.
the class CuratorPersisterTest method testAclBehavior.
// Uses a real ZK instance to ensure that our integration works as expected:
@Test
public void testAclBehavior() throws Exception {
CuratorTestUtils.clear(testZk);
when(mockServiceSpec.getZookeeperConnection()).thenReturn(testZk.getConnectString());
Persister nonAclPersister = CuratorPersister.newBuilder(mockServiceSpec).build();
Persister aclPersister = CuratorPersister.newBuilder(mockServiceSpec).setCredentials("testuser", "testpw").build();
// Store value with ACL.
aclPersister.set(PATH_1, DATA_1);
// Readable with appropriate Auth and ACL.
assertArrayEquals(DATA_1, aclPersister.get(PATH_1));
// Readable with world:anyone permission.
assertArrayEquals(DATA_1, nonAclPersister.get(PATH_1));
// Not overwriteable with world:anyone permission.
try {
nonAclPersister.set(PATH_1, DATA_2);
fail("Should have failed with auth exception");
} catch (PersisterException e) {
assertEquals(Reason.STORAGE_ERROR, e.getReason());
assertTrue(e.getCause() instanceof KeeperException.NoAuthException);
}
// Not overwriteable with incorrect Auth
try {
Persister wrongAclPersister = CuratorPersister.newBuilder(mockServiceSpec).setCredentials("testuser", "otherpw").build();
wrongAclPersister.set(PATH_1, DATA_SUB_1);
fail("Should have failed with auth exception");
} catch (PersisterException e) {
assertEquals(Reason.STORAGE_ERROR, e.getReason());
assertTrue(e.getCause() instanceof KeeperException.NoAuthException);
}
// Delete ACL'ed data so that other tests don't have ACL problems trying to clear it:
aclPersister.recursiveDelete(PATH_PARENT);
}
use of com.mesosphere.sdk.storage.PersisterException in project dcos-commons by mesosphere.
the class CuratorPersister method recursiveDelete.
@Override
public void recursiveDelete(String unprefixedPath) throws PersisterException {
final String path = withFrameworkPrefix(unprefixedPath);
if (path.equals(serviceRootPath)) {
// Special case: If we're being told to delete root, we should instead delete the contents OF root. We don't
// have access to delete the root-level '/dcos-service-<svcname>' node itself, despite having created it.
/* Effective 5/8/2017:
* We cannot delete the root node of a service directly.
* This is due to the ACLs on the global DC/OS ZK.
*
* The root has:
* [zk: localhost:2181(CONNECTED) 1] getAcl /
* 'world,'anyone
* : cr
* 'ip,'127.0.0.1
* : cdrwa
*
* Our service nodes have:
* [zk: localhost:2181(CONNECTED) 0] getAcl /dcos-service-hello-world
* 'world,'anyone
* : cdrwa
*
* The best we can do is to wipe everything under the root node. A proposed way to "fix" things
* lives at https://jira.mesosphere.com/browse/INFINITY-1470.
*/
LOGGER.debug("Deleting children of root {}", path);
try {
CuratorTransactionFinal transaction = client.inTransaction().check().forPath(serviceRootPath).and();
Set<String> pendingDeletePaths = new HashSet<>();
for (String child : client.getChildren().forPath(serviceRootPath)) {
// Custom logic for root-level children: don't delete the lock node
if (child.equals(CuratorLocker.LOCK_PATH_NAME)) {
continue;
}
String childPath = PersisterUtils.join(serviceRootPath, child);
transaction = deleteChildrenOf(client, childPath, transaction, pendingDeletePaths).delete().forPath(childPath).and();
}
transaction.commit();
} catch (Exception e) {
throw new PersisterException(Reason.STORAGE_ERROR, String.format("Unable to delete children of root %s: %s", path, e.getMessage()), e);
}
// Need to explicitly set null or else curator will return a zero-bytes value later:
set(unprefixedPath, null);
} else {
// Normal case: Delete node itself and any/all children.
LOGGER.debug("Deleting {} (and any children)", path);
try {
client.delete().deletingChildrenIfNeeded().forPath(path);
} catch (KeeperException.NoNodeException e) {
throw new PersisterException(Reason.NOT_FOUND, String.format("Path to delete does not exist: %s", path), e);
} catch (Exception e) {
throw new PersisterException(Reason.STORAGE_ERROR, String.format("Unable to delete %s", path), e);
}
}
}
use of com.mesosphere.sdk.storage.PersisterException in project dcos-commons by mesosphere.
the class CuratorPersister method getMany.
@Override
public Map<String, byte[]> getMany(Collection<String> unprefixedPaths) throws PersisterException {
if (unprefixedPaths.isEmpty()) {
return Collections.emptyMap();
}
LOGGER.debug("Getting {} entries: {}", unprefixedPaths.size(), unprefixedPaths);
Map<String, byte[]> result = new TreeMap<>();
// changes, then it may make sense to look into some form of proper read locking here.
for (String unprefixedPath : unprefixedPaths) {
String path = withFrameworkPrefix(unprefixedPath);
try {
result.put(unprefixedPath, client.getData().forPath(path));
} catch (KeeperException.NoNodeException e) {
result.put(unprefixedPath, null);
} catch (Exception e) {
throw new PersisterException(Reason.STORAGE_ERROR, String.format("Unable to retrieve data from %s", path), e);
}
}
return result;
}
use of com.mesosphere.sdk.storage.PersisterException in project dcos-commons by mesosphere.
the class StateQueries method refreshCache.
/**
* Refreshes the state store cache to reflect current data on ZK. Should only be needed if ZK was edited behind the
* scheduler's back, or if there's a bug in the cache handling.
*/
public static Response refreshCache(StateStore stateStore) {
PersisterCache cache = getPersisterCache(stateStore);
if (cache == null) {
LOGGER.warn("State store is not cached: Refresh is not applicable");
return Response.status(Response.Status.CONFLICT).build();
}
try {
LOGGER.info("Refreshing state store cache...");
LOGGER.info("Before:\n- tasks: {}\n- properties: {}", stateStore.fetchTaskNames(), stateStore.fetchPropertyKeys());
cache.refresh();
LOGGER.info("After:\n- tasks: {}\n- properties: {}", stateStore.fetchTaskNames(), stateStore.fetchPropertyKeys());
return ResponseUtils.jsonOkResponse(getCommandResult("refresh"));
} catch (PersisterException ex) {
LOGGER.error("Failed to refresh state cache", ex);
return Response.serverError().build();
}
}
use of com.mesosphere.sdk.storage.PersisterException in project dcos-commons by mesosphere.
the class SchedulerRunner method run.
/**
* Runs the scheduler. Don't forget to call this!
* This should never exit, instead the entire process will be terminated internally.
*/
@Override
public void run() {
SchedulerConfig schedulerConfig = schedulerBuilder.getSchedulerConfig();
ServiceSpec serviceSpec = schedulerBuilder.getServiceSpec();
Persister persister = schedulerBuilder.getPersister();
// Get a curator lock, then check the schema version:
CuratorLocker.lock(serviceSpec.getName(), serviceSpec.getZookeeperConnection());
// Check and/or initialize schema version before doing any other storage access:
new SchemaVersionStore(persister).check(SUPPORTED_SCHEMA_VERSION_SINGLE_SERVICE);
Metrics.configureStatsd(schedulerConfig);
AbstractScheduler scheduler = schedulerBuilder.build();
scheduler.start();
Optional<Scheduler> mesosScheduler = scheduler.getMesosScheduler();
if (mesosScheduler.isPresent()) {
ApiServer apiServer = new ApiServer(schedulerConfig, scheduler.getResources());
apiServer.start(new AbstractLifeCycle.AbstractLifeCycleListener() {
@Override
public void lifeCycleStarted(LifeCycle event) {
scheduler.markApiServerStarted();
}
});
runScheduler(new FrameworkRunner(FrameworkConfig.fromServiceSpec(serviceSpec), PodSpecsCannotUseUnsupportedFeatures.serviceRequestsGpuResources(serviceSpec), schedulerBuilder.isRegionAwarenessEnabled()).getFrameworkInfo(new FrameworkStore(schedulerBuilder.getPersister()).fetchFrameworkId()), mesosScheduler.get(), schedulerBuilder.getServiceSpec(), schedulerBuilder.getSchedulerConfig());
} else {
/**
* If no MesosScheduler is provided this scheduler has been deregistered and should report itself healthy
* and provide an empty COMPLETE deploy plan so it may complete its UNINSTALL.
*
* See {@link UninstallScheduler#getMesosScheduler()}.
*/
Plan emptyDeployPlan = new Plan() {
@Override
public List<Phase> getChildren() {
return Collections.emptyList();
}
@Override
public Strategy<Phase> getStrategy() {
return new SerialStrategy<>();
}
@Override
public UUID getId() {
return UUID.randomUUID();
}
@Override
public String getName() {
return Constants.DEPLOY_PLAN_NAME;
}
@Override
public List<String> getErrors() {
return Collections.emptyList();
}
};
try {
PersisterUtils.clearAllData(persister);
} catch (PersisterException e) {
// Best effort.
LOGGER.error("Failed to clear all data", e);
}
ApiServer apiServer = new ApiServer(schedulerConfig, Arrays.asList(new PlansResource(Collections.singletonList(DefaultPlanManager.createProceeding(emptyDeployPlan))), new HealthResource(Collections.emptyList())));
apiServer.start(new AbstractLifeCycle.AbstractLifeCycleListener() {
@Override
public void lifeCycleStarted(LifeCycle event) {
LOGGER.info("Started trivially healthy API server.");
}
});
}
}
Aggregations