Files
qbit-backups/src/main/java/com/kingsrook/qbits/backups/BackupsQBitConfig.java
T
james.maesandClaude Sonnet 5.5 26c174f7bf feat(home): null-safe home, readable plan rows, record sections and child lists, runnable demo
- Fix the NPE in BackupsHomeData.plansNeedingAttention when slaStatus is null (and null plan ids)
- Home: full-width plan status rows, derived lateness, links that work in the Next UI (tablePathPrefix), bars for the size trend
- The Backups app attaches itself to its parent app (Admin) so the nav shows it
- Nav lists the main tables only; artifacts, verifications, restores and per-table results are child lists on their parents
- Record screens grouped into sections
- Test-scope demo server (memory backend, real engine history incl. a failed run)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 19:07:45 -05:00

456 lines
15 KiB
Java

/*
* Copyright 2026 Kingsrook, LLC
*
* 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.kingsrook.qbits.backups;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import com.kingsrook.qbits.backups.codec.ArtifactTransform;
import com.kingsrook.qbits.backups.verify.ScratchTarget;
import com.kingsrook.qbits.backups.storage.BackupStorage;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitConfig;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
** Configuration of the Backups qbit.
**
** Storage is resolved through a function from a bucket alias (the value of
** backups_plan.storageBucketAlias) to a BackupStorage. The production resolver
** is backed by qbit-object-storage; tests and local development use the
** in-memory implementation. No credential is ever held here or in a table.
*******************************************************************************/
public class BackupsQBitConfig implements QBitConfig
{
public static final String TABLE_NAME_PREFIX = "backups_";
public static final String PERMISSION_BASE_NAME = "backups";
private String backendName;
private String appName = "backups";
private String appLabel = "Backups";
private String parentAppName;
private String tablePathPrefix;
private String schedulerName;
private String instanceName;
private Integer maxConcurrentRuns = 1;
private Integer slaCheckIntervalSeconds = 300;
private Boolean openWhenAnonymous = false;
private Boolean prometheusEndpoint = false;
private Function<String, BackupStorage> storageResolver;
private Integer fileReverifyDays = 30;
private Function<String, ArtifactTransform> artifactTransformResolver;
private ScratchTarget scratchTarget;
private Predicate<String> planOwnerValidator;
private String esbDestinationName;
/*******************************************************************************
** The backend must be named.
*******************************************************************************/
@Override
public void validate(QInstance qInstance, List<String> errors)
{
assertCondition(StringUtils.hasContent(backendName), "backendName is required for the Backups QBit", errors);
}
/*******************************************************************************
** Tables without their own backend use the configured backend.
*******************************************************************************/
@Override
public String getDefaultBackendNameForTables()
{
return (backendName);
}
/*******************************************************************************
** Getter for backendName
*******************************************************************************/
public String getBackendName()
{
return (this.backendName);
}
/*******************************************************************************
** Setter for backendName
*******************************************************************************/
public void setBackendName(String backendName)
{
this.backendName = backendName;
}
/*******************************************************************************
** Fluent setter for backendName
*******************************************************************************/
public BackupsQBitConfig withBackendName(String backendName)
{
this.backendName = backendName;
return (this);
}
/*******************************************************************************
** Getter for appName
*******************************************************************************/
public String getAppName()
{
return (appName);
}
/*******************************************************************************
** Fluent setter for appName
*******************************************************************************/
public BackupsQBitConfig withAppName(String appName)
{
this.appName = appName;
return (this);
}
/*******************************************************************************
** Getter for appLabel
*******************************************************************************/
public String getAppLabel()
{
return (appLabel);
}
/*******************************************************************************
** Fluent setter for appLabel
*******************************************************************************/
public BackupsQBitConfig withAppLabel(String appLabel)
{
this.appLabel = appLabel;
return (this);
}
/*******************************************************************************
** Getter for parentAppName (for example "admin", so this is Admin, Backups).
*******************************************************************************/
public String getParentAppName()
{
return (parentAppName);
}
/*******************************************************************************
** Fluent setter for parentAppName
*******************************************************************************/
public BackupsQBitConfig withParentAppName(String parentAppName)
{
this.parentAppName = parentAppName;
return (this);
}
/*******************************************************************************
** Getter for tablePathPrefix (the front of the links the home makes to tables and
** records, "/app" for the Next dashboard, which routes /app/{table}/{id}).
*******************************************************************************/
public String getTablePathPrefix()
{
return (tablePathPrefix == null ? "/app" : tablePathPrefix);
}
/*******************************************************************************
** Fluent setter for tablePathPrefix
*******************************************************************************/
public BackupsQBitConfig withTablePathPrefix(String tablePathPrefix)
{
this.tablePathPrefix = tablePathPrefix;
return (this);
}
/*******************************************************************************
** Getter for schedulerName (the QQQ scheduler used for plan jobs and the SLA checker)
*******************************************************************************/
public String getSchedulerName()
{
return (schedulerName);
}
/*******************************************************************************
** Fluent setter for schedulerName
*******************************************************************************/
public BackupsQBitConfig withSchedulerName(String schedulerName)
{
this.schedulerName = schedulerName;
return (this);
}
/*******************************************************************************
** Getter for instanceName (used in object keys); defaults to the QInstance name
*******************************************************************************/
public String getInstanceName()
{
return (instanceName);
}
/*******************************************************************************
** Fluent setter for instanceName
*******************************************************************************/
public BackupsQBitConfig withInstanceName(String instanceName)
{
this.instanceName = instanceName;
return (this);
}
/*******************************************************************************
** Getter for maxConcurrentRuns
*******************************************************************************/
public Integer getMaxConcurrentRuns()
{
return (maxConcurrentRuns);
}
/*******************************************************************************
** Fluent setter for maxConcurrentRuns
*******************************************************************************/
public BackupsQBitConfig withMaxConcurrentRuns(Integer maxConcurrentRuns)
{
this.maxConcurrentRuns = maxConcurrentRuns;
return (this);
}
/*******************************************************************************
** Getter for slaCheckIntervalSeconds
*******************************************************************************/
public Integer getSlaCheckIntervalSeconds()
{
return (slaCheckIntervalSeconds);
}
/*******************************************************************************
** Fluent setter for slaCheckIntervalSeconds
*******************************************************************************/
public BackupsQBitConfig withSlaCheckIntervalSeconds(Integer slaCheckIntervalSeconds)
{
this.slaCheckIntervalSeconds = slaCheckIntervalSeconds;
return (this);
}
/*******************************************************************************
** Getter for openWhenAnonymous (local development only)
*******************************************************************************/
public Boolean getOpenWhenAnonymous()
{
return (openWhenAnonymous);
}
/*******************************************************************************
** Fluent setter for openWhenAnonymous
*******************************************************************************/
public BackupsQBitConfig withOpenWhenAnonymous(Boolean openWhenAnonymous)
{
this.openWhenAnonymous = openWhenAnonymous;
return (this);
}
/*******************************************************************************
** Getter for prometheusEndpoint
*******************************************************************************/
public Boolean getPrometheusEndpoint()
{
return (prometheusEndpoint);
}
/*******************************************************************************
** Fluent setter for prometheusEndpoint
*******************************************************************************/
public BackupsQBitConfig withPrometheusEndpoint(Boolean prometheusEndpoint)
{
this.prometheusEndpoint = prometheusEndpoint;
return (this);
}
/*******************************************************************************
** Getter for storageResolver
*******************************************************************************/
public Function<String, BackupStorage> getStorageResolver()
{
return (storageResolver);
}
/*******************************************************************************
** Fluent setter for storageResolver: bucket alias to storage
*******************************************************************************/
public BackupsQBitConfig withStorageResolver(Function<String, BackupStorage> storageResolver)
{
this.storageResolver = storageResolver;
return (this);
}
/*******************************************************************************
** Getter for fileReverifyDays: CONTENT verification skips file-store objects
** verified more recently than this.
*******************************************************************************/
public Integer getFileReverifyDays()
{
return (fileReverifyDays);
}
/*******************************************************************************
** Fluent setter for fileReverifyDays
*******************************************************************************/
public BackupsQBitConfig withFileReverifyDays(Integer fileReverifyDays)
{
this.fileReverifyDays = fileReverifyDays;
return (this);
}
/*******************************************************************************
** Getter for artifactTransformResolver (the decrypt hook for verify)
*******************************************************************************/
public Function<String, ArtifactTransform> getArtifactTransformResolver()
{
return (artifactTransformResolver);
}
/*******************************************************************************
** Fluent setter for artifactTransformResolver: encryption key reference (the name
** of a key in a key provider) to the transform that decrypts what that key wrote.
*******************************************************************************/
public BackupsQBitConfig withArtifactTransformResolver(Function<String, ArtifactTransform> artifactTransformResolver)
{
this.artifactTransformResolver = artifactTransformResolver;
return (this);
}
/*******************************************************************************
** Getter for scratchTarget (where TEST_RESTORE restores to; null means MEMORY)
*******************************************************************************/
public ScratchTarget getScratchTarget()
{
return (scratchTarget);
}
/*******************************************************************************
** Fluent setter for scratchTarget
*******************************************************************************/
public BackupsQBitConfig withScratchTarget(ScratchTarget scratchTarget)
{
this.scratchTarget = scratchTarget;
return (this);
}
/*******************************************************************************
** Getter for planOwnerValidator (true when the owner still exists and holds backups.admin)
*******************************************************************************/
public Predicate<String> getPlanOwnerValidator()
{
return (planOwnerValidator);
}
/*******************************************************************************
** Fluent setter for planOwnerValidator: with none, plan owners are not checked.
*******************************************************************************/
public BackupsQBitConfig withPlanOwnerValidator(Predicate<String> planOwnerValidator)
{
this.planOwnerValidator = planOwnerValidator;
return (this);
}
/*******************************************************************************
** Getter for esbDestinationName (ESB events are published here, when set)
*******************************************************************************/
public String getEsbDestinationName()
{
return (esbDestinationName);
}
/*******************************************************************************
** Fluent setter for esbDestinationName
*******************************************************************************/
public BackupsQBitConfig withEsbDestinationName(String esbDestinationName)
{
this.esbDestinationName = esbDestinationName;
return (this);
}
}