Skip to content

Commit

Permalink
NOD-690: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fparisitas committed Feb 8, 2024
1 parent b6c41c2 commit 3547363
Show file tree
Hide file tree
Showing 21 changed files with 878 additions and 28 deletions.
141 changes: 139 additions & 2 deletions openapi/openapi.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"openapi" : "3.0.1",
"info" : {
"title" : "job-manager",
"title" : "cfg-sync",
"description" : "Microservice to update configuration schema of Nodo dei Pagamenti",
"termsOfService" : "https://www.pagopa.gov.it/",
"version" : "0.0.0"
Expand All @@ -10,8 +10,145 @@
"url" : "http://localhost",
"description" : "Generated server url"
} ],
"paths" : { },
"paths" : {
"/sync/v1/{target}" : {
"get" : {
"tags" : [ "Cache" ],
"summary" : "Sync target v1 config",
"operationId" : "cache",
"parameters" : [ {
"name" : "target",
"in" : "path",
"required" : true,
"schema" : {
"type" : "string",
"enum" : [ "CONFIG", "STANDIN" ]
}
} ],
"responses" : {
"200" : {
"description" : "OK",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : { }
}
},
"400" : {
"description" : "Bad Request",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
"401" : {
"description" : "Unauthorized",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
}
},
"403" : {
"description" : "Forbidden",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
}
},
"429" : {
"description" : "Too many requests",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
}
},
"500" : {
"description" : "Service unavailable",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/ProblemJson"
}
}
}
}
},
"security" : [ {
"ApiKey" : [ ]
} ]
},
"parameters" : [ {
"name" : "X-Request-Id",
"in" : "header",
"description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
"schema" : {
"type" : "string"
}
} ]
}
},
"components" : {
"schemas" : {
"ProblemJson" : {
"type" : "object",
"properties" : {
"title" : {
"type" : "string",
"description" : "A short, summary of the problem type. Written in english and readable for engineers (usually not suited for non technical stakeholders and not localized); example: Service Unavailable"
},
"status" : {
"maximum" : 600,
"minimum" : 100,
"type" : "integer",
"description" : "The HTTP status code generated by the origin server for this occurrence of the problem.",
"format" : "int32",
"example" : 200
},
"detail" : {
"type" : "string",
"description" : "A human readable explanation specific to this occurrence of the problem.",
"example" : "There was an error processing the request"
}
}
}
},
"securitySchemes" : {
"ApiKey" : {
"type" : "apiKey",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package it.gov.pagopa.node.cfg_sync.client;

import feign.Headers;
import feign.Param;
import feign.RequestLine;
import feign.Response;
import org.springframework.stereotype.Service;

@Service
public interface ApiConfigCacheClient {

@RequestLine("GET /cache")
@Headers({
"Ocp-Apim-Subscription-Key: {subscriptionKey}"
})
Response getCache(@Param String subscriptionKey);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package it.gov.pagopa.node.cfg_sync.client;

import feign.Headers;
import feign.Param;
import feign.RequestLine;
import feign.Response;
import org.springframework.stereotype.Service;

@Service
public interface StandInManagerClient {

@RequestLine("GET /cache/refresh")
@Headers({
"Content-Type: application/json",
"Ocp-Apim-Subscription-Key: {subscriptionKey}"
})
Response refresh(@Param String subscriptionKey);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//package it.gov.pagopa.node.cfg_sync.config;
//
//import com.azure.identity.DefaultAzureCredentialBuilder;
//import com.azure.messaging.eventhubs.EventHubClientBuilder;
//import com.azure.messaging.eventhubs.EventHubProducerClient;
//import com.azure.messaging.eventhubs.EventProcessorClient;
//import com.azure.messaging.eventhubs.EventProcessorClientBuilder;
//import com.azure.messaging.eventhubs.checkpointstore.blob.BlobCheckpointStore;
//import com.azure.messaging.eventhubs.models.ErrorContext;
//import com.azure.messaging.eventhubs.models.EventContext;
//import com.azure.storage.blob.BlobContainerAsyncClient;
//import com.azure.storage.blob.BlobContainerClientBuilder;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//@Configuration
//public class EventHubClientConfiguration {
//
// private static final Logger LOGGER = LoggerFactory.getLogger(EventHubClientConfiguration.class);
// private static final String CONSUMER_GROUP = "$Default";
// private static final String STORAGE_ACCOUNT_ENDPOINT = "https://pagopadapiconfigfesa.blob.core.windows.net/";
// private static final String STORAGE_CONTAINER_NAME = "cfg-sync";
//
// @Value("${nodo-dei-pagamenti-cache-rx-connection-string}")
// private String ndpConnectionString;
//
// @Value("${nodo-dei-pagamenti-cache-rx-name}")
// private String ndpEventHubName;
//
// @Bean
// EventHubClientBuilder eventHubClientBuilder() {
// return new EventHubClientBuilder().credential(ndpConnectionString, ndpEventHubName,
// new DefaultAzureCredentialBuilder()
// .build());
// }
//
// @Bean
// BlobContainerClientBuilder blobContainerClientBuilder() {
// return new BlobContainerClientBuilder().credential(new DefaultAzureCredentialBuilder()
// .build())
// .endpoint(STORAGE_ACCOUNT_ENDPOINT)
// .containerName(STORAGE_CONTAINER_NAME);
// }
//
// @Bean
// BlobContainerAsyncClient blobContainerAsyncClient(BlobContainerClientBuilder blobContainerClientBuilder) {
// return blobContainerClientBuilder.buildAsyncClient();
// }
//
// @Bean
// EventProcessorClientBuilder eventProcessorClientBuilder(BlobContainerAsyncClient blobContainerAsyncClient) {
// return new EventProcessorClientBuilder().credential(ndpConnectionString, ndpEventHubName,
// new DefaultAzureCredentialBuilder()
// .build())
// .consumerGroup(CONSUMER_GROUP)
// .checkpointStore(new BlobCheckpointStore(blobContainerAsyncClient))
// .processEvent(EventHubClientConfiguration::processEvent)
// .processError(EventHubClientConfiguration::processError);
// }
//
// @Bean
// EventProcessorClient eventProcessorClient(EventProcessorClientBuilder eventProcessorClientBuilder) {
// return eventProcessorClientBuilder.buildEventProcessorClient();
// }
//
// public static void processEvent(EventContext eventContext) {
// LOGGER.info("Processing event from partition {} with sequence number {} with body: {}",
// eventContext.getPartitionContext().getPartitionId(), eventContext.getEventData().getSequenceNumber(),
// eventContext.getEventData().getBodyAsString());
// }
//
// public static void processError(ErrorContext errorContext) {
// LOGGER.info("Error occurred in partition processor for partition {}, {}",
// errorContext.getPartitionContext().getPartitionId(),
// errorContext.getThrowable().getMessage(),
// errorContext.getThrowable());
// }
//
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package it.gov.pagopa.node.cfg_sync.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import it.gov.pagopa.node.cfg_sync.model.ProblemJson;
import it.gov.pagopa.node.cfg_sync.model.RefreshResponse;
import it.gov.pagopa.node.cfg_sync.model.TargetRefreshEnum;
import it.gov.pagopa.node.cfg_sync.service.CacheServiceFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/sync")
@Validated
public class SyncCacheController {

@Autowired
private CacheServiceFactory cacheServiceFactory;


@Operation(
summary = "Sync target v1 config",
security = {@SecurityRequirement(name = "ApiKey")},
tags = {
"Cache",
})
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "OK",
content =
@Content(
mediaType = MediaType.APPLICATION_JSON_VALUE
)),
@ApiResponse(
responseCode = "400",
description = "Bad Request",
content =
@Content(
mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(
responseCode = "401",
description = "Unauthorized",
content = @Content(schema = @Schema())),
@ApiResponse(
responseCode = "403",
description = "Forbidden",
content = @Content(schema = @Schema())),
@ApiResponse(
responseCode = "429",
description = "Too many requests",
content = @Content(schema = @Schema())),
@ApiResponse(
responseCode = "500",
description = "Service unavailable",
content =
@Content(
mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class)))
})
@GetMapping(
value = "/v1/{target}",
produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<RefreshResponse> cache(@PathVariable TargetRefreshEnum target) {

log.debug("Sync {} configuration", target.label);
CacheServiceFactory.getService(target).syncCache();

String requestId = UUID.randomUUID().toString();
ZonedDateTime timestamp = ZonedDateTime.now();

HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("X-REQUEST-ID", requestId);
responseHeaders.set("X-CACHE-TIMESTAMP", DateTimeFormatter.ISO_DATE_TIME.format(timestamp));

return ResponseEntity.ok()
.headers(responseHeaders)
.body(RefreshResponse.builder().timestamp(timestamp).id(requestId).build());
}

}
Loading

0 comments on commit 3547363

Please sign in to comment.