├── .git-blame-ignore-revs ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── cd.yaml │ └── jenkins-security-scan.yml ├── .gitignore ├── .mvn ├── extensions.xml └── maven.config ├── Jenkinsfile ├── LICENSE.md ├── README.md ├── docs └── images │ └── support_page.png ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── cloudbees │ │ └── jenkins │ │ └── support │ │ ├── AsyncResultCache.java │ │ ├── BundleFileName.java │ │ ├── BundleNameInstanceTypeProvider.java │ │ ├── DefaultSupportMetricsFilter.java │ │ ├── SupportAction.java │ │ ├── SupportCommand.java │ │ ├── SupportContextImpl.java │ │ ├── SupportLogHandler.java │ │ ├── SupportMetricsFilter.java │ │ ├── SupportPlugin.java │ │ ├── actions │ │ ├── SupportAbstractItemAction.java │ │ ├── SupportComputerAction.java │ │ ├── SupportObjectAction.java │ │ └── SupportRunAction.java │ │ ├── api │ │ ├── BaseCommandOutputContent.java │ │ ├── BaseFileContent.java │ │ ├── CommandOutputContent.java │ │ ├── Component.java │ │ ├── ComponentVisitor.java │ │ ├── Container.java │ │ ├── Content.java │ │ ├── FileContent.java │ │ ├── FilePathContent.java │ │ ├── GenerateOnDemandContent.java │ │ ├── LaunchLogsFileContent.java │ │ ├── ObjectComponent.java │ │ ├── ObjectComponentDescriptor.java │ │ ├── PrefilteredPrintedContent.java │ │ ├── PrintedContent.java │ │ ├── StringContent.java │ │ ├── SupportContext.java │ │ ├── SupportProvider.java │ │ ├── SupportProviderDescriptor.java │ │ ├── TemporaryFileContent.java │ │ ├── TruncatedContent.java │ │ ├── TruncationException.java │ │ ├── UnfilteredCommandOutputContent.java │ │ ├── UnfilteredFileContent.java │ │ └── UnfilteredStringContent.java │ │ ├── config │ │ ├── SupportAutomatedBundleConfiguration.java │ │ ├── SupportPluginConfigurationCategory.java │ │ └── SupportPluginManagement.java │ │ ├── configfiles │ │ ├── AgentsConfigFile.java │ │ ├── ConfigFileComponent.java │ │ ├── OtherConfigFilesComponent.java │ │ ├── SecretHandler.java │ │ └── XmlRedactedSecretFileContent.java │ │ ├── filter │ │ ├── AdditionalFromFileStopWords.java │ │ ├── AllAsciiCharactersStopWords.java │ │ ├── AllContentFilters.java │ │ ├── AllowedOSNamesStopWords.java │ │ ├── ContentFilter.java │ │ ├── ContentFilters.java │ │ ├── ContentMapping.java │ │ ├── ContentMappings.java │ │ ├── DataFaker.java │ │ ├── DefaultStopWords.java │ │ ├── FilteredConstants.java │ │ ├── FilteredInputStream.java │ │ ├── FilteredOutputStream.java │ │ ├── FilteredWriter.java │ │ ├── InetAddressContentFilter.java │ │ ├── NameProvider.java │ │ ├── NoneFilter.java │ │ ├── PasswordRedactor.java │ │ ├── PasswordRedactorRegexBuilder.java │ │ ├── PluginsStopWords.java │ │ ├── PrefilteredContent.java │ │ ├── SensitiveContentFilter.java │ │ ├── StopWords.java │ │ └── WordsTrie.java │ │ ├── impl │ │ ├── AboutBrowser.java │ │ ├── AboutJenkins.java │ │ ├── AboutUser.java │ │ ├── AbstractItemDirectoryComponent.java │ │ ├── AdministrativeMonitors.java │ │ ├── AdvancedProcFilesRetriever.java │ │ ├── BuildQueue.java │ │ ├── CustomLogs.java │ │ ├── DirectoryComponent.java │ │ ├── DumpExportTable.java │ │ ├── EnvironmentVariables.java │ │ ├── FileDescriptorLimit.java │ │ ├── GCLogs.java │ │ ├── HeapUsageHistogram.java │ │ ├── ItemsContent.java │ │ ├── JVMProcessSystemMetricsContents.java │ │ ├── JenkinsLogs.java │ │ ├── LoadStats.java │ │ ├── LogFilenameAgentFilter.java │ │ ├── LogFilenameFilter.java │ │ ├── LogRecordContent.java │ │ ├── LoggerManager.java │ │ ├── Metrics.java │ │ ├── MetricsContent.java │ │ ├── NetworkInterfaces.java │ │ ├── NodeExecutors.java │ │ ├── NodeMonitors.java │ │ ├── NodeRemoteDirectoryComponent.java │ │ ├── OtherLogs.java │ │ ├── ProcFilesRetriever.java │ │ ├── ProxyConfiguration.java │ │ ├── RemotingDiagnostics.java │ │ ├── ReverseProxy.java │ │ ├── RootCAs.java │ │ ├── RunDirectoryComponent.java │ │ ├── RunningBuilds.java │ │ ├── SlaveCommandStatistics.java │ │ ├── SlaveLaunchLogs.java │ │ ├── SlaveLogs.java │ │ ├── SmartLogCleaner.java │ │ ├── SmartLogFetcher.java │ │ ├── SystemConfiguration.java │ │ ├── SystemProperties.java │ │ ├── TaskLogs.java │ │ ├── ThreadDumps.java │ │ ├── UpdateCenter.java │ │ ├── UserCount.java │ │ └── WinswLogfileFilter.java │ │ ├── slowrequest │ │ ├── InflightRequest.java │ │ ├── SlowRequestChecker.java │ │ ├── SlowRequestComponent.java │ │ ├── SlowRequestFilter.java │ │ ├── SlowRequestThreadDumpsComponent.java │ │ └── SlowRequestThreadDumpsGenerator.java │ │ ├── startup │ │ ├── ShutdownComponent.java │ │ ├── StartupComponent.java │ │ └── StartupReport.java │ │ ├── threaddump │ │ ├── HighLoadComponent.java │ │ └── HighLoadCpuChecker.java │ │ ├── timer │ │ ├── DeadlockRequestComponent.java │ │ ├── DeadlockTrackChecker.java │ │ ├── FileListCap.java │ │ ├── FileListCapComponent.java │ │ └── UnfilteredFileListCapComponent.java │ │ └── util │ │ ├── CallAsyncWrapper.java │ │ ├── Helper.java │ │ ├── IgnoreCloseOutputStream.java │ │ ├── IgnoreCloseWriter.java │ │ ├── Markdown.java │ │ ├── OutputStreamSelector.java │ │ ├── Persistence.java │ │ ├── StreamUtils.java │ │ ├── SystemPlatform.java │ │ ├── WordReplacer.java │ │ └── WrapperOutputStream.java ├── resources │ ├── com │ │ └── cloudbees │ │ │ └── jenkins │ │ │ └── support │ │ │ ├── Messages.properties │ │ │ ├── SupportAction │ │ │ ├── action.jelly │ │ │ ├── index.jelly │ │ │ ├── index.properties │ │ │ └── progressPage.jelly │ │ │ ├── SupportPlugin │ │ │ └── GlobalConfigurationImpl │ │ │ │ └── config.jelly │ │ │ ├── actions │ │ │ ├── Messages.properties │ │ │ ├── SupportAbstractItemAction │ │ │ │ ├── action.jelly │ │ │ │ └── index.jelly │ │ │ ├── SupportComputerAction │ │ │ │ ├── action.jelly │ │ │ │ └── index.jelly │ │ │ └── SupportRunAction │ │ │ │ ├── action.jelly │ │ │ │ └── index.jelly │ │ │ ├── api │ │ │ ├── ObjectComponent │ │ │ │ └── config.jelly │ │ │ └── SupportProvider │ │ │ │ └── config.jelly │ │ │ ├── config │ │ │ ├── Messages.properties │ │ │ ├── SupportAutomatedBundleConfiguration │ │ │ │ ├── components.jelly │ │ │ │ ├── config.jelly │ │ │ │ ├── config.properties │ │ │ │ ├── help-components.html │ │ │ │ ├── help-enabled.html │ │ │ │ └── help-period.html │ │ │ └── SupportPluginManagement │ │ │ │ ├── index.jelly │ │ │ │ └── sidepanel.jelly │ │ │ ├── configfiles │ │ │ └── Messages.properties │ │ │ ├── filter │ │ │ ├── ContentFilters │ │ │ │ └── config.jelly │ │ │ ├── ContentMappings │ │ │ │ └── index.jelly │ │ │ └── Messages.properties │ │ │ ├── impl │ │ │ ├── AbstractItemDirectoryComponent │ │ │ │ └── help.html │ │ │ ├── DirectoryComponent │ │ │ │ ├── component.jelly │ │ │ │ ├── help-defaultExcludes.groovy │ │ │ │ ├── help-defaultExcludes.properties │ │ │ │ ├── help-excludes.html │ │ │ │ ├── help-includes.html │ │ │ │ └── help-maxDepth.html │ │ │ ├── Messages.properties │ │ │ ├── NodeRemoteDirectoryComponent │ │ │ │ └── help.html │ │ │ └── RunDirectoryComponent │ │ │ │ └── help.html │ │ │ └── threaddump │ │ │ └── Messages.properties │ ├── index.jelly │ └── js │ │ └── progressPage.js └── webapp │ └── images │ └── support.svg ├── spotbugs └── excludesFilter.xml └── test ├── java └── com │ └── cloudbees │ └── jenkins │ └── support │ ├── BundleFileNameTest.java │ ├── BundleNamePrefixTest.java │ ├── CasCTest.java │ ├── CheckFilterTest.java │ ├── Security2186Test.java │ ├── SupportActionTest.java │ ├── SupportPluginTest.java │ ├── SupportTestUtils.java │ ├── actions │ ├── SupportAbstractItemActionTest.java │ ├── SupportComputerActionTest.java │ └── SupportRunActionTest.java │ ├── api │ └── FileContentTest.java │ ├── config │ ├── SupportAutomatedBundleConfigurationSystemPropertiesTest.java │ └── SupportAutomatedBundleConfigurationTest.java │ ├── configfiles │ ├── AgentsConfigFileTest.java │ ├── OtherConfigFilesComponentTest.java │ └── SecretHandlerTest.java │ ├── filter │ ├── ContentMappingsTest.java │ ├── FilteredInputStreamTest.java │ ├── FilteredOutputStreamTest.java │ ├── FilteredWriterTest.java │ ├── InetAddressContentFilterTest.java │ ├── PasswordRedactorRegexBuilderTest.java │ ├── PasswordRedactorTest.java │ └── SensitiveContentFilterTest.java │ ├── impl │ ├── AboutJenkinsTest.java │ ├── AbstractItemDirectoryComponentTest.java │ ├── AdministrativeMonitorsTest.java │ ├── BuildQueueTest.java │ ├── CustomLogsTest.java │ ├── DumpExportTableTest.java │ ├── FileDescriptorLimitTest.java │ ├── GCLogsTest.java │ ├── ItemsContentTest.java │ ├── JenkinsLogsTest.java │ ├── NetworkInterfacesTest.java │ ├── NodeExecutorsTest.java │ ├── NodeRemoteDirectoryComponentTest.java │ ├── OtherLogsTest.java │ ├── ProxyConfigurationTest.java │ ├── ReverseProxyTest.java │ ├── RootCAsTest.java │ ├── RunDirectoryComponentTest.java │ ├── RunningBuildsTest.java │ ├── SlaveCommandStatisticsTest.java │ ├── SlaveLaunchLogsRestartTest.java │ ├── SlaveLaunchLogsTest.java │ ├── SmartLogCleanerTest.java │ ├── TaskLogsTest.java │ ├── UpdateCenterTest.java │ └── UserCountTest.java │ ├── measures │ └── ChronoTest.java │ ├── slowrequest │ └── InflightRequestTest.java │ ├── startup │ ├── ShutdownComponentTest.java │ └── StartupReportTest.java │ ├── timer │ ├── DeadlockTest.java │ └── FileListCapTest.java │ └── util │ ├── Chrono.java │ ├── IgnoreCloseOutputStreamTest.java │ ├── IgnoreCloseWriterTest.java │ ├── MarkdownTest.java │ ├── OutputStreamSelectorTest.java │ ├── StreamUtilsTest.java │ └── WordReplacerTest.java └── resources ├── com └── cloudbees │ └── jenkins │ └── support │ ├── api │ └── non-utf8.txt │ ├── configuration-as-code.yaml │ └── filter │ └── ContentMappingsTest │ ├── additionalStopWordsIncludedAsStopWord │ └── support │ │ └── additional-stop-words.txt │ ├── jenkinsVersionIncludedAsStopWord │ ├── com.cloudbees.jenkins.support.filter.ContentFilters.xml │ └── com.cloudbees.jenkins.support.filter.ContentMappings.xml │ └── operatingSystemIncludedAsStopWord │ ├── com.cloudbees.jenkins.support.filter.ContentFilters.xml │ └── com.cloudbees.jenkins.support.filter.ContentMappings.xml └── images └── support.png /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # https://github.com/jenkinsci/support-core-plugin/pull/490 2 | f7a50cf1b106f37bb8ae076d25c91d1f9ef87e87 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/support-core-plugin-developers -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: github-actions 8 | directory: / 9 | schedule: 10 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | maven-cd: 12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 13 | secrets: 14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: [ opened, synchronize, reopened ] 8 | workflow_dispatch: 9 | 10 | permissions: 11 | security-events: write 12 | contents: read 13 | actions: read 14 | 15 | jobs: 16 | security-scan: 17 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 18 | with: 19 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 20 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven build files 2 | target/ 3 | 4 | # Jenkins plugin development 5 | work/ 6 | 7 | # IntelliJ project files 8 | *.iml 9 | *.ipr 10 | *.iws 11 | .idea/ 12 | 13 | # Eclipse project files 14 | .settings/ 15 | .classpath 16 | .project 17 | .metadata 18 | .loadpath 19 | 20 | # NetBeans project files 21 | nbproject/private/ 22 | build/ 23 | nbbuild/ 24 | dist/ 25 | nbdist/ 26 | nbactions.xml 27 | nb-configuration.xml 28 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.8 6 | 7 | 8 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | See the documentation for more options: 3 | https://github.com/jenkins-infra/pipeline-library/ 4 | */ 5 | buildPlugin( 6 | forkCount: '1C', // run this number of tests in parallel for faster feedback. If the number terminates with a 'C', the value will be multiplied by the number of available CPU cores 7 | useContainerAgent: true, // Set to `false` if you need to use Docker for containerized tests 8 | configurations: [ 9 | [platform: 'linux', jdk: 21], 10 | [platform: 'windows', jdk: 17], 11 | ]) 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013-, Stephen Connolly, Jesse Glick, Steven Christou, CloudBees, Inc., and a number of other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/images/support_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/support-core-plugin/a2a9f06eed6188fb78f636ad9b2e6ba5c048ea88/docs/images/support_page.png -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/DefaultSupportMetricsFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support; 26 | 27 | import com.codahale.metrics.MetricRegistry; 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | 31 | /** 32 | * A default metrics filter. 33 | * 34 | * @author Stephen Connolly 35 | */ 36 | public class DefaultSupportMetricsFilter extends SupportMetricsFilter { 37 | private static final String NAME_PREFIX = "responseCodes."; 38 | private static final int OK = 200; 39 | private static final int CREATED = 201; 40 | private static final int NO_CONTENT = 204; 41 | private static final int BAD_REQUEST = 400; 42 | private static final int NOT_FOUND = 404; 43 | private static final int SERVER_ERROR = 500; 44 | 45 | /** 46 | * Creates a new instance of the filter. 47 | * 48 | * @param registry Metric registry to use. 49 | */ 50 | public DefaultSupportMetricsFilter(MetricRegistry registry) { 51 | super(registry, createMeterNamesByStatusCode(), NAME_PREFIX + "other"); 52 | } 53 | 54 | private static Map createMeterNamesByStatusCode() { 55 | final Map meterNamesByStatusCode = new HashMap(6); 56 | meterNamesByStatusCode.put(OK, NAME_PREFIX + "ok"); 57 | meterNamesByStatusCode.put(CREATED, NAME_PREFIX + "created"); 58 | meterNamesByStatusCode.put(NO_CONTENT, NAME_PREFIX + "noContent"); 59 | meterNamesByStatusCode.put(BAD_REQUEST, NAME_PREFIX + "badRequest"); 60 | meterNamesByStatusCode.put(NOT_FOUND, NAME_PREFIX + "notFound"); 61 | meterNamesByStatusCode.put(SERVER_ERROR, NAME_PREFIX + "serverError"); 62 | return meterNamesByStatusCode; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/SupportContextImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support; 26 | 27 | import com.cloudbees.jenkins.support.api.SupportContext; 28 | import com.codahale.metrics.MetricRegistry; 29 | import com.codahale.metrics.health.HealthCheckRegistry; 30 | import jenkins.metrics.api.Metrics; 31 | 32 | /** 33 | * The implementation of {@link SupportContext} 34 | * 35 | * @author Stephen Connolly 36 | * @deprecated usage removed 37 | */ 38 | @Deprecated 39 | public class SupportContextImpl implements SupportContext { 40 | 41 | @Deprecated 42 | public SupportContextImpl() {} 43 | 44 | /** 45 | * {@inheritDoc} 46 | * @deprecated 47 | */ 48 | @Deprecated 49 | public MetricRegistry getMetricsRegistry() { 50 | return Metrics.metricRegistry(); 51 | } 52 | 53 | /** 54 | * {@inheritDoc} 55 | * @deprecated 56 | */ 57 | @Deprecated 58 | public HealthCheckRegistry getHealthCheckRegistry() { 59 | return Metrics.healthCheckRegistry(); 60 | } 61 | 62 | @Deprecated 63 | public void shutdown() {} 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/actions/SupportAbstractItemAction.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.actions; 2 | 3 | import com.cloudbees.jenkins.support.filter.ContentFilters; 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import hudson.Extension; 6 | import hudson.model.AbstractItem; 7 | import hudson.model.Action; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import jenkins.model.TransientActionFactory; 11 | import org.kohsuke.accmod.Restricted; 12 | import org.kohsuke.accmod.restrictions.NoExternalUse; 13 | import org.kohsuke.stapler.DataBoundConstructor; 14 | 15 | /** 16 | * A {@link SupportObjectAction} applicable to {@link AbstractItem}. 17 | */ 18 | public class SupportAbstractItemAction extends SupportObjectAction { 19 | 20 | @DataBoundConstructor 21 | public SupportAbstractItemAction(AbstractItem target) { 22 | super(target); 23 | } 24 | 25 | @Override 26 | public String getDisplayName() { 27 | return Messages.SupportItemAction_DisplayName(getObject().getPronoun()); 28 | } 29 | 30 | @Override 31 | protected String getBundleNameQualifier() { 32 | return "item"; 33 | } 34 | 35 | @Restricted(NoExternalUse.class) // stapler 36 | @SuppressWarnings("unused") // used by Stapler 37 | public boolean isAnonymized() { 38 | return ContentFilters.get().isEnabled(); 39 | } 40 | 41 | @Extension 42 | public static class Factory extends TransientActionFactory { 43 | 44 | @Override 45 | public Class type() { 46 | return AbstractItem.class; 47 | } 48 | 49 | @NonNull 50 | @Override 51 | public Collection createFor(@NonNull AbstractItem item) { 52 | return Collections.singleton(new SupportAbstractItemAction(item)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/actions/SupportComputerAction.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.actions; 2 | 3 | import com.cloudbees.jenkins.support.filter.ContentFilters; 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import hudson.Extension; 6 | import hudson.model.Action; 7 | import hudson.model.Computer; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import jenkins.model.Jenkins; 11 | import jenkins.model.TransientActionFactory; 12 | import org.kohsuke.accmod.Restricted; 13 | import org.kohsuke.accmod.restrictions.NoExternalUse; 14 | import org.kohsuke.stapler.DataBoundConstructor; 15 | 16 | /** 17 | * A {@link SupportObjectAction} applicable to {@link Computer}. 18 | */ 19 | public class SupportComputerAction extends SupportObjectAction { 20 | 21 | @DataBoundConstructor 22 | public SupportComputerAction(Computer target) { 23 | super(target); 24 | } 25 | 26 | @Override 27 | public String getDisplayName() { 28 | return Messages.SupportComputerAction_DisplayName(); 29 | } 30 | 31 | @Override 32 | protected String getBundleNameQualifier() { 33 | return "agent"; 34 | } 35 | 36 | @Restricted(NoExternalUse.class) // stapler 37 | @SuppressWarnings("unused") // used by Stapler 38 | public boolean isAnonymized() { 39 | return ContentFilters.get().isEnabled(); 40 | } 41 | 42 | @Extension 43 | public static class Factory extends TransientActionFactory { 44 | 45 | @Override 46 | public Class type() { 47 | return Computer.class; 48 | } 49 | 50 | @NonNull 51 | @Override 52 | public Collection createFor(@NonNull Computer computer) { 53 | if (computer == Jenkins.get().toComputer()) { 54 | return Collections.emptyList(); 55 | } 56 | return Collections.singleton(new SupportComputerAction(computer)); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/actions/SupportRunAction.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.actions; 2 | 3 | import com.cloudbees.jenkins.support.filter.ContentFilters; 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import hudson.Extension; 6 | import hudson.model.Action; 7 | import hudson.model.Run; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import jenkins.model.TransientActionFactory; 11 | import org.kohsuke.accmod.Restricted; 12 | import org.kohsuke.accmod.restrictions.NoExternalUse; 13 | import org.kohsuke.stapler.DataBoundConstructor; 14 | 15 | /** 16 | * A {@link SupportObjectAction} applicable to {@link Run}. 17 | */ 18 | public class SupportRunAction extends SupportObjectAction { 19 | 20 | @DataBoundConstructor 21 | public SupportRunAction(Run target) { 22 | super(target); 23 | } 24 | 25 | @Override 26 | public String getDisplayName() { 27 | return Messages.SupportRunAction_DisplayName(getObject().getParent().getTaskNoun()); 28 | } 29 | 30 | @Override 31 | protected String getBundleNameQualifier() { 32 | return "build"; 33 | } 34 | 35 | @Restricted(NoExternalUse.class) // stapler 36 | @SuppressWarnings("unused") // used by Stapler 37 | public boolean isAnonymized() { 38 | return ContentFilters.get().isEnabled(); 39 | } 40 | 41 | @Extension 42 | public static class Factory extends TransientActionFactory { 43 | 44 | @Override 45 | public Class type() { 46 | return Run.class; 47 | } 48 | 49 | @NonNull 50 | @Override 51 | public Collection createFor(@NonNull Run run) { 52 | return Collections.singleton(new SupportRunAction(run)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/CommandOutputContent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.api; 2 | 3 | import hudson.model.Node; 4 | import java.util.WeakHashMap; 5 | 6 | /** 7 | * Content of a command output. You can only instantiate this content with 8 | * a builder method which launch the command immediately. 9 | */ 10 | public class CommandOutputContent extends StringContent { 11 | private CommandOutputContent(String name, String[] filterableParameters, String value) { 12 | super(name, filterableParameters, value); 13 | } 14 | 15 | public static CommandOutputContent runOnNode(Node node, String name, String... command) { 16 | return runOnNode(node, name, null, command); 17 | } 18 | 19 | public static CommandOutputContent runOnNode( 20 | Node node, String name, String[] filterableParameters, String... command) { 21 | String content = BaseCommandOutputContent.runOnNode(node, command); 22 | return new CommandOutputContent(name, filterableParameters, content); 23 | } 24 | 25 | public static CommandOutputContent runOnNodeAndCache( 26 | WeakHashMap cache, Node node, String name, String... command) { 27 | return runOnNodeAndCache(cache, node, name, null, command); 28 | } 29 | 30 | public static CommandOutputContent runOnNodeAndCache( 31 | WeakHashMap cache, Node node, String name, String[] filterableParameters, String... command) { 32 | String content = BaseCommandOutputContent.runOnNodeAndCache(cache, node, command); 33 | return new CommandOutputContent(name, filterableParameters, content); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/ComponentVisitor.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.api; 2 | 3 | /** 4 | * A Visitor that define actions to carry out when visiting {@link Component}s. 5 | */ 6 | public interface ComponentVisitor { 7 | 8 | /** 9 | * Call for each {@link Component}. 10 | * 11 | * @param container a {@link Container} 12 | * @param component the {@link Component} being visited 13 | * @param must be a subclass of {@link Component} 14 | */ 15 | void visit(Container container, T component); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/Container.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.api; 26 | 27 | import com.cloudbees.jenkins.support.SupportPlugin; 28 | import edu.umd.cs.findbugs.annotations.CheckForNull; 29 | import java.io.OutputStream; 30 | import java.util.List; 31 | 32 | /** 33 | * Represents something that can contain {@link Content} 34 | * 35 | * @author Stephen Connolly 36 | */ 37 | public abstract class Container { 38 | public abstract void add(@CheckForNull Content content); 39 | 40 | /** 41 | * The set of components which are being asked to contribute to this bundle, if known. 42 | * @return the set of components, if known; null if not 43 | * @see SupportPlugin#writeBundle(OutputStream, List) 44 | */ 45 | @CheckForNull 46 | public List getComponents() { 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/GenerateOnDemandContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.api; 26 | 27 | import java.io.IOException; 28 | import java.io.OutputStream; 29 | 30 | /** 31 | * Content that is generated when required. 32 | * 33 | * @author Stephen Connolly 34 | */ 35 | public abstract class GenerateOnDemandContent extends Content { 36 | public GenerateOnDemandContent(String name) { 37 | super(name); 38 | } 39 | 40 | public GenerateOnDemandContent(String name, String... filterableParameters) { 41 | super(name, filterableParameters); 42 | } 43 | 44 | public abstract void writeTo(OutputStream os) throws IOException; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/LaunchLogsFileContent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.api; 2 | 3 | import com.cloudbees.jenkins.support.filter.FilteredInputStream; 4 | import com.cloudbees.jenkins.support.filter.PasswordRedactor; 5 | import com.cloudbees.jenkins.support.impl.SlaveLaunchLogs; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.nio.charset.Charset; 11 | import java.util.function.Function; 12 | 13 | /** 14 | * @see SlaveLaunchLogs 15 | */ 16 | public class LaunchLogsFileContent extends FileContent { 17 | 18 | public LaunchLogsFileContent(String name, String[] filterableParameters, File file, long maxSize) { 19 | super(name, filterableParameters, file, maxSize); 20 | } 21 | 22 | @Override 23 | protected InputStream getInputStream() throws IOException { 24 | Function filter = PasswordRedactor.get()::redact; 25 | return new FilteredInputStream(new FileInputStream(file), Charset.defaultCharset(), filter); 26 | } 27 | 28 | @Override 29 | protected String getSimpleValueOrRedactedPassword(String value) { 30 | return PasswordRedactor.get().redact(value); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/ObjectComponentDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.api; 2 | 3 | import hudson.model.AbstractModelObject; 4 | import hudson.model.Descriptor; 5 | 6 | /** 7 | * Descriptor of {@link ObjectComponent} 8 | * 9 | * @param The object type that the {@link ObjectComponent} handles. 10 | */ 11 | public class ObjectComponentDescriptor extends Descriptor> {} 12 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/StringContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.api; 26 | 27 | import com.cloudbees.jenkins.support.filter.ContentFilter; 28 | import com.cloudbees.jenkins.support.filter.PrefilteredContent; 29 | import edu.umd.cs.findbugs.annotations.NonNull; 30 | import java.io.IOException; 31 | import java.io.OutputStream; 32 | import java.nio.charset.StandardCharsets; 33 | 34 | /** 35 | * Content that is a string. 36 | * 37 | * @author Stephen Connolly 38 | */ 39 | public class StringContent extends PrefilteredContent { 40 | 41 | private final String value; 42 | 43 | public StringContent(String name, String value) { 44 | super(name); 45 | this.value = value; 46 | } 47 | 48 | public StringContent(String name, String[] filterableParameters, String value) { 49 | super(name, filterableParameters); 50 | this.value = value; 51 | } 52 | 53 | @Override 54 | public void writeTo(OutputStream os) throws IOException { 55 | writeTo(os, ContentFilter.NONE); 56 | } 57 | 58 | @Override 59 | public void writeTo(OutputStream os, @NonNull ContentFilter filter) throws IOException { 60 | String filtered = ContentFilter.filter(filter, value); 61 | os.write(filtered.getBytes(StandardCharsets.UTF_8)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/SupportContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.api; 26 | 27 | import com.codahale.metrics.MetricRegistry; 28 | import com.codahale.metrics.health.HealthCheckRegistry; 29 | 30 | /** 31 | * The context that a {@link Component} is being instantiated in. 32 | * 33 | * @author Stephen Connolly 34 | * @deprecated usage removed 35 | */ 36 | @Deprecated 37 | public interface SupportContext { 38 | /** 39 | * Returns the {@link MetricRegistry} for the current Jenkins. 40 | * 41 | * @return the {@link MetricRegistry} for the current Jenkins. 42 | * @deprecated use {@link jenkins.metrics.api.Metrics#metricRegistry()} 43 | */ 44 | @Deprecated 45 | MetricRegistry getMetricsRegistry(); 46 | 47 | /** 48 | * Returns the {@link HealthCheckRegistry} for the current. 49 | * 50 | * @return the {@link HealthCheckRegistry} for the current. 51 | * @deprecated use {@link jenkins.metrics.api.Metrics#healthCheckRegistry()} 52 | */ 53 | @Deprecated 54 | HealthCheckRegistry getHealthCheckRegistry(); 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/SupportProviderDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.api; 26 | 27 | import hudson.model.Descriptor; 28 | 29 | /** 30 | * Base class for {@link Descriptor}s of {@link SupportProvider} 31 | * 32 | * @author Stephen Connolly 33 | */ 34 | public abstract class SupportProviderDescriptor extends Descriptor { 35 | 36 | /** 37 | * Construct a default instance of the {@link SupportProvider}. This method is used when there is no current 38 | * selected {@link SupportProvider} and this provider has been selected to act as the default {@link 39 | * SupportProvider} 40 | * 41 | * @return the instance. 42 | */ 43 | public SupportProvider newDefaultInstance() { 44 | try { 45 | return clazz.newInstance(); 46 | } catch (InstantiationException e) { 47 | throw new RuntimeException("Failed to instantiate " + clazz, e); 48 | } catch (IllegalAccessException e) { 49 | throw new RuntimeException("Failed to instantiate " + clazz, e); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/TemporaryFileContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2016, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.cloudbees.jenkins.support.api; 25 | 26 | import com.cloudbees.jenkins.support.filter.ContentFilter; 27 | import hudson.Util; 28 | import java.io.File; 29 | import java.io.IOException; 30 | import java.io.OutputStream; 31 | import java.util.logging.Level; 32 | import java.util.logging.Logger; 33 | 34 | /** 35 | * Temporary file content, auto-deleted after {@link #writeTo(OutputStream)}. 36 | */ 37 | public class TemporaryFileContent extends FileContent { 38 | 39 | private File f; 40 | 41 | public TemporaryFileContent(String name, File file) { 42 | super(name, file); 43 | f = file; 44 | } 45 | 46 | public TemporaryFileContent(String name, String[] filterableParameters, File file) { 47 | super(name, filterableParameters, file); 48 | f = file; 49 | } 50 | 51 | @Override 52 | public void writeTo(OutputStream os) throws IOException { 53 | try { 54 | super.writeTo(os); 55 | } finally { 56 | delete(); 57 | } 58 | } 59 | 60 | @Override 61 | public void writeTo(OutputStream os, ContentFilter filter) throws IOException { 62 | try { 63 | super.writeTo(os, filter); 64 | } finally { 65 | delete(); 66 | } 67 | } 68 | 69 | private void delete() { 70 | try { 71 | Util.deleteFile(f); 72 | } catch (IOException e) { 73 | LOGGER.log(Level.WARNING, "Failed to delete tmp file " + f.getAbsolutePath(), e); 74 | } 75 | } 76 | 77 | private static final Logger LOGGER = Logger.getLogger(TemporaryFileContent.class.getName()); 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/TruncationException.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.api; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Limit size for a specific file has been reached, and has been truncated. 7 | * 8 | * @author schristou 9 | */ 10 | public class TruncationException extends IOException { 11 | public TruncationException(String message) { 12 | super(message); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/UnfilteredCommandOutputContent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.api; 2 | 3 | import hudson.model.Node; 4 | import java.util.WeakHashMap; 5 | 6 | /** 7 | * Content of a command output. You can only instantiate this content with 8 | * a builder method which launches the command immediately. It doesn't pre filter the result. 9 | */ 10 | public class UnfilteredCommandOutputContent extends UnfilteredStringContent { 11 | private UnfilteredCommandOutputContent(String name, String[] filterableParameters, String value) { 12 | super(name, filterableParameters, value); 13 | } 14 | 15 | public static UnfilteredCommandOutputContent runOnNode(Node node, String name, String... command) { 16 | return runOnNode(node, name, null, command); 17 | } 18 | 19 | public static UnfilteredCommandOutputContent runOnNode( 20 | Node node, String name, String[] filterableParameters, String... command) { 21 | String content = BaseCommandOutputContent.runOnNode(node, command); 22 | return new UnfilteredCommandOutputContent(name, filterableParameters, content); 23 | } 24 | 25 | public static UnfilteredCommandOutputContent runOnNodeAndCache( 26 | WeakHashMap cache, Node node, String name, String... command) { 27 | return runOnNodeAndCache(cache, node, name, null, command); 28 | } 29 | 30 | public static UnfilteredCommandOutputContent runOnNodeAndCache( 31 | WeakHashMap cache, Node node, String name, String[] filterableParameters, String... command) { 32 | String content = BaseCommandOutputContent.runOnNodeAndCache(cache, node, command); 33 | return new UnfilteredCommandOutputContent(name, filterableParameters, content); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/api/UnfilteredStringContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.api; 26 | 27 | import java.io.IOException; 28 | import java.io.OutputStream; 29 | 30 | /** 31 | * Content that is a string and cannot be pre-filtered. 32 | * 33 | * @author M Ramón León 34 | */ 35 | public class UnfilteredStringContent extends Content { 36 | 37 | private final String value; 38 | 39 | public UnfilteredStringContent(String name, String value) { 40 | super(name); 41 | this.value = value; 42 | } 43 | 44 | public UnfilteredStringContent(String name, String[] filterableParameters, String value) { 45 | super(name, filterableParameters); 46 | this.value = value; 47 | } 48 | 49 | @Override 50 | public void writeTo(OutputStream os) throws IOException { 51 | os.write(value.getBytes("utf-8")); 52 | } 53 | 54 | @Override 55 | public boolean shouldBeFiltered() { 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/config/SupportPluginConfigurationCategory.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.config; 2 | 3 | import hudson.Extension; 4 | import jenkins.model.GlobalConfigurationCategory; 5 | import org.jenkinsci.Symbol; 6 | 7 | /** 8 | * A {@link GlobalConfigurationCategory} for the global configuration implementation for Support Core. 9 | * 10 | * @author Allan Burdajewicz 11 | */ 12 | @Extension 13 | @Symbol({"support"}) 14 | public class SupportPluginConfigurationCategory extends GlobalConfigurationCategory { 15 | @Override 16 | public String getShortDescription() { 17 | return com.cloudbees.jenkins.support.config.Messages.SupportPluginConfigurationCategory_shortDescription(); 18 | } 19 | 20 | @Override 21 | public String getDisplayName() { 22 | return com.cloudbees.jenkins.support.config.Messages.SupportPluginConfigurationCategory_displayName(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/configfiles/ConfigFileComponent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.configfiles; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import hudson.Extension; 7 | import hudson.security.Permission; 8 | import java.io.File; 9 | import java.util.Collections; 10 | import java.util.Set; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | import jenkins.model.Jenkins; 14 | 15 | /** 16 | * Support component to add config.xml to the support bundle. 17 | */ 18 | @Extension 19 | public class ConfigFileComponent extends Component { 20 | @NonNull 21 | @Override 22 | public Set getRequiredPermissions() { 23 | return Collections.singleton(Jenkins.ADMINISTER); 24 | } 25 | 26 | @NonNull 27 | @Override 28 | public String getDisplayName() { 29 | return "Jenkins Global Configuration File (Encrypted secrets are redacted)"; 30 | } 31 | 32 | @Override 33 | public void addContents(@NonNull Container container) { 34 | Jenkins jenkins = Jenkins.get(); 35 | File configFile = new File(jenkins.getRootDir(), "config.xml"); 36 | if (configFile.exists()) { 37 | container.add(new XmlRedactedSecretFileContent( 38 | "jenkins-root-configuration-files/{0}", new String[] {configFile.getName()}, configFile)); 39 | } else { 40 | // this should never happen.. 41 | LOGGER.log(Level.WARNING, "Jenkins global config file does not exist."); 42 | } 43 | } 44 | 45 | @Override 46 | public boolean isSelectedByDefault() { 47 | return false; 48 | } 49 | 50 | @NonNull 51 | @Override 52 | public ComponentCategory getCategory() { 53 | return ComponentCategory.CONTROLLER; 54 | } 55 | 56 | private static final Logger LOGGER = Logger.getLogger(ConfigFileComponent.class.getName()); 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/configfiles/XmlRedactedSecretFileContent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.configfiles; 2 | 3 | import com.cloudbees.jenkins.support.api.FileContent; 4 | import com.cloudbees.jenkins.support.filter.PasswordRedactor; 5 | import java.io.ByteArrayInputStream; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import javax.xml.transform.TransformerException; 10 | import org.xml.sax.SAXException; 11 | 12 | class XmlRedactedSecretFileContent extends FileContent { 13 | 14 | private static final String STRING_TAG = ""; 15 | private static final String CLOSE_STRING_TAG = ""; 16 | 17 | private String previousStringTagValue; 18 | 19 | public XmlRedactedSecretFileContent(String name, File file) { 20 | super(name, file); 21 | } 22 | 23 | public XmlRedactedSecretFileContent(String name, String[] filterableParameters, File file) { 24 | super(name, filterableParameters, file); 25 | } 26 | 27 | @Override 28 | protected InputStream getInputStream() throws IOException { 29 | try { 30 | return new ByteArrayInputStream(SecretHandler.findSecrets(file).getBytes(SecretHandler.OUTPUT_ENCODING)); 31 | } catch (SAXException | TransformerException e) { 32 | throw new IOException(e); 33 | } 34 | } 35 | 36 | @Override 37 | protected String getSimpleValueOrRedactedPassword(String value) { 38 | if (value.contains(STRING_TAG)) { 39 | return redactStringTagIfNeeded(value); 40 | } 41 | return PasswordRedactor.get().redact(value); 42 | } 43 | 44 | private String redactStringTagIfNeeded(String value) { 45 | if (previousStringTagValue != null) { 46 | if (previousStringTagValue.contains(STRING_TAG) 47 | && PasswordRedactor.get().match(previousStringTagValue)) { 48 | previousStringTagValue = null; 49 | return value.substring(0, value.indexOf(STRING_TAG)) 50 | + STRING_TAG 51 | + PasswordRedactor.REDACTED 52 | + CLOSE_STRING_TAG; 53 | } 54 | previousStringTagValue = null; 55 | return value; 56 | } 57 | previousStringTagValue = value; 58 | return value; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/AdditionalFromFileStopWords.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import com.cloudbees.jenkins.support.SupportPlugin; 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import hudson.Extension; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.nio.charset.Charset; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | 16 | @Extension 17 | public class AdditionalFromFileStopWords implements StopWords { 18 | 19 | private static final Logger LOGGER = Logger.getLogger(AdditionalFromFileStopWords.class.getName()); 20 | 21 | /** 22 | * Name of the file containing additional user-provided stop words. 23 | */ 24 | private static final String ADDITIONAL_STOP_WORDS_FILENAME = "additional-stop-words.txt"; 25 | 26 | /** 27 | * Property to set to add additional stop words. 28 | * The location should point to a line separated file containing words. Each line is treated as a word. 29 | */ 30 | static final String ADDITIONAL_STOP_WORDS_PROPERTY = ContentMappings.class.getName() + ".additionalStopWordsFile"; 31 | 32 | @NonNull 33 | @Override 34 | public Set getWords() { 35 | Set words = new HashSet<>(); 36 | String fileLocationFromProperty = System.getProperty(ADDITIONAL_STOP_WORDS_PROPERTY); 37 | String fileLocation = fileLocationFromProperty == null 38 | ? SupportPlugin.getRootDirectory() + "/" + ADDITIONAL_STOP_WORDS_FILENAME 39 | : fileLocationFromProperty; 40 | LOGGER.log(Level.FINE, "Attempting to load user provided stop words from ''{0}''.", fileLocation); 41 | File f = new File(fileLocation); 42 | if (f.exists()) { 43 | if (!f.canRead()) { 44 | LOGGER.log( 45 | Level.WARNING, 46 | "Could not load user provided stop words as " + fileLocation + " is not readable."); 47 | } else { 48 | try { 49 | words.addAll(Files.readAllLines(Path.of(fileLocation), Charset.defaultCharset())); 50 | } catch (IOException ex) { 51 | LOGGER.log( 52 | Level.WARNING, 53 | "Could not load user provided stop words. there was an error reading " + fileLocation, 54 | ex); 55 | } 56 | } 57 | } else if (fileLocationFromProperty != null) { 58 | LOGGER.log( 59 | Level.WARNING, 60 | "Could not load user provided stop words as " + fileLocationFromProperty + " does not exists."); 61 | } 62 | return words; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/AllAsciiCharactersStopWords.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | import org.kohsuke.accmod.Restricted; 8 | import org.kohsuke.accmod.restrictions.NoExternalUse; 9 | 10 | /** 11 | * To avoid corrupting the content of the files in the bundle just in case we have an object name as 'a' or '.', we 12 | * avoid replacing one single character (ascii codes actually). A one single character in other languages could 13 | * have a meaning, so we remain replacing them. Example: 日 (Sun) 14 | */ 15 | @Extension 16 | @Restricted(NoExternalUse.class) 17 | public class AllAsciiCharactersStopWords implements StopWords { 18 | 19 | @NonNull 20 | @Override 21 | public Set getWords() { 22 | final int SPACE = ' '; // 20 23 | final int TILDE = '~'; // 126 24 | Set singleChars = new HashSet<>(TILDE - SPACE + 1); 25 | 26 | for (char i = SPACE; i <= TILDE; i++) { 27 | singleChars.add(Character.toString(i)); 28 | } 29 | 30 | return singleChars; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/AllContentFilters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.filter; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import org.kohsuke.accmod.Restricted; 29 | import org.kohsuke.accmod.restrictions.NoExternalUse; 30 | 31 | /** 32 | * Composite ContentFilter of all registered ContentFilter extensions. 33 | * 34 | * @since TODO 35 | */ 36 | @Restricted(NoExternalUse.class) 37 | class AllContentFilters implements ContentFilter { 38 | @Override 39 | public @NonNull String filter(@NonNull String input) { 40 | String filtered = input; 41 | for (ContentFilter filter : ContentFilter.all()) { 42 | filtered = filter.filter(filtered); 43 | } 44 | return filtered; 45 | } 46 | 47 | @Override 48 | public void reload() { 49 | ContentFilter.all().forEach(ContentFilter::reload); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/AllowedOSNamesStopWords.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | import org.kohsuke.accmod.Restricted; 9 | import org.kohsuke.accmod.restrictions.NoExternalUse; 10 | 11 | @Extension 12 | @Restricted(NoExternalUse.class) 13 | public class AllowedOSNamesStopWords implements StopWords { 14 | 15 | @NonNull 16 | @Override 17 | public Set getWords() { 18 | // JENKINS-54688 19 | return new HashSet<>(Arrays.asList( 20 | "linux", 21 | "windows", 22 | "win", 23 | "mac", 24 | "macos", 25 | "macosx", 26 | "mac os x", 27 | "ubuntu", 28 | "debian", 29 | "fedora", 30 | "red hat", 31 | "sunos", 32 | "freebsd")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/ContentFilters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.filter; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.ExtensionList; 30 | import jenkins.model.GlobalConfiguration; 31 | import jenkins.model.GlobalConfigurationCategory; 32 | import org.jenkinsci.Symbol; 33 | import org.kohsuke.accmod.Restricted; 34 | import org.kohsuke.accmod.restrictions.NoExternalUse; 35 | import org.kohsuke.stapler.DataBoundSetter; 36 | 37 | /** 38 | * Configures content filters for anonymization. 39 | * 40 | * @see ContentFilter 41 | * @since TODO 42 | */ 43 | @Extension 44 | @Restricted(NoExternalUse.class) 45 | @Symbol("anonymizeSupportBundle") 46 | public class ContentFilters extends GlobalConfiguration { 47 | 48 | public static ContentFilters get() { 49 | return ExtensionList.lookupSingleton(ContentFilters.class); 50 | } 51 | 52 | private boolean enabled; 53 | 54 | public ContentFilters() { 55 | super(); 56 | load(); 57 | } 58 | 59 | public boolean isEnabled() { 60 | return enabled; 61 | } 62 | 63 | @DataBoundSetter 64 | public void setEnabled(boolean enabled) { 65 | this.enabled = enabled; 66 | save(); 67 | } 68 | 69 | @Override 70 | public @NonNull String getDisplayName() { 71 | return Messages.ContentFilters_DisplayName(); 72 | } 73 | 74 | /** 75 | * 76 | * @return the global configuration category for CasC where this config lands 77 | */ 78 | @Override 79 | public @NonNull GlobalConfigurationCategory getCategory() { 80 | return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/DataFaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.filter; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.ExtensionList; 30 | import hudson.ExtensionPoint; 31 | import java.util.Locale; 32 | import java.util.function.Function; 33 | import java.util.function.Supplier; 34 | import org.kohsuke.accmod.Restricted; 35 | import org.kohsuke.accmod.restrictions.NoExternalUse; 36 | import org.kohsuke.randname.RandomNameGenerator; 37 | 38 | /** 39 | * Provides a way to generate random names. 40 | * 41 | * @since TODO 42 | */ 43 | @Extension 44 | @Restricted(NoExternalUse.class) 45 | public class DataFaker implements ExtensionPoint, Function, Supplier> { 46 | 47 | /** 48 | * @return the singleton instance 49 | */ 50 | public static DataFaker get() { 51 | return ExtensionList.lookupSingleton(DataFaker.class); 52 | } 53 | 54 | private final RandomNameGenerator generator = new RandomNameGenerator(); 55 | 56 | /** 57 | * Applies the provided function to a random name and normalizes the result. 58 | */ 59 | @Override 60 | public Supplier apply(@NonNull Function nameTransformer) { 61 | return () -> nameTransformer 62 | .apply(generator.next()) 63 | .toLowerCase(Locale.ENGLISH) 64 | .replace(' ', '_'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/DefaultStopWords.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import java.util.Set; 6 | import jenkins.model.Jenkins; 7 | import org.kohsuke.accmod.Restricted; 8 | import org.kohsuke.accmod.restrictions.NoExternalUse; 9 | 10 | @Extension 11 | @Restricted(NoExternalUse.class) 12 | public class DefaultStopWords implements StopWords { 13 | 14 | @NonNull 15 | @Override 16 | public Set getWords() { 17 | return Set.of( 18 | "agent", 19 | "jenkins", 20 | "build", 21 | "scm", 22 | "builder", 23 | "publisher", 24 | "test", 25 | "plugin", 26 | "node", 27 | "master", 28 | "controller", 29 | "computer", 30 | "item", 31 | "label", 32 | "view", 33 | "all", 34 | "unknown", 35 | "user", 36 | "anonymous", 37 | "authenticated", 38 | "everyone", 39 | "system", 40 | "admin", 41 | "up", 42 | "running", 43 | Jenkins.VERSION, 44 | "tmp", 45 | "git", 46 | "retry", 47 | "vault", 48 | "exists", 49 | "log", 50 | "info", 51 | "java", 52 | "url"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/FilteredConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.filter; 26 | 27 | import java.util.regex.Pattern; 28 | 29 | final class FilteredConstants { 30 | 31 | static final Pattern EOL = Pattern.compile("\r?\n|" + '\0'); 32 | static final int DEFAULT_DECODER_CAPACITY = 1024; 33 | 34 | private FilteredConstants() {} 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/FilteredInputStream.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import java.io.BufferedReader; 5 | import java.io.ByteArrayInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.nio.charset.Charset; 10 | import java.util.function.Function; 11 | 12 | /** 13 | * A custom {@link InputStream} that filters lines of text read from an underlying {@link InputStream} using a provided 14 | * mapping function. Each line read from the input stream is processed by the function before being returned, allowing 15 | * for modifications such as redaction or transformation of the line content. 16 | * 17 | * @author Basil Crow 18 | */ 19 | public class FilteredInputStream extends InputStream { 20 | 21 | private final Function filter; 22 | private final Charset encoding; 23 | private final BufferedReader reader; 24 | private ByteArrayInputStream buffer; 25 | 26 | /** 27 | * Constructs a filtered stream using the provided filter and encoding. 28 | * 29 | * @param is Input stream to read line content from 30 | * @param encoding Character set to use for decoding and encoding bytes read from this stream 31 | * @param filter Filter to apply to lines read from this stream 32 | */ 33 | public FilteredInputStream( 34 | @NonNull InputStream is, @NonNull Charset encoding, @NonNull Function filter) { 35 | this.encoding = encoding; 36 | this.reader = new BufferedReader(new InputStreamReader(is, encoding)); 37 | this.filter = filter; 38 | } 39 | 40 | @Override 41 | public int read() throws IOException { 42 | if (buffer == null) { 43 | String line = reader.readLine(); 44 | if (line != null) { 45 | line = filter.apply(line); 46 | line += System.lineSeparator(); 47 | buffer = new ByteArrayInputStream(line.getBytes(encoding)); 48 | } else { 49 | return -1; 50 | } 51 | } 52 | int ch = buffer.read(); 53 | if (ch != -1) { 54 | return ch; 55 | } else { 56 | buffer = null; 57 | return read(); 58 | } 59 | } 60 | 61 | @Override 62 | public void close() throws IOException { 63 | reader.close(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/NoneFilter.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import org.kohsuke.accmod.Restricted; 5 | import org.kohsuke.accmod.restrictions.NoExternalUse; 6 | 7 | /** 8 | * A {@link ContentFilter} that blindly pass the value through. 9 | */ 10 | @Restricted(NoExternalUse.class) 11 | public class NoneFilter implements ContentFilter { 12 | @NonNull 13 | @Override 14 | public String filter(@NonNull String input) { 15 | return input; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/PluginsStopWords.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Locale; 8 | import java.util.Set; 9 | import jenkins.model.Jenkins; 10 | 11 | @Extension 12 | public class PluginsStopWords implements StopWords { 13 | @NonNull 14 | @Override 15 | public Set getWords() { 16 | final Set pluginsWords = new HashSet<>(); 17 | Jenkins.get().pluginManager.getPlugins().forEach(pluginWrapper -> { 18 | pluginsWords.addAll(List.of( 19 | pluginWrapper.getShortName().toLowerCase(Locale.ENGLISH).split("-"))); 20 | pluginsWords.addAll(List.of( 21 | pluginWrapper.getDisplayName().toLowerCase(Locale.ENGLISH).split(" "))); 22 | }); 23 | return pluginsWords; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/PrefilteredContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.filter; 26 | 27 | import com.cloudbees.jenkins.support.api.Content; 28 | import edu.umd.cs.findbugs.annotations.NonNull; 29 | import java.io.IOException; 30 | import java.io.OutputStream; 31 | 32 | /** 33 | * Represents some content in a support bundle which will be filtered previously to the zip created. 34 | */ 35 | public abstract class PrefilteredContent extends Content { 36 | 37 | protected PrefilteredContent(String name) { 38 | super(name); 39 | } 40 | 41 | protected PrefilteredContent(String name, String... filterableParameters) { 42 | super(name, filterableParameters); 43 | } 44 | 45 | /** 46 | * Write the component in the bundle filtering the content 47 | * @param os OutputStream where write the content 48 | * @param filter ContentFilter to apply 49 | * @throws IOException If an input or output exception occurs 50 | */ 51 | public abstract void writeTo(OutputStream os, @NonNull ContentFilter filter) throws IOException; 52 | 53 | @Override 54 | public final boolean shouldBeFiltered() { 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/filter/StopWords.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.ExtensionList; 5 | import hudson.ExtensionPoint; 6 | import java.util.Set; 7 | 8 | /** 9 | * Extension to contribute to the list of stop words in anonymization. 10 | */ 11 | public interface StopWords extends ExtensionPoint { 12 | 13 | /** 14 | * @return all {@link StopWords} extensions 15 | */ 16 | static ExtensionList all() { 17 | return ExtensionList.lookup(StopWords.class); 18 | } 19 | 20 | /** 21 | * Return the stop words that will be added to {@link ContentMappings}. 22 | * @return a set of words 23 | */ 24 | @NonNull 25 | Set getWords(); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/AboutUser.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrefilteredPrintedContent; 6 | import com.cloudbees.jenkins.support.filter.ContentFilter; 7 | import edu.umd.cs.findbugs.annotations.NonNull; 8 | import hudson.Extension; 9 | import hudson.security.ACL; 10 | import hudson.security.Permission; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | import java.util.Collection; 14 | import java.util.Collections; 15 | import java.util.Set; 16 | import jenkins.model.Jenkins; 17 | import org.springframework.security.core.Authentication; 18 | import org.springframework.security.core.GrantedAuthority; 19 | 20 | /** 21 | * Basic information about the user's authentication. 22 | * 23 | * @author Stephen Connolly 24 | */ 25 | @Extension 26 | public class AboutUser extends Component { 27 | @Override 28 | @NonNull 29 | public String getDisplayName() { 30 | return "About user (basic authentication details only)"; 31 | } 32 | 33 | @Override 34 | public Set getRequiredPermissions() { 35 | return Collections.emptySet(); 36 | } 37 | 38 | @Override 39 | public void addContents(@NonNull Container result) { 40 | final Authentication authentication = Jenkins.getAuthentication2(); 41 | if (!authentication.equals(ACL.SYSTEM2)) { 42 | result.add(new PrefilteredPrintedContent("user.md") { 43 | @Override 44 | protected void printTo(PrintWriter out, ContentFilter filter) throws IOException { 45 | out.println("User"); 46 | out.println("===="); 47 | out.println(); 48 | out.println("Authentication"); 49 | out.println("--------------"); 50 | out.println(); 51 | out.println(" * Authenticated: " + authentication.isAuthenticated()); 52 | out.println(" * Name: " + ContentFilter.filter(filter, authentication.getName())); 53 | Collection authorities = authentication.getAuthorities(); 54 | if (authorities != null) { 55 | out.println(" * Authorities "); 56 | for (GrantedAuthority authority : authorities) { 57 | out.println(" - " 58 | + (authority == null 59 | ? "null" 60 | : "`" + authority.toString().replaceAll("`", "`") + "`")); 61 | } 62 | } 63 | out.println(); 64 | } 65 | }); 66 | } 67 | } 68 | 69 | @NonNull 70 | @Override 71 | public ComponentCategory getCategory() { 72 | return ComponentCategory.MISC; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/LogFilenameAgentFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2020, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.impl; 26 | 27 | import java.io.File; 28 | import java.io.FilenameFilter; 29 | import java.io.Serializable; 30 | import java.util.Date; 31 | import java.util.concurrent.TimeUnit; 32 | 33 | /** 34 | * Matches agent log files in an interval of time 35 | */ 36 | class LogFilenameAgentFilter implements FilenameFilter, Serializable { 37 | 38 | public static final long MAX_TIME_AGENT_LOG_RETRIEVAL = Long.getLong( 39 | System.getProperty(LogFilenameAgentFilter.class.getName() + ".maxTimeAgentLogRetrieval"), 40 | TimeUnit.DAYS.toMillis(7)); 41 | 42 | public boolean accept(File dir, String name) { 43 | // We should avoid taking agent files which are very old 44 | // as they are not usually very helpful to troubleshoot 45 | // 1 week should be enough in most of the cases 46 | if (name.endsWith(".log") && new Date().getTime() - dir.lastModified() < MAX_TIME_AGENT_LOG_RETRIEVAL) { 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | private static final long serialVersionUID = 1L; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/LogFilenameFilter.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Matches log files. 9 | */ 10 | class LogFilenameFilter implements FilenameFilter, Serializable { 11 | public boolean accept(File dir, String name) { 12 | return name.endsWith(".log"); 13 | } 14 | 15 | private static final long serialVersionUID = 1L; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/LogRecordContent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Content; 4 | import com.cloudbees.jenkins.support.filter.ContentFilter; 5 | import com.cloudbees.jenkins.support.filter.PrefilteredContent; 6 | import com.google.common.collect.Lists; 7 | import edu.umd.cs.findbugs.annotations.NonNull; 8 | import io.jenkins.lib.support_log_formatter.SupportLogFormatter; 9 | import java.io.BufferedWriter; 10 | import java.io.IOException; 11 | import java.io.OutputStream; 12 | import java.io.OutputStreamWriter; 13 | import java.io.PrintWriter; 14 | import java.nio.charset.StandardCharsets; 15 | import java.util.List; 16 | import java.util.logging.Formatter; 17 | import java.util.logging.LogRecord; 18 | 19 | /** 20 | * {@link Content} that formats {@link LogRecord}s. 21 | * 22 | * @author Kohsuke Kawaguchi 23 | */ 24 | public abstract class LogRecordContent extends PrefilteredContent { 25 | public LogRecordContent(String name) { 26 | super(name); 27 | } 28 | 29 | public LogRecordContent(String name, String... filterableParameters) { 30 | super(name, filterableParameters); 31 | } 32 | 33 | /** 34 | * Iterates {@link LogRecord}s to be printed as this content. 35 | * 36 | * @return the {@link LogRecord}s to be printed as this content. 37 | * @see Lists#reverse(List) 38 | * @throws IOException if an error occurs while performing the operation. 39 | */ 40 | public abstract Iterable getLogRecords() throws IOException; 41 | 42 | @Override 43 | public final void writeTo(OutputStream os) throws IOException { 44 | writeTo(os, ContentFilter.NONE); 45 | } 46 | 47 | @Override 48 | public final void writeTo(OutputStream os, @NonNull ContentFilter filter) throws IOException { 49 | final PrintWriter writer = getWriter(os); 50 | try { 51 | printTo(writer, filter); 52 | } finally { 53 | writer.flush(); 54 | } 55 | } 56 | 57 | protected void printTo(PrintWriter out) throws IOException { 58 | printTo(out, ContentFilter.NONE); 59 | } 60 | 61 | protected void printTo(PrintWriter out, @NonNull ContentFilter filter) throws IOException { 62 | for (LogRecord logRecord : getLogRecords()) { 63 | String filtered = LOG_FORMATTER.format(logRecord); 64 | filtered = ContentFilter.filter(filter, filtered); 65 | out.print(filtered); 66 | } 67 | 68 | out.flush(); 69 | } 70 | 71 | private PrintWriter getWriter(OutputStream os) { 72 | return new PrintWriter(new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))); 73 | } 74 | 75 | private static final Formatter LOG_FORMATTER = new SupportLogFormatter(); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/LoggerManager.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrintedContent; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import hudson.Extension; 8 | import hudson.security.Permission; 9 | import java.io.IOException; 10 | import java.io.PrintWriter; 11 | import java.util.Collections; 12 | import java.util.Enumeration; 13 | import java.util.Set; 14 | import java.util.logging.Level; 15 | import java.util.logging.LogManager; 16 | import java.util.logging.Logger; 17 | import jenkins.model.Jenkins; 18 | 19 | /** 20 | * Output the current list of loggers for the controller and display the 21 | * logging level. This is to diagnose if a specific logger is causing 22 | * some performance issues by logging too much data. 23 | * 24 | * @since 2.30 25 | */ 26 | @Extension 27 | public class LoggerManager extends Component { 28 | @NonNull 29 | @Override 30 | public Set getRequiredPermissions() { 31 | return Collections.singleton(Jenkins.ADMINISTER); 32 | } 33 | 34 | @NonNull 35 | @Override 36 | public String getDisplayName() { 37 | return "All loggers currently enabled"; 38 | } 39 | 40 | @Override 41 | public void addContents(@NonNull Container container) { 42 | container.add(new PrintedContent("loggers.md") { 43 | @Override 44 | protected void printTo(PrintWriter out) throws IOException { 45 | out.println("Loggers currently enabled"); 46 | out.println("========================="); 47 | LogManager logManager = LogManager.getLogManager(); 48 | Enumeration loggerNames = logManager.getLoggerNames(); 49 | while (loggerNames.hasMoreElements()) { 50 | String loggerName = loggerNames.nextElement(); 51 | Logger loggerByName = logManager.getLogger(loggerName); 52 | if (loggerByName != null) { 53 | Level level = loggerByName.getLevel(); 54 | if (level != null) { 55 | out.println(loggerName + " - " + level); 56 | } 57 | } 58 | } 59 | } 60 | }); 61 | } 62 | 63 | @NonNull 64 | @Override 65 | public ComponentCategory getCategory() { 66 | return ComponentCategory.LOGS; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/Metrics.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import hudson.Extension; 7 | import hudson.security.Permission; 8 | import java.util.Collections; 9 | import java.util.Set; 10 | import jenkins.model.Jenkins; 11 | 12 | /** 13 | * Metrics from the different nodes. 14 | * 15 | * @author Stephen Connolly 16 | */ 17 | @Extension 18 | public class Metrics extends Component { 19 | 20 | /* 21 | private static final String UNAVAILABLE = "\"N/A\""; 22 | 23 | private final WeakHashMap metricsCache = new WeakHashMap(); 24 | */ 25 | 26 | @Override 27 | @NonNull 28 | public String getDisplayName() { 29 | return "Metrics"; 30 | } 31 | 32 | @Override 33 | public Set getRequiredPermissions() { 34 | // TODO was originally no permissions, but that seems iffy 35 | return Collections.singleton(Jenkins.ADMINISTER); 36 | } 37 | 38 | @Override 39 | public void addContents(@NonNull Container result) { 40 | result.add(new MetricsContent("nodes/master/metrics.json", jenkins.metrics.api.Metrics.metricRegistry())); 41 | /* TODO pick up a per-agent metrics registry 42 | for (final Node node : Jenkins.getInstance().getNodes()) { 43 | result.add(new RemoteMetricsContent("nodes/slave/" + node.getNodeName() + "/metrics.json", node, 44 | metricsCache)); 45 | } 46 | */ 47 | } 48 | 49 | @NonNull 50 | @Override 51 | public ComponentCategory getCategory() { 52 | return ComponentCategory.CONTROLLER; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/MetricsContent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Content; 4 | import com.codahale.metrics.Clock; 5 | import com.codahale.metrics.MetricRegistry; 6 | import com.codahale.metrics.json.HealthCheckModule; 7 | import com.codahale.metrics.json.MetricsModule; 8 | import com.fasterxml.jackson.databind.ObjectMapper; 9 | import com.fasterxml.jackson.databind.SerializationFeature; 10 | import java.io.IOException; 11 | import java.io.OutputStream; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * A metric content. 16 | * 17 | * @author Stephen Connolly 18 | */ 19 | public class MetricsContent extends Content { 20 | private final Clock clock = Clock.defaultClock(); 21 | private MetricRegistry registry; 22 | private ObjectMapper objectMapper; 23 | 24 | public MetricsContent(String name, MetricRegistry metricsRegistry) { 25 | super(name); 26 | 27 | this.registry = metricsRegistry; 28 | objectMapper = new ObjectMapper(); 29 | objectMapper.registerModule(new MetricsModule(TimeUnit.MINUTES, TimeUnit.SECONDS, true)); 30 | objectMapper.registerModule(new HealthCheckModule()); 31 | objectMapper.enable(SerializationFeature.INDENT_OUTPUT); 32 | } 33 | 34 | public MetricsContent(String name, String[] filterableParameters, MetricRegistry metricsRegistry) { 35 | super(name, filterableParameters); 36 | 37 | this.registry = metricsRegistry; 38 | objectMapper = new ObjectMapper(); 39 | objectMapper.registerModule(new MetricsModule(TimeUnit.MINUTES, TimeUnit.SECONDS, true)); 40 | objectMapper.registerModule(new HealthCheckModule()); 41 | objectMapper.enable(SerializationFeature.INDENT_OUTPUT); 42 | } 43 | 44 | @Override 45 | public void writeTo(OutputStream os) throws IOException { 46 | objectMapper.writer().writeValue(os, registry); 47 | } 48 | 49 | @Override 50 | public boolean shouldBeFiltered() { 51 | // The information of this content is not sensible, so it doesn't need to be filtered. 52 | return false; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/NodeMonitors.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrefilteredPrintedContent; 6 | import com.cloudbees.jenkins.support.filter.ContentFilter; 7 | import edu.umd.cs.findbugs.annotations.NonNull; 8 | import hudson.Extension; 9 | import hudson.model.Computer; 10 | import hudson.node_monitors.AbstractDiskSpaceMonitor; 11 | import hudson.node_monitors.NodeMonitor; 12 | import hudson.security.Permission; 13 | import java.io.PrintWriter; 14 | import java.util.Collections; 15 | import java.util.Set; 16 | import jenkins.model.Jenkins; 17 | 18 | /** 19 | * Created by schristou88 on 11/4/16. 20 | */ 21 | @Extension 22 | public class NodeMonitors extends Component { 23 | @NonNull 24 | @Override 25 | public Set getRequiredPermissions() { 26 | return Collections.singleton(Jenkins.ADMINISTER); 27 | } 28 | 29 | @NonNull 30 | @Override 31 | public String getDisplayName() { 32 | return "Node monitors"; 33 | } 34 | 35 | @Override 36 | public void addContents(@NonNull Container container) { 37 | container.add(new PrefilteredPrintedContent("node-monitors.md") { 38 | @Override 39 | protected void printTo(PrintWriter out, ContentFilter filter) { 40 | out.println("Node monitors"); 41 | out.println("============="); 42 | try { 43 | for (NodeMonitor monitor : NodeMonitor.getAll()) { 44 | out.println(monitor.getColumnCaption()); 45 | out.println("----"); 46 | out.println(" - Is Ignored: " + monitor.isIgnored()); 47 | if (monitor instanceof AbstractDiskSpaceMonitor) { 48 | out.println(" - Threshold: " + ((AbstractDiskSpaceMonitor) monitor).freeSpaceThreshold); 49 | } 50 | if (!monitor.isIgnored()) { 51 | out.println(" - Computers:"); 52 | for (Computer c : Jenkins.get().getComputers()) { 53 | out.println(" * " + ContentFilter.filter(filter, c.getDisplayName()) + ": " 54 | + monitor.data(c)); 55 | } 56 | } 57 | } 58 | } finally { 59 | out.flush(); 60 | } 61 | } 62 | }); 63 | } 64 | 65 | @NonNull 66 | @Override 67 | public ComponentCategory getCategory() { 68 | return ComponentCategory.AGENT; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/ProxyConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrefilteredPrintedContent; 6 | import com.cloudbees.jenkins.support.filter.ContentFilter; 7 | import com.cloudbees.jenkins.support.util.Markdown; 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | import hudson.Extension; 10 | import hudson.security.Permission; 11 | import java.io.PrintWriter; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.Set; 15 | import jenkins.model.Jenkins; 16 | 17 | /** 18 | * Add information about the Jenkins proxy configuration. 19 | */ 20 | @Extension 21 | public class ProxyConfiguration extends Component { 22 | @NonNull 23 | @Override 24 | public Set getRequiredPermissions() { 25 | return Collections.singleton(Jenkins.ADMINISTER); 26 | } 27 | 28 | @NonNull 29 | @Override 30 | public String getDisplayName() { 31 | return "Proxy Configuration"; 32 | } 33 | 34 | @Override 35 | public void addContents(@NonNull Container container) { 36 | container.add(new PrefilteredPrintedContent("proxy.md") { 37 | 38 | @Override 39 | public void printTo(PrintWriter out, @NonNull ContentFilter filter) { 40 | out.println("Proxy"); 41 | out.println("==============="); 42 | out.println(); 43 | hudson.ProxyConfiguration proxy = Jenkins.get().getProxy(); 44 | if (proxy != null) { 45 | out.println(" - Host: `" + Markdown.escapeBacktick(ContentFilter.filter(filter, proxy.getName())) 46 | + "`"); 47 | out.println(" - Port: `" + proxy.getPort() + "`"); 48 | out.println(" - No Proxy Hosts: "); 49 | String noProxyHostsString = proxy.getNoProxyHost(); 50 | if (noProxyHostsString != null) { 51 | Arrays.stream(noProxyHostsString.split("[ \t\n,|]+")) 52 | .forEach(noProxyHost -> out.println(" * `" 53 | + Markdown.escapeBacktick(ContentFilter.filter(filter, noProxyHost)) + "`")); 54 | } 55 | } 56 | } 57 | }); 58 | } 59 | 60 | @NonNull 61 | @Override 62 | public ComponentCategory getCategory() { 63 | return ComponentCategory.CONTROLLER; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/RemotingDiagnostics.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrintedContent; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import hudson.Functions; 8 | import hudson.remoting.Channel; 9 | import hudson.security.Permission; 10 | import java.io.IOException; 11 | import java.io.PrintWriter; 12 | import java.lang.reflect.Method; 13 | import java.util.Collections; 14 | import java.util.Set; 15 | import jenkins.model.Jenkins; 16 | 17 | /** 18 | * Captures diagnostics information from remoting channels. 19 | * 20 | * @author Kohsuke Kawaguchi 21 | */ 22 | public class RemotingDiagnostics extends Component { 23 | 24 | @NonNull 25 | @Override 26 | public Set getRequiredPermissions() { 27 | return Collections.singleton(Jenkins.ADMINISTER); 28 | } 29 | 30 | @NonNull 31 | @Override 32 | public String getDisplayName() { 33 | return "Remoting Channel Diagnostics"; 34 | } 35 | 36 | @Override 37 | public void addContents(@NonNull Container container) { 38 | container.add(new PrintedContent("channel-diagnostics.md") { 39 | @Override 40 | protected void printTo(PrintWriter out) throws IOException { 41 | // this method is new in remoting. see JENKINS-39150 change in remoting 42 | try { 43 | Method m = Channel.class.getMethod("dumpDiagnosticsForAll", PrintWriter.class); 44 | m.invoke(null, out); 45 | } catch (Exception e) { 46 | Functions.printStackTrace(e, out); 47 | } 48 | } 49 | 50 | @Override 51 | public boolean shouldBeFiltered() { 52 | // The information of this content is not sensible, so it doesn't need to be filtered. 53 | return false; 54 | } 55 | }); 56 | } 57 | 58 | @NonNull 59 | @Override 60 | public ComponentCategory getCategory() { 61 | return ComponentCategory.AGENT; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/RunningBuilds.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrefilteredPrintedContent; 6 | import com.cloudbees.jenkins.support.filter.ContentFilter; 7 | import edu.umd.cs.findbugs.annotations.NonNull; 8 | import hudson.Extension; 9 | import hudson.security.Permission; 10 | import java.io.PrintWriter; 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import java.util.Optional; 14 | import java.util.Set; 15 | import java.util.stream.Collectors; 16 | import jenkins.model.Jenkins; 17 | 18 | @Extension 19 | public class RunningBuilds extends Component { 20 | 21 | @NonNull 22 | @Override 23 | public Set getRequiredPermissions() { 24 | return Collections.singleton(Jenkins.ADMINISTER); 25 | } 26 | 27 | @Override 28 | @NonNull 29 | public String getDisplayName() { 30 | return "Running Builds"; 31 | } 32 | 33 | @Override 34 | public void addContents(@NonNull Container result) { 35 | result.add(new PrefilteredPrintedContent("running-builds.txt") { 36 | @Override 37 | protected void printTo(PrintWriter out, ContentFilter filter) { 38 | Arrays.stream(Jenkins.get().getComputers()) 39 | .flatMap(computer -> computer.getAllExecutors().stream()) 40 | .collect(Collectors.toList()) 41 | .forEach(executor -> Optional.ofNullable(executor.getCurrentExecutable()) 42 | .filter(executable -> executable.getParent() 43 | == executable.getParent().getOwnerTask()) 44 | .ifPresent(executable -> 45 | out.println(ContentFilter.filter(filter, executable.toString())))); 46 | } 47 | }); 48 | } 49 | 50 | @NonNull 51 | @Override 52 | public ComponentCategory getCategory() { 53 | return ComponentCategory.BUILDS; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/TaskLogs.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static com.cloudbees.jenkins.support.impl.JenkinsLogs.ROTATED_LOGFILE_FILTER; 4 | 5 | import com.cloudbees.jenkins.support.api.Component; 6 | import com.cloudbees.jenkins.support.api.Container; 7 | import com.cloudbees.jenkins.support.api.FileContent; 8 | import com.cloudbees.jenkins.support.timer.FileListCapComponent; 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | import hudson.Extension; 11 | import hudson.security.Permission; 12 | import hudson.triggers.SafeTimerTask; 13 | import java.io.File; 14 | import java.util.Arrays; 15 | import java.util.Collections; 16 | import java.util.Set; 17 | import jenkins.model.Jenkins; 18 | 19 | /** 20 | * Task Log files from the controller node. 21 | */ 22 | @Extension(ordinal = 100.0) // put this first as largest content and can let the slower ones complete 23 | public class TaskLogs extends Component { 24 | 25 | @NonNull 26 | @Override 27 | public Set getRequiredPermissions() { 28 | return Collections.singleton(Jenkins.ADMINISTER); 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public String getDisplayName() { 34 | return "Controller Task Log Recorders"; 35 | } 36 | 37 | @Override 38 | public boolean isSelectedByDefault() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public void addContents(@NonNull Container result) { 44 | addControllerTasksLogs(result); 45 | } 46 | 47 | @NonNull 48 | @Override 49 | public ComponentCategory getCategory() { 50 | return ComponentCategory.LOGS; 51 | } 52 | 53 | /** 54 | * Grabs any files that look like log files directly under $JENKINS_HOME/logs, just in case 55 | * any of them are useful. 56 | * Does not add anything if Jenkins instance is unavailable. 57 | * Some plugins write log files here. 58 | */ 59 | private void addControllerTasksLogs(Container result) { 60 | Jenkins jenkins = Jenkins.getInstanceOrNull(); 61 | if (jenkins != null) { 62 | File logsRoot = SafeTimerTask.getLogsRoot(); 63 | for (File logs : new File[] {logsRoot, new File(logsRoot, "tasks")}) { 64 | File[] files = logs.listFiles(ROTATED_LOGFILE_FILTER); 65 | if (files != null) { 66 | Arrays.sort(files); 67 | long recently = System.currentTimeMillis() - FileListCapComponent.MAX_LOG_FILE_AGE_MS; 68 | for (File f : files) { 69 | if (f.getName().startsWith("Periodic background build discarder.log")) { 70 | continue; // https://github.com/jenkinsci/jenkins/pull/9663 71 | } 72 | if (f.lastModified() > recently) { 73 | result.add(new FileContent("task-logs/{0}", new String[] {f.getName()}, f)); 74 | } 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/UpdateCenter.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.PrefilteredPrintedContent; 6 | import com.cloudbees.jenkins.support.filter.ContentFilter; 7 | import edu.umd.cs.findbugs.annotations.NonNull; 8 | import hudson.Extension; 9 | import hudson.model.UpdateSite; 10 | import hudson.security.Permission; 11 | import java.io.PrintWriter; 12 | import java.util.Collections; 13 | import java.util.Set; 14 | import jenkins.model.Jenkins; 15 | 16 | /** 17 | * Add information about the different update centers available to 18 | * the Jenkins instance. 19 | * 20 | * @since 2.30 21 | */ 22 | @Extension 23 | public class UpdateCenter extends Component { 24 | @NonNull 25 | @Override 26 | public Set getRequiredPermissions() { 27 | return Collections.singleton(Jenkins.ADMINISTER); 28 | } 29 | 30 | @NonNull 31 | @Override 32 | public String getDisplayName() { 33 | return "Update Center"; 34 | } 35 | 36 | @Override 37 | public void addContents(@NonNull Container container) { 38 | container.add(new PrefilteredPrintedContent("update-center.md") { 39 | @Override 40 | public void printTo(PrintWriter out, @NonNull ContentFilter filter) { 41 | hudson.model.UpdateCenter updateCenter = Jenkins.get().getUpdateCenter(); 42 | out.println("Sites"); 43 | out.println("==============="); 44 | out.println(); 45 | for (UpdateSite c : updateCenter.getSiteList()) { 46 | out.printf(" - Id: %s%n", c.getId()); 47 | out.println(" - Url: " + ContentFilter.filter(filter, c.getUrl())); 48 | out.println(" - Connection Url: " + ContentFilter.filter(filter, c.getConnectionCheckUrl())); 49 | out.println(" - Implementation Type: " + c.getClass().getName()); 50 | } 51 | 52 | out.println(); 53 | out.println("Refresh"); 54 | out.println("==============="); 55 | out.println(); 56 | out.println(" - Last updated: " + updateCenter.getLastUpdatedString()); 57 | } 58 | }); 59 | } 60 | 61 | @NonNull 62 | @Override 63 | public ComponentCategory getCategory() { 64 | return ComponentCategory.CONTROLLER; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/impl/WinswLogfileFilter.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Matches log files from winsw. 9 | * 10 | * @see LogAppenders.cs 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | class WinswLogfileFilter implements FilenameFilter, Serializable { 14 | public boolean accept(File dir, String name) { 15 | // RollingLogAppender uses *.out.log.old, so instead of the endsWith() method, 16 | // we use the contains() method. 17 | return name.contains(".out.log") || name.contains(".err.log"); 18 | } 19 | 20 | private static final long serialVersionUID = 1L; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/slowrequest/InflightRequest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.slowrequest; 2 | 3 | import com.cloudbees.jenkins.support.filter.ContentFilter; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import java.io.File; 6 | import java.io.PrintWriter; 7 | import java.util.Date; 8 | import jenkins.model.Jenkins; 9 | import net.sf.uadetector.service.UADetectorServiceFactory; 10 | 11 | /** 12 | * Tracks the request handling in progress. 13 | * 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | final class InflightRequest { 17 | /** 18 | * Thread that's processing the request 19 | */ 20 | final Thread thread = Thread.currentThread(); 21 | 22 | /** 23 | * When did this request processing start? 24 | */ 25 | final long startTime; 26 | 27 | /** 28 | * Request URL being processed. 29 | */ 30 | final String url; 31 | 32 | /** 33 | * Set to true when the request handling is completed. 34 | */ 35 | volatile boolean ended; 36 | 37 | /** 38 | * When we start writing slow records, this field is set to non-null. 39 | */ 40 | File record; 41 | 42 | /** 43 | * Username of user who made the http call. 44 | */ 45 | final String userName; 46 | 47 | /** 48 | * Referer link to track any redirect urls. 49 | */ 50 | final String referer; 51 | 52 | /** 53 | * User Agent that invoked the slow request. 54 | */ 55 | private final String userAgent; 56 | 57 | /** 58 | * Locale of slow request 59 | */ 60 | final String locale; 61 | 62 | InflightRequest(HttpServletRequest req) { 63 | String query = req.getQueryString(); 64 | url = req.getRequestURL() + (query == null ? "" : "?" + query); 65 | startTime = System.currentTimeMillis(); 66 | userName = Jenkins.getAuthentication().getName(); 67 | referer = req.getHeader("Referer"); 68 | userAgent = req.getHeader("User-Agent"); 69 | locale = req.getLocale().toString(); 70 | } 71 | 72 | void writeHeader(PrintWriter w, ContentFilter filter) { 73 | w.println("Username: " + filter.filter(userName)); 74 | w.println("Referer: " + filter.filter(referer)); 75 | w.println("User Agent: " 76 | + (userAgent != null 77 | ? UADetectorServiceFactory.getResourceModuleParser().parse(userAgent) 78 | : null)); 79 | w.println("Date: " + new Date()); 80 | w.println("URL: " + filter.filter(url)); 81 | w.println("Locale: " + locale); 82 | w.println(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/slowrequest/SlowRequestComponent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.slowrequest; 2 | 3 | import com.cloudbees.jenkins.support.api.Container; 4 | import com.cloudbees.jenkins.support.timer.UnfilteredFileListCapComponent; 5 | import com.google.inject.Inject; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import hudson.Extension; 8 | 9 | /** 10 | * Contributes slow request reports into the support bundle. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | @Extension 15 | public class SlowRequestComponent extends UnfilteredFileListCapComponent { 16 | @Inject 17 | SlowRequestChecker checker; 18 | 19 | @NonNull 20 | @Override 21 | public String getDisplayName() { 22 | return "Slow Request Records"; 23 | } 24 | 25 | @Override 26 | public void addContents(@NonNull Container container) { 27 | super.addContents(container, checker.logs); 28 | } 29 | 30 | @NonNull 31 | @Override 32 | public ComponentCategory getCategory() { 33 | return ComponentCategory.CONTROLLER; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/slowrequest/SlowRequestFilter.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.slowrequest; 2 | 3 | import com.google.inject.Injector; 4 | import hudson.Extension; 5 | import hudson.init.Initializer; 6 | import hudson.util.PluginServletFilter; 7 | import jakarta.servlet.Filter; 8 | import jakarta.servlet.FilterChain; 9 | import jakarta.servlet.FilterConfig; 10 | import jakarta.servlet.ServletException; 11 | import jakarta.servlet.ServletRequest; 12 | import jakarta.servlet.ServletResponse; 13 | import jakarta.servlet.http.HttpServletRequest; 14 | import java.io.IOException; 15 | import java.util.concurrent.ConcurrentHashMap; 16 | import java.util.concurrent.ConcurrentMap; 17 | import jenkins.model.Jenkins; 18 | 19 | /** 20 | * Marks the beginning and the end of the request processing so that {@link SlowRequestChecker} can find them. 21 | * 22 | * @author Kohsuke Kawaguchi 23 | */ 24 | @Extension 25 | public class SlowRequestFilter implements Filter { 26 | final ConcurrentMap tracker = new ConcurrentHashMap(); 27 | 28 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 29 | throws IOException, ServletException { 30 | if (SlowRequestChecker.DISABLED) { 31 | chain.doFilter(request, response); 32 | } else { 33 | Thread t = Thread.currentThread(); 34 | InflightRequest req = new InflightRequest((HttpServletRequest) request); 35 | tracker.put(t, req); 36 | try { 37 | chain.doFilter(request, response); 38 | } finally { 39 | req.ended = true; 40 | tracker.remove(t); 41 | } 42 | } 43 | } 44 | 45 | public void init(FilterConfig filterConfig) throws ServletException {} 46 | 47 | public void destroy() {} 48 | 49 | @Initializer 50 | public static void init() throws ServletException { 51 | Injector inj = Jenkins.get().getInjector(); 52 | if (inj == null) { 53 | return; 54 | } 55 | PluginServletFilter.addFilter(inj.getInstance(SlowRequestFilter.class)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/slowrequest/SlowRequestThreadDumpsComponent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.slowrequest; 2 | 3 | import com.cloudbees.jenkins.support.api.Container; 4 | import com.cloudbees.jenkins.support.timer.UnfilteredFileListCapComponent; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import hudson.Extension; 7 | import hudson.ExtensionList; 8 | 9 | /** 10 | * Contributes thread dumps slow request reports into the support bundle. 11 | * 12 | * @author Ignacio Roncero 13 | */ 14 | @Extension 15 | public class SlowRequestThreadDumpsComponent extends UnfilteredFileListCapComponent { 16 | 17 | @NonNull 18 | @Override 19 | public String getDisplayName() { 20 | return "Thread Dumps on Slow Request Records"; 21 | } 22 | 23 | @Override 24 | public void addContents(@NonNull Container container) { 25 | SlowRequestThreadDumpsGenerator generator = 26 | ExtensionList.lookup(SlowRequestThreadDumpsGenerator.class).get(SlowRequestThreadDumpsGenerator.class); 27 | if (generator != null && generator.logs.getSize() > 0) { 28 | super.addContents(container, generator.logs); 29 | } 30 | } 31 | 32 | @NonNull 33 | @Override 34 | public ComponentCategory getCategory() { 35 | return ComponentCategory.CONTROLLER; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/threaddump/HighLoadComponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2020 CloudBees, Inc 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.threaddump; 26 | 27 | import com.cloudbees.jenkins.support.api.Container; 28 | import com.cloudbees.jenkins.support.timer.UnfilteredFileListCapComponent; 29 | import edu.umd.cs.findbugs.annotations.NonNull; 30 | import hudson.Extension; 31 | import hudson.ExtensionList; 32 | 33 | /** 34 | * HighLoadComponent component 35 | */ 36 | @Extension 37 | public class HighLoadComponent extends UnfilteredFileListCapComponent { 38 | 39 | public String getDisplayName() { 40 | return Messages.ThreadDumpHighCPU_DisplayName(); 41 | } 42 | 43 | @Override 44 | public void addContents(@NonNull Container container) { 45 | HighLoadCpuChecker checker = 46 | ExtensionList.lookup(HighLoadCpuChecker.class).get(HighLoadCpuChecker.class); 47 | if (checker != null && checker.logs.getSize() > 0) { 48 | super.addContents(container, checker.logs); 49 | } 50 | } 51 | 52 | @NonNull 53 | @Override 54 | public ComponentCategory getCategory() { 55 | return ComponentCategory.PLATFORM; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/timer/DeadlockRequestComponent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.timer; 2 | 3 | import com.cloudbees.jenkins.support.api.Container; 4 | import com.google.inject.Inject; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import hudson.Extension; 7 | 8 | /** 9 | * @author stevenchristou 10 | * Date: 4/23/14 11 | * Time: 4:50 PM 12 | */ 13 | @Extension 14 | public class DeadlockRequestComponent extends UnfilteredFileListCapComponent { 15 | @Inject 16 | DeadlockTrackChecker checker; 17 | 18 | @NonNull 19 | @Override 20 | public String getDisplayName() { 21 | return "Deadlock Records"; 22 | } 23 | 24 | @Override 25 | public void addContents(@NonNull Container container) { 26 | super.addContents(container, checker.logs); 27 | } 28 | 29 | @NonNull 30 | @Override 31 | public ComponentCategory getCategory() { 32 | return ComponentCategory.PLATFORM; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/timer/DeadlockTrackChecker.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.timer; 2 | 3 | import com.cloudbees.jenkins.support.SupportPlugin; 4 | import com.cloudbees.jenkins.support.filter.ContentFilter; 5 | import com.cloudbees.jenkins.support.impl.ThreadDumps; 6 | import hudson.Extension; 7 | import hudson.model.PeriodicWork; 8 | import java.io.File; 9 | import java.io.PrintWriter; 10 | import java.lang.management.ManagementFactory; 11 | import java.lang.management.ThreadInfo; 12 | import java.lang.management.ThreadMXBean; 13 | import java.text.SimpleDateFormat; 14 | import java.util.Date; 15 | import java.util.TimeZone; 16 | import java.util.concurrent.TimeUnit; 17 | import jenkins.model.Jenkins; 18 | 19 | /** 20 | * @author Steven Chrisou 21 | */ 22 | @Extension 23 | public class DeadlockTrackChecker extends PeriodicWork { 24 | 25 | final SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-HHmmss"); 26 | 27 | { 28 | format.setTimeZone(TimeZone.getTimeZone("UTC")); 29 | } 30 | 31 | final FileListCap logs = new FileListCap(new File(Jenkins.get().getRootDir(), "deadlocks"), 50); 32 | 33 | @Override 34 | public long getRecurrencePeriod() { 35 | return TimeUnit.SECONDS.toMillis(15); 36 | } 37 | 38 | @Override 39 | protected void doRun() throws Exception { 40 | ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); 41 | long[] deadLocks; 42 | try { 43 | deadLocks = mbean.findDeadlockedThreads(); 44 | } catch (UnsupportedOperationException x) { 45 | deadLocks = null; 46 | } 47 | 48 | if (deadLocks != null && deadLocks.length != 0) { 49 | File file = logs.file("DeadlockDetected-" + format.format(new Date()) + ".txt"); 50 | logs.add(file); 51 | PrintWriter builder = new PrintWriter(file, "UTF-8"); 52 | try { 53 | builder.println("=============="); 54 | builder.println("Deadlock Found"); 55 | builder.println("=============="); 56 | ThreadInfo[] deadLockThreads = mbean.getThreadInfo(deadLocks, Integer.MAX_VALUE); 57 | 58 | ContentFilter contentFilter = SupportPlugin.getDefaultContentFilter(); 59 | for (ThreadInfo threadInfo : deadLockThreads) { 60 | try { 61 | ThreadDumps.printThreadInfo(builder, threadInfo, mbean, contentFilter); 62 | } catch (LinkageError e) { 63 | builder.println(threadInfo); 64 | } 65 | } 66 | } finally { 67 | builder.close(); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/timer/FileListCapComponent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.timer; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.FileContent; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import hudson.security.Permission; 8 | import java.io.File; 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | import java.util.Set; 12 | import java.util.concurrent.TimeUnit; 13 | import jenkins.model.Jenkins; 14 | import org.apache.commons.io.FileUtils; 15 | 16 | /** 17 | * {@link Component} that attaches files inside {@link FileListCap} into a support bundle. 18 | * 19 | * @author stevenchristou 20 | */ 21 | public abstract class FileListCapComponent extends Component { 22 | 23 | /** Maximum file size to pack is 2Mb. */ 24 | public static final int MAX_FILE_SIZE = 2 * 1000000; 25 | 26 | /** 27 | * Maximum age (in milliseconds) of log files we would bother including in a bundle. 28 | * Anything older is likely no longer relevant. 29 | */ 30 | public static final long MAX_LOG_FILE_AGE_MS = TimeUnit.DAYS.toMillis(90); 31 | 32 | @NonNull 33 | @Override 34 | public Set getRequiredPermissions() { 35 | return Collections.singleton(Jenkins.ADMINISTER); 36 | } 37 | 38 | @NonNull 39 | @Override 40 | public ComponentCategory getCategory() { 41 | return ComponentCategory.PLATFORM; 42 | } 43 | 44 | public void addContents(@NonNull Container container, FileListCap fileListCap) { 45 | synchronized (fileListCap) { 46 | // while we read and put the reports into the support bundle, we don't want 47 | // the FileListCap to delete files. So we lock it. 48 | 49 | final Collection files = FileUtils.listFiles(fileListCap.getFolder(), new String[] {"txt"}, false); 50 | long recently = System.currentTimeMillis() - MAX_LOG_FILE_AGE_MS; 51 | for (File f : files) { 52 | if (f.lastModified() > recently) { 53 | container.add(new FileContent( 54 | "{0}/{1}", 55 | new String[] {fileListCap.getFolder().getName(), f.getName()}, f, MAX_FILE_SIZE)); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/timer/UnfilteredFileListCapComponent.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.timer; 2 | 3 | import com.cloudbees.jenkins.support.api.Component; 4 | import com.cloudbees.jenkins.support.api.Container; 5 | import com.cloudbees.jenkins.support.api.UnfilteredFileContent; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import hudson.security.Permission; 8 | import java.io.File; 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Set; 13 | import jenkins.model.Jenkins; 14 | import org.apache.commons.io.FileUtils; 15 | 16 | /** 17 | * {@link Component} that attaches files inside {@link FileListCap} into a support bundle without filtering the 18 | * content of the files. 19 | * 20 | * @author stevenchristou 21 | */ 22 | public abstract class UnfilteredFileListCapComponent extends Component { 23 | 24 | @NonNull 25 | @Override 26 | public Set getRequiredPermissions() { 27 | return Collections.singleton(Jenkins.ADMINISTER); 28 | } 29 | 30 | public void addContents(@NonNull Container container, FileListCap fileListCap) { 31 | synchronized (fileListCap) { 32 | // while we read and put the reports into the support bundle, we don't want 33 | // the FileListCap to delete files. So we lock it. 34 | 35 | final List files = 36 | new ArrayList<>(FileUtils.listFiles(fileListCap.getFolder(), new String[] {"txt"}, false)); 37 | Collections.sort(files); 38 | long recently = System.currentTimeMillis() - FileListCapComponent.MAX_LOG_FILE_AGE_MS; 39 | for (File f : files) { 40 | if (f.lastModified() > recently) { 41 | container.add(new UnfilteredFileContent( 42 | "{0}/{1}", 43 | new String[] {fileListCap.getFolder().getName(), f.getName()}, 44 | f, 45 | FileListCapComponent.MAX_FILE_SIZE)); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/CallAsyncWrapper.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.util; 2 | 3 | import com.cloudbees.jenkins.support.SupportPlugin; 4 | import hudson.model.Computer; 5 | import hudson.remoting.Callable; 6 | import hudson.remoting.Future; 7 | import hudson.remoting.VirtualChannel; 8 | import java.io.IOException; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.concurrent.TimeoutException; 12 | 13 | public final class CallAsyncWrapper { 14 | 15 | public static Future callAsync( 16 | final VirtualChannel channel, final Callable callable) throws IOException { 17 | var executorFuture = Computer.threadPoolForRemoting.submit(() -> channel.callAsync(callable)); 18 | try { 19 | return executorFuture.get(SupportPlugin.REMOTE_OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); 20 | } catch (InterruptedException | ExecutionException e) { 21 | throw new IOException(e); 22 | } catch (TimeoutException te) { 23 | executorFuture.cancel(true); 24 | throw new IOException(te); 25 | } 26 | } 27 | 28 | private CallAsyncWrapper() {} 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/Helper.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.util; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import jenkins.model.Jenkins; 5 | 6 | /** 7 | * Simple helper so we don't have to check {@code Jenkins.getInstance() != null} everywhere. 8 | * 9 | * TODO: replace with Jenkins.getActiveInstance() when on core {@literal >=} 1.609 10 | * 11 | */ 12 | @Deprecated 13 | public final class Helper { 14 | /** Not instantiable. */ 15 | private Helper() { 16 | throw new AssertionError("Not instantiable"); 17 | } 18 | 19 | @NonNull 20 | public static Jenkins getActiveInstance() { 21 | Jenkins instance = Jenkins.getInstance(); 22 | if (instance == null) { 23 | throw new IllegalStateException("Jenkins has not been started, or was already shut down"); 24 | } 25 | return instance; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/IgnoreCloseOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.util; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import java.io.BufferedOutputStream; 29 | import java.io.IOException; 30 | import java.io.OutputStream; 31 | import org.kohsuke.accmod.Restricted; 32 | import org.kohsuke.accmod.restrictions.NoExternalUse; 33 | 34 | /** 35 | * Provides a {@link BufferedOutputStream} that ignores calls to close its underlying stream and instead simply flushes it. 36 | * 37 | * @since TODO 38 | */ 39 | @Restricted(NoExternalUse.class) 40 | public final class IgnoreCloseOutputStream extends BufferedOutputStream implements WrapperOutputStream { 41 | /** 42 | * The underlying output stream to be filtered. 43 | * 44 | * @param out the underlying output stream. 45 | */ 46 | public IgnoreCloseOutputStream(@NonNull OutputStream out) { 47 | super(out); 48 | } 49 | 50 | @Override 51 | public void close() throws IOException { 52 | flush(); 53 | } 54 | 55 | @Override 56 | public @NonNull OutputStream unwrap() { 57 | return out; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/IgnoreCloseWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.util; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import java.io.FilterWriter; 29 | import java.io.IOException; 30 | import java.io.Writer; 31 | import org.kohsuke.accmod.Restricted; 32 | import org.kohsuke.accmod.restrictions.NoExternalUse; 33 | 34 | /** 35 | * Provides a {@link FilterWriter} that ignores calls to close its underlying writer and instead simply flushes it. 36 | * 37 | * @since TODO 38 | */ 39 | @Restricted(NoExternalUse.class) 40 | public final class IgnoreCloseWriter extends FilterWriter { 41 | public IgnoreCloseWriter(@NonNull Writer out) { 42 | super(out); 43 | } 44 | 45 | @Override 46 | public void close() throws IOException { 47 | flush(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/Markdown.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.util; 2 | 3 | import edu.umd.cs.findbugs.annotations.CheckForNull; 4 | 5 | public final class Markdown { 6 | public static final String NONE_STRING = "(none)"; 7 | 8 | /** Not instantiable. */ 9 | private Markdown() { 10 | throw new AssertionError("Not instantiable"); 11 | } 12 | 13 | public static String escapeUnderscore(@CheckForNull String raw) { 14 | return (raw == null) ? null : raw.replaceAll("_", "_"); 15 | } 16 | 17 | public static String escapeBacktick(@CheckForNull String raw) { 18 | return (raw == null) ? null : raw.replaceAll("`", "`"); 19 | } 20 | 21 | public static String prettyNone(String raw) { 22 | return raw != null && !raw.isEmpty() ? raw : NONE_STRING; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/SystemPlatform.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.util; 2 | 3 | import java.util.Locale; 4 | import jenkins.security.MasterToSlaveCallable; 5 | 6 | /** 7 | * System platform 8 | */ 9 | public enum SystemPlatform { 10 | LINUX, 11 | SOLARIS, 12 | WINDOWS, 13 | MACOSX, 14 | UNKNOWN; 15 | 16 | public static SystemPlatform current() { 17 | String arch = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); 18 | if (arch.contains("linux")) { 19 | return LINUX; 20 | } else if (arch.contains("windows")) { 21 | return WINDOWS; 22 | } else if (arch.contains("sun") || arch.contains("solaris")) { 23 | return SOLARIS; 24 | } else if (arch.contains("mac")) { 25 | return MACOSX; 26 | } else { 27 | return UNKNOWN; 28 | } 29 | } 30 | 31 | public static class GetCurrentPlatform extends MasterToSlaveCallable { 32 | private static final long serialVersionUID = 1L; 33 | 34 | public SystemPlatform call() { 35 | return current(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/support/util/WrapperOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.util; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import java.io.IOException; 29 | import java.io.OutputStream; 30 | import org.kohsuke.accmod.Restricted; 31 | import org.kohsuke.accmod.restrictions.NoExternalUse; 32 | 33 | /** 34 | * Allows for nested OutputStream wrappers and getting access to the unwrapped stream. 35 | * 36 | * @since TODO 37 | */ 38 | @Restricted(NoExternalUse.class) 39 | public interface WrapperOutputStream { 40 | /** 41 | * Unwraps this stream, potentially forcing unwritten data to be flushed. 42 | * 43 | * @return the underlying stream being wrapped 44 | * @throws IOException if an exception occurs preparing the unwrapped reference 45 | * @throws IllegalStateException if this stream is closed 46 | */ 47 | @NonNull 48 | OutputStream unwrap() throws IOException; 49 | 50 | /** 51 | * Unwraps this stream, recursively descending through any further WrapperOutputStream instances. 52 | * 53 | * @return the underlying stream being wrapped 54 | * @throws IOException if an exception occurs during any unwrap stage 55 | * @throws IllegalStateException if this stream is closed 56 | */ 57 | default @NonNull OutputStream unwrapRecursively() throws IOException { 58 | OutputStream out = unwrap(); 59 | while (out instanceof WrapperOutputStream) { 60 | out = ((WrapperOutputStream) out).unwrap(); 61 | } 62 | return out; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/SupportAction/action.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/SupportAction/index.properties: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License 3 | # 4 | # Copyright (c) 2013, CloudBees, Inc. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | detail=It is best to include all of the following information in the support bundle, but if you are unable to provide \ 26 | some of the information due to corporate policy, you can either deselect the information to exclude prior to \ 27 | generating the bundle or edit the generated bundle to remove the specific information that you must exclude. \ 28 | Each bundle is a simple ZIP file containing mostly plain text files and you can examine and/or modify the bundle \ 29 | prior to sharing the bundle if you have any concerns about the information contained within. 30 | 31 | permissionPreReqs=Requires: {0} 32 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/SupportAction/progressPage.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 |

Generating Support Bundle

11 |

Generating a support bundle for this Jenkins instance. This may take a few minutes.

12 | 13 | 14 |
15 | 16 | 17 |
18 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/SupportPlugin/GlobalConfigurationImpl/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/actions/Messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License 3 | # 4 | # Copyright (c) 2018, CloudBees, Inc. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | SupportRunAction_DisplayName={0} Support 26 | SupportRunAction_DefaultActionTitle=Support 27 | SupportRunAction_CreateBundle=Generate bundle 28 | 29 | SupportItemAction_DisplayName={0} Support 30 | SupportItemAction_DefaultActionTitle=Support 31 | SupportItemAction_CreateBundle=Generate bundle 32 | 33 | SupportComputerAction_DisplayName=Agent Support 34 | SupportComputerAction_DefaultActionTitle=Support 35 | SupportComputerAction_CreateBundle=Generate bundle 36 | 37 | SupportObjectAction_DisplayName=Support 38 | SupportObjectAction_DefaultActionTitle=Support 39 | SupportObjectAction_CreateBundle=Generate bundle 40 | SupportObjectAction_DefaultActionBlurb=\ 41 | In order to assist the Jenkins community to provide you with a response to your issues please consider generating \ 42 | a bundle of the commonly requested information and consider attaching this bundle to the corresponding issue in \ 43 | the Jenkins community issue tracker. Be mindful that attachments to the Jenkins community issue tracker are public \ 44 | so be extra careful not to include sensitive information. Note that certain metadata can be automatically \ 45 | anonymized when support bundle anonymization is enabled through the global configuration settings. \ 46 | When anonymization is enabled, the following information is replaced with automatically generated anonymized names: \ 47 | nodes, computers, labels, users, items (including jobs), views, and IP addresses. 48 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/actions/SupportAbstractItemAction/action.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/actions/SupportComputerAction/action.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/actions/SupportRunAction/action.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/api/ObjectComponent/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/api/SupportProvider/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/Messages.properties: -------------------------------------------------------------------------------- 1 | SupportPluginManagement.displayName=Support Core 2 | SupportPluginManagement.description=Manage Support Core features and functionalities 3 | SupportPluginManagement.iconDescription=Manage Support Core features and functionalities 4 | SupportPluginConfigurationCategory.displayName=Support Core 5 | SupportPluginConfigurationCategory.shortDescription=Manage Support Core features and functionalities 6 | 7 | SupportAutomatedBundleConfiguration.displayName=Automated Support Bundle Generation 8 | SupportAutomatedBundleConfiguration.enabled.noComponents="Automated generation is enabled but no components are selected" 9 | SupportAutomatedBundleConfiguration.period.mustBeSpecified=The period must be specified 10 | SupportAutomatedBundleConfiguration.period.isNotAnInteger=The period must be an Integer between 1 and 24. 11 | SupportAutomatedBundleConfiguration.period.lowerThanMin=1h is the shortest period permitted. 12 | SupportAutomatedBundleConfiguration.period.greaterThanMax=24h is the longest period permitted. -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportAutomatedBundleConfiguration/components.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 |
7 | 8 | 11 | 12 | 13 | 17 | 21 | 22 | 23 |
24 |
25 |
26 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportAutomatedBundleConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 |
(${%enforcedDisable})
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | (${%enforcedPeriod}) 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportAutomatedBundleConfiguration/config.properties: -------------------------------------------------------------------------------- 1 | enforcedPeriod=Period enforced on startup by system property 2 | enforcedDisable=Disable enforced on startup by system property -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportAutomatedBundleConfiguration/help-components.html: -------------------------------------------------------------------------------- 1 |
2 | Select the components to include in the automated generated bundle. 3 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportAutomatedBundleConfiguration/help-enabled.html: -------------------------------------------------------------------------------- 1 |
2 | Enable the automated generation of a Support Bundle. 3 |
4 | The system property com.cloudbees.jenkins.support.SupportPlugin.AUTO_BUNDLE_PERIOD_HOURS=0 can be used to 5 | enforce this to disabled. 6 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportAutomatedBundleConfiguration/help-period.html: -------------------------------------------------------------------------------- 1 |
2 | How often automatic support bundles should be collected, in hours. Should be 1h unless you have very good reason 3 | to use a different period. 24h is the longest period permitted. 4 |
5 | The system property com.cloudbees.jenkins.support.SupportPlugin.AUTO_BUNDLE_PERIOD_HOURS can be used to 6 | enforce the value of the period. 7 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportPluginManagement/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 |

10 | 11 | ${it.displayName} 12 |

13 |

14 |

${%LOADING}
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/config/SupportPluginManagement/sidepanel.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/configfiles/Messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License 3 | # 4 | # Copyright (c) 2016, CloudBees, Inc. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | AgentsConfigFile.displayName=Agents config files (Encrypted secrets are redacted) -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/filter/ContentFilters/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/filter/ContentMappings/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |

Anonymized Items

32 |

Mappings

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Actual NameAnonymized Name
${item.key}${item.value}
45 |

Stop Words

46 |
    47 | 48 |
  • ${stopWord}
  • 49 |
    50 |
51 |
52 |
53 |
54 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/filter/Messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License 3 | # 4 | # Copyright (c) 2018, CloudBees, Inc. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | ContentMappings_DisplayName=Support Bundle Anonymization 26 | ContentMappings_Description=Provides anonymization mappings about support bundles 27 | ContentFilters_DisplayName=Support Bundle Anonymization 28 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/AbstractItemDirectoryComponent/help.html: -------------------------------------------------------------------------------- 1 |
2 | Archives the content of this item root directory. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/DirectoryComponent/component.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/DirectoryComponent/help-defaultExcludes.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Brian Westrich, Jean-Baptiste Quenot 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import org.apache.commons.lang.StringUtils 26 | 27 | div { 28 | p { 29 | raw(_("p1")) 30 | br {} 31 | code { 32 | text(StringUtils.join(org.apache.tools.ant.DirectoryScanner.defaultExcludes, ',')) 33 | } 34 | } 35 | p { 36 | raw(_("p2")) 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/DirectoryComponent/help-defaultExcludes.properties: -------------------------------------------------------------------------------- 1 | p1=This component uses Ant org.apache.tools.ant.DirectoryScanner which excludes by default the following patterns: 2 | p2=This option allows to enable or disable the default Ant exclusions. -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/DirectoryComponent/help-excludes.html: -------------------------------------------------------------------------------- 1 |
2 | Optionally specify the “excludes” pattern, 3 | such as **/subdir/subsubdir/ or dir/file*.txt 4 | (syntax reference). 5 | A file that matches this mask will not be archived even if it matches the mask specified in Includes section. 6 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/DirectoryComponent/help-includes.html: -------------------------------------------------------------------------------- 1 |
2 | Optionally specify the “includes” pattern, 3 | such as jobs/**/log*. 4 | A file that matches this mask will be archived unless it matches the mask specified in the Excludes section. 5 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/DirectoryComponent/help-maxDepth.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the depth below which directories / files will not be included. This must be a positive integer. 3 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/Messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License 3 | # 4 | # Copyright (c) 2018, CloudBees, Inc. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | DirectoryComponent_DisplayName=Files in Directory 26 | 27 | RunDirectoryComponent_DisplayName=Files in Build Root Directory 28 | 29 | AbstractItemDirectoryComponent_DisplayName=Files in Item Root Directory 30 | 31 | NodeRemoteDirectoryComponent_DisplayName=Files in Agent Remote FS Directory 32 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/NodeRemoteDirectoryComponent/help.html: -------------------------------------------------------------------------------- 1 |
2 | Archives the content of this Node remote directory. 3 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/impl/RunDirectoryComponent/help.html: -------------------------------------------------------------------------------- 1 |
2 | Archives the content of this build root directory. 3 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/support/threaddump/Messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License 3 | # 4 | # Copyright (c) 2020, CloudBees, Inc. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | ThreadDumpHighCPU_DisplayName=Thread dumps on high CPU usage -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 |
26 | This support plugin allows generation of support request bundles that contains diagnostic information to 27 | aid with resolving issues. 28 |
-------------------------------------------------------------------------------- /src/main/resources/js/progressPage.js: -------------------------------------------------------------------------------- 1 | function updateProgressUI(data) { 2 | if (data.isCompleted) { 3 | downloadMessage.style.display = "block"; 4 | downloadButton.href = "downloadBundle?taskId=" + data.taskId; // Update this path accordingly 5 | document.getElementById("progressMessage").textContent = "Support bundle has been generated."; 6 | downloadButton.click(); // Automatically start the download 7 | } 8 | } -------------------------------------------------------------------------------- /src/spotbugs/excludesFilter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/BundleFileNameTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support; 2 | 3 | import static org.hamcrest.CoreMatchers.equalTo; 4 | import static org.hamcrest.MatcherAssert.assertThat; 5 | 6 | import com.cloudbees.jenkins.support.api.SupportProvider; 7 | import edu.umd.cs.findbugs.annotations.NonNull; 8 | import java.io.PrintWriter; 9 | import java.time.Clock; 10 | import java.time.Instant; 11 | import java.time.ZoneOffset; 12 | import org.junit.Ignore; 13 | import org.junit.Rule; 14 | import org.junit.Test; 15 | import org.jvnet.hudson.test.JenkinsRule; 16 | import org.jvnet.hudson.test.TestExtension; 17 | import org.jvnet.localizer.Localizable; 18 | 19 | public class BundleFileNameTest { 20 | 21 | private static final Clock TEST_CLOCK = Clock.fixed(Instant.parse("2020-10-01T10:20:30Z"), ZoneOffset.UTC); 22 | 23 | @Rule 24 | public JenkinsRule j = new JenkinsRule(); 25 | 26 | @Test 27 | public void testGenerate_Default() { 28 | assertThat(BundleFileName.generate(TEST_CLOCK, null), equalTo("support_2020-10-01_10.20.30.zip")); 29 | } 30 | 31 | @Ignore("Relies on SupportPlugin object which is not instantiated by TestPluginManager") 32 | @Test 33 | public void testGenerate_WithSupportProvider() { 34 | assertThat(BundleFileName.generate(TEST_CLOCK, null), equalTo("amazing-support_2020-10-01_10.20.30.zip")); 35 | } 36 | 37 | @TestExtension("testGenerate_WithSupportProvider") 38 | public static class AmazingSupportProvider extends SupportProvider { 39 | @Override 40 | public String getName() { 41 | return "amazing-support"; 42 | } 43 | 44 | @Override 45 | public String getDisplayName() { 46 | return "Amazing Support"; 47 | } 48 | 49 | @Override 50 | public Localizable getActionTitle() { 51 | return null; 52 | } 53 | 54 | @Override 55 | public Localizable getActionBlurb() { 56 | return null; 57 | } 58 | 59 | @Override 60 | public void printAboutJenkins(PrintWriter out) {} 61 | } 62 | 63 | @Test 64 | public void testGenerate_WithQualifier() { 65 | assertThat( 66 | BundleFileName.generate(TEST_CLOCK, "qualifier"), equalTo("support_qualifier_2020-10-01_10.20.30.zip")); 67 | } 68 | 69 | @Test 70 | public void testGenerate_WithQualifierAndInstanceType() { 71 | assertThat( 72 | BundleFileName.generate(TEST_CLOCK, "qualifier"), 73 | equalTo("support_qualifier_instance_type_2020-10-01_10.20.30.zip")); 74 | } 75 | 76 | @TestExtension("testGenerate_WithQualifierAndInstanceType") 77 | public static class TestBundleNameInstanceTypeProvider extends BundleNameInstanceTypeProvider { 78 | @Override 79 | @NonNull 80 | public String getInstanceType() { 81 | return "instance_type"; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/BundleNamePrefixTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.core.StringStartsWith.startsWith; 5 | 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import org.junit.Rule; 10 | import org.junit.Test; 11 | import org.jvnet.hudson.test.JenkinsRule; 12 | import org.jvnet.hudson.test.TestExtension; 13 | 14 | public class BundleNamePrefixTest { 15 | 16 | private static final String CURRENT_YEAR = new SimpleDateFormat("yyyy").format(new Date()); 17 | 18 | @Rule 19 | public JenkinsRule j = new JenkinsRule(); 20 | 21 | @Test 22 | public void checkOriginalBehaviour() { 23 | assertThat(BundleFileName.generate(), startsWith("support_" + CURRENT_YEAR)); 24 | } 25 | 26 | @Test 27 | public void checkWithOneProvider() { 28 | assertThat(BundleFileName.generate(), startsWith("support_pouet_" + CURRENT_YEAR)); 29 | } 30 | 31 | @Test 32 | public void tooManyProviders() { 33 | assertThat(BundleFileName.generate(), startsWith("support_Zis_" + CURRENT_YEAR)); 34 | } 35 | 36 | @Test 37 | public void withSysProp() { 38 | System.setProperty(BundleNameInstanceTypeProvider.SUPPORT_BUNDLE_NAMING_INSTANCE_SPEC_PROPERTY, "paf"); 39 | assertThat(BundleFileName.generate(), startsWith("support_paf_" + CURRENT_YEAR)); 40 | System.getProperties().remove(BundleNameInstanceTypeProvider.SUPPORT_BUNDLE_NAMING_INSTANCE_SPEC_PROPERTY); 41 | } 42 | 43 | @TestExtension("checkWithOneProvider") 44 | public static class TestProvider extends BundleNameInstanceTypeProvider { 45 | @NonNull 46 | @Override 47 | public String getInstanceType() { 48 | return "pouet"; 49 | } 50 | } 51 | 52 | @TestExtension("tooManyProviders") 53 | public static class SpuriousProvider1 extends BundleNameInstanceTypeProvider { 54 | @NonNull 55 | @Override 56 | public String getInstanceType() { 57 | return "Zis"; 58 | } 59 | } 60 | 61 | @TestExtension("tooManyProviders") 62 | public static class SpuriousProvider2 extends BundleNameInstanceTypeProvider { 63 | @NonNull 64 | @Override 65 | public String getInstanceType() { 66 | return "Zat"; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/configfiles/AgentsConfigFileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2016, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.cloudbees.jenkins.support.configfiles; 25 | 26 | import static org.hamcrest.Matchers.hasKey; 27 | import static org.hamcrest.Matchers.not; 28 | import static org.junit.Assert.assertTrue; 29 | 30 | import com.cloudbees.jenkins.support.SupportTestUtils; 31 | import com.cloudbees.jenkins.support.filter.ContentFilters; 32 | import com.cloudbees.jenkins.support.filter.ContentMappings; 33 | import hudson.EnvVars; 34 | import java.util.Map; 35 | import org.hamcrest.MatcherAssert; 36 | import org.junit.Rule; 37 | import org.junit.Test; 38 | import org.jvnet.hudson.test.Issue; 39 | import org.jvnet.hudson.test.JenkinsRule; 40 | 41 | public class AgentsConfigFileTest { 42 | 43 | private static final String SENSITIVE_AGENT_NAME = "sensitive-agent"; 44 | 45 | @Rule 46 | public JenkinsRule j = new JenkinsRule(); 47 | 48 | @Test 49 | public void agentsConfigFile() throws Exception { 50 | j.createSlave("node1", "node1", new EnvVars()); 51 | String fileContent = SupportTestUtils.invokeComponentToString(new AgentsConfigFile()); 52 | assertTrue(fileContent.contains("node1")); 53 | } 54 | 55 | @Issue("JENKINS-66064") 56 | @Test 57 | public void agentsConfigFileFiltered() throws Exception { 58 | ContentFilters.get().setEnabled(true); 59 | j.createSlave(SENSITIVE_AGENT_NAME, "node1", new EnvVars()); 60 | Map output = SupportTestUtils.invokeComponentToMap(new AgentsConfigFile()); 61 | String filtered = ContentMappings.get().getMappings().get(SENSITIVE_AGENT_NAME); 62 | MatcherAssert.assertThat(output, hasKey("nodes/slave/" + filtered + "/config.xml")); 63 | MatcherAssert.assertThat(output, not(hasKey("nodes/slave/" + SENSITIVE_AGENT_NAME + "/config.xml"))); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/filter/FilteredInputStreamTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.ByteArrayInputStream; 6 | import java.io.IOException; 7 | import java.nio.charset.StandardCharsets; 8 | import org.junit.Test; 9 | 10 | public class FilteredInputStreamTest { 11 | 12 | @Test 13 | public void testReadSingleLine() throws IOException { 14 | String input = "foo bar"; 15 | String output; 16 | try (FilteredInputStream fis = new FilteredInputStream( 17 | new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)), 18 | StandardCharsets.UTF_8, 19 | String::toUpperCase)) { 20 | output = new String(fis.readAllBytes(), StandardCharsets.UTF_8); 21 | } 22 | assertEquals("FOO BAR" + System.lineSeparator(), output); 23 | } 24 | 25 | @Test 26 | public void testReadMultipleLines() throws IOException { 27 | String input = "Line 1\nLine 2\nLine 3"; 28 | String output; 29 | try (FilteredInputStream fis = new FilteredInputStream( 30 | new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)), 31 | StandardCharsets.UTF_8, 32 | String::toUpperCase)) { 33 | output = new String(fis.readAllBytes(), StandardCharsets.UTF_8); 34 | } 35 | assertEquals( 36 | "LINE 1" + System.lineSeparator() + "LINE 2" + System.lineSeparator() + "LINE 3" 37 | + System.lineSeparator(), 38 | output); 39 | } 40 | 41 | @Test 42 | public void testReadEmptyStream() throws IOException { 43 | byte[] input = new byte[0]; 44 | String output; 45 | try (FilteredInputStream fis = 46 | new FilteredInputStream(new ByteArrayInputStream(input), StandardCharsets.UTF_8, String::toUpperCase)) { 47 | output = new String(fis.readAllBytes(), StandardCharsets.UTF_8); 48 | } 49 | assertEquals("", output); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/filter/PasswordRedactorRegexBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.filter; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.is; 5 | import static org.hamcrest.Matchers.nullValue; 6 | 7 | import java.util.Collections; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.jvnet.hudson.test.JenkinsRule; 11 | 12 | public class PasswordRedactorRegexBuilderTest { 13 | 14 | @Rule 15 | public JenkinsRule r = new JenkinsRule(); 16 | 17 | @Test 18 | public void getPasswordPatternWhenWordsIsEmptyThenReturnNull() { 19 | assertThat(PasswordRedactorRegexBuilder.getPasswordPattern(Collections.emptySet()), is(nullValue())); 20 | } 21 | 22 | @Test 23 | public void getSecretMatcherWhenWordsIsEmptyThenReturnNull() { 24 | assertThat(PasswordRedactorRegexBuilder.getSecretMatcher(Collections.emptySet()), is(nullValue())); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/DumpExportTableTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.containsString; 5 | import static org.hamcrest.Matchers.hasItems; 6 | import static org.hamcrest.Matchers.lessThanOrEqualTo; 7 | import static org.junit.Assert.assertFalse; 8 | 9 | import com.cloudbees.jenkins.support.SupportTestUtils; 10 | import com.cloudbees.jenkins.support.timer.FileListCapComponent; 11 | import hudson.remoting.VirtualChannel; 12 | import hudson.slaves.DumbSlave; 13 | import java.io.Serializable; 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.List; 17 | import org.junit.Rule; 18 | import org.junit.Test; 19 | import org.jvnet.hudson.test.JenkinsRule; 20 | 21 | public class DumpExportTableTest { 22 | 23 | @Rule 24 | public JenkinsRule j = new JenkinsRule(); 25 | 26 | @Test 27 | public void testAddContents() throws Exception { 28 | // Given 29 | DumbSlave onlineAgent = j.createOnlineSlave(); 30 | 31 | // When 32 | String dumpTableString = SupportTestUtils.invokeComponentToString(new DumpExportTable()); 33 | 34 | // Then 35 | assertFalse("Should have dumped the export table.", dumpTableString.isEmpty()); 36 | 37 | List output = new ArrayList<>(Arrays.asList(dumpTableString.split("\n"))); 38 | assertThat(output, hasItems(containsString("hudson.remoting.ExportTable"))); 39 | } 40 | 41 | @Test 42 | public void testLargeExportTableTruncated() throws Exception { 43 | // Given 44 | DumbSlave onlineAgent = j.createOnlineSlave(); 45 | VirtualChannel channel = onlineAgent.getChannel(); 46 | // This will generate an export table with 2MB of content. 47 | for (int i = 0; i < 35000; i++) { 48 | channel.export(MockSerializable.class, new MockSerializable() {}); 49 | } 50 | 51 | // When 52 | String dumpTableString = SupportTestUtils.invokeComponentToString(new DumpExportTable()); 53 | 54 | // Then 55 | assertThat(dumpTableString.length(), lessThanOrEqualTo(FileListCapComponent.MAX_FILE_SIZE)); 56 | } 57 | 58 | public interface MockSerializable extends Serializable {} 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/ItemsContentTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.hamcrest.CoreMatchers.containsString; 4 | import static org.hamcrest.MatcherAssert.assertThat; 5 | 6 | import com.cloudbees.jenkins.support.SupportTestUtils; 7 | import com.cloudbees.jenkins.support.api.Component; 8 | import hudson.ExtensionList; 9 | import hudson.model.FreeStyleProject; 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.jvnet.hudson.test.JenkinsRule; 13 | import org.jvnet.hudson.test.MockFolder; 14 | 15 | /** 16 | * @author Allan Burdajewicz 17 | */ 18 | public class ItemsContentTest { 19 | 20 | @Rule 21 | public JenkinsRule j = new JenkinsRule(); 22 | 23 | @Test 24 | public void testItemsContent() throws Exception { 25 | MockFolder testFolder1 = j.createFolder("testFolder1"); 26 | FreeStyleProject project11 = testFolder1.createProject(FreeStyleProject.class, "testProject12"); 27 | project11.scheduleBuild2(0); 28 | j.waitUntilNoActivity(); 29 | project11.scheduleBuild2(0); 30 | j.waitUntilNoActivity(); 31 | 32 | testFolder1.createProject(FreeStyleProject.class, "testProject21"); 33 | 34 | FreeStyleProject project21 = 35 | j.createFolder("testFolder2").createProject(FreeStyleProject.class, "testProject21"); 36 | project21.scheduleBuild2(0); 37 | j.waitUntilNoActivity(); 38 | 39 | String itemsContentToString = SupportTestUtils.invokeComponentToString( 40 | ExtensionList.lookup(Component.class).get(ItemsContent.class)); 41 | 42 | assertThat(itemsContentToString, containsString(" * `hudson.model.FreeStyleProject`")); 43 | assertThat(itemsContentToString, containsString(" - Number of items: 3")); 44 | assertThat(itemsContentToString, containsString(" - Number of builds per job: 1.0 [n=3, s=1.0]")); 45 | assertThat(itemsContentToString, containsString(" * `org.jvnet.hudson.test.MockFolder`")); 46 | assertThat(itemsContentToString, containsString(" - Number of items: 2")); 47 | assertThat(itemsContentToString, containsString(" - Number of items per container: 1.5 [n=2, s=0.7]")); 48 | assertThat(itemsContentToString, containsString(" * Number of jobs: 3")); 49 | assertThat(itemsContentToString, containsString(" * Number of builds per job: 1.0 [n=3, s=1.0]")); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/JenkinsLogsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 CloudBees, Inc. 3 | */ 4 | package com.cloudbees.jenkins.support.impl; 5 | 6 | import static org.junit.Assert.assertFalse; 7 | 8 | import com.cloudbees.jenkins.support.SupportTestUtils; 9 | import com.cloudbees.jenkins.support.api.Component; 10 | import hudson.ExtensionList; 11 | import java.util.Objects; 12 | import org.junit.Rule; 13 | import org.junit.Test; 14 | import org.jvnet.hudson.test.JenkinsRule; 15 | 16 | public class JenkinsLogsTest { 17 | 18 | @Rule 19 | public JenkinsRule j = new JenkinsRule(); 20 | 21 | @Test 22 | public void testJenkinsLogsContent() { 23 | String jenkinsLogs = SupportTestUtils.invokeComponentToString( 24 | Objects.requireNonNull(ExtensionList.lookup(Component.class).get(JenkinsLogs.class))); 25 | assertFalse("Should write something", jenkinsLogs.isEmpty()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/NetworkInterfacesTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.containsString; 5 | 6 | import com.cloudbees.jenkins.support.api.Container; 7 | import com.cloudbees.jenkins.support.api.Content; 8 | import edu.umd.cs.findbugs.annotations.CheckForNull; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.IOException; 11 | import java.net.NetworkInterface; 12 | import java.util.Enumeration; 13 | import org.junit.Rule; 14 | import org.junit.Test; 15 | import org.jvnet.hudson.test.JenkinsRule; 16 | 17 | public class NetworkInterfacesTest { 18 | 19 | @Rule 20 | public JenkinsRule j = new JenkinsRule(); 21 | 22 | @Test 23 | public void testGetNetworkInterface() throws Exception { 24 | // This machine might not have a network interface. But how did it get this code? 25 | Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); 26 | if (!networkInterfaces.hasMoreElements()) return; 27 | 28 | NetworkInterface networkInterface = networkInterfaces.nextElement(); 29 | 30 | String expectedName = networkInterface.getDisplayName(); 31 | 32 | NetworkInterfaces ni = new NetworkInterfaces(); 33 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 34 | ni.addContents(new Container() { 35 | @Override 36 | public void add(@CheckForNull Content content) { 37 | try { 38 | content.writeTo(baos); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | }); 44 | String controllerNetworkInterfaces = baos.toString(); 45 | 46 | assertThat( 47 | "Should at least contain one network interface.", 48 | controllerNetworkInterfaces, 49 | containsString(expectedName)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/ProxyConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.hamcrest.CoreMatchers.containsString; 4 | import static org.hamcrest.CoreMatchers.not; 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | 7 | import com.cloudbees.jenkins.support.SupportTestUtils; 8 | import com.cloudbees.jenkins.support.api.Component; 9 | import hudson.ExtensionList; 10 | import hudson.ProxyConfiguration; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.Objects; 14 | import org.junit.Rule; 15 | import org.junit.Test; 16 | import org.jvnet.hudson.test.Issue; 17 | import org.jvnet.hudson.test.JenkinsRule; 18 | 19 | public class ProxyConfigurationTest { 20 | 21 | @Rule 22 | public JenkinsRule j = new JenkinsRule(); 23 | 24 | @Test 25 | @Issue({"JENKINS-68008", "JENKINS-73599"}) 26 | public void testProxyContent() { 27 | List noProxyHosts = Arrays.asList(".server.com", "*.example.com"); 28 | j.jenkins.setProxy(new ProxyConfiguration( 29 | "proxy.server.com", 30 | 1234, 31 | "proxyUser", 32 | "proxyPass", 33 | String.join("\n", noProxyHosts), 34 | "http://localhost:8080")); 35 | 36 | String ucMdToString = 37 | SupportTestUtils.invokeComponentToString(Objects.requireNonNull(ExtensionList.lookup(Component.class) 38 | .get(com.cloudbees.jenkins.support.impl.ProxyConfiguration.class))); 39 | assertThat(ucMdToString, containsString(" - Host: `proxy.server.com`")); 40 | assertThat(ucMdToString, containsString(" - Port: `1234`")); 41 | assertThat(ucMdToString, not(containsString("proxyUser"))); 42 | assertThat(ucMdToString, not(containsString("proxyPass"))); 43 | for (String noProxyHost : noProxyHosts) { 44 | assertThat(ucMdToString, containsString(" * `" + noProxyHost + "`")); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/RootCAsTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.startsWith; 5 | 6 | import java.io.StringWriter; 7 | import org.junit.Test; 8 | 9 | public class RootCAsTest { 10 | 11 | @Test 12 | public void getRootCAList() { 13 | StringWriter certsWriter = new StringWriter(); 14 | RootCAs.getRootCAList(certsWriter); 15 | String rootCAs = certsWriter.toString(); 16 | 17 | assertThat("output doesn't start with the Exception", rootCAs, startsWith("===== Trust Manager 0 =====\n")); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/SlaveLaunchLogsRestartTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2024 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.cloudbees.jenkins.support.impl; 26 | 27 | import static org.hamcrest.MatcherAssert.assertThat; 28 | import static org.hamcrest.Matchers.allOf; 29 | import static org.hamcrest.Matchers.containsString; 30 | 31 | import com.cloudbees.jenkins.support.SupportTestUtils; 32 | import hudson.ExtensionList; 33 | import org.junit.Rule; 34 | import org.junit.Test; 35 | import org.jvnet.hudson.test.JenkinsSessionRule; 36 | 37 | public final class SlaveLaunchLogsRestartTest { 38 | 39 | @Rule 40 | public JenkinsSessionRule rr = new JenkinsSessionRule(); 41 | 42 | @Test 43 | public void twoAgents() throws Throwable { 44 | rr.then(r -> { 45 | var s = r.createSlave("agent1", null, null); 46 | r.waitOnline(s); 47 | assertThat( 48 | "reflects launch of agent1", 49 | SupportTestUtils.invokeComponentToString(ExtensionList.lookupSingleton(SlaveLaunchLogs.class)), 50 | containsString("Z agent1] Remoting version: ")); 51 | r.jenkins.removeNode(s); 52 | }); 53 | rr.then(r -> { 54 | var s = r.createSlave("agent2", null, null); 55 | r.waitOnline(s); 56 | assertThat( 57 | "reflects launch of both agent1 & agent2", 58 | SupportTestUtils.invokeComponentToString(ExtensionList.lookupSingleton(SlaveLaunchLogs.class)), 59 | allOf( 60 | containsString("Z agent1] Remoting version: "), 61 | containsString("Z agent2] Remoting version: "))); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/SmartLogCleanerTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import com.cloudbees.jenkins.support.SupportPlugin; 7 | import com.cloudbees.jenkins.support.api.Component; 8 | import com.cloudbees.jenkins.support.filter.ContentFilters; 9 | import hudson.ExtensionList; 10 | import hudson.slaves.DumbSlave; 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.io.OutputStream; 14 | import java.nio.file.Files; 15 | import java.util.Collections; 16 | import java.util.List; 17 | import java.util.zip.ZipFile; 18 | import org.junit.Rule; 19 | import org.junit.Test; 20 | import org.junit.rules.TemporaryFolder; 21 | import org.jvnet.hudson.test.JenkinsRule; 22 | 23 | public class SmartLogCleanerTest { 24 | 25 | @Rule 26 | public JenkinsRule j = new JenkinsRule(); 27 | 28 | @Rule 29 | public TemporaryFolder temp = new TemporaryFolder(); 30 | 31 | @Test 32 | public void cleanUp() throws Exception { 33 | File cacheDir = new File(SupportPlugin.getLogsDirectory(), "winsw"); 34 | 35 | DumbSlave agent1 = j.createOnlineSlave(); 36 | DumbSlave agent2 = j.createOnlineSlave(); 37 | generateBundle(); 38 | 39 | assertNotNull("The cache directory is empty", cacheDir.list()); 40 | 41 | // wait for completion of SmartLogFetcher async tasks during the bundle generation 42 | for (int i = 0; i < 10; i++) { 43 | int cacheDirsCount = cacheDir.list().length; 44 | if (cacheDirsCount == 2) { 45 | break; 46 | } else { 47 | Thread.sleep(1000 * 10); 48 | } 49 | } 50 | 51 | assertEquals(cacheDir.list().length, 2); 52 | agent2.toComputer().disconnect(null).get(); 53 | j.getInstance().removeNode(agent2); 54 | 55 | generateBundle(); 56 | 57 | // wait for completion of SmartLogFetcher async tasks during the bundle generation 58 | for (int i = 0; i < 10; i++) { 59 | int cacheDirsCount = cacheDir.list().length; 60 | if (cacheDirsCount == 1) { 61 | break; 62 | } else { 63 | Thread.sleep(1000 * 10); 64 | } 65 | } 66 | 67 | assertEquals(cacheDir.list().length, 1); 68 | } 69 | 70 | private ZipFile generateBundle() throws IOException { 71 | List componentsToCreate = 72 | Collections.singletonList(ExtensionList.lookup(Component.class).get(SlaveLogs.class)); 73 | File bundleFile = temp.newFile(); 74 | try (OutputStream os = Files.newOutputStream(bundleFile.toPath())) { 75 | ContentFilters.get().setEnabled(false); 76 | SupportPlugin.writeBundle(os, componentsToCreate); 77 | return new ZipFile(bundleFile); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/TaskLogsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 CloudBees, Inc. 3 | */ 4 | package com.cloudbees.jenkins.support.impl; 5 | 6 | import static org.hamcrest.MatcherAssert.assertThat; 7 | import static org.junit.Assert.assertFalse; 8 | 9 | import com.cloudbees.jenkins.support.SupportTestUtils; 10 | import com.cloudbees.jenkins.support.api.Component; 11 | import hudson.ExtensionList; 12 | import hudson.triggers.SafeTimerTask; 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.nio.charset.Charset; 16 | import java.nio.file.Files; 17 | import java.util.Collections; 18 | import java.util.Objects; 19 | import org.hamcrest.Matchers; 20 | import org.junit.Rule; 21 | import org.junit.Test; 22 | import org.jvnet.hudson.test.JenkinsRule; 23 | 24 | public class TaskLogsTest { 25 | 26 | @Rule 27 | public JenkinsRule j = new JenkinsRule(); 28 | 29 | @Test 30 | public void testTaskRootSafeTimerLogs() throws IOException { 31 | File safeTimerTasksDir = SafeTimerTask.getLogsRoot(); 32 | safeTimerTasksDir.mkdir(); 33 | File testFile = new File(safeTimerTasksDir, "test.log"); 34 | Files.createFile(testFile.toPath()); 35 | Files.write( 36 | testFile.toPath(), 37 | Collections.singletonList("This is a test from SafeTimerTask dir"), 38 | Charset.defaultCharset()); 39 | 40 | String otherLogs = SupportTestUtils.invokeComponentToString( 41 | Objects.requireNonNull(ExtensionList.lookup(Component.class).get(TaskLogs.class))); 42 | assertFalse("Should collect *.log under the SafeTimerTask dir", otherLogs.isEmpty()); 43 | assertThat(otherLogs, Matchers.containsString("This is a test from SafeTimerTask dir")); 44 | } 45 | 46 | @Test 47 | public void testTaskLogs() throws IOException { 48 | File tasksDir = new File(SafeTimerTask.getLogsRoot(), "tasks"); 49 | SafeTimerTask.getLogsRoot().mkdir(); 50 | tasksDir.mkdir(); 51 | File testFile = new File(tasksDir, "test.log"); 52 | Files.createFile(testFile.toPath()); 53 | Files.write( 54 | testFile.toPath(), 55 | Collections.singletonList("This is a test from tasks dir"), 56 | Charset.defaultCharset()); 57 | 58 | String otherLogs = SupportTestUtils.invokeComponentToString( 59 | Objects.requireNonNull(ExtensionList.lookup(Component.class).get(TaskLogs.class))); 60 | assertFalse("Should collect *.log under the tasks dir", otherLogs.isEmpty()); 61 | assertThat(otherLogs, Matchers.containsString("This is a test from tasks dir")); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/UpdateCenterTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.impl; 2 | 3 | import static org.hamcrest.CoreMatchers.containsString; 4 | import static org.hamcrest.MatcherAssert.assertThat; 5 | 6 | import com.cloudbees.jenkins.support.SupportTestUtils; 7 | import com.cloudbees.jenkins.support.api.Component; 8 | import hudson.ExtensionList; 9 | import hudson.model.UpdateSite; 10 | import java.util.Objects; 11 | import org.junit.Rule; 12 | import org.junit.Test; 13 | import org.jvnet.hudson.test.JenkinsRule; 14 | 15 | public class UpdateCenterTest { 16 | 17 | @Rule 18 | public JenkinsRule j = new JenkinsRule(); 19 | 20 | @Test 21 | public void testUpdateCenterContent() { 22 | String ucMdToString = SupportTestUtils.invokeComponentToString( 23 | Objects.requireNonNull(ExtensionList.lookup(Component.class).get(UpdateCenter.class))); 24 | for (UpdateSite site : j.jenkins.getUpdateCenter().getSiteList()) { 25 | assertThat(ucMdToString, containsString(" - Id: " + site.getId())); 26 | assertThat(ucMdToString, containsString(" - Url: " + site.getUrl())); 27 | assertThat(ucMdToString, containsString(" - Connection Url: " + site.getConnectionCheckUrl())); 28 | assertThat( 29 | ucMdToString, 30 | containsString(" - Implementation Type: " + site.getClass().getName())); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/impl/UserCountTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 CloudBees, Inc. 3 | */ 4 | package com.cloudbees.jenkins.support.impl; 5 | 6 | import static org.hamcrest.CoreMatchers.containsString; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | import com.cloudbees.jenkins.support.SupportTestUtils; 10 | import com.cloudbees.jenkins.support.api.Component; 11 | import hudson.ExtensionList; 12 | import hudson.model.User; 13 | import jenkins.security.LastGrantedAuthoritiesProperty; 14 | import org.junit.Rule; 15 | import org.junit.Test; 16 | import org.jvnet.hudson.test.Issue; 17 | import org.jvnet.hudson.test.JenkinsRule; 18 | 19 | public class UserCountTest { 20 | 21 | @Rule 22 | public JenkinsRule j = new JenkinsRule(); 23 | 24 | @Test 25 | @Issue("JENKINS-56245") 26 | public void testAboutJenkinsContent() throws Exception { 27 | User.getOrCreateByIdOrFullName("alice"); 28 | User.getOrCreateByIdOrFullName("bob"); 29 | User.getOrCreateByIdOrFullName("charlie"); 30 | User.getOrCreateByIdOrFullName("dave").addProperty(new LastGrantedAuthoritiesProperty()); 31 | User.getOrCreateByIdOrFullName("eve").addProperty(new LastGrantedAuthoritiesProperty()); 32 | 33 | String usersMdToString = SupportTestUtils.invokeComponentToString( 34 | ExtensionList.lookup(Component.class).get(UserCount.class)); 35 | assertThat(usersMdToString, containsString(" * Non Authenticated User Count: " + 3)); 36 | assertThat(usersMdToString, containsString(" * Authenticated User Count: " + 2)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/measures/ChronoTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.measures; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import com.cloudbees.jenkins.support.util.Chrono; 7 | import org.junit.Test; 8 | 9 | public class ChronoTest { 10 | @Test 11 | public void chronoTest() throws Exception { 12 | Chrono c = new Chrono("Test Chrono"); 13 | Thread.sleep(1000); 14 | c.markFromPrevious("After 1s"); 15 | assertTrue(c.getMeasure("After 1s") >= 1000); 16 | 17 | Thread.sleep(3000); 18 | c.mark("After 3s", "After 1s", "Test Chrono"); 19 | assertTrue(c.getMeasure("After 3s") >= 3000); 20 | assertTrue(c.getMeasures("After 3s").get("Test Chrono") >= 4000); 21 | 22 | c.mark("After 3s from beginning"); 23 | assertTrue(c.getMeasure("After 3s from beginning") >= 4000); 24 | 25 | Thread.sleep(400); 26 | c.markFromPrevious("After 400"); 27 | assertTrue(c.getMeasure("After 400") >= 400); 28 | assertEquals(c.getMeasure("After 400"), c.getMeasures("After 400").get("After 3s from beginning")); 29 | 30 | System.out.println(c.printMeasures()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/startup/ShutdownComponentTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.startup; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.greaterThan; 5 | 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.jvnet.hudson.test.JenkinsRule; 9 | import org.jvnet.hudson.test.RealJenkinsRule; 10 | 11 | public class ShutdownComponentTest { 12 | @Rule 13 | public RealJenkinsRule rr = new RealJenkinsRule() 14 | .javaOptions("-Dcom.cloudbees.jenkins.support.startup.ShutdownComponent.INITIAL_DELAY_SECONDS=0"); 15 | 16 | @Test 17 | public void checkThreadDumpsAreCreated() throws Throwable { 18 | rr.startJenkins(); 19 | rr.stopJenkins(); 20 | rr.then(ShutdownComponentTest::assertThreadDumpsAreCreated); 21 | } 22 | 23 | private static void assertThreadDumpsAreCreated(JenkinsRule r) { 24 | assertThat(ShutdownComponent.get().getLogs().getSize(), greaterThan(0)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/timer/FileListCapTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.cloudbees.jenkins.support.timer; 25 | 26 | import static org.junit.Assert.assertEquals; 27 | 28 | import org.junit.Rule; 29 | import org.junit.Test; 30 | import org.junit.rules.TemporaryFolder; 31 | 32 | public class FileListCapTest { 33 | 34 | @Rule 35 | public TemporaryFolder tmp = new TemporaryFolder(); 36 | 37 | @Test 38 | public void add() throws Exception { 39 | FileListCap flc = new FileListCap(tmp.getRoot(), 3); 40 | for (int i = 0; i < 10; i++) { 41 | flc.add(tmp.newFile()); 42 | } 43 | assertEquals(3, flc.getFolder().list().length); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/util/IgnoreCloseOutputStreamTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.cloudbees.jenkins.support.util; 25 | 26 | import static org.mockito.BDDMockito.then; 27 | 28 | import java.io.IOException; 29 | import java.io.OutputStream; 30 | import org.junit.Rule; 31 | import org.junit.Test; 32 | import org.mockito.Mock; 33 | import org.mockito.junit.MockitoJUnit; 34 | import org.mockito.junit.MockitoRule; 35 | 36 | public class IgnoreCloseOutputStreamTest { 37 | 38 | @Rule 39 | public MockitoRule rule = MockitoJUnit.rule(); 40 | 41 | @Mock 42 | private OutputStream out; 43 | 44 | @Test 45 | public void shouldFlushInsteadOfClose() throws IOException { 46 | IgnoreCloseOutputStream stream = new IgnoreCloseOutputStream(out); 47 | 48 | stream.close(); 49 | 50 | then(out).should().flush(); 51 | then(out).shouldHaveNoMoreInteractions(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/util/IgnoreCloseWriterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.cloudbees.jenkins.support.util; 25 | 26 | import static org.mockito.BDDMockito.then; 27 | 28 | import java.io.IOException; 29 | import java.io.Writer; 30 | import org.junit.Rule; 31 | import org.junit.Test; 32 | import org.mockito.Mock; 33 | import org.mockito.junit.MockitoJUnit; 34 | import org.mockito.junit.MockitoRule; 35 | 36 | public class IgnoreCloseWriterTest { 37 | 38 | @Rule 39 | public MockitoRule rule = MockitoJUnit.rule(); 40 | 41 | @Mock 42 | private Writer out; 43 | 44 | @Test 45 | public void shouldFlushInsteadOfClose() throws IOException { 46 | IgnoreCloseWriter stream = new IgnoreCloseWriter(out); 47 | 48 | stream.close(); 49 | 50 | then(out).should().flush(); 51 | then(out).shouldHaveNoMoreInteractions(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/util/MarkdownTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class MarkdownTest { 8 | 9 | @Test 10 | public void escapeUnderscore() { 11 | assertEquals("a_b", Markdown.escapeUnderscore("a_b")); 12 | assertEquals("a`b", Markdown.escapeUnderscore("a`b")); 13 | } 14 | 15 | @Test 16 | public void escapeBacktick() { 17 | assertEquals("a`b", Markdown.escapeBacktick("a`b")); 18 | assertEquals("a_b", Markdown.escapeBacktick("a_b")); 19 | } 20 | 21 | @Test 22 | public void prettyNone() { 23 | assertEquals(Markdown.NONE_STRING, Markdown.prettyNone(null)); 24 | assertEquals(Markdown.NONE_STRING, Markdown.prettyNone("")); 25 | assertEquals("a", Markdown.prettyNone("a")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/support/util/StreamUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.support.util; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | 5 | import org.junit.Test; 6 | 7 | public class StreamUtilsTest { 8 | 9 | @Test 10 | public void nullCharacterShouldNotMarkFileAsBinary() { 11 | String withNullCharacter = "a" + '\0' + "b"; 12 | assertFalse(StreamUtils.isNonWhitespaceControlCharacter(withNullCharacter.getBytes())); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/api/non-utf8.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/support-core-plugin/a2a9f06eed6188fb78f636ad9b2e6ba5c048ea88/src/test/resources/com/cloudbees/jenkins/support/api/non-utf8.txt -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/configuration-as-code.yaml: -------------------------------------------------------------------------------- 1 | security: 2 | anonymizeSupportBundle: 3 | enabled: true 4 | support: 5 | automatedBundleConfiguration: 6 | componentIds: 7 | - "AboutBrowser" 8 | - "AboutJenkins" 9 | - "AboutUser" 10 | - "AdministrativeMonitors" 11 | - "AgentProtocols" 12 | - "BuildQueue" 13 | - "CustomLogs" 14 | - "DumpExportTable" 15 | - "EnvironmentVariables" 16 | - "FileDescriptorLimit" 17 | - "ItemsContent" 18 | - "ControllerJVMProcessSystemMetricsContents" 19 | - "JenkinsLogs" 20 | - "LoadStats" 21 | - "LoggerManager" 22 | - "Metrics" 23 | - "NetworkInterfaces" 24 | - "NodeMonitors" 25 | - "ReverseProxy" 26 | - "RunningBuilds" 27 | - "AgentCommandStatistics" 28 | - "ControllerSystemConfiguration" 29 | - "SystemProperties" 30 | - "TaskLogs" 31 | - "ThreadDumps" 32 | - "UpdateCenter" 33 | - "UserCount" 34 | - "SlowRequestComponent" 35 | - "DeadlockRequestComponent" 36 | - "PipelineTimings" 37 | - "PipelineThreadDump" 38 | enabled: true 39 | period: 2 40 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/filter/ContentMappingsTest/additionalStopWordsIncludedAsStopWord/support/additional-stop-words.txt: -------------------------------------------------------------------------------- 1 | abc 2 | 3 | https://core.example.com 4 | 5 | john doe 6 | a very long sentence 7 | agents 8 | 192.168.0.1 9 |

10 | leadingspaces 11 | trailingspaces -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/filter/ContentMappingsTest/jenkinsVersionIncludedAsStopWord/com.cloudbees.jenkins.support.filter.ContentFilters.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/filter/ContentMappingsTest/jenkinsVersionIncludedAsStopWord/com.cloudbees.jenkins.support.filter.ContentMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | all 5 | authenticated 6 | item 7 | everyone 8 | admin 9 | label 10 | master 11 | unknown 12 | node 13 | computer 14 | view 15 | system 16 | jenkins 17 | anonymous 18 | user 19 | 20 | 21 | 22 | 1.2.3.4 23 | ip_thin_idea 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/filter/ContentMappingsTest/operatingSystemIncludedAsStopWord/com.cloudbees.jenkins.support.filter.ContentFilters.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/support/filter/ContentMappingsTest/operatingSystemIncludedAsStopWord/com.cloudbees.jenkins.support.filter.ContentMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | all 5 | authenticated 6 | item 7 | everyone 8 | admin 9 | label 10 | master 11 | unknown 12 | node 13 | computer 14 | view 15 | system 16 | jenkins 17 | anonymous 18 | user 19 | 20 | 21 | 22 | Linux 23 | label_characteristic_chocolate 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/test/resources/images/support.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/support-core-plugin/a2a9f06eed6188fb78f636ad9b2e6ba5c048ea88/src/test/resources/images/support.png --------------------------------------------------------------------------------