Skip to content

Commit

Permalink
[TH2-1056] Refactoring: prepared for repository library extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
georgiano authored Nov 30, 2020
1 parent 7ec2d10 commit 99a303f
Show file tree
Hide file tree
Showing 23 changed files with 253 additions and 210 deletions.
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
variables:
APP_NAME: "th2-infra-mgr"
MAJOR_VERSION: "0"
MINOR_VERSION: "8"
MAINTENANCE_VERSION: "6"
MINOR_VERSION: "9"
MAINTENANCE_VERSION: "0"
DOCKER_PUBLISH_ENABLED: "true"

include:
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
release_version = 0.8.6
release_version = 0.9.0
29 changes: 12 additions & 17 deletions src/main/java/com/exactpro/th2/inframgr/SchemaController.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,10 @@
import com.exactpro.th2.inframgr.initializer.SchemaInitializer;
import com.exactpro.th2.inframgr.k8s.K8sCustomResource;
import com.exactpro.th2.inframgr.k8s.Kubernetes;
import com.exactpro.th2.inframgr.models.RepositoryResource;
import com.exactpro.th2.inframgr.models.RepositorySettings;
import com.exactpro.th2.inframgr.models.RepositorySnapshot;
import com.exactpro.th2.inframgr.models.RequestEntry;
import com.exactpro.th2.inframgr.repository.Gitter;
import com.exactpro.th2.inframgr.repository.InconsistentRepositoryStateException;
import com.exactpro.th2.inframgr.repository.Repository;
import com.exactpro.th2.inframgr.repository.RepositoryUpdateEvent;
import com.exactpro.th2.inframgr.util.Stringifier;
import com.exactpro.th2.infrarepo.*;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jgit.api.errors.RefNotAdvertisedException;
Expand Down Expand Up @@ -69,7 +64,7 @@ public Set<String> getAvailableSchemas() throws ServiceException {

@GetMapping("/schema/{name}")
@ResponseBody
public RepositorySnapshot getSchemaFiles(@PathVariable(name="name") String schemaName) throws Exception {
public SchemaControllerResponse getSchemaFiles(@PathVariable(name="name") String schemaName) throws Exception {

if (schemaName.equals(SOURCE_BRANCH))
throw new NotAcceptableException(REPOSITORY_ERROR, "Not Allowed");
Expand All @@ -78,7 +73,7 @@ public RepositorySnapshot getSchemaFiles(@PathVariable(name="name") String schem
final Gitter gitter = Gitter.getBranch(gitConfig, schemaName);
try {
gitter.lock();
return Repository.getSnapshot(gitter);
return new SchemaControllerResponse(Repository.getSnapshot(gitter));
} catch (RefNotAdvertisedException | RefNotFoundException e) {
throw new ServiceException(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.name(), "schema does not exists");
} catch (Exception e) {
Expand All @@ -91,7 +86,7 @@ public RepositorySnapshot getSchemaFiles(@PathVariable(name="name") String schem

@PutMapping("/schema/{name}")
@ResponseBody
public RepositorySnapshot createSchema(@PathVariable(name="name") String schemaName) throws Exception {
public SchemaControllerResponse createSchema(@PathVariable(name="name") String schemaName) throws Exception {

if (schemaName.equals(SOURCE_BRANCH))
throw new NotAcceptableException(REPOSITORY_ERROR, "Not Allowed");
Expand Down Expand Up @@ -131,7 +126,7 @@ public RepositorySnapshot createSchema(@PathVariable(name="name") String schemaN
event.setSyncingK8s(!(rs != null && (rs.isK8sPropagationDenied() || rs.isK8sSynchronizationRequired())));
router.addEvent(event);

return snapshot;
return new SchemaControllerResponse(snapshot);

} catch (ServiceException se) {
throw se;
Expand All @@ -144,7 +139,7 @@ public RepositorySnapshot createSchema(@PathVariable(name="name") String schemaN

@PostMapping("/schema/{name}")
@ResponseBody
public RepositorySnapshot updateSchema(@PathVariable(name="name") String schemaName, @RequestBody String requestBody)
public SchemaControllerResponse updateSchema(@PathVariable(name="name") String schemaName, @RequestBody String requestBody)
throws Exception {

if (schemaName.equals(SOURCE_BRANCH))
Expand Down Expand Up @@ -208,7 +203,7 @@ public RepositorySnapshot updateSchema(@PathVariable(name="name") String schemaN
// delegate this job to K8sSynchronization
event.setSyncingK8s(false);
router.addEvent(event);
return snapshot;
return new SchemaControllerResponse(snapshot);
}

event.setSyncingK8s(true);
Expand All @@ -218,7 +213,7 @@ public RepositorySnapshot updateSchema(@PathVariable(name="name") String schemaN
synchronizeWithK8s(config.getKubernetes(), operations, schemaName);
}

return snapshot;
return new SchemaControllerResponse(snapshot);
} catch (ServiceException se) {
throw se;
} catch (Exception e) {
Expand All @@ -240,7 +235,7 @@ private void synchronizeWithK8s(Config.K8sConfig k8sConfig, List<RequestEntry> o
if (entry.getPayload().getKind().isK8sResource()) {
try {
Stringifier.stringify(entry.getPayload().getSpec());
RepositoryResource resource = new RepositoryResource(entry.getPayload());
RepositoryResource resource = entry.getPayload().toRepositoryResource();
switch (entry.getOperation()) {
case add:
kube.createCustomResource(resource);
Expand Down Expand Up @@ -281,13 +276,13 @@ private String updateRepository(Gitter gitter, List<RequestEntry> operations) th
for (RequestEntry entry : operations)
switch (entry.getOperation()) {
case add:
Repository.add(gitter.getConfig(), branchName, entry.getPayload());
Repository.add(gitter.getConfig(), branchName, entry.getPayload().toRepositoryResource());
break;
case update:
Repository.update(gitter.getConfig(), branchName, entry.getPayload());
Repository.update(gitter.getConfig(), branchName, entry.getPayload().toRepositoryResource());
break;
case remove:
Repository.remove(gitter.getConfig(), branchName, entry.getPayload());
Repository.remove(gitter.getConfig(), branchName, entry.getPayload().toRepositoryResource());
break;
}
return gitter.commitAndPush("schema update");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2020-2020 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.exactpro.th2.inframgr;

import com.exactpro.th2.inframgr.models.ResourceEntry;
import com.exactpro.th2.infrarepo.RepositorySnapshot;

import java.util.HashSet;
import java.util.Set;

public class SchemaControllerResponse {
private String commitRef;
private Set<ResourceEntry> resources;

public SchemaControllerResponse(RepositorySnapshot snapshot) {
this.commitRef = snapshot.getCommitRef();
resources = new HashSet<>();
snapshot.getResources().forEach(e -> resources.add(new ResourceEntry(e)));
}

public String getCommitRef() {
return commitRef;
}

public Set<ResourceEntry> getResources() {
return resources;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import com.exactpro.th2.inframgr.Config;
import com.exactpro.th2.inframgr.k8s.K8sCustomResource;
import com.exactpro.th2.inframgr.k8s.Kubernetes;
import com.exactpro.th2.inframgr.models.RepositoryResource;
import com.exactpro.th2.inframgr.models.ResourceType;
import com.exactpro.th2.infrarepo.RepositoryResource;
import com.exactpro.th2.infrarepo.ResourceType;
import com.exactpro.th2.inframgr.statuswatcher.ResourcePath;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.api.model.ConfigMap;
Expand Down Expand Up @@ -210,8 +210,7 @@ private static void copyIngress(Config config, Kubernetes kube) {
logger.info("Creating \"{}\"", ResourcePath.annotationFor(namespace, "Ingress", ingressName));
K8sCustomResource ingress = kube.currentNamespace().loadCustomResource(ResourceType.HelmRelease, ingressName);

RepositoryResource.Metadata meta = new RepositoryResource.Metadata();
meta.setName(ingressName);
RepositoryResource.Metadata meta = new RepositoryResource.Metadata(ingressName);

RepositoryResource resource = new RepositoryResource(ResourceType.HelmRelease);
resource.setSpec(ingress.getSpec());
Expand Down
40 changes: 19 additions & 21 deletions src/main/java/com/exactpro/th2/inframgr/k8s/K8sOperator.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
package com.exactpro.th2.inframgr.k8s;

import com.exactpro.th2.inframgr.Config;
import com.exactpro.th2.inframgr.models.*;
import com.exactpro.th2.inframgr.repository.Gitter;
import com.exactpro.th2.inframgr.repository.Repository;
import com.exactpro.th2.inframgr.statuswatcher.ResourcePath;
import com.exactpro.th2.inframgr.util.RetryableTaskQueue;
import com.exactpro.th2.inframgr.util.Stringifier;
import com.exactpro.th2.infrarepo.*;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.KubernetesClientException;
Expand Down Expand Up @@ -111,7 +109,7 @@ private void processEvent(Watcher.Action action, K8sCustomResource res, Kubernet
String hash = res.getSourceHash();

String resourceLabel = "\"" + ResourcePath.annotationFor(namespace, kind, name) + "\"";
String hashTag = "[" + (hash == null ? "no-hash" : hash) + "]";
String hashTag = "[" + (res.getSourceHash() == null ? "no-hash" : res.getSourceHash()) + "]";
logger.debug("Received {} event on resource {} {}", action.name(), resourceLabel, hashTag);

Lock lock = cache.lockFor(namespace, kind, name);
Expand All @@ -123,14 +121,14 @@ private void processEvent(Watcher.Action action, K8sCustomResource res, Kubernet
String cachedHash = cacheEntry == null ? null : cacheEntry.getHash();
if (action.equals(Watcher.Action.DELETED) && cacheEntry != null && cacheEntry.isMarkedAsDeleted()
&& Objects.equals(cachedHash, hash)) {
logger.debug("No action needed for resource {}", resourceLabel);
logger.debug("No action needed for resource {} {}", resourceLabel, hashTag);
return;
}

if (!action.equals(Watcher.Action.DELETED) && cacheEntry != null && !cacheEntry.isMarkedAsDeleted()
&& Objects.equals(cachedHash, hash)) {

logger.debug("No action needed for resource {}", resourceLabel);
logger.debug("No action needed for resource {} {}", resourceLabel, hashTag);
return;
}

Expand All @@ -139,7 +137,7 @@ private void processEvent(Watcher.Action action, K8sCustomResource res, Kubernet
Gitter gitter = Gitter.getBranch(config.getGit(), kube.extractSchemaName(namespace));
logger.info("Checking out branch \"{}\" from repository", gitter.getBranch()) ;

ResourceEntry resourceEntry = null;
RepositoryResource resource = null;
try {
gitter.lock();
RepositorySnapshot snapshot = Repository.getSnapshot(gitter);
Expand All @@ -150,20 +148,16 @@ private void processEvent(Watcher.Action action, K8sCustomResource res, Kubernet
return;

// refresh cache for this namespace
for (ResourceEntry e :snapshot.getResources()) {
cache.add(namespace, e);
if (e.getKind().kind().equals(kind) && e.getName().equals(name))
resourceEntry = e;
for (RepositoryResource r :snapshot.getResources()) {
cache.add(namespace, r);
if (r.getKind().equals(kind) && r.getMetadata().getName().equals(name))
resource = r;
}

} finally {
gitter.unlock();
}

hash = null;
if (resourceEntry != null)
hash = resourceEntry.getSourceHash();
hashTag = "[" + (hash == null ? "no-hash" : hash) + "]";

// recheck item
cacheEntry = cache.get(namespace, kind, name);
Expand All @@ -183,16 +177,20 @@ private void processEvent(Watcher.Action action, K8sCustomResource res, Kubernet
else {
actionDelete = true;

resourceEntry = new ResourceEntry();
resourceEntry.setKind(ResourceType.forKind(kind));
resourceEntry.setName(name);
resource = new RepositoryResource();
resource.setKind(kind);
resource.setMetadata(new RepositoryResource.Metadata(name));
}
}

Stringifier.stringify(resourceEntry.getSpec());
RepositoryResource resource = new RepositoryResource(resourceEntry);
hash = null;
if (resource != null)
hash = resource.getSourceHash();
hashTag = "[" + (hash == null ? "no-hash" : hash) + "]";

Stringifier.stringify(resource.getSpec());
if (actionReplace) {
logger.info("Detected external manipulation on {} {}, recreating resource", resourceLabel,hashTag) ;
logger.info("Detected external manipulation on {} {}, recreating resource", resourceLabel, hashTag) ;

// check current status of namespace
Namespace n = kube.getNamespace(namespace);
Expand Down
24 changes: 11 additions & 13 deletions src/main/java/com/exactpro/th2/inframgr/k8s/K8sResourceCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package com.exactpro.th2.inframgr.k8s;

import com.exactpro.th2.inframgr.models.ResourceEntry;
import com.exactpro.th2.inframgr.models.ResourceType;
import com.exactpro.th2.infrarepo.RepositoryResource;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -27,7 +26,7 @@
public enum K8sResourceCache {
INSTANCE;

public class CacheEntry {
public static class CacheEntry {
private boolean markedDeleted;
private String hash;

Expand All @@ -48,26 +47,26 @@ private void setHash(String hash) {
}
}

private Map<String, CacheEntry> cache = new HashMap<>();
private Map<String, Lock> locks = new HashMap<>();
private final Map<String, CacheEntry> cache = new HashMap<>();
private final Map<String, Lock> locks = new HashMap<>();

private String keyFor(String namespace, ResourceType type, String resourceName) {
return String.format("%s.%s.%s", namespace, type.kind(), resourceName);
private String keyFor(String namespace, String type, String resourceName) {
return String.format("%s:%s/%s", namespace, type, resourceName);
}

public synchronized void add(String namespace, K8sCustomResource resource) {

String key = keyFor(namespace, ResourceType.forKind(resource.getKind()), resource.getMetadata().getName());
String key = keyFor(namespace, resource.getKind(), resource.getMetadata().getName());

CacheEntry entry = new CacheEntry();
entry.setHash(resource.getSourceHash());

cache.put(key, entry);
}

public synchronized void add(String namespace, ResourceEntry resource) {
public synchronized void add(String namespace, RepositoryResource resource) {

String key = keyFor(namespace, resource.getKind(), resource.getName());
String key = keyFor(namespace, resource.getKind(), resource.getMetadata().getName());
CacheEntry entry = new CacheEntry();
entry.setHash(resource.getSourceHash());

Expand All @@ -76,7 +75,7 @@ public synchronized void add(String namespace, ResourceEntry resource) {

public synchronized CacheEntry get(String namespace, String resourceType, String resourceName) {

String key = keyFor(namespace, ResourceType.forKind(resourceType), resourceName);
String key = keyFor(namespace, resourceType, resourceName);
return cache.get(key);
}

Expand All @@ -87,15 +86,14 @@ public synchronized CacheEntry get(String namespace, K8sCustomResource resource)

public synchronized void remove(String namespace, String resourceType, String resourceName) {

String key = keyFor(namespace, ResourceType.forKind(resourceType), resourceName);
CacheEntry entry = get(namespace, resourceType, resourceName);
if (entry != null)
entry.markAsDeleted();
}

public synchronized Lock lockFor(String namespace, String resourceType, String resourceName) {

String key = keyFor(namespace, ResourceType.forKind(resourceType), resourceName);
String key = keyFor(namespace, resourceType, resourceName);
return locks.computeIfAbsent(key, v -> new ReentrantLock());
}

Expand Down
Loading

0 comments on commit 99a303f

Please sign in to comment.