Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 253d9c6

Browse files
ilayaperumalgmarkpollack
authored andcommitted
Add skipper history/manifest/platform commands
- Add StreamTemplate and Operations methods for history/manifest/platform commands - Add hack to fix plaintext retrieval as a response from Skipper server - Make explicit Skipper client configuration with StringHttpMessageConverter taking the highest precedence Resolves #1804 Resolves #1805 Resolves #1803
1 parent 49de3ab commit 253d9c6

File tree

8 files changed

+219
-14
lines changed

8 files changed

+219
-14
lines changed

spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/StreamOperations.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
package org.springframework.cloud.dataflow.rest.client;
1818

19+
import java.util.Collection;
1920
import java.util.Map;
2021

2122
import org.springframework.cloud.dataflow.rest.resource.StreamDefinitionResource;
23+
import org.springframework.cloud.skipper.domain.Deployer;
2224
import org.springframework.cloud.skipper.domain.PackageIdentifier;
25+
import org.springframework.cloud.skipper.domain.Release;
2326
import org.springframework.hateoas.PagedResources;
2427

2528
/**
@@ -105,4 +108,25 @@ void updateStream(String streamName, String releaseName, PackageIdentifier packa
105108
*/
106109
StreamDefinitionResource getStreamDefinition(String streamName);
107110

111+
/**
112+
* Get manifest for the given stream deployed via Skipper.
113+
* Optionally, the version can be used to retrieve the version for a specific version of the stream.
114+
* @param streamName the stream(release) name
115+
* @param version the version of the release
116+
* @return the manifest for the given stream and version
117+
*/
118+
String getManifest(String streamName, int version);
119+
120+
/**
121+
* Get the history of releases for the given stream deployed via Skipper.
122+
* @param streamName the stream(release) name
123+
* @param max the maximum number of revisions to include in the history
124+
* @return the history of releases for the stream
125+
*/
126+
Collection<Release> history(String streamName, int max);
127+
128+
/**
129+
* @return the list of all Skipper platforms
130+
*/
131+
Collection<Deployer> listPlatforms();
108132
}

spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/StreamTemplate.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@
1616

1717
package org.springframework.cloud.dataflow.rest.client;
1818

19+
import java.util.Collection;
20+
import java.util.HashMap;
1921
import java.util.Map;
2022

2123
import org.springframework.cloud.dataflow.rest.UpdateStreamRequest;
2224
import org.springframework.cloud.dataflow.rest.resource.StreamDefinitionResource;
25+
import org.springframework.cloud.skipper.domain.Deployer;
2326
import org.springframework.cloud.skipper.domain.PackageIdentifier;
27+
import org.springframework.cloud.skipper.domain.Release;
28+
import org.springframework.core.ParameterizedTypeReference;
2429
import org.springframework.hateoas.Link;
2530
import org.springframework.hateoas.ResourceSupport;
31+
import org.springframework.http.HttpMethod;
2632
import org.springframework.util.Assert;
2733
import org.springframework.util.LinkedMultiValueMap;
2834
import org.springframework.util.MultiValueMap;
@@ -132,6 +138,54 @@ public void rollbackStream(String streamName, int version) {
132138
restTemplate.postForObject(url, null, Object.class);
133139
}
134140

141+
142+
@Override
143+
public String getManifest(String streamName, int version) {
144+
Assert.hasText(streamName, "Release name cannot be null or empty");
145+
String url = String.format("%s/%s/%s/%s", deploymentsLink.getHref(), "manifest", streamName, version);
146+
String manifest = restTemplate.getForObject(url, String.class);
147+
// TODO - DataFlow only uses Jackson Marshaller, which does strange things to Strings as return values.
148+
// \n is converted to two ascii characters 92 and 110...
149+
String prunedManifest = manifest.substring(1, manifest.length() - 1);
150+
StringBuilder sb = new StringBuilder();
151+
for (int i = 0; i < prunedManifest.length(); i++) {
152+
char testChar = prunedManifest.charAt(i);
153+
if ( (int)testChar == 92) {
154+
if (i != prunedManifest.length() -1) {
155+
char nChar = prunedManifest.charAt(i+1);
156+
if ( (int)nChar == 110) {
157+
sb.append("\n");
158+
i++;
159+
}
160+
}
161+
} else {
162+
sb.append(testChar);
163+
}
164+
}
165+
return sb.toString();
166+
}
167+
168+
@Override
169+
public Collection<Release> history(String streamName, int maxRevisions) {
170+
Assert.hasText(streamName, "Release name cannot be null or empty");
171+
ParameterizedTypeReference<Collection<Release>> typeReference = new ParameterizedTypeReference<Collection<Release>>
172+
() {
173+
};
174+
Map<String, Object> parameters = new HashMap<>();
175+
String url = String.format("%s/%s/%s/%s", deploymentsLink.getHref(), "history", streamName, maxRevisions);
176+
return this.restTemplate.exchange(url, HttpMethod.GET, null, typeReference, parameters).getBody();
177+
}
178+
179+
@Override
180+
public Collection<Deployer> listPlatforms() {
181+
ParameterizedTypeReference<Collection<Deployer>> typeReference = new ParameterizedTypeReference<Collection<Deployer>>
182+
() {
183+
};
184+
Map<String, Object> parameters = new HashMap<>();
185+
String url = url = deploymentsLink.getHref() + "/platform/list";
186+
return this.restTemplate.exchange(url, HttpMethod.GET, null, typeReference, parameters).getBody();
187+
}
188+
135189
@Override
136190
public StreamDefinitionResource getStreamDefinition(String streamName) {
137191
String uriTemplate = this.definitionLink.expand(streamName).getHref();

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowControllerAutoConfiguration.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package org.springframework.cloud.dataflow.server.config;
1818

19+
import java.util.Arrays;
1920
import java.util.HashMap;
2021
import java.util.Map;
2122

2223
import javax.sql.DataSource;
2324

25+
import com.fasterxml.jackson.databind.ObjectMapper;
2426
import org.apache.commons.logging.Log;
2527
import org.apache.commons.logging.LogFactory;
2628

@@ -36,6 +38,7 @@
3638
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3739
import org.springframework.boot.context.properties.ConfigurationProperties;
3840
import org.springframework.boot.context.properties.EnableConfigurationProperties;
41+
import org.springframework.boot.web.client.RestTemplateBuilder;
3942
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
4043
import org.springframework.cloud.common.security.AuthorizationProperties;
4144
import org.springframework.cloud.common.security.support.FileSecurityProperties;
@@ -89,17 +92,21 @@
8992
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
9093
import org.springframework.cloud.deployer.spi.app.AppDeployer;
9194
import org.springframework.cloud.deployer.spi.task.TaskLauncher;
95+
import org.springframework.cloud.skipper.client.DefaultSkipperClient;
9296
import org.springframework.cloud.skipper.client.SkipperClient;
93-
import org.springframework.cloud.skipper.client.SkipperClientConfiguration;
9497
import org.springframework.cloud.skipper.client.SkipperClientProperties;
98+
import org.springframework.cloud.skipper.client.SkipperClientResponseErrorHandler;
9599
import org.springframework.cloud.task.repository.TaskExplorer;
96100
import org.springframework.context.annotation.Bean;
97101
import org.springframework.context.annotation.Conditional;
98102
import org.springframework.context.annotation.Configuration;
99103
import org.springframework.context.annotation.Import;
100104
import org.springframework.core.io.ResourceLoader;
101105
import org.springframework.hateoas.EntityLinks;
106+
import org.springframework.http.converter.StringHttpMessageConverter;
107+
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
102108
import org.springframework.scheduling.concurrent.ForkJoinPoolFactoryBean;
109+
import org.springframework.web.client.RestTemplate;
103110

104111
/**
105112
* Configuration for the Data Flow Server Controllers.
@@ -156,8 +163,8 @@ public StreamDefinitionController streamDefinitionController(StreamDefinitionRep
156163
@Bean
157164
@ConditionalOnBean({ StreamDefinitionRepository.class, StreamDeploymentRepository.class })
158165
public StreamDeploymentController streamDeploymentController(StreamDefinitionRepository repository,
159-
StreamService streamService) {
160-
return new StreamDeploymentController(repository, streamService);
166+
StreamService streamService, SkipperClient skipperClient) {
167+
return new StreamDeploymentController(repository, streamService, skipperClient);
161168
}
162169

163170
@Bean
@@ -378,10 +385,19 @@ public SecurityStateBean securityStateBean() {
378385
}
379386

380387
@Configuration
381-
@Import(SkipperClientConfiguration.class)
382388
@ConditionalOnBean({ StreamDefinitionRepository.class, StreamDeploymentRepository.class })
389+
@EnableConfigurationProperties(SkipperClientProperties.class)
383390
public static class SkipperConfiguration {
384391

392+
@Bean
393+
public SkipperClient skipperClient(SkipperClientProperties properties,
394+
RestTemplateBuilder restTemplateBuilder, ObjectMapper objectMapper) {
395+
RestTemplate restTemplate = restTemplateBuilder.errorHandler(new SkipperClientResponseErrorHandler
396+
(objectMapper)).messageConverters(Arrays.asList(new StringHttpMessageConverter(), new
397+
MappingJackson2HttpMessageConverter(objectMapper))).build();
398+
return new DefaultSkipperClient(properties.getUri(), restTemplate);
399+
}
400+
385401
@Bean
386402
public SkipperStreamDeployer skipperStreamDeployer(SkipperClient skipperClient,
387403
StreamDeploymentRepository streamDeploymentRepository,

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/StreamDeploymentController.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,22 @@
1616

1717
package org.springframework.cloud.dataflow.server.controller;
1818

19+
import java.util.Collection;
1920
import java.util.Map;
2021

22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
2125
import org.springframework.cloud.dataflow.core.StreamDefinition;
2226
import org.springframework.cloud.dataflow.rest.UpdateStreamRequest;
2327
import org.springframework.cloud.dataflow.rest.resource.StreamDeploymentResource;
2428
import org.springframework.cloud.dataflow.server.repository.NoSuchStreamDefinitionException;
2529
import org.springframework.cloud.dataflow.server.repository.StreamDefinitionRepository;
2630
import org.springframework.cloud.dataflow.server.service.StreamService;
2731
import org.springframework.cloud.deployer.spi.app.AppDeployer;
32+
import org.springframework.cloud.skipper.client.SkipperClient;
33+
import org.springframework.cloud.skipper.domain.Deployer;
34+
import org.springframework.cloud.skipper.domain.Release;
2835
import org.springframework.hateoas.ExposesResourceFor;
2936
import org.springframework.http.HttpStatus;
3037
import org.springframework.util.Assert;
@@ -50,8 +57,12 @@
5057
@ExposesResourceFor(StreamDeploymentResource.class)
5158
public class StreamDeploymentController {
5259

60+
private static final Logger logger = LoggerFactory.getLogger(StreamDeploymentController.class);
61+
5362
private final StreamService streamService;
5463

64+
private final SkipperClient skipperClient;
65+
5566
/**
5667
* The repository this controller will use for stream CRUD operations.
5768
*/
@@ -67,12 +78,16 @@ public class StreamDeploymentController {
6778
*
6879
* @param repository the repository this controller will use for stream CRUD operations
6980
* @param streamService the underlying StreamService to deploy the stream
81+
* @param skipperClient the Skipper client to use for Skipper related services
7082
*/
71-
public StreamDeploymentController(StreamDefinitionRepository repository, StreamService streamService) {
83+
public StreamDeploymentController(StreamDefinitionRepository repository, StreamService streamService,
84+
SkipperClient skipperClient) {
7285
Assert.notNull(repository, "StreamDefinitionRepository must not be null");
7386
Assert.notNull(streamService, "StreamService must not be null");
87+
Assert.notNull(skipperClient, "SkipperClient must not be null");
7488
this.repository = repository;
7589
this.streamService = streamService;
90+
this.skipperClient = skipperClient;
7691
}
7792

7893
/**
@@ -126,4 +141,32 @@ public void rollback(@PathVariable("name") String name, @PathVariable("version")
126141
this.streamService.rollbackStream(name, version);
127142
}
128143

144+
@RequestMapping(value = "/manifest/{name}/{version}", method = RequestMethod.GET)
145+
@ResponseStatus(HttpStatus.OK)
146+
public String manifest(@PathVariable("name") String name, @PathVariable("version") int version) {
147+
if (version > 0) {
148+
return this.skipperClient.manifest(name, version);
149+
}
150+
else {
151+
return this.skipperClient.manifest(name);
152+
}
153+
}
154+
155+
@RequestMapping(path = "/history/{name}/{max}", method = RequestMethod.GET)
156+
@ResponseStatus(HttpStatus.OK)
157+
public Collection<Release> history(@PathVariable("name") String releaseName,
158+
@PathVariable("max") int maxRevisions) {
159+
if (maxRevisions > 0) {
160+
return this.skipperClient.history(releaseName, String.valueOf(maxRevisions));
161+
}
162+
else {
163+
return this.skipperClient.history(releaseName).getContent();
164+
}
165+
}
166+
167+
@RequestMapping(path = "/platform/list", method = RequestMethod.GET)
168+
@ResponseStatus(HttpStatus.OK)
169+
public Collection<Deployer> platformList() {
170+
return this.skipperClient.listDeployers().getContent();
171+
}
129172
}

spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/TestDependencies.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ public ResourceLoader resourceLoader() {
133133

134134
@Bean
135135
public StreamDeploymentController streamDeploymentController(StreamDefinitionRepository repository,
136-
StreamService streamService) {
137-
return new StreamDeploymentController(repository, streamService);
136+
StreamService streamService, SkipperClient skipperClient) {
137+
return new StreamDeploymentController(repository, streamService, skipperClient);
138138
}
139139

140140
@Bean

spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/controller/StreamControllerTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.springframework.cloud.deployer.spi.app.AppStatus;
5353
import org.springframework.cloud.deployer.spi.app.DeploymentState;
5454
import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest;
55+
import org.springframework.cloud.skipper.client.SkipperClient;
5556
import org.springframework.http.MediaType;
5657
import org.springframework.test.annotation.DirtiesContext;
5758
import org.springframework.test.annotation.DirtiesContext.ClassMode;
@@ -125,6 +126,9 @@ public class StreamControllerTests {
125126
@Autowired
126127
private DefaultStreamService defaultStreamService;
127128

129+
@Autowired
130+
private SkipperClient skipperClient;
131+
128132
@Before
129133
public void setupMocks() {
130134
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
@@ -141,7 +145,7 @@ public void tearDown() {
141145
@Test(expected = IllegalArgumentException.class)
142146
public void testConstructorMissingRepository() {
143147
StreamDeploymentController deploymentController = new StreamDeploymentController(
144-
new InMemoryStreamDefinitionRepository(), defaultStreamService);
148+
new InMemoryStreamDefinitionRepository(), defaultStreamService, skipperClient);
145149
new StreamDefinitionController(null, appRegistry, defaultStreamService);
146150
}
147151

spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/controller/StreamDeploymentControllerTests.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package org.springframework.cloud.dataflow.server.controller;
1818

19+
import static org.mockito.Mockito.*;
20+
import static org.springframework.cloud.dataflow.rest.SkipperStream.SKIPPER_ENABLED_PROPERTY_KEY;
21+
22+
import java.util.ArrayList;
1923
import java.util.HashMap;
2024
import java.util.Map;
2125

@@ -28,12 +32,10 @@
2832
import org.mockito.ArgumentCaptor;
2933
import org.mockito.Mock;
3034
import org.mockito.runners.MockitoJUnitRunner;
31-
3235
import org.springframework.cloud.dataflow.server.repository.StreamDefinitionRepository;
3336
import org.springframework.cloud.dataflow.server.service.impl.DefaultStreamService;
34-
35-
import static org.mockito.Mockito.verify;
36-
import static org.springframework.cloud.dataflow.rest.SkipperStream.SKIPPER_ENABLED_PROPERTY_KEY;
37+
import org.springframework.cloud.skipper.client.SkipperClient;
38+
import org.springframework.hateoas.Resources;
3739

3840
/**
3941
* Unit tests for StreamDeploymentController.
@@ -55,9 +57,12 @@ public class StreamDeploymentControllerTests {
5557
@Mock
5658
private DefaultStreamService defaultStreamService;
5759

60+
@Mock
61+
private SkipperClient skipperClient;
62+
5863
@Before
5964
public void setup() {
60-
this.controller = new StreamDeploymentController(streamDefinitionRepository, defaultStreamService);
65+
this.controller = new StreamDeploymentController(streamDefinitionRepository, defaultStreamService, skipperClient);
6166
}
6267

6368
@Test
@@ -84,4 +89,11 @@ public void testRollbackViaStreamService() {
8489
Assert.assertTrue("Rollback version is incorrect", argumentCaptor2.getValue() == 2);
8590
}
8691

92+
@Test
93+
public void tesPlatformsListViaSkipperClient() {
94+
when(skipperClient.listDeployers()).thenReturn(new Resources<>(new ArrayList<>(), new ArrayList<>()));
95+
this.controller.platformList();
96+
verify(skipperClient, times(1)).listDeployers();
97+
}
98+
8799
}

0 commit comments

Comments
 (0)