Skip to content

Commit

Permalink
Merge pull request #16 from ts4nfdi/feature/add-ontoportal-api-key-en…
Browse files Browse the repository at this point in the history
…v-var

Feature: Add OntoPortal APIKEY  env variable
  • Loading branch information
syphax-bouazzouni authored Jul 24, 2024
2 parents cdb0ad6 + 2a50677 commit 89f41f7
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 53 deletions.
67 changes: 40 additions & 27 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,80 +1,93 @@
name: Continuous Integration

on:
push:
branches: [ "main" ]
tags: [ "*" ]
branches:
- "main"
tags:
- "*"

env:
KUBECONFIG: .kube/config
KUBECONFIG_FILE: ${{ secrets.KUBECONFIG }}

jobs:
build:
name: "Build Image"
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- id: generate-image-tag
name: Generate Image Tag
env:
ref_name: "${{ github.ref_name }}"
head_ref: "${{ github.head_ref }}"
run: |
head_ref="${head_ref/\//-}"
ref_name="${head_ref:-${ref_name/main/latest}}"
echo "::set-output name=imageTag::${ref_name#v}"
head_ref="${GITHUB_HEAD_REF//\//-}"
ref_name="${head_ref:-${GITHUB_REF_NAME/main/latest}}"
echo "imageTag=${ref_name#v}" >> $GITHUB_ENV
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up JDK
uses: actions/setup-java@v2
with:
distribution: 'temurin'
distribution: 'temurin'
java-version: '11'

- name: Build with Maven
run: mvn clean install

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push
uses: docker/build-push-action@v5
with:
context: ./
file: ./Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ steps.generate-image-tag.outputs.imageTag }}
ghcr.io/${{ github.repository }}:${{ env.imageTag }}
ghcr.io/${{ github.repository }}:${{ github.event.pull_request.head.sha || github.sha }}
deploy_main:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- id: generate-image-tag
name: Generate Image Tag
env:
ref_name: "${{ github.ref_name }}"
head_ref: "${{ github.head_ref }}"
run: |
head_ref="${head_ref/\//-}"
ref_name="${head_ref:-${ref_name/main/latest}}"
echo "::set-output name=imageTag::${ref_name#v}"
head_ref="${GITHUB_HEAD_REF//\//-}"
ref_name="${head_ref:-${GITHUB_REF_NAME/main/latest}}"
echo "imageTag=${ref_name#v}" >> $GITHUB_ENV
- uses: actions/checkout@v2
- run: |

- name: Set up Kubernetes config
run: |
mkdir -p .kube
echo "${{ env.KUBECONFIG_FILE }}" > $KUBECONFIG
- uses: stefanprodan/kube-tools@v1
echo "${{ secrets.KUBECONFIG }}" > $KUBECONFIG
- name: Create Kubernetes secret for ONTOPORTAL_APIKEY
run: |
kubectl create secret generic ontoportal-secret \
--from-literal=ONTOPORTAL_APIKEY=${{ secrets.ONTOPORTAL_APIKEY }} \
--dry-run=client -o yaml | kubectl apply -f -
- name: Deploy to Kubernetes
uses: stefanprodan/kube-tools@v1
with:
helmv3: 3.12.0
command: |
kubectl get nodes
helmv3 repo add api-gateway-deployment https://ts4nfdi.github.io/api-gateway-deployment/
helmv3 repo update
helmv3 upgrade ts4nfdi \
--install \
api-gateway-deployment/api-gateway
--install \
api-gateway-deployment/api-gateway
2 changes: 2 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ services:
container_name: api-gateway
ports:
- "8080:8080"
environment:
ONTOPORTAL_APIKEY: "put here APIKEY"
restart: always
networks:
- api-gateway
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.semantics.apigateway.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import org.semantics.apigateway.config.DatabaseConfig;
import org.semantics.apigateway.config.OntologyConfig;
import org.semantics.apigateway.model.DynTransformResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Service
@Getter
public class ConfigurationLoader {

@Autowired
private ConfigurableEnvironment environment;

@Autowired
private ResourceLoader resourceLoader;

private static final Logger logger = LoggerFactory.getLogger(DynSearchService.class);
private List<OntologyConfig> ontologyConfigs;
private Map<String, Map<String, String>> responseMappings;

// Method invoked after on server start, loads database configurations and replace environment variables
@PostConstruct
public void loadDbConfigs() throws IOException {
Resource resource = resourceLoader.getResource("classpath:response-config.json");
String jsonContent = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);

for (Map.Entry<String, Object> property : environment.getSystemEnvironment().entrySet()) {
String key = property.getKey();
String value = (String) property.getValue();
jsonContent = jsonContent.replace("${" + key + "}", value);
}

ObjectMapper objectMapper = new ObjectMapper();
DatabaseConfig dbConfig = objectMapper.readValue(jsonContent, DatabaseConfig.class);
this.ontologyConfigs = dbConfig.getDatabases();
this.responseMappings = loadResponseMappings();
ontologyConfigs.forEach(config -> logger.info("Loaded config: {}", config));
}

// Loads response mappings from a json configuration file
private Map<String, Map<String, String>> loadResponseMappings() throws IOException {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("response-mappings.json");
if (inputStream != null) {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Map<String, String>> mappings = objectMapper.readValue(inputStream, new TypeReference<Map<String, Map<String, String>>>() {
});
if (mappings != null) {
return mappings;
}
}
return Collections.emptyMap();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@
import org.semantics.apigateway.model.JsonLdTransform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -32,38 +40,19 @@
@Service
public class DynSearchService {

// Resource path to the JSON configuration file for database configurations
@Value("classpath:response-config.json")
private Resource dbConfigResource;
private ConfigurationLoader configurationLoader;
private static final Logger logger = LoggerFactory.getLogger(DynSearchService.class);
private final RestTemplate restTemplate = new RestTemplate();
private final DynTransformResponse dynTransformResponse = new DynTransformResponse();
private List<OntologyConfig> ontologyConfigs;
private Map<String, Map<String, String>> responseMappings;

// Method invoked after the bean’s properties have been set, loads database configurations
@PostConstruct
public void loadDbConfigs() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
try (InputStream in = dbConfigResource.getInputStream()) {
DatabaseConfig dbConfig = objectMapper.readValue(in, DatabaseConfig.class);
this.ontologyConfigs = dbConfig.getDatabases();
this.responseMappings = loadResponseMappings();
ontologyConfigs.forEach(config -> logger.info("Loaded config: {}", config));
}
}

// Loads response mappings from a json configuration file
private Map<String, Map<String, String>> loadResponseMappings() throws IOException {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("response-mappings.json");
if (inputStream != null) {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Map<String, String>> mappings = objectMapper.readValue(inputStream, new TypeReference<Map<String, Map<String, String>>>(){});
if (mappings != null) {
return mappings;
}
}
return Collections.emptyMap();
@Autowired
public DynSearchService(ConfigurationLoader configurationLoader) {
this.configurationLoader = configurationLoader;
this.ontologyConfigs = configurationLoader.getOntologyConfigs();
this.responseMappings = configurationLoader.getResponseMappings();
}

// Constructs the URL for the API call based on the query and configuration
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/response-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"database": "ontoportal",
"url": "https://data.biodivportal.gfbio.dev/search?q=%s&apikey=%s",
"apiKey": "xxx",
"apiKey": "${ONTOPORTAL_APIKEY}",
"responseMapping": {
"nestedJson": "collection",
"label": "prefLabel",
Expand Down

0 comments on commit 89f41f7

Please sign in to comment.