|
24 | 24 | import java.util.Arrays; |
25 | 25 | import java.util.Collections; |
26 | 26 | import java.util.List; |
| 27 | +import java.util.Map; |
27 | 28 | import java.util.Properties; |
28 | 29 | import java.util.concurrent.ForkJoinPool; |
29 | 30 |
|
| 31 | +import com.fasterxml.jackson.core.type.TypeReference; |
| 32 | +import com.fasterxml.jackson.databind.ObjectMapper; |
30 | 33 | import org.slf4j.Logger; |
31 | 34 | import org.slf4j.LoggerFactory; |
32 | 35 |
|
33 | 36 | import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; |
34 | 37 | import org.springframework.cloud.dataflow.configuration.metadata.ApplicationConfigurationMetadataResolver; |
35 | 38 | import org.springframework.cloud.dataflow.core.ApplicationType; |
| 39 | +import org.springframework.cloud.dataflow.core.StreamAppDefinition; |
| 40 | +import org.springframework.cloud.dataflow.core.StreamDefinition; |
| 41 | +import org.springframework.cloud.dataflow.core.StreamDeployment; |
36 | 42 | import org.springframework.cloud.dataflow.registry.domain.AppRegistration; |
37 | 43 | import org.springframework.cloud.dataflow.registry.service.AppRegistryService; |
38 | 44 | import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService; |
39 | 45 | import org.springframework.cloud.dataflow.registry.support.NoSuchAppRegistrationException; |
40 | 46 | import org.springframework.cloud.dataflow.registry.support.ResourceUtils; |
| 47 | +import org.springframework.cloud.dataflow.rest.SkipperStream; |
41 | 48 | import org.springframework.cloud.dataflow.rest.resource.AppRegistrationResource; |
42 | 49 | import org.springframework.cloud.dataflow.rest.resource.DetailedAppRegistrationResource; |
| 50 | +import org.springframework.cloud.dataflow.server.DataFlowServerUtil; |
| 51 | +import org.springframework.cloud.dataflow.server.repository.StreamDefinitionRepository; |
| 52 | +import org.springframework.cloud.dataflow.server.service.StreamService; |
| 53 | +import org.springframework.cloud.dataflow.server.support.CannotDetermineApplicationTypeException; |
43 | 54 | import org.springframework.cloud.deployer.resource.maven.MavenProperties; |
44 | 55 | import org.springframework.core.io.ByteArrayResource; |
45 | 56 | import org.springframework.core.io.DefaultResourceLoader; |
|
75 | 86 | @RestController |
76 | 87 | @RequestMapping("/apps") |
77 | 88 | @ExposesResourceFor(AppRegistrationResource.class) |
78 | | -public class VersionedAppRegistryController { |
| 89 | +public class SkipperAppRegistryController { |
79 | 90 |
|
80 | | - private static final Logger logger = LoggerFactory.getLogger(VersionedAppRegistryController.class); |
| 91 | + private static final Logger logger = LoggerFactory.getLogger(SkipperAppRegistryController.class); |
81 | 92 |
|
82 | 93 | private final Assembler assembler = new Assembler(); |
83 | 94 |
|
| 95 | + private final StreamDefinitionRepository streamDefinitionRepository; |
| 96 | + |
84 | 97 | private final AppRegistryService appRegistryService; |
85 | 98 |
|
| 99 | + private final MavenProperties mavenProperties; |
| 100 | + |
| 101 | + private final StreamService streamService; |
| 102 | + |
86 | 103 | private ApplicationConfigurationMetadataResolver metadataResolver; |
87 | 104 |
|
88 | 105 | private ForkJoinPool forkJoinPool; |
89 | 106 |
|
90 | | - private final MavenProperties mavenProperties; |
91 | | - |
92 | 107 | private ResourceLoader resourceLoader = new DefaultResourceLoader(); |
93 | 108 |
|
94 | | - public VersionedAppRegistryController(AppRegistryService appRegistryService, |
| 109 | + public SkipperAppRegistryController(StreamDefinitionRepository streamDefinitionRepository, |
| 110 | + StreamService streamService, |
| 111 | + AppRegistryService appRegistryService, |
95 | 112 | ApplicationConfigurationMetadataResolver metadataResolver, |
96 | 113 | ForkJoinPool forkJoinPool, MavenProperties mavenProperties) { |
| 114 | + this.streamDefinitionRepository = streamDefinitionRepository; |
| 115 | + this.streamService = streamService; |
97 | 116 | this.appRegistryService = appRegistryService; |
98 | 117 | this.metadataResolver = metadataResolver; |
99 | 118 | this.forkJoinPool = forkJoinPool; |
@@ -230,9 +249,70 @@ public void makeDefault(@PathVariable("type") ApplicationType type, @PathVariabl |
230 | 249 | @ResponseStatus(HttpStatus.OK) |
231 | 250 | public void unregister(@PathVariable("type") ApplicationType type, @PathVariable("name") String name, |
232 | 251 | @PathVariable("version") String version) { |
| 252 | + |
| 253 | + if (type != ApplicationType.task) { |
| 254 | + String streamWithApp = findStreamContainingAppOf(type, name, version); |
| 255 | + if (streamWithApp != null) { |
| 256 | + throw new UnregisterAppException(String.format("The app [%s:%s:%s] you're trying to unregister is " + |
| 257 | + "currently used in stream '%s'.", name, type, version, streamWithApp)); |
| 258 | + } |
| 259 | + } |
| 260 | + |
233 | 261 | appRegistryService.delete(name, type, version); |
234 | 262 | } |
235 | 263 |
|
| 264 | + /** |
| 265 | + * Given the application type, name, and version, determine if it is being used in a deployed stream definition. |
| 266 | + * |
| 267 | + * @param appType the application type |
| 268 | + * @param appName the application name |
| 269 | + * @param appVersion application version |
| 270 | + * @return the name of the deployed stream where the app is being used. If the app is not deployed in a stream, |
| 271 | + * return {@code null}. |
| 272 | + */ |
| 273 | + private String findStreamContainingAppOf(ApplicationType appType, String appName, String appVersion) { |
| 274 | + Iterable<StreamDefinition> streamDefinitions = streamDefinitionRepository.findAll(); |
| 275 | + for (StreamDefinition streamDefinition : streamDefinitions) { |
| 276 | + StreamDeployment streamDeployment = this.streamService.info(streamDefinition.getName()); |
| 277 | + for (StreamAppDefinition streamAppDefinition : streamDefinition.getAppDefinitions()) { |
| 278 | + final String streamAppName = streamAppDefinition.getRegisteredAppName(); |
| 279 | + final ApplicationType streamAppType; |
| 280 | + try { |
| 281 | + streamAppType = DataFlowServerUtil.determineApplicationType(streamAppDefinition); |
| 282 | + } |
| 283 | + catch (CannotDetermineApplicationTypeException e) { |
| 284 | + logger.warn("Can not determine ApplicationType for " + streamAppDefinition); |
| 285 | + continue; |
| 286 | + } |
| 287 | + if (appType != streamAppType) { |
| 288 | + continue; |
| 289 | + } |
| 290 | + Map<String, Map<String, String>> streamDeploymentPropertiesMap; |
| 291 | + String streamDeploymentPropertiesString = streamDeployment.getDeploymentProperties(); |
| 292 | + ObjectMapper objectMapper = new ObjectMapper(); |
| 293 | + try { |
| 294 | + streamDeploymentPropertiesMap = objectMapper.readValue(streamDeploymentPropertiesString, |
| 295 | + new TypeReference<Map<String, Map<String, String>>>() { |
| 296 | + }); |
| 297 | + } |
| 298 | + catch (IOException e) { |
| 299 | + throw new RuntimeException("Can not deserialize Stream Deployment Properties JSON '" |
| 300 | + + streamDeploymentPropertiesString + "'"); |
| 301 | + } |
| 302 | + if (streamDeploymentPropertiesMap.containsKey(appName)) { |
| 303 | + Map<String, String> appDeploymentProperties = streamDeploymentPropertiesMap.get(streamAppName); |
| 304 | + if (appDeploymentProperties.containsKey(SkipperStream.SKIPPER_SPEC_VERSION)) { |
| 305 | + String version = appDeploymentProperties.get(SkipperStream.SKIPPER_SPEC_VERSION); |
| 306 | + if (version != null && version.equals(appVersion)) { |
| 307 | + return streamDefinition.getName(); |
| 308 | + } |
| 309 | + } |
| 310 | + } |
| 311 | + } |
| 312 | + } |
| 313 | + return null; |
| 314 | + } |
| 315 | + |
236 | 316 | @Deprecated |
237 | 317 | @RequestMapping(value = "/{type}/{name}", method = RequestMethod.DELETE) |
238 | 318 | @ResponseStatus(HttpStatus.OK) |
@@ -306,7 +386,7 @@ private void prefetchMetadata(List<AppRegistration> appRegistrations) { |
306 | 386 | class Assembler extends ResourceAssemblerSupport<AppRegistration, AppRegistrationResource> { |
307 | 387 |
|
308 | 388 | public Assembler() { |
309 | | - super(VersionedAppRegistryController.class, AppRegistrationResource.class); |
| 389 | + super(SkipperAppRegistryController.class, AppRegistrationResource.class); |
310 | 390 | } |
311 | 391 |
|
312 | 392 | @Override |
|
0 commit comments