use of com.amazon.aws.iot.greengrass.component.common.DependencyType in project aws-greengrass-nucleus by aws-greengrass.
the class MultiGroupDeploymentTest method GIVEN_device_belongs_to_two_groups_WHEN_device_is_removed_from_one_group_THEN_next_deployment_removes_corresponding_component.
@Test
void GIVEN_device_belongs_to_two_groups_WHEN_device_is_removed_from_one_group_THEN_next_deployment_removes_corresponding_component() throws Exception {
CountDownLatch firstGroupCDL = new CountDownLatch(1);
CountDownLatch secondGroupCDL = new CountDownLatch(1);
DeploymentStatusKeeper deploymentStatusKeeper = kernel.getContext().get(DeploymentStatusKeeper.class);
deploymentStatusKeeper.registerDeploymentStatusConsumer(Deployment.DeploymentType.IOT_JOBS, (status) -> {
if (status.get(DEPLOYMENT_ID_KEY_NAME).equals("firstGroup") && status.get(DEPLOYMENT_STATUS_KEY_NAME).equals("SUCCEEDED")) {
firstGroupCDL.countDown();
}
if (status.get(DEPLOYMENT_ID_KEY_NAME).equals("secondGroup") && status.get(DEPLOYMENT_STATUS_KEY_NAME).equals("SUCCEEDED")) {
secondGroupCDL.countDown();
}
return true;
}, "dummyValue");
when(thingGroupHelper.listThingGroupsForDevice(anyInt())).thenReturn(Optional.of(new HashSet<>(Arrays.asList("firstGroup", "secondGroup"))));
submitSampleJobDocument(DeploymentServiceIntegrationTest.class.getResource("FleetConfigWithRedSignalService.json").toURI(), "firstGroup", Deployment.DeploymentType.IOT_JOBS);
assertTrue(firstGroupCDL.await(10, TimeUnit.SECONDS));
when(thingGroupHelper.listThingGroupsForDevice(anyInt())).thenReturn(Optional.of(new HashSet<>(Arrays.asList("secondGroup"))));
submitSampleJobDocument(DeploymentServiceIntegrationTest.class.getResource("FleetConfigWithSomeService.json").toURI(), "secondGroup", Deployment.DeploymentType.IOT_JOBS);
assertTrue(secondGroupCDL.await(10, TimeUnit.SECONDS));
Topics groupToRootTopic = kernel.getConfig().lookupTopics(SERVICES_NAMESPACE_TOPIC, DEPLOYMENT_SERVICE_TOPICS, GROUP_TO_ROOT_COMPONENTS_TOPICS);
List<String> groupNames = new ArrayList<>();
groupToRootTopic.forEach(node -> groupNames.add(node.getName()));
assertTrue(groupNames.containsAll(Arrays.asList("secondGroup")), "Device should belong to firstGroup and secondGroup");
Map<GreengrassService, DependencyType> dependenciesAfter = kernel.getMain().getDependencies();
List<String> serviceNames = dependenciesAfter.keySet().stream().map(service -> service.getName()).collect(Collectors.toList());
assertTrue(serviceNames.containsAll(Arrays.asList("SomeService")));
Topics componentsToGroupTopic = kernel.getConfig().lookupTopics(SERVICES_NAMESPACE_TOPIC, DEPLOYMENT_SERVICE_TOPICS, COMPONENTS_TO_GROUPS_TOPICS);
assertNotNull(componentsToGroupTopic.find("SomeService", "secondGroup"));
}
use of com.amazon.aws.iot.greengrass.component.common.DependencyType in project aws-greengrass-nucleus by aws-greengrass.
the class GreengrassService method setupDependencies.
private synchronized void setupDependencies(Collection<String> dependencyList) throws ServiceLoadException, InputValidationException {
Map<GreengrassService, DependencyType> oldDependencies = new HashMap<>(getDependencies());
Map<GreengrassService, DependencyType> keptDependencies = getDependencyTypeMap(dependencyList);
Set<GreengrassService> removedDependencies = dependencies.entrySet().stream().filter(e -> !keptDependencies.containsKey(e.getKey()) && !e.getValue().isDefaultDependency).map(Map.Entry::getKey).collect(Collectors.toSet());
if (!removedDependencies.isEmpty()) {
logger.atDebug("removing-unused-dependencies").kv("removedDependencies", removedDependencies).log();
removedDependencies.forEach(dependency -> {
DependencyInfo dependencyInfo = dependencies.remove(dependency);
dependency.removeStateSubscriber(dependencyInfo.stateTopicSubscriber);
});
context.get(Kernel.class).clearODcache();
}
AtomicBoolean hasNewService = new AtomicBoolean(false);
keptDependencies.forEach((dependentService, dependencyType) -> {
try {
if (!oldDependencies.containsKey(dependentService)) {
hasNewService.set(true);
}
addOrUpdateDependency(dependentService, dependencyType, false);
} catch (InputValidationException e) {
logger.atWarn("add-dependency").log("Unable to add dependency {}", dependentService, e);
}
});
if (hasNewService.get()) {
requestRestart();
} else if (!dependencyReady() && !getState().equals(State.FINISHED)) {
// if dependency type changed, restart this service.
requestRestart();
}
}
use of com.amazon.aws.iot.greengrass.component.common.DependencyType in project aws-greengrass-nucleus by aws-greengrass.
the class GreengrassService method parseSingleDependency.
/**
* Parse a string into a dependency specification.
*
* @param dependency string in the format of one service dependency
* @return a pair of dependency name and type
* @throws InputValidationException if the dependency string has invalid format
*/
public static Pair<String, DependencyType> parseSingleDependency(String dependency) throws InputValidationException {
String[] dependencyInfo = dependency.split(":");
if (dependencyInfo.length == 0 || dependencyInfo.length > 2) {
throw new InputValidationException("Bad dependency syntax");
}
String typeString = dependencyInfo.length > 1 ? dependencyInfo[1] : null;
DependencyType type = null;
if (typeString != null && !typeString.isEmpty()) {
// do "friendly" match
for (DependencyType s : DependencyType.values()) {
if (typeString.regionMatches(true, 0, s.name(), 0, typeString.length())) {
type = s;
break;
}
}
if (type == null) {
throw new InputValidationException(typeString + " does not match any Service dependency type");
}
}
return new Pair<>(dependencyInfo[0], type == null ? DependencyType.HARD : type);
}
use of com.amazon.aws.iot.greengrass.component.common.DependencyType in project aws-greengrass-nucleus by aws-greengrass.
the class Kernel method locateGreengrassService.
@SuppressWarnings({ "UseSpecificCatch", "PMD.AvoidCatchingThrowable", "PMD.AvoidDeeplyNestedIfStmts", "PMD.ConfusingTernary" })
private GreengrassService locateGreengrassService(Context.Value v, String name, CrashableFunction<String, GreengrassService, ServiceLoadException> locateFunction) throws ServiceLoadException {
Topics serviceRootTopics = findServiceTopic(name);
Class<?> clazz = null;
if (serviceRootTopics != null) {
// Try locating all the dependencies first so that they'll all exist prior to their dependant.
// This is to fix an ordering problem with plugins such as lambda manager. The plugin needs to be
// located *before* the dependant is located so that the plugin has its jar loaded into the classloader.
Topic dependenciesTopic = serviceRootTopics.findLeafChild(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC);
if (dependenciesTopic != null && dependenciesTopic.getOnce() instanceof Collection) {
try {
for (Pair<String, DependencyType> p : GreengrassService.parseDependencies((Collection<String>) dependenciesTopic.getOnce())) {
locateFunction.apply(p.getLeft());
}
} catch (ServiceLoadException | InputValidationException e) {
throw new ServiceLoadException("Unable to load service " + name, e);
}
}
Topic classTopic = serviceRootTopics.findLeafChild(SERVICE_CLASS_TOPIC_KEY);
String className = null;
// If a "class" is specified in the recipe, then use that
if (classTopic != null) {
className = Coerce.toString(classTopic);
} else {
Topic componentTypeTopic = serviceRootTopics.findLeafChild(SERVICE_TYPE_TOPIC_KEY);
// If a "componentType" is specified, then map that to a class
if (componentTypeTopic != null) {
className = ((Map<String, String>) context.getvIfExists(SERVICE_TYPE_TO_CLASS_MAP_KEY).get()).get(Coerce.toString(componentTypeTopic).toLowerCase());
// plugin
if (className == null && Coerce.toString(componentTypeTopic).equalsIgnoreCase(PLUGIN_SERVICE_TYPE_NAME)) {
clazz = locateExternalPlugin(name, serviceRootTopics);
}
}
}
if (className != null) {
try {
clazz = context.get(EZPlugins.class).forName(className);
} catch (Throwable ex) {
throw new ServiceLoadException("Can't load service class from " + className, ex);
}
}
}
// try to find service implementation class from plugins.
if (clazz == null) {
Map<String, Class<?>> si = context.getIfExists(Map.class, CONTEXT_SERVICE_IMPLEMENTERS);
if (si != null) {
logger.atInfo().kv(GreengrassService.SERVICE_NAME_KEY, name).log("Attempt to load service from plugins");
clazz = si.get(name);
}
}
GreengrassService ret;
// If found class, try to load service class from plugins.
if (clazz != null) {
try {
// Lookup the service topics here because the Topics passed into the GreengrassService
// constructor must not be null
Topics topics = config.lookupTopics(SERVICES_NAMESPACE_TOPIC, name);
try {
Constructor<?> ctor = clazz.getConstructor(Topics.class);
ret = (GreengrassService) ctor.newInstance(topics);
} catch (NoSuchMethodException e) {
// If the basic constructor doesn't exist, then try injecting from the context
ret = (GreengrassService) context.newInstance(clazz);
}
// Force plugins to be singletons
if (clazz.getAnnotation(Singleton.class) != null || PluginService.class.isAssignableFrom(clazz)) {
context.put(ret.getClass(), v);
}
if (clazz.getAnnotation(ImplementsService.class) != null) {
topics.createLeafChild(VERSION_CONFIG_KEY).withNewerValue(0L, clazz.getAnnotation(ImplementsService.class).version());
}
logger.atDebug("service-loaded").kv(GreengrassService.SERVICE_NAME_KEY, ret.getName()).log();
return ret;
} catch (Throwable ex) {
throw new ServiceLoadException("Can't create Greengrass Service instance " + clazz.getSimpleName(), ex);
}
}
if (serviceRootTopics == null || serviceRootTopics.isEmpty()) {
throw new ServiceLoadException("No matching definition in system model for: " + name);
}
// if not found, initialize GenericExternalService
try {
ret = new GenericExternalService(serviceRootTopics);
logger.atDebug("generic-service-loaded").kv(GreengrassService.SERVICE_NAME_KEY, ret.getName()).log();
} catch (Throwable ex) {
throw new ServiceLoadException("Can't create generic service instance " + name, ex);
}
return ret;
}
use of com.amazon.aws.iot.greengrass.component.common.DependencyType in project aws-greengrass-nucleus by aws-greengrass.
the class MultipleGroupsDeploymentE2ETest method GIVEN_deployment_2_multiple_groups_WHEN_device_removed_from_group_THEN_components_removed_on_next_deployment.
@Timeout(value = 10, unit = TimeUnit.MINUTES)
@Test
void GIVEN_deployment_2_multiple_groups_WHEN_device_removed_from_group_THEN_components_removed_on_next_deployment() throws Exception {
CreateDeploymentRequest deploymentToFirstGroup = CreateDeploymentRequest.builder().targetArn(thingGroupArn).components(Utils.immutableMap("CustomerApp", ComponentDeploymentSpecification.builder().componentVersion("1.0.0").build())).build();
CreateDeploymentResponse firstDeploymentResult = draftAndCreateDeployment(deploymentToFirstGroup);
IotJobsUtils.waitForJobExecutionStatusToSatisfy(iotClient, firstDeploymentResult.iotJobId(), thingInfo.getThingName(), Duration.ofMinutes(5), s -> s.equals(JobExecutionStatus.SUCCEEDED));
CreateDeploymentRequest deviceDeployment = CreateDeploymentRequest.builder().targetArn(thingInfo.getThingArn()).components(Utils.immutableMap("SomeService", ComponentDeploymentSpecification.builder().componentVersion("1.0.0").build())).build();
CountDownLatch deviceDeploymentSucceeded = listenToShadowDeploymentUpdates();
draftAndCreateDeployment(deviceDeployment);
deviceDeploymentSucceeded.await(5, TimeUnit.MINUTES);
CreateThingGroupResponse thirdThingGroup = IotJobsUtils.createThingGroupAndAddThing(iotClient, thingInfo);
createdThingGroups.add(thirdThingGroup.thingGroupName());
CreateDeploymentRequest deploymentToThirdGroup = CreateDeploymentRequest.builder().targetArn(thirdThingGroup.thingGroupArn()).components(Utils.immutableMap("YellowSignal", ComponentDeploymentSpecification.builder().componentVersion("1.0.0").build())).build();
CreateDeploymentResponse thirdDeploymentResult = draftAndCreateDeployment(deploymentToThirdGroup);
IotJobsUtils.waitForJobExecutionStatusToSatisfy(iotClient, thirdDeploymentResult.iotJobId(), thingInfo.getThingName(), Duration.ofMinutes(5), s -> s.equals(JobExecutionStatus.SUCCEEDED));
IotJobsUtils.removeFromThingGroup(iotClient, thingInfo, thirdThingGroup.thingGroupArn());
CreateThingGroupResponse fourthThingGroup = IotJobsUtils.createThingGroupAndAddThing(iotClient, thingInfo);
createdThingGroups.add(fourthThingGroup.thingGroupName());
CreateDeploymentRequest deploymentToFourthGroup = CreateDeploymentRequest.builder().targetArn(fourthThingGroup.thingGroupArn()).components(Utils.immutableMap("RedSignal", ComponentDeploymentSpecification.builder().componentVersion("1.0.0").build())).build();
CreateDeploymentResponse fourthDeploymentResult = draftAndCreateDeployment(deploymentToFourthGroup);
IotJobsUtils.waitForJobExecutionStatusToSatisfy(iotClient, fourthDeploymentResult.iotJobId(), thingInfo.getThingName(), Duration.ofMinutes(5), s -> s.equals(JobExecutionStatus.SUCCEEDED));
Map<GreengrassService, DependencyType> dependenciesAfter = kernel.getMain().getDependencies();
List<String> serviceNames = dependenciesAfter.keySet().stream().map(service -> service.getName()).collect(Collectors.toList());
assertTrue(serviceNames.containsAll(Arrays.asList(getTestComponentNameInCloud("CustomerApp"), getTestComponentNameInCloud("SomeService"), getTestComponentNameInCloud("RedSignal"))));
assertFalse(serviceNames.containsAll(Arrays.asList(getTestComponentNameInCloud("YellowSignal"))));
Topics groupToRootTopic = kernel.getConfig().lookupTopics(SERVICES_NAMESPACE_TOPIC, DEPLOYMENT_SERVICE_TOPICS, GROUP_TO_ROOT_COMPONENTS_TOPICS);
assertNotNull(groupToRootTopic.findTopics(THING_GROUP_RESOURCE_TYPE_PREFIX + thingGroupName, getTestComponentNameInCloud("CustomerApp")));
assertNotNull(groupToRootTopic.findTopics("thing/" + thingInfo.getThingName(), getTestComponentNameInCloud("SomeService")));
assertNotNull(groupToRootTopic.findTopics(THING_GROUP_RESOURCE_TYPE_PREFIX + fourthThingGroup.thingGroupName(), getTestComponentNameInCloud("RedSignal")));
assertNull(groupToRootTopic.findTopics(THING_GROUP_RESOURCE_TYPE_PREFIX + thirdThingGroup.thingGroupName()));
Topics componentsToGroupTopic = kernel.getConfig().lookupTopics(SERVICES_NAMESPACE_TOPIC, DEPLOYMENT_SERVICE_TOPICS, COMPONENTS_TO_GROUPS_TOPICS);
assertNotNull(componentsToGroupTopic.findTopics(getTestComponentNameInCloud("CustomerApp")));
assertNotNull(componentsToGroupTopic.findTopics(getTestComponentNameInCloud("SomeService")));
assertNotNull(componentsToGroupTopic.findTopics(getTestComponentNameInCloud("RedSignal")));
assertNull(componentsToGroupTopic.findTopics(getTestComponentNameInCloud("YellowSignal")));
}
Aggregations