Skip to content

Commit

Permalink
[TH2-5132] Refactored Controllers
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikita-Smirnov-Exactpro committed Nov 28, 2023
1 parent 0c93c64 commit 511e41b
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 121 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020-2022 Exactpro (Exactpro Systems Limited)
# Copyright 2020-2023 Exactpro (Exactpro Systems Limited)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,20 @@
import com.exactpro.th2.inframgr.statuswatcher.ResourceCondition;
import com.exactpro.th2.inframgr.statuswatcher.StatusCache;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.List;

@Controller
@SuppressWarnings("unused")
public class DeploymentController {

private static final Logger logger = LoggerFactory.getLogger(DeploymentController.class);

public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR";

public static final String BAD_RESOURCE_NAME = "BAD_RESOURCE_NAME";
Expand All @@ -64,12 +63,11 @@ public List<ResponseEntry> getResourceDeploymentStatuses(
}

return response;

} catch (ServiceException e) {
throw e;
} catch (Exception e) {
logger.error("Exception retrieving schema {} from repository", schemaName, e);
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR,
"Exception retrieving schema " + schemaName + " from repository", e);
}
}

Expand Down
29 changes: 6 additions & 23 deletions src/main/java/com/exactpro/th2/inframgr/DescriptorController.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import static com.exactpro.th2.inframgr.statuswatcher.ResourcePath.annotationFor;

@Controller
@SuppressWarnings("unused")
public class DescriptorController {

private static final String PROTOBUF_DESCRIPTOR = "protobuf-description-base64";
Expand Down Expand Up @@ -77,13 +78,13 @@ public Response getDescriptor(@PathVariable(name = "schema") String schemaName,
String resourceLabel = annotationFor(schemaName, kind, box);
descriptor = descriptorExtractor.getImageDescriptor(resourceLabel, kind, box, PROTOBUF_DESCRIPTOR);
} catch (ResourceNotFoundException e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND.name(), e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND.name(), e);
} catch (InvalidImageNameFormatException e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, FORMATTING_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, FORMATTING_ERROR, e);
} catch (RegistryRequestException e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REGISTRY_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REGISTRY_ERROR, e);
} catch (Exception e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR, e);
}
if (descriptor != null) {
return new Response(PROTOBUF_DESCRIPTOR, descriptor);
Expand All @@ -92,23 +93,5 @@ public Response getDescriptor(@PathVariable(name = "schema") String schemaName,
return null;
}

public static class Response {
private final String descriptor;

private final String content;

public Response(String descriptor, String content) {
this.descriptor = descriptor;
this.content = content;
}

public String getDescriptor() {
return descriptor;
}

public String getContent() {
return content;
}
}

public record Response(String descriptor, String content) { }
}
13 changes: 7 additions & 6 deletions src/main/java/com/exactpro/th2/inframgr/JobController.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import static com.exactpro.th2.inframgr.statuswatcher.ResourcePath.annotationFor;

@RestController
@SuppressWarnings("unused")
public class JobController {

private static final String UNKNOWN_ERROR = "UNKNOWN_ERROR";
Expand All @@ -46,12 +47,12 @@ public class JobController {

private static final String BAD_RESOURCE_NAME = "BAD_RESOURCE_NAME";

private static final Logger logger = LoggerFactory.getLogger(JobController.class);
private static final Logger LOGGER = LoggerFactory.getLogger(JobController.class);

@PutMapping("/jobs/{schemaName}/{jobName}")
public void putSecrets(@PathVariable(name = "schemaName") String schemaName,
@PathVariable(name = "jobName") String jobName) {
logger.debug("received request for job creation, job name: {}", jobName);
LOGGER.debug("received request for job creation, job name: {}", jobName);
if (!K8sCustomResource.isSchemaNameValid(schemaName)) {
throw new NotAcceptableException(BAD_RESOURCE_NAME, "Invalid schema name");
}
Expand All @@ -72,16 +73,16 @@ public void putSecrets(@PathVariable(name = "schemaName") String schemaName,
resource = Repository.getResource(gitter, ResourceType.Th2Job.kind(), jobName);
resourceLabel = annotationFor(kube.getNamespaceName(), ResourceType.Th2Job.kind(), jobName);
} catch (GitAPIException e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, GIT_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, GIT_ERROR, e);
} finally {
gitter.unlock();
}
kube.deleteCustomResource(resource);
logger.info("Delete resource : {}", resourceLabel);
LOGGER.info("Delete resource : {}", resourceLabel);
kube.createCustomResource(resource);
logger.info("Created job with name : {}", resourceLabel);
LOGGER.info("Created job with name : {}", resourceLabel);
} catch (IOException e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, CONFIG_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, CONFIG_ERROR, e);
}
}
}
29 changes: 16 additions & 13 deletions src/main/java/com/exactpro/th2/inframgr/PodController.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import static com.exactpro.th2.inframgr.statuswatcher.ResourcePath.annotationFor;

@Controller

@SuppressWarnings("unused")
public class PodController {
private static final Logger LOGGER = LoggerFactory.getLogger(PodController.class);

Expand All @@ -60,25 +60,28 @@ public ResponseEntity<?> deleteResourcePods(
}

Config config = Config.getInstance();
Kubernetes kubernetes = new Kubernetes(config.getBehaviour(), config.getKubernetes(), schemaName);
for (var resource : statusCache.getResourceDependencyStatuses(schemaName, kind, resourceName)) {
if (resource.getKind().equals(Kubernetes.KIND_POD)) {
try {
kubernetes.deletePodWithName(resource.getName(), force);
} catch (KubernetesClientException e) {
LOGGER.error("Could not delete pod \"{}\"",
annotationFor(kubernetes.getNamespaceName(), Kubernetes.KIND_POD, resource.getName()));
try(Kubernetes kubernetes = new Kubernetes(config.getBehaviour(), config.getKubernetes(), schemaName)) {
for (var resource : statusCache.getResourceDependencyStatuses(schemaName, kind, resourceName)) {
if (resource.getKind().equals(Kubernetes.KIND_POD)) {
String annotation = annotationFor(kubernetes.getNamespaceName(),
Kubernetes.KIND_POD, resource.getName());
try {
kubernetes.deletePodWithName(resource.getName(), force);
LOGGER.info("Deleted pod \"{}\", schema name \"{}\"", annotation, schemaName);
} catch (KubernetesClientException e) {
LOGGER.error("Could not delete pod \"{}\"", annotation, e);
}
}
}
}

// TODO: return correct HTTP response
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (ServiceException e) {
LOGGER.error(e.getMessage(), e);
throw e;
} catch (Exception e) {
LOGGER.error("Exception deleting pods for \"{}/{}\" in schema \"{}\"", kind, resourceName, schemaName, e);
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR,
"Exception deleting pods for \"" + kind + "/" + resourceName +
"\" in schema \"" + schemaName + "\"", e);
}
}
}
68 changes: 39 additions & 29 deletions src/main/java/com/exactpro/th2/inframgr/SchemaController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 Exactpro (Exactpro Systems Limited)
* Copyright 2020-2023 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,7 +37,6 @@
import com.exactpro.th2.validator.SchemaValidator;
import com.exactpro.th2.validator.ValidationReport;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.kotlin.KotlinModule;
Expand All @@ -47,13 +46,25 @@
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

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

@Controller
@SuppressWarnings("unused")
public class SchemaController {

private static final Logger LOGGER = LoggerFactory.getLogger(SchemaController.class);

public static final String SCHEMA_EXISTS = "SCHEMA_EXISTS";

private static final String REPOSITORY_ERROR = "REPOSITORY_ERROR";
Expand All @@ -62,8 +73,6 @@ public class SchemaController {

public static final String SOURCE_BRANCH = "master";

private static final Logger logger = LoggerFactory.getLogger(SchemaController.class);

@GetMapping("/schemas")
@ResponseBody
public Set<String> getAvailableSchemas() throws ServiceException {
Expand All @@ -74,7 +83,7 @@ public Set<String> getAvailableSchemas() throws ServiceException {
schemas.remove(SOURCE_BRANCH);
return schemas;
} catch (Exception e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, e);
}
}

Expand All @@ -93,10 +102,10 @@ public SchemaControllerResponse getSchemaFiles(@PathVariable(name = "name") Stri
gitter.lock();
return new SchemaControllerResponse(Repository.getSnapshot(gitter));
} catch (RefNotAdvertisedException | RefNotFoundException e) {
throw new ServiceException(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.name(), "schema does not exists");
throw new ServiceException(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.name(), "schema does not exists", e);
} catch (Exception e) {
logger.error("Exception retrieving schema {} from repository", schemaName, e);
throw new NotAcceptableException(REPOSITORY_ERROR, e.getMessage());
LOGGER.error("Exception retrieving schema {} from repository", schemaName, e);
throw new NotAcceptableException(REPOSITORY_ERROR, e);
} finally {
gitter.unlock();
}
Expand Down Expand Up @@ -136,13 +145,14 @@ public SchemaControllerResponse createSchema(@PathVariable(name = "name") String

issueRepoUpdateEvent(schemaName, snapshot);

LOGGER.info("Created schema \"{}\"", schemaName);
return new SchemaControllerResponse(snapshot);

} catch (ServiceException se) {
throw se;
} catch (Exception e) {
logger.error("Exception creating schema \"{}\"", schemaName, e);
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR,
"Exception creating schema \"" + schemaName + "\"", e);
}
}

Expand All @@ -151,7 +161,7 @@ private boolean schemaAlreadyExists(String schemaName, GitterContext ctx) {
try {
branches = ctx.getBranches();
} catch (Exception e) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, e);
}
return branches.contains(schemaName);
}
Expand All @@ -175,7 +185,7 @@ public SchemaControllerResponse updateSchema(@PathVariable(name = "name") String
operations = mapper.readValue(requestBody, new TypeReference<>() {
});
} catch (Exception e) {
throw new BadRequestException(e.getMessage());
throw new BadRequestException(e);
}

validateResourceNames(operations);
Expand All @@ -185,7 +195,8 @@ public SchemaControllerResponse updateSchema(@PathVariable(name = "name") String
GitterContext ctx = GitterContext.getContext(gitConfig);

if (!schemaAlreadyExists(schemaName, ctx)) {
throw new ServiceException(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.name(), "Schema does not exist");
throw new ServiceException(HttpStatus.NOT_FOUND,
HttpStatus.NOT_FOUND.name(), "Schema does not exist", null);
}

//validate schema and apply updates if valid
Expand All @@ -207,7 +218,7 @@ public SchemaControllerResponse updateSchema(@PathVariable(name = "name") String
);
if (!validationContext.isValid()) {
// do not update repository and kubernetes if requested changes contain errors.
logger.error("Schema \"{}\" contains errors, update request will be ignored", schemaName);
LOGGER.error("Schema \"{}\" contains errors, update request will be ignored", schemaName);
ValidationReport report = validationContext.getReport();
SchemaErrorPrinter.printErrors(report, "editor");
return new SchemaControllerResponse(report);
Expand All @@ -220,21 +231,20 @@ public SchemaControllerResponse updateSchema(@PathVariable(name = "name") String
}

if (commitRef == null) {
logger.info("Nothing changed, leaving");
LOGGER.info("Nothing changed, leaving");
} else {
issueRepoUpdateEvent(schemaName, snapshot);
}
return new SchemaControllerResponse(snapshot);
} catch (ServiceException se) {
throw se;
} catch (Exception e) {
logger.error("Exception updating schema \"{}\" request", schemaName, e);
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, e.getMessage());
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR,
"Exception updating schema \"" + schemaName + "\" request", e);
}
}

private void issueRepoUpdateEvent(String schemaName, RepositorySnapshot snapshot)
throws JsonProcessingException {
private void issueRepoUpdateEvent(String schemaName, RepositorySnapshot snapshot) {
SchemaEventRouter router = SchemaEventRouter.getInstance();
RepositoryUpdateEvent event = new RepositoryUpdateEvent(schemaName, snapshot.getCommitRef());
RepositorySettingsSpec rs = snapshot.getRepositorySettingsSpec();
Expand Down Expand Up @@ -265,23 +275,23 @@ private String updateRepository(Gitter gitter, List<RequestEntry> operations) th
} catch (InconsistentRepositoryStateException irse) {
// this exception is thrown when inconsistent state of git repository is expected
// discard local cache and re-download repository
logger.error("Inconsistent repository state exception for branch \"{}\"", branchName, irse);
LOGGER.error("Inconsistent repository state exception for branch \"{}\"", branchName, irse);

var se = new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, irse.getMessage());
var se = new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, REPOSITORY_ERROR, irse);
se.addSuppressed(irse);

try {
gitter.recreateCache();
} catch (Exception re) {
logger.error("Exception recreating repository's local cache for branch \"{}\"", branchName, re);
LOGGER.error("Exception recreating repository's local cache for branch \"{}\"", branchName, re);
se.addSuppressed(re);
}
throw se;

} catch (Exception e) {
logger.error("Exception updating repository for branch \"{}\"", branchName, e);
LOGGER.error("Exception updating repository for branch \"{}\"", branchName, e);
gitter.reset();
throw new NotAcceptableException(REPOSITORY_ERROR, e.getMessage());
throw new NotAcceptableException(REPOSITORY_ERROR, e);
}
}

Expand All @@ -293,7 +303,7 @@ public static void validateResourceNames(List<RequestEntry> operations) {
String resourceName = entry.getPayload().getName();

if (!K8sCustomResource.isNameValid(resourceName)) {
logger.error("Invalid resource name: \"{}\"", resourceName);
LOGGER.error("Invalid resource name: \"{}\"", resourceName);
throw new NotAcceptableException(BAD_RESOURCE_NAME, String.format(
"Invalid resource name : \"%s\" (%s)"
, entry.getPayload().getName()
Expand All @@ -302,7 +312,7 @@ public static void validateResourceNames(List<RequestEntry> operations) {
}

if (!names.add(resourceName)) {
logger.error("Multiple operations on the same resource: \"{}\"", resourceName);
LOGGER.error("Multiple operations on the same resource: \"{}\"", resourceName);
throw new NotAcceptableException(REPOSITORY_ERROR, "Multiple operation on the resource");
}
}
Expand Down
Loading

0 comments on commit 511e41b

Please sign in to comment.