Skip to content

Commit

Permalink
Merge pull request #125 from jenkinsci/jcasc
Browse files Browse the repository at this point in the history
support jcasc and renovate plugin
  • Loading branch information
StefanSpieker authored Apr 18, 2024
2 parents d945928 + 5cc958f commit 3e9363d
Show file tree
Hide file tree
Showing 74 changed files with 1,367 additions and 1,258 deletions.
49 changes: 46 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,28 @@

This plugin simply backs up the global and job specific configurations (not the archive or the workspace). It can be scheduled and only backs up the most vital configuration info. It also let's you decide what vital means for you.

<!-- TOC -->
* [Thin Backup Plugin](#thin-backup-plugin)
* [Documentation](#documentation)
* [Backup Now](#backup-now)
* [Restore](#restore)
* [Settings](#settings)
* [Jenkins Configuration as Code (JCasC) support](#jenkins-configuration-as-code-jcasc-support)
* [Backup process](#backup-process)
* [Feature requests or bug reports](#feature-requests-or-bug-reports)
<!-- TOC -->
## Documentation

This plugin adds another management link to "Manage Jenkins" in the Tools section in newer Jenkins versions, called ThinBackup which looks like
this:
This plugin adds a management link to "Manage Jenkins" in the Tools section, called ThinBackup which looks like this:

![](images/ManagementLink.png)

This new link provides the following actions:
This link provides the following actions:

![](images/thinBackup.png)

**Note:** If you are using a version older than 2.0 this will also contain a settings button, as illustrated in [this screenshot](/images/thinBackupOld.png)

### Backup Now

Triggers a manual full back up right now.
Expand Down Expand Up @@ -48,6 +59,8 @@ update server, because plugins will be downloaded from the update server to keep

### Settings

**Note:** The settings are present in the global configuration since version 2.0

![](/images/thinBackupSettings.png)

#### Backup directory
Expand Down Expand Up @@ -137,6 +150,36 @@ as well.
**Note**: In case "Clean up differential backups" is checked, differential cleanup will be performed
before zipping is done, and therefore no differential backups will be in the ZIP files.

## Jenkins Configuration as Code (JCasC) support

Since version 2.0 the plugin fully supports JCasC. An example config as a basis can be used from here.

**Note**: Remember to escape backslashes in the YAML

```yaml
unclassified:
thinBackup:
backupAdditionalFiles: false
backupAdditionalFilesRegex: "^.*\\.(txt)$"
backupBuildArchive: false
backupBuildResults: true
backupBuildsToKeepOnly: false
backupConfigHistory: false
backupNextBuildNumber: false
backupPath: "c:\\temp\\thin-backup"
backupPluginArchives: false
backupUserContents: false
cleanupDiff: false
diffBackupSchedule: "0 12 * * 1-5"
excludedFilesRegex: "^.*\\.(log)$"
failFast: true
forceQuietModeTimeout: 120
fullBackupSchedule: "0 12 * * 1"
moveOldBackupsToZipFile: false
nrMaxStoredFull: -1
waitForIdle: true
```
## Backup process
Because many of you are asking why Jenkins is going to shutdown when a backup is triggered, I
Expand Down
Binary file modified images/restore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/thinBackup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/thinBackupOld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/thinBackupSettings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
<jenkins.version>2.401.3</jenkins.version>
<gitHubRepo>jenkinsci/thin-backup-plugin</gitHubRepo>
<spotless.check.skip>false</spotless.check.skip>
<hpi.compatibleSinceVersion>2.0</hpi.compatibleSinceVersion>
</properties>

<dependencyManagement>
Expand All @@ -93,8 +94,13 @@
<artifactId>ionicons-api</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<groupId>io.jenkins</groupId>
<artifactId>configuration-as-code</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jenkins.configuration-as-code</groupId>
<artifactId>test-harness</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import hudson.Extension;
import hudson.model.ManagementLink;
import hudson.model.TaskListener;
import hudson.util.ListBoxModel;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
Expand All @@ -35,16 +36,18 @@
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.verb.POST;

/**
* A backup solution for Hudson. Backs up configuration files from Hudson and its jobs.
*
* <p>
* Originally based on the Backup plugin by Vincent Sellier, Manufacture Fran�aise des Pneumatiques Michelin, Romain
* Seguy, et.al. Subsequently heavily modified.
*/
@Extension
public class ThinBackupMgmtLink extends ManagementLink {
private static final String THIN_BACKUP_SUBPATH = "/thinBackup";

private static final Logger LOGGER = Logger.getLogger("hudson.plugins.thinbackup");

@Override
Expand All @@ -67,14 +70,11 @@ public String getDescription() {
return "Backup your global and job specific configuration.";
}

@POST
public void doBackupManual(final StaplerRequest res, final StaplerResponse rsp) throws IOException {
LOGGER.info("Starting manual backup.");

final Jenkins jenkins = Jenkins.getInstanceOrNull();
if (jenkins == null) {
return;
}
final Jenkins jenkins = Jenkins.get();
jenkins.checkPermission(Jenkins.ADMINISTER);
LOGGER.info("Starting manual backup.");

final ThinBackupPeriodicWork manualBackupWorker = new ThinBackupPeriodicWork() {
@Override
Expand All @@ -87,6 +87,7 @@ protected void execute(final TaskListener arg0) {
rsp.sendRedirect(res.getContextPath() + THIN_BACKUP_SUBPATH);
}

@POST
public void doRestore(
final StaplerRequest res,
final StaplerResponse rsp,
Expand All @@ -96,23 +97,20 @@ public void doRestore(
throws IOException {
LOGGER.info("Starting restore operation.");

final Jenkins jenkins = Jenkins.getInstanceOrNull();
if (jenkins == null) {
return;
}
final Jenkins jenkins = Jenkins.get();
jenkins.checkPermission(Jenkins.ADMINISTER);

jenkins.doQuietDown();
LOGGER.fine("Waiting until executors are idle to perform restore...");
Utils.waitUntilIdle();

try {
final File hudsonHome = jenkins.getRootDir();
final File jenkinsHome = jenkins.getRootDir();
final Date restoreFromDate = new SimpleDateFormat(Utils.DISPLAY_DATE_FORMAT).parse(restoreBackupFrom);

final HudsonRestore hudsonRestore = new HudsonRestore(
hudsonHome,
ThinBackupPluginImpl.getInstance().getExpandedBackupPath(),
jenkinsHome,
ThinBackupPluginImpl.get().getExpandedBackupPath(),
restoreFromDate,
"on".equals(restoreNextBuildNumber),
"on".equals(restorePlugins));
Expand All @@ -129,69 +127,28 @@ public void doRestore(
}
}

public void doSaveSettings(
final StaplerRequest res,
final StaplerResponse rsp,
@QueryParameter("backupPath") final String backupPath,
@QueryParameter("fullBackupSchedule") final String fullBackupSchedule,
@QueryParameter("diffBackupSchedule") final String diffBackupSchedule,
@QueryParameter("nrMaxStoredFull") final String nrMaxStoredFull,
@QueryParameter("excludedFilesRegex") final String excludedFilesRegex,
@QueryParameter("moveOldBackupsToZipFile") final boolean moveOldBackupsToZipFile,
@QueryParameter("cleanupDiff") final boolean cleanupDiff,
@QueryParameter("backupBuildResults") final boolean backupBuildResults,
@QueryParameter("backupBuildArchive") final boolean backupBuildArchive,
@QueryParameter("backupBuildsToKeepOnly") final boolean backupBuildsToKeepOnly,
@QueryParameter("backupUserContents") final boolean backupUserContents,
@QueryParameter("backupNextBuildNumber") final boolean backupNextBuildNumber,
@QueryParameter("backupPluginArchives") final boolean backupPluginArchives,
@QueryParameter("backupAdditionalFiles") final boolean backupAdditionalFiles,
@QueryParameter("backupAdditionalFilesRegex") final String backupAdditionalFilesRegex,
@QueryParameter("waitForIdle") final boolean waitForIdle,
@QueryParameter("backupConfigHistory") final boolean backupConfigHistory,
@QueryParameter("forceQuietModeTimeout") final String forceQuietModeTimeout,
@QueryParameter("failFast") final boolean failFast)
throws IOException {
Jenkins jenkins = Jenkins.getInstanceOrNull();
if (jenkins == null) {
return;
}
jenkins.checkPermission(Jenkins.ADMINISTER);

final ThinBackupPluginImpl plugin = ThinBackupPluginImpl.getInstance();
plugin.setBackupPath(backupPath);
plugin.setFullBackupSchedule(fullBackupSchedule);
plugin.setDiffBackupSchedule(diffBackupSchedule);
plugin.setNrMaxStoredFullAsString(nrMaxStoredFull);
plugin.setExcludedFilesRegex(excludedFilesRegex);
plugin.setCleanupDiff(cleanupDiff);
plugin.setMoveOldBackupsToZipFile(moveOldBackupsToZipFile);
plugin.setBackupBuildResults(backupBuildResults);
plugin.setBackupBuildArchive(backupBuildArchive);
plugin.setBackupBuildsToKeepOnly(backupBuildsToKeepOnly);
plugin.setBackupUserContents(backupUserContents);
plugin.setBackupConfigHistory(backupConfigHistory);
plugin.setBackupNextBuildNumber(backupNextBuildNumber);
plugin.setBackupPluginArchives(backupPluginArchives);
plugin.setBackupAdditionalFiles(backupAdditionalFiles);
plugin.setBackupAdditionalFilesRegex(backupAdditionalFilesRegex);
plugin.setWaitForIdle(waitForIdle);
plugin.setForceQuietModeTimeout(Integer.parseInt(forceQuietModeTimeout));
plugin.setFailFast(failFast);
plugin.save();
LOGGER.finest("Saving backup settings done.");
rsp.sendRedirect(res.getContextPath() + THIN_BACKUP_SUBPATH);
}

public ThinBackupPluginImpl getConfiguration() {
return ThinBackupPluginImpl.getInstance();
return ThinBackupPluginImpl.get();
}

public List<String> getAvailableBackups() {
final ThinBackupPluginImpl plugin = ThinBackupPluginImpl.getInstance();
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
final ThinBackupPluginImpl plugin = ThinBackupPluginImpl.get();
return Utils.getBackupsAsDates(new File(plugin.getExpandedBackupPath()));
}

@POST
public ListBoxModel doFillBackupItems() {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
final ThinBackupPluginImpl plugin = ThinBackupPluginImpl.get();
final List<String> backupsAsDates = Utils.getBackupsAsDates(new File(plugin.getExpandedBackupPath()));
var model = new ListBoxModel();
for (String entry : backupsAsDates) {
model.add(new ListBoxModel.Option(entry));
}
return model;

Check warning on line 149 in src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupMgmtLink.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 75-149 are not covered by tests
}

/**
* Name of the category for this management link. Exists so that plugins with core dependency pre-dating the version
* when this was introduced can define a category.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/
package org.jvnet.hudson.plugins.thinbackup;

import antlr.ANTLRException;
import hudson.Extension;
import hudson.model.AsyncPeriodicWork;
import hudson.model.TaskListener;
Expand All @@ -29,7 +28,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;
import org.jvnet.hudson.plugins.thinbackup.backup.HudsonBackup;
import org.jvnet.hudson.plugins.thinbackup.utils.Utils;

Expand All @@ -38,7 +36,7 @@ public class ThinBackupPeriodicWork extends AsyncPeriodicWork {

private static final Logger LOGGER = Logger.getLogger("hudson.plugins.thinbackup");

private final ThinBackupPluginImpl plugin = ThinBackupPluginImpl.getInstance();
private final ThinBackupPluginImpl plugin = ThinBackupPluginImpl.get();

public enum BackupType {
NONE,
Expand Down Expand Up @@ -68,17 +66,14 @@ protected void execute(final TaskListener arg0) {
}

protected void backupNow(final BackupType type) {
final Jenkins jenkins = Jenkins.getInstanceOrNull();
if (jenkins == null) {
return;
}
final Jenkins jenkins = Jenkins.get();
final boolean inQuietModeBeforeBackup = jenkins.isQuietingDown();

String backupPath = null;
try {
backupPath = plugin.getExpandedBackupPath();

if (StringUtils.isNotEmpty(backupPath)) {
if (backupPath != null && !backupPath.isEmpty()) {

Check warning on line 76 in src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 69-76 are not covered by tests
if (plugin.isWaitForIdle()) {
LOGGER.fine("Wait until executors are idle to perform backup.");
Utils.waitUntilIdleAndSwitchToQuietMode(plugin.getForceQuietModeTimeout(), TimeUnit.MINUTES);
Expand Down Expand Up @@ -107,7 +102,7 @@ protected void backupNow(final BackupType type) {
}
}

BackupType getNextScheduledBackupType(final long currentTime, final String fullCron, final String diffCron) {
static BackupType getNextScheduledBackupType(final long currentTime, final String fullCron, final String diffCron) {
final long fullDelay = calculateDelay(currentTime, BackupType.FULL, fullCron);
final long diffDelay = calculateDelay(currentTime, BackupType.DIFF, diffCron);

Expand All @@ -133,10 +128,10 @@ BackupType getNextScheduledBackupType(final long currentTime, final String fullC
return delay < MIN ? res : BackupType.NONE;
}

long calculateDelay(final long currentTime, final BackupType backupType, final String cron) {
static long calculateDelay(final long currentTime, final BackupType backupType, final String cron) {
CronTab cronTab;
try {
if (StringUtils.isEmpty(cron)) {
if (cron == null || cron.isEmpty()) {

Check warning on line 134 in src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 134 is only partially covered, 2 branches are missing
return -1;
}

Expand All @@ -162,7 +157,7 @@ long calculateDelay(final long currentTime, final BackupType backupType, final S
}

return delay;
} catch (final ANTLRException e) {
} catch (final IllegalArgumentException e) {

Check warning on line 160 in src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 160 is not covered by tests
LOGGER.warning(MessageFormat.format(
"Cannot parse the specified ''Backup schedule for {0} backups''. Check cron notation.",
backupType));
Expand Down
Loading

0 comments on commit 3e9363d

Please sign in to comment.