Add update steps for namespaces

This adds a new update step API dedicated
to handle namespace related data.

Pushed-by: Rene Pfeuffer<rene.pfeuffer@cloudogu.com>
Co-authored-by: René Pfeuffer<rene.pfeuffer@cloudogu.com>
Committed-by: René Pfeuffer<rene.pfeuffer@cloudogu.com>
This commit is contained in:
Rene Pfeuffer
2023-10-05 11:00:20 +02:00
parent 1a22307f18
commit 2ca68c43b3
17 changed files with 492 additions and 26 deletions

View File

@@ -61,6 +61,7 @@ import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.store.DataStoreFactory;
import sonia.scm.store.DefaultBlobDirectoryAccess;
import sonia.scm.store.FileBlobStoreFactory;
import sonia.scm.store.FileNamespaceUpdateIterator;
import sonia.scm.store.FileRepositoryUpdateIterator;
import sonia.scm.store.FileStoreUpdateStepUtilFactory;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
@@ -68,6 +69,7 @@ import sonia.scm.store.JAXBConfigurationStoreFactory;
import sonia.scm.store.JAXBDataStoreFactory;
import sonia.scm.store.JAXBPropertyFileAccess;
import sonia.scm.update.BlobDirectoryAccess;
import sonia.scm.update.NamespaceUpdateIterator;
import sonia.scm.update.PropertyFileAccess;
import sonia.scm.update.RepositoryUpdateIterator;
import sonia.scm.update.StoreUpdateStepUtilFactory;
@@ -124,6 +126,7 @@ public class BootstrapModule extends AbstractModule {
bind(PropertyFileAccess.class, JAXBPropertyFileAccess.class);
bind(BlobDirectoryAccess.class, DefaultBlobDirectoryAccess.class);
bind(RepositoryUpdateIterator.class, FileRepositoryUpdateIterator.class);
bind(NamespaceUpdateIterator.class, FileNamespaceUpdateIterator.class);
bind(StoreUpdateStepUtilFactory.class, FileStoreUpdateStepUtilFactory.class);
bind(new TypeLiteral<UpdateStepRepositoryMetadataAccess<Path>>() {}).to(new TypeLiteral<MetadataStore>() {});

View File

@@ -26,6 +26,7 @@ package sonia.scm.lifecycle.modules;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
import sonia.scm.migration.NamespaceUpdateStep;
import sonia.scm.migration.RepositoryUpdateStep;
import sonia.scm.migration.UpdateStep;
import sonia.scm.plugin.PluginLoader;
@@ -41,7 +42,8 @@ public class UpdateStepModule extends AbstractModule {
@Override
protected void configure() {
Multibinder<UpdateStep> updateStepBinder = Multibinder.newSetBinder(binder(), UpdateStep.class);
Multibinder<RepositoryUpdateStep> repositoryUdateStepBinder = Multibinder.newSetBinder(binder(), RepositoryUpdateStep.class);
Multibinder<RepositoryUpdateStep> repositoryUpdateStepBinder = Multibinder.newSetBinder(binder(), RepositoryUpdateStep.class);
Multibinder<NamespaceUpdateStep> namespaceUpdateStepBinder = Multibinder.newSetBinder(binder(), NamespaceUpdateStep.class);
pluginLoader
.getExtensionProcessor()
.byExtensionPoint(UpdateStep.class)
@@ -49,6 +51,10 @@ public class UpdateStepModule extends AbstractModule {
pluginLoader
.getExtensionProcessor()
.byExtensionPoint(RepositoryUpdateStep.class)
.forEach(stepClass -> repositoryUdateStepBinder.addBinding().to(stepClass));
.forEach(stepClass -> repositoryUpdateStepBinder.addBinding().to(stepClass));
pluginLoader
.getExtensionProcessor()
.byExtensionPoint(NamespaceUpdateStep.class)
.forEach(stepClass -> namespaceUpdateStepBinder.addBinding().to(stepClass));
}
}

View File

@@ -26,6 +26,8 @@ package sonia.scm.update;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.migration.NamespaceUpdateContext;
import sonia.scm.migration.NamespaceUpdateStep;
import sonia.scm.migration.RepositoryUpdateContext;
import sonia.scm.migration.RepositoryUpdateStep;
import sonia.scm.migration.UpdateException;
@@ -46,28 +48,33 @@ public class UpdateEngine {
public static final Logger LOG = LoggerFactory.getLogger(UpdateEngine.class);
private final List<UpdateStepWrapper> steps;
private final RepositoryUpdateIterator repositoryUpdateIterator;
private final NamespaceUpdateIterator namespaceUpdateIterator;
private final UpdateStepStore updateStepStore;
@Inject
public UpdateEngine(
Set<UpdateStep> globalSteps,
Set<RepositoryUpdateStep> repositorySteps,
Set<NamespaceUpdateStep> namespaceSteps,
RepositoryUpdateIterator repositoryUpdateIterator,
UpdateStepStore updateStepStore) {
NamespaceUpdateIterator namespaceUpdateIterator, UpdateStepStore updateStepStore) {
this.repositoryUpdateIterator = repositoryUpdateIterator;
this.namespaceUpdateIterator = namespaceUpdateIterator;
this.updateStepStore = updateStepStore;
this.steps = sortSteps(globalSteps, repositorySteps);
this.steps = sortSteps(globalSteps, repositorySteps, namespaceSteps);
}
private List<UpdateStepWrapper> sortSteps(Set<UpdateStep> globalSteps, Set<RepositoryUpdateStep> repositorySteps) {
private List<UpdateStepWrapper> sortSteps(Set<UpdateStep> globalSteps, Set<RepositoryUpdateStep> repositorySteps, Set<NamespaceUpdateStep> namespaceSteps) {
LOG.trace("sorting available update steps:");
List<UpdateStepWrapper> sortedSteps =
concat(
globalSteps.stream().filter(this::notRunYet).map(GlobalUpdateStepWrapper::new),
repositorySteps.stream().map(RepositoryUpdateStepWrapper::new))
concat(
globalSteps.stream().filter(this::notRunYet).map(GlobalUpdateStepWrapper::new),
repositorySteps.stream().map(RepositoryUpdateStepWrapper::new)),
namespaceSteps.stream().map(NamespaceUpdateStepWrapper::new)
)
.sorted(
Comparator
.comparing(UpdateStepWrapper::getTargetVersion)
@@ -248,4 +255,52 @@ public class UpdateEngine {
return updateStepStore.notRunYet(repositoryId, delegate);
}
}
private class NamespaceUpdateStepWrapper extends UpdateStepWrapper {
private final NamespaceUpdateStep delegate;
public NamespaceUpdateStepWrapper(NamespaceUpdateStep delegate) {
super(delegate);
this.delegate = delegate;
}
@Override
public boolean isGlobalUpdateStep() {
return false;
}
@Override
boolean isCoreUpdate() {
return false;
}
@Override
void doUpdate() {
namespaceUpdateIterator.updateEachNamespace(this::doUpdate);
}
@Override
void doUpdate(String namespace) throws Exception {
if (notRunYet(namespace)) {
LOG.info("running update step for type {} and version {} (class {}) for namespace {}",
delegate.getAffectedDataType(),
delegate.getTargetVersion(),
delegate.getClass().getName(),
namespace
);
delegate.doUpdate(new NamespaceUpdateContext(namespace));
updateStepStore.storeExecutedUpdate(namespace, delegate);
}
}
private boolean notRunYet(String namespace) {
LOG.trace("checking whether to run update step for type {} and version {} on namespace {}",
delegate.getAffectedDataType(),
delegate.getTargetVersion(),
namespace
);
return updateStepStore.notRunYet(namespace, delegate);
}
}
}

View File

@@ -26,6 +26,7 @@ package sonia.scm.update;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.migration.NamespaceUpdateStep;
import sonia.scm.migration.RepositoryUpdateStep;
import sonia.scm.migration.UpdateStep;
import sonia.scm.migration.UpdateStepTarget;
@@ -52,6 +53,11 @@ class UpdateStepStore {
storeNewVersion(store, updateStep);
}
void storeExecutedUpdate(String namespace, NamespaceUpdateStep updateStep) {
ConfigurationEntryStore<UpdateVersionInfo> store = createNamespaceStore(namespace);
storeNewVersion(store, updateStep);
}
void storeExecutedUpdate(UpdateStep updateStep) {
ConfigurationEntryStore<UpdateVersionInfo> store = createGlobalStore();
storeNewVersion(store, updateStep);
@@ -65,6 +71,10 @@ class UpdateStepStore {
return notRunYet(createRepositoryStore(repositoryId), updateStep);
}
boolean notRunYet(String namespace, NamespaceUpdateStep updateStep) {
return notRunYet(createNamespaceStore(namespace), updateStep);
}
private void storeNewVersion(ConfigurationEntryStore<UpdateVersionInfo> store, UpdateStepTarget updateStep) {
UpdateVersionInfo newVersionInfo = new UpdateVersionInfo(updateStep.getTargetVersion().getParsedVersion());
store.put(updateStep.getAffectedDataType(), newVersionInfo);
@@ -99,4 +109,12 @@ class UpdateStepStore {
.forRepository(repositoryId)
.build();
}
private ConfigurationEntryStore<UpdateVersionInfo> createNamespaceStore(String namespace) {
return storeFactory
.withType(UpdateVersionInfo.class)
.withName(STORE_NAME)
.forNamespace(namespace)
.build();
}
}