Fix deployer app
Run it, then
$ curl localhost:8080/admin
{"sample":{"name":"sample","id":"81c568e36c7909ec1dd841aa7ee6d3e3","path":"..."}}
undeploy:
$ curl localhost:8080/admin/sample -X DELETE
{"id":"81c568e36c7909ec1dd841aa7ee6d3e3"}
redeploy
$ curl localhost:8080/admin/sample -d path=maven://com.example:function-sample-pojo:1.0.0.BUILD-SNAPSHOT
{"id":"81c568e36c7909ec1dd841aa7ee6d3e3"}
(Takes about 500ms)
This commit is contained in:
@@ -21,7 +21,6 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -30,24 +29,19 @@ import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.graph.Dependency;
|
||||
|
||||
import org.springframework.boot.Banner.Mode;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.thin.ArchiveUtils;
|
||||
import org.springframework.boot.loader.thin.DependencyResolver;
|
||||
import org.springframework.cloud.deployer.thin.ContextRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.SpringVersion;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.context.support.LiveBeansView;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -56,10 +50,6 @@ import reactor.core.publisher.Flux;
|
||||
// NOT a @Component (to prevent it from being scanned by the "main" application).
|
||||
public class ApplicationRunner implements CommandLineRunner {
|
||||
|
||||
private static final String DEFAULT_REACTOR_VERSION = "3.0.4.RELEASE";
|
||||
|
||||
private static final String DEFAULT_SPRING_VERSION = SpringVersion.getVersion();
|
||||
|
||||
private static Log logger = LogFactory.getLog(ApplicationRunner.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
@@ -84,8 +74,9 @@ public class ApplicationRunner implements CommandLineRunner {
|
||||
ClassUtils.overrideThreadContextClassLoader(classLoader);
|
||||
Class<?> cls = classLoader.loadClass(ContextRunner.class.getName());
|
||||
this.app = cls.newInstance();
|
||||
runContext(DeployedFunctionApplication.class.getName(),
|
||||
Collections.emptyMap(), args);
|
||||
runContext(DeployedFunctionApplication.class.getName(), Collections
|
||||
.singletonMap(LiveBeansView.MBEAN_DOMAIN_PROPERTY_NAME, "deployer"),
|
||||
args);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Cannot deploy", e);
|
||||
@@ -93,6 +84,10 @@ public class ApplicationRunner implements CommandLineRunner {
|
||||
finally {
|
||||
ClassUtils.overrideThreadContextClassLoader(contextLoader);
|
||||
}
|
||||
RuntimeException e = getError();
|
||||
if (e != null) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
@@ -100,6 +95,22 @@ public class ApplicationRunner implements CommandLineRunner {
|
||||
closeContext();
|
||||
}
|
||||
|
||||
private RuntimeException getError() {
|
||||
if (this.app == null) {
|
||||
return null;
|
||||
}
|
||||
Method method = ReflectionUtils.findMethod(this.app.getClass(), "getError");
|
||||
Throwable e;
|
||||
e = (Throwable) ReflectionUtils.invokeMethod(method, this.app);
|
||||
if (e==null) {
|
||||
return null;
|
||||
}
|
||||
if (e instanceof RuntimeException) {
|
||||
return (RuntimeException) e;
|
||||
}
|
||||
return new IllegalStateException("Cannot launch", e);
|
||||
}
|
||||
|
||||
private void runContext(String mainClass, Map<String, String> properties,
|
||||
String... args) {
|
||||
Method method = ReflectionUtils.findMethod(this.app.getClass(), "run",
|
||||
@@ -125,14 +136,7 @@ public class ApplicationRunner implements CommandLineRunner {
|
||||
for (URL url : urls) {
|
||||
child.add(url);
|
||||
}
|
||||
DependencyResolver resolver = DependencyResolver.instance();
|
||||
String reactor = getReactorCoordinates();
|
||||
// spring-core is OK, spring-context is not, spring-messaging depends on
|
||||
// spring-context (so it is not OK)
|
||||
String spring = getSpringCoordinates();
|
||||
List<File> resolved = Arrays.asList(
|
||||
resolver.resolve(new Dependency(new DefaultArtifact(reactor), "runtime")),
|
||||
resolver.resolve(new Dependency(new DefaultArtifact(spring), "runtime")));
|
||||
List<File> resolved = resolveParent();
|
||||
for (File archive : resolved) {
|
||||
try {
|
||||
URL url = archive.toURI().toURL();
|
||||
@@ -151,42 +155,15 @@ public class ApplicationRunner implements CommandLineRunner {
|
||||
return new URLClassLoader(child.toArray(new URL[0]), base);
|
||||
}
|
||||
|
||||
private String getSpringCoordinates() {
|
||||
Package pkg = Message.class.getPackage();
|
||||
String version = null;
|
||||
version = (pkg != null ? pkg.getImplementationVersion() : DEFAULT_SPRING_VERSION);
|
||||
return "org.springframework:spring-core:" + version;
|
||||
}
|
||||
|
||||
private String getReactorCoordinates() {
|
||||
Package pkg = Flux.class.getPackage();
|
||||
String version = null;
|
||||
version = (pkg != null ? pkg.getImplementationVersion()
|
||||
: DEFAULT_REACTOR_VERSION);
|
||||
if (version == null) {
|
||||
Archive archive = ArchiveUtils.getArchive(Flux.class);
|
||||
try {
|
||||
String path = archive.getUrl().toString();
|
||||
if (path.endsWith("!/")) {
|
||||
path = path.substring(0, path.length() - 2);
|
||||
}
|
||||
path = StringUtils.getFilename(path);
|
||||
if (path.startsWith("reactor-core-")) {
|
||||
path = path.substring("reactor-core-".length());
|
||||
}
|
||||
if (path.endsWith(".jar")) {
|
||||
path = path.substring(0, path.length() - ".jar".length());
|
||||
}
|
||||
version = path;
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
// ignore
|
||||
}
|
||||
private List<File> resolveParent() {
|
||||
DependencyResolver resolver = DependencyResolver.instance();
|
||||
List<Dependency> dependencies = resolver
|
||||
.dependencies(new ClassPathResource("core-pom.xml"));
|
||||
List<File> resolved = new ArrayList<>();
|
||||
for (Dependency dependency : dependencies) {
|
||||
resolved.add(resolver.resolve(dependency));
|
||||
}
|
||||
if (version == null) {
|
||||
version = DEFAULT_REACTOR_VERSION;
|
||||
}
|
||||
return "io.projectreactor:reactor-core:" + version;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.loader.thin.ArchiveUtils;
|
||||
import org.springframework.cloud.deployer.spi.app.AppDeployer;
|
||||
import org.springframework.cloud.deployer.spi.core.AppDefinition;
|
||||
import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest;
|
||||
import org.springframework.context.support.LiveBeansView;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
@@ -62,10 +64,10 @@ public class FunctionAdminController implements CommandLineRunner {
|
||||
}
|
||||
|
||||
@DeleteMapping(path = "/{name}")
|
||||
public Map<String, Object> undeploy(@PathVariable String name,
|
||||
@RequestParam String path) throws Exception {
|
||||
public Map<String, Object> undeploy(@PathVariable String name) throws Exception {
|
||||
String id = names.get(name);
|
||||
if (id == null) {
|
||||
// TODO: Convert to 404
|
||||
throw new IllegalStateException("No such app");
|
||||
}
|
||||
deployer.undeploy(id);
|
||||
@@ -78,8 +80,8 @@ public class FunctionAdminController implements CommandLineRunner {
|
||||
public Map<String, Object> deployed() {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
for (String name : names.keySet()) {
|
||||
result.put(name, new DeployedArtifact(name, names.get(name),
|
||||
deployed.get(names.get(name))));
|
||||
String id = names.get(name);
|
||||
result.put(name, new DeployedArtifact(name, id, deployed.get(id)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -93,12 +95,14 @@ public class FunctionAdminController implements CommandLineRunner {
|
||||
Resource resource = new FileSystemResource(
|
||||
ArchiveUtils.getArchiveRoot(ArchiveUtils.getArchive(path)));
|
||||
AppDefinition definition = new AppDefinition(resource.getFilename(),
|
||||
Collections.emptyMap());
|
||||
Collections.singletonMap(LiveBeansView.MBEAN_DOMAIN_PROPERTY_NAME,
|
||||
"functions." + name));
|
||||
AppDeploymentRequest request = new AppDeploymentRequest(definition, resource,
|
||||
Collections.emptyMap(), Arrays.asList(args));
|
||||
Collections.singletonMap(AppDeployer.GROUP_PROPERTY_KEY, "functions"),
|
||||
Arrays.asList(args));
|
||||
String deployed = deployer.deploy(request);
|
||||
this.deployed.put(deployed, path);
|
||||
this.names.put(deployed, name);
|
||||
this.names.put(name, deployed);
|
||||
return deployed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-function-deployer</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>spring-cloud-function-deployer</name>
|
||||
<description>Spring Cloud Function Web Support</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.3.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<reactor.version>3.0.7.RELEASE</reactor.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>Dalston.BUILD-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user