use of com.mesosphere.sdk.state.ConfigStoreException in project dcos-commons by mesosphere.
the class DefaultServiceSpec method getConfigurationFactory.
/**
* Returns a {@link ConfigFactory} which may be used to deserialize
* {@link DefaultServiceSpec}s, which has been confirmed to successfully and
* consistently serialize/deserialize the provided {@code ServiceSpecification} instance.
*
* @param serviceSpec specification to test for successful serialization/deserialization
* @param additionalSubtypesToRegister any class subtypes which should be registered with Jackson for
* deserialization. any custom placement rule implementations must be provided
* @throws IllegalArgumentException if testing the provided specification fails
*/
public static ConfigurationFactory<ServiceSpec> getConfigurationFactory(ServiceSpec serviceSpec, Collection<Class<?>> additionalSubtypesToRegister) {
ConfigurationFactory<ServiceSpec> factory = new ConfigFactory(additionalSubtypesToRegister, ConfigFactory.getReferenceTerminalGoalState(serviceSpec));
final byte[] serviceSpecBytes;
try {
serviceSpecBytes = serviceSpec.getBytes();
} catch (ConfigStoreException e) {
throw new IllegalArgumentException("Failed to convert ServiceSpec to bytes", e);
}
final ServiceSpec loopbackSpecification;
try {
// Serialize and then deserialize:
loopbackSpecification = factory.parse(serviceSpecBytes);
} catch (Exception e) {
LOGGER.error("Failed to parse JSON for loopback validation", e);
LOGGER.error("JSON to be parsed was:\n{}", new String(serviceSpecBytes, StandardCharsets.UTF_8));
throw new IllegalArgumentException("Failed to parse JSON for loopback validation", e);
}
// Verify that equality works:
if (!loopbackSpecification.equals(serviceSpec)) {
final String originalSpecString;
try {
originalSpecString = serviceSpec.toJsonString();
} catch (ConfigStoreException e) {
throw new IllegalArgumentException("Failed to convert original ServiceSpec to String", e);
}
final String loopbackSpecString;
try {
loopbackSpecString = loopbackSpecification.toJsonString();
} catch (ConfigStoreException e) {
throw new IllegalArgumentException("Failed to convert loopback ServiceSpec to String", e);
}
StringBuilder error = new StringBuilder();
error.append("Equality test failed: Loopback result is not equal to original:\n");
error.append("- Original:\n");
error.append(originalSpecString);
error.append('\n');
error.append("- Result:\n");
error.append(loopbackSpecString);
error.append('\n');
throw new IllegalArgumentException(error.toString());
}
return factory;
}
use of com.mesosphere.sdk.state.ConfigStoreException in project dcos-commons by mesosphere.
the class SchedulerBuilder method build.
/**
* Creates a new Mesos scheduler instance with the provided values or their defaults, or an empty {@link Optional}
* if no Mesos scheduler should be registered for this run.
*
* @return a new Mesos scheduler instance to be registered, or an empty {@link Optional}
* @throws IllegalArgumentException if validating the provided configuration failed
*/
public AbstractScheduler build() {
// If region awareness is enabled (via java bit or via env) and the cluster supports it, update the ServiceSpec
// to include region constraints.
final ServiceSpec serviceSpec;
if (Capabilities.getInstance().supportsDomains()) {
// This cluster supports domains. We need to update pod placement with region configuration, for any pods
// that weren't already configured by the developer (expected to be rare, but possible).
// Whether region awareness is enabled for the service (via env or via java).
boolean regionAwarenessEnabled = isRegionAwarenessEnabled();
// A region to target, as specified in env, if any.
Optional<String> schedulerRegion = schedulerConfig.getSchedulerRegion();
// Target the specified region, or use the local region.
// Local region is determined at framework registration, see IsLocalRegionRule.setLocalDomain().
final PlacementRule placementRuleToAdd;
if (regionAwarenessEnabled && schedulerRegion.isPresent()) {
logger.info("Updating pods with placement rule for region={}", schedulerRegion.get());
placementRuleToAdd = RegionRuleFactory.getInstance().require(ExactMatcher.create(schedulerRegion.get()));
} else {
logger.info("Updating pods with local region placement rule: region awareness={}, scheduler region={}", regionAwarenessEnabled, schedulerRegion);
placementRuleToAdd = new IsLocalRegionRule();
}
List<PodSpec> updatedPodSpecs = new ArrayList<>();
for (PodSpec podSpec : originalServiceSpec.getPods()) {
if (PlacementUtils.placementRuleReferencesRegion(podSpec)) {
// Pod already has a region constraint (specified by developer?). Leave it as-is.
logger.info("Pod {} already has a region rule defined, leaving as-is", podSpec.getType());
updatedPodSpecs.add(podSpec);
} else {
// Combine the new rule with any existing rules:
PlacementRule mergedRule = podSpec.getPlacementRule().isPresent() ? new AndRule(placementRuleToAdd, podSpec.getPlacementRule().get()) : placementRuleToAdd;
updatedPodSpecs.add(DefaultPodSpec.newBuilder(podSpec).placementRule(mergedRule).build());
}
}
DefaultServiceSpec.Builder builder = DefaultServiceSpec.newBuilder(originalServiceSpec).pods(updatedPodSpecs);
if (schedulerRegion.isPresent()) {
builder.region(schedulerRegion.get());
}
serviceSpec = builder.build();
} else {
serviceSpec = originalServiceSpec;
}
// NOTE: we specifically avoid accessing the provided persister before build() is called.
// This is to ensure that upstream has a chance to e.g. lock it via CuratorLocker.
// When multi-service is enabled, state/configs are stored within a namespace matching the service name.
// Otherwise use an empty namespace, which indicates single-service mode.
String namespaceStr = namespace.orElse("");
FrameworkStore frameworkStore = new FrameworkStore(persister);
StateStore stateStore = new StateStore(persister, namespaceStr);
ConfigStore<ServiceSpec> configStore = new ConfigStore<>(DefaultServiceSpec.getConfigurationFactory(serviceSpec), persister, namespaceStr);
if (schedulerConfig.isUninstallEnabled()) {
// uninstall mode. UninstallScheduler will internally flag the stateStore with an uninstall bit if needed.
return new UninstallScheduler(serviceSpec, frameworkStore, stateStore, configStore, FrameworkConfig.fromServiceSpec(serviceSpec), schedulerConfig, Optional.ofNullable(planCustomizer));
}
if (StateStoreUtils.isUninstalling(stateStore)) {
// SERVICE UNINSTALL: The service has an uninstall bit set in its (potentially namespaced) state store.
if (namespace.isPresent()) {
// Launch the service in uninstall mode so that it can continue with whatever may be left.
return new UninstallScheduler(serviceSpec, frameworkStore, stateStore, configStore, FrameworkConfig.fromServiceSpec(serviceSpec), schedulerConfig, Optional.ofNullable(planCustomizer));
} else {
// This is an illegal state for a single-service scheduler. SchedulerConfig's uninstall bit should have
// also been enabled. If we got here, it means that the user likely tampered with the scheduler env
// after having previously triggered an uninstall, which had set the bit in stateStore. Just exit,
// because the service is likely now in an inconsistent state resulting from the incomplete uninstall.
logger.error("Service has been previously told to uninstall, this cannot be reversed. " + "Reenable the uninstall flag to complete the process.");
SchedulerUtils.hardExit(SchedulerErrorCode.SCHEDULER_ALREADY_UNINSTALLING);
}
}
try {
return getDefaultScheduler(serviceSpec, frameworkStore, stateStore, configStore);
} catch (ConfigStoreException e) {
logger.error("Failed to construct scheduler.", e);
SchedulerUtils.hardExit(SchedulerErrorCode.INITIALIZATION_FAILURE);
// This is so the compiler doesn't complain. The scheduler is going down anyway.
return null;
}
}
use of com.mesosphere.sdk.state.ConfigStoreException in project dcos-commons by mesosphere.
the class ArtifactQueriesTest method testGetTemplateServiceConfigNotFound.
@Test
public void testGetTemplateServiceConfigNotFound() throws ConfigStoreException {
UUID uuid = UUID.randomUUID();
when(mockConfigStore.fetch(uuid)).thenThrow(new ConfigStoreException(Reason.NOT_FOUND, "hi"));
assertEquals(404, ArtifactQueries.getTemplate(mockConfigStore, uuid.toString(), "pod", "task", "conffile").getStatus());
}
use of com.mesosphere.sdk.state.ConfigStoreException in project dcos-commons by mesosphere.
the class ConfigQueriesTest method testGetConfigNotFound.
@Test
public void testGetConfigNotFound() throws ConfigStoreException {
when(mockConfigStore.fetch(ID1)).thenThrow(new ConfigStoreException(Reason.NOT_FOUND, "hi"));
Response response = ConfigQueries.getConfiguration(mockConfigStore, ID1.toString());
assertEquals(404, response.getStatus());
}
use of com.mesosphere.sdk.state.ConfigStoreException in project dcos-commons by mesosphere.
the class ConfigQueriesTest method testGetTargetIdFails.
@Test
public void testGetTargetIdFails() throws ConfigStoreException {
when(mockConfigStore.getTargetConfig()).thenThrow(new ConfigStoreException(Reason.STORAGE_ERROR, "hi"));
Response response = ConfigQueries.getTargetId(mockConfigStore);
assertEquals(500, response.getStatus());
}
Aggregations