Skip to content

Commit

Permalink
[#740] Uses components endpoint on service discovery (#1549)
Browse files Browse the repository at this point in the history
* [#740] Uses components endpoint on service discovery
  • Loading branch information
paulodiniz authored Apr 15, 2021
1 parent e2d1c79 commit 6c2b0f7
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class ClientConfigController {
private final ServiceDiscovery serviceDiscovery;
Expand All @@ -18,7 +16,6 @@ public ClientConfigController(ServiceDiscovery serviceDiscovery) {
public ResponseEntity<ClientConfigResponsePayload> getConfig() {
return ResponseEntity.ok(ClientConfigResponsePayload.builder()
.components(serviceDiscovery.getComponents())
.features(Map.of())
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@
@AllArgsConstructor
public class ClientConfigResponsePayload {
private Map<String, Map<String, Object>> components;
private Map<String, String> features;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package co.airy.core.api.config;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class ComponentResponsePayload {
private String name;
private Boolean enabled;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package co.airy.core.api.config;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ComponentsResponsePayload implements Serializable {
private List<String> components;
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
package co.airy.core.api.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
public class ServiceDiscovery {
private final String namespace;
private final RestTemplate restTemplate;

private final Map<String, Map<String, Object>> components = new ConcurrentHashMap<>();

private static final List<String> services = List.of(
"sources-chatplugin",
"sources-facebook-connector",
"sources-twilio-connector",
"sources-google-connector"
);
private Map<String, Map<String, Object>> components = new ConcurrentHashMap<>();

public ServiceDiscovery(@Value("${kubernetes.namespace}") String namespace, RestTemplate restTemplate) {
this.namespace = namespace;
Expand All @@ -36,13 +30,12 @@ public Map<String, Map<String, Object>> getComponents() {

@Scheduled(fixedRate = 1_000)
private void updateComponentsStatus() {
for (String service : services) {
try {
ResponseEntity<Object> response = restTemplate.exchange(String.format("http://%s.%s/actuator/health", service, namespace), HttpMethod.GET, null, Object.class);
components.put(service.replace("-connector", ""), Map.of("enabled", response.getStatusCode().is2xxSuccessful()));
} catch (Exception e) {
components.put(service.replace("-connector", ""), Map.of("enabled",false));
}
final ResponseEntity<ComponentsResponsePayload> response = restTemplate.getForEntity("http://airy-controller.default/components", ComponentsResponsePayload.class);
Map<String, Map<String, Object>> newComponents = new ConcurrentHashMap<>();
for (String component: response.getBody().getComponents()) {
newComponents.put(component, Map.of("enabled", true));
}
components.clear();
components.putAll(newComponents);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.client.MockRestServiceServer;
Expand All @@ -31,11 +31,12 @@
import static co.airy.test.Timing.retryOnException;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.springframework.test.web.client.ExpectedCount.min;
import static org.springframework.test.web.client.ExpectedCount.once;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

Expand Down Expand Up @@ -91,25 +92,16 @@ void beforeEach() throws Exception {

@Test
public void canReturnConfig() throws Exception {
mockServer.expect(min(1), requestTo(new URI("http://sources-chatplugin.default/actuator/health")))
mockServer.expect(once(), requestTo(new URI("http://airy-controller.default/components")))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK));

mockServer.expect(min(1), requestTo(new URI("http://sources-facebook-connector.default/actuator/health")))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK));

mockServer.expect(min(1), requestTo(new URI("http://sources-twilio-connector.default/actuator/health")))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK));

mockServer.expect(min(1), requestTo(new URI("http://sources-google-connector.default/actuator/health")))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK));
.andRespond(
withSuccess("{\"components\": [\"api-communication\"]}", MediaType.APPLICATION_JSON)
);

retryOnException(() -> webTestHelper.post("/client.config", "{}", "user-id")
.andExpect(status().isOk())
.andExpect(jsonPath("$.components.*", hasSize(4)))
.andExpect(jsonPath("$.components.*", hasSize(1)))
.andExpect(jsonPath("$.components", hasKey("api-communication")))
.andExpect(jsonPath("$.components.*.enabled", everyItem(is(true)))),
"client.config call failed");
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/ui/src/pages/Channels/MainPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => {
sourceInfo={infoItem}
displayButton={!channelsBySource(infoItem.type).length}
addChannelAction={() => {
if (config.components[infoItem.configKey].enabled) {
if (config.components[infoItem.configKey] && config.components[infoItem.configKey].enabled) {
props.history.push(infoItem.newChannelRoute);
} else {
setDisplayDialogFromSource(infoItem.type);
Expand Down
32 changes: 2 additions & 30 deletions frontend/ui/src/reducers/data/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,11 @@ import * as actions from '../../../actions/config';
type Action = ActionType<typeof actions>;

export type Config = {
components: {
'sources-chatplugin': {
enabled: boolean;
};
'sources-facebook': {
enabled: boolean;
};
'sources-google': {
enabled: boolean;
};
'sources-twilio': {
enabled: boolean;
};
};
features: {};
components: {[key: string]: {enabled: boolean}};
};

const defaultState = {
components: {
'sources-chatplugin': {
enabled: false,
},
'sources-facebook': {
enabled: false,
},
'sources-google': {
enabled: false,
},
'sources-twilio': {
enabled: false,
},
},
features: {},
components: {},
};

export default function configReducer(state = defaultState, action: Action): Config {
Expand Down
16 changes: 1 addition & 15 deletions lib/typescript/model/Config.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
export interface Config {
components: {
'sources-chatplugin': {
enabled: boolean;
};
'sources-facebook': {
enabled: boolean;
};
'sources-google': {
enabled: boolean;
};
'sources-twilio': {
enabled: boolean;
};
};
features: {};
components: {[key: string]: {enabled: boolean}};
}

0 comments on commit 6c2b0f7

Please sign in to comment.