Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#740] Uses components endpoint on service discovery #1549

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
Expand All @@ -18,7 +19,7 @@ public ClientConfigController(ServiceDiscovery serviceDiscovery) {
public ResponseEntity<ClientConfigResponsePayload> getConfig() {
return ResponseEntity.ok(ClientConfigResponsePayload.builder()
.components(serviceDiscovery.getComponents())
.features(Map.of())
.features(List.of())
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Map;
import java.util.List;
import java.util.Set;

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClientConfigResponsePayload {
private Map<String, Map<String, Object>> components;
private Map<String, String> features;
private Set<ComponentResponsePayload> components;
private List<FeatureResponsePayload> 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
@@ -0,0 +1,7 @@
package co.airy.core.api.config;

import lombok.Data;

@Data
public class FeatureResponsePayload {
paulodiniz marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
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.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Set;
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 Set<ComponentResponsePayload> components = new CopyOnWriteArraySet<>();

public ServiceDiscovery(@Value("${kubernetes.namespace}") String namespace, RestTemplate restTemplate) {
this.namespace = namespace;
this.restTemplate = restTemplate;
}

public Map<String, Map<String, Object>> getComponents() {
public Set<ComponentResponsePayload> getComponents() {
return components;
}

@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);
paulodiniz marked this conversation as resolved.
Show resolved Hide resolved
Set<ComponentResponsePayload> newComponents = new HashSet<>();
for (String component: response.getBody().getComponents()) {
newComponents.add(ComponentResponsePayload.builder()
.enabled(true)
.name(component)
.build());
}
components.clear();
components.addAll(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 @@ -32,10 +32,10 @@
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.is;
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 +91,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[0].name", is("api-communication")))
.andExpect(jsonPath("$.components.*.enabled", everyItem(is(true)))),
"client.config call failed");
}
Expand Down
7 changes: 6 additions & 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,12 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => {
sourceInfo={infoItem}
displayButton={!channelsBySource(infoItem.type).length}
addChannelAction={() => {
if (config.components[infoItem.configKey].enabled) {
if (
config.components
.filter(c => c.enabled === true)
.map(c => c.name)
.includes(infoItem.configKey)
) {
props.history.push(infoItem.newChannelRoute);
} else {
setDisplayDialogFromSource(infoItem.type);
Expand Down
34 changes: 4 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,13 @@ 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: {name: string; enabled: boolean}[];
features: {}[];
};

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

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