Retire the project on OpenDev

It has been migrated to the Jenkins community:
https://github.com/jenkinsci/gearman-plugin/

Depends-On: Ib6010d7ce85a934501c50a53e9ac78dcf74bc403
Change-Id: I0c84db2ad3fbb4d9f0eff793a0159c6ed3a8e25c
This commit is contained in:
Antoine Musso 2021-05-27 17:23:43 +02:00
parent 6f898a9b4d
commit 0c47b4292d
50 changed files with 8 additions and 4595 deletions

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

4
.gitignore vendored
View File

@ -1,4 +0,0 @@
/target
/version.properties
/work
/.config

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>gearman-plugin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>
<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
</pydev_project>

View File

@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -1,4 +0,0 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

202
LICENSE
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,55 +1,11 @@
Overview
========
This plugin uses Gearman to support multiple Jenkins masters.
More info can be found at https://wiki.jenkins-ci.org/display/JENKINS/Gearman+Plugin
This project is no longer maintained on OpenDev.
Contributing
============
If you would like to contribute to the development of OpenStack,
you must follow the steps in this page:
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
http://docs.openstack.org/infra/manual/developers.html
If you already have a good understanding of how the system works and your
OpenStack accounts are set up, you can skip to the development workflow section
of this documentation to learn how changes to OpenStack should be submitted for
review via the Gerrit tool:
http://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.
Project site:
* https://wiki.jenkins-ci.org/display/JENKINS/Gearman+Plugin
Patches are submitted via Gerrit at:
* https://review.openstack.org/
Bugs should be filed on StoryBoard, not GitHub:
https://storyboard.openstack.org/#!/project/706
Cloning:
* https://git.openstack.org/openstack-infra/gearman-plugin
License
=======
Copyright 2013 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The Jenkins Gearman plugin development has been migrated to the Jenkins
community and is being continued at:
https://github.com/jenkinsci/gearman-plugin/

31
bsd.txt
View File

@ -1,31 +0,0 @@
Gearman Java library
Copyright (C) 2009 Eric Lambert
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* The names of its contributors may not be used to endorse or
promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,3 +0,0 @@
#!/bin/bash -eux
. version-properties.sh
mvn -Dproject-version="$PROJECT_VER" -DskipTests=true clean package

3
debug
View File

@ -1,3 +0,0 @@
export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
rm -rf work/plugins
mvn -Dmaven.test.skip=true -DskipTests=true clean hpi:run

View File

@ -1 +0,0 @@
mvn -Dmaven.test.skip=true -DskipTests=true clean install

345
pom.xml
View File

@ -1,345 +0,0 @@
<?xml version="1.0"?>
<!--
Copyright 2013 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
Pass in the version on manual builds (i.e. mvn clean package -Dproject-version=1.0)
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.625.3</version> <!--which version of Jenkins is this plugin built against? -->
</parent>
<artifactId>gearman-plugin</artifactId>
<packaging>hpi</packaging>
<version>${project-version}</version>
<name>Gearman Plugin</name>
<description>Integrates Gearman application framework with Jenkins</description>
<url>http://wiki.jenkins-ci.org/display/JENKINS/Gearman+Plugin</url>
<licenses>
<license>
<name>Apache License Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>zaro0508</id>
<name>Khai Do</name>
<email>zaro0508@gmail.com</email>
</developer>
</developers>
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
</repository>
<repository>
<id>dev.nightlabs.org</id>
<url>http://dev.nightlabs.org/maven-repository/repo/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
<distributionManagement>
<repository>
<id>maven.jenkins-ci.org</id>
<url>http://maven.jenkins-ci.org:8081/content/repositories/releases/</url>
</repository>
<site>
<id>github-project-site</id>
<url>gitsite:git@github.com/openstack-infra/gearman-plugin</url>
</site>
</distributionManagement>
<properties>
<!-- http://docs.codehaus.org/display/MAVENUSER/POM+Element+for+Source+File+Encoding -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compileTarget>1.6</compileTarget>
<!-- define all plugin versions -->
<maven.version>3.0.1</maven.version>
<maven-antrun-plugin.version>1.6</maven-antrun-plugin.version>
<maven-assembly-plugin.version>2.2</maven-assembly-plugin.version>
<maven-changelog-plugin.version>2.2</maven-changelog-plugin.version>
<maven-checkstyle-plugin.version>2.6</maven-checkstyle-plugin.version>
<maven-clean-plugin.version>2.4.1</maven-clean-plugin.version>
<maven-compiler-plugin.version>2.3.2</maven-compiler-plugin.version>
<maven-dependency-plugin.version>2.1</maven-dependency-plugin.version>
<maven-deploy-plugin.version>2.5</maven-deploy-plugin.version>
<maven-doap-plugin.version>1.0</maven-doap-plugin.version>
<maven-eclipse-plugin.version>2.8</maven-eclipse-plugin.version>
<maven-enforcer-plugin.version>1.0</maven-enforcer-plugin.version>
<maven-help-plugin.version>2.1.1</maven-help-plugin.version>
<maven-install-plugin.version>2.3.1</maven-install-plugin.version>
<maven-javadoc-plugin.version>2.7</maven-javadoc-plugin.version>
<maven-jar-plugin.version>2.3.1</maven-jar-plugin.version>
<maven-jetty-plugin.version>6.1.26</maven-jetty-plugin.version>
<maven-jxr-plugin.version>2.2</maven-jxr-plugin.version>
<maven-pmd-plugin.version>2.5</maven-pmd-plugin.version>
<maven-project-info-reports-plugin.version>2.3.1</maven-project-info-reports-plugin.version>
<maven-plugin-plugin.version>2.4.3</maven-plugin-plugin.version>
<maven-reactor-plugin.version>1.0</maven-reactor-plugin.version>
<maven-release-plugin.version>2.1</maven-release-plugin.version>
<maven-remote-resources-plugin.version>1.1</maven-remote-resources-plugin.version>
<maven-resources-plugin.version>2.4.3</maven-resources-plugin.version>
<maven-site-plugin.version>2.1.1</maven-site-plugin.version>
<maven-source-plugin.version>2.1.2</maven-source-plugin.version>
<maven-surefire-plugin.version>2.7.2</maven-surefire-plugin.version>
<maven-surefire-report-plugin.version>2.7.2</maven-surefire-report-plugin.version>
<maven-war-plugin.version>2.1.1</maven-war-plugin.version>
<apt-maven-plugin.version>1.0-alpha-4</apt-maven-plugin.version>
<axistools-maven-plugin.version>1.4</axistools-maven-plugin.version>
<buildnumber-maven-plugin.version>1.0-beta-4</buildnumber-maven-plugin.version>
<build-helper-maven-plugin.version>1.5</build-helper-maven-plugin.version>
<cargo-maven2-plugin.version>1.0.5</cargo-maven2-plugin.version>
<cobertura-maven-plugin.version>2.4</cobertura-maven-plugin.version>
<exec-maven-plugin.version>1.2</exec-maven-plugin.version>
<findbugs-maven-plugin.version>2.3.1</findbugs-maven-plugin.version>
<gwt-maven-plugin.version>2.1.0-1</gwt-maven-plugin.version>
<javancss-maven-plugin.version>2.0</javancss-maven-plugin.version>
<jdepend-maven-plugin.version>2.0-beta-2</jdepend-maven-plugin.version>
<openjpa-maven-plugin.version>1.2</openjpa-maven-plugin.version>
<taglist-maven-plugin.version>2.4</taglist-maven-plugin.version>
<versions-maven-plugin.version>1.2</versions-maven-plugin.version>
<xml-maven-plugin.version>1.0-beta-3</xml-maven-plugin.version>
<gson.version>2.2.2</gson.version>
<gearman.version>0.6</gearman.version>
<hamcrest.version>1.3</hamcrest.version>
<mockito.version>1.9.0</mockito.version>
<powermock.version>1.4.12</powermock.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${compileSource}</source>
<target>${compileTarget}</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven-enforcer-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>${maven-install-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>${maven-release-plugin.version}</version>
<configuration>
<allowTimestampedSnapshots>true</allowTimestampedSnapshots>
<autoVersionSubmodules>true</autoVersionSubmodules>
<goals>clean deploy</goals>
<preparationGoals>clean deploy</preparationGoals>
<releaseProfiles>release</releaseProfiles>
</configuration>
</plugin>
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>${maven-remote-resources-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-doap-plugin</artifactId>
<version>${maven-doap-plugin.version}</version>
<executions>
<execution>
<id>site</id>
<phase>pre-site</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<doapFile>${project.reporting.outputDirectory}/doap.rdf</doapFile>
<asfExtOptions>
<included>false</included>
</asfExtOptions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-changelog-plugin</artifactId>
<version>${maven-changelog-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${maven-checkstyle-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-jxr-plugin</artifactId>
<version>${maven-jxr-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-pmd-plugin</artifactId>
<version>${maven-pmd-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>${maven-plugin-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>${maven-project-info-reports-plugin.version}</version>
<reportSets>
<reportSet>
<reports>
<report>cim</report>
<report>distribution-management</report>
<report>index</report>
<report>issue-tracking</report>
<report>license</report>
<report>mailing-list</report>
<report>project-team</report>
<report>summary</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven-surefire-report-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>javancss-maven-plugin</artifactId>
<version>${javancss-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
<version>${jdepend-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>taglist-maven-plugin</artifactId>
<version>${taglist-maven-plugin.version}</version>
</plugin>
</plugins>
</reporting>
<dependencies>
<dependency>
<groupId>org.gearman</groupId>
<artifactId>gearman-java</artifactId>
<version>${gearman.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,2 +0,0 @@
rm -rf work/plugins/gearman*
mvn -Dmaven.test.skip=true -DskipTests=true clean hpi:run

View File

@ -1,189 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import java.util.Date;
import java.util.Set;
import org.gearman.common.GearmanNIOJobServerConnection;
import org.gearman.worker.GearmanFunctionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base object for gearman worker threads
*
*
* @author Khai Do
*/
public abstract class AbstractWorkerThread implements Runnable {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
protected String host;
protected int port;
protected String name;
protected MyGearmanWorkerImpl worker;
protected GearmanNIOJobServerConnection conn;
protected AvailabilityMonitor availability;
private Thread thread;
private boolean running = false;
public AbstractWorkerThread(String host, int port, String name,
AvailabilityMonitor availability) {
setHost(host);
setPort(port);
setName(name);
setAvailability(availability);
}
protected void initWorker() {
synchronized(this) {
if (running) {
worker = new MyGearmanWorkerImpl(getAvailability());
conn = new GearmanNIOJobServerConnection(host, port);
}
}
}
// Only for unit tests:
protected void testInitWorker() {
running = true;
initWorker();
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AvailabilityMonitor getAvailability() {
return availability;
}
public void setAvailability(AvailabilityMonitor availability) {
this.availability = availability;
}
/*
* Register jobs with the gearman worker.
* This method should be overriden.
*/
public void registerJobs() {
logger.info("---- AbstractorWorker registerJobs function ----");
}
public void updateJobs(Set<GearmanFunctionFactory> functions) {
worker.setFunctions(functions);
}
/*
* Start the thread
*/
public void start() {
running = true;
thread = new Thread(this, "Gearman worker " + name);
thread.start();
}
/*
* Stop the thread
*/
public void stop() {
logger.info("---- " + getName() + " Request to stop AWT: " + this);
logger.info("---- " + getName() + " Thread: " + thread + " name: " + thread.getName());
logger.info("---- " + getName() + " Worker: " + worker);
synchronized(this) {
running = false;
if (worker != null) {
worker.stop();
}
}
logger.info("---- " + getName() + " Interrupting worker");
// Interrupt the thread so it unblocks any blocking call
thread.interrupt();
logger.info("---- " + getName() + " Stop request done");
}
/*
* Execute the thread (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
initWorker();
while (running) {
try {
logger.info("---- Starting Worker "+ getName() +" ("+new Date().toString()+")");
worker.addServer(conn);
worker.setWorkerID(name);
worker.setJobUniqueIdRequired(true);
registerJobs();
worker.work();
} catch (Exception e) {
logger.error("---- Exception while running worker " + getName(), e);
if (!running) continue;
worker.shutdown();
if (!running) continue;
try {
Thread.sleep(2000);
} catch (InterruptedException e2) {
logger.error("---- Exception while waiting to restart worker " + getName(), e2);
}
if (!running) continue;
initWorker();
}
}
// Thread exits
}
public boolean isAlive() {
return thread.isAlive();
}
}

View File

@ -1,40 +0,0 @@
/*
*
* Copyright 2013 OpenStack Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Queue;
public interface AvailabilityMonitor {
// Reserve exclusive access for this worker.
public void lock(MyGearmanWorkerImpl worker)
throws InterruptedException;
// Release exclusive access for this worker.
public void unlock(MyGearmanWorkerImpl worker);
// Notify waiting workers that they should try again to get the
// lock.
public void wake();
// A worker holding the lock has scheduled a build with this UUID.
public void expectUUID(String UUID);
// Called by Jenkins to decide if a build can run on this node.
public boolean canTake(Queue.BuildableItem item);
}

View File

@ -1,130 +0,0 @@
/*
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.Extension;
import hudson.model.TaskListener;
import hudson.model.Computer;
import hudson.slaves.ComputerListener;
import hudson.slaves.OfflineCause;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Update gearman workers on node state and configuration changes
*/
@Extension
public class ComputerListenerImpl extends ComputerListener {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
@Override
public void onConfigurationChange() {
// only fired on nodes configuration changes like a label or
// name change. Not fired on state changes, like offline or online.
logger.info("---- " + ComputerListenerImpl.class.getName() + ":"
+ " onConfigurationChange");
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
// re-register gearman functions on node configuration changes,
// specifically node label changes
GearmanProxy.getInstance().registerJobs();
// TODO: adjust for an update to executors. Method does not provide the
// computer to know which thread to remove or add
}
@Override
public void onOffline(Computer c) {
// gets called when existing slave dis-connects
// gets called when slave is deleted.
logger.info("---- " + ComputerListenerImpl.class.getName() + ":"
+ " onOffline computer" + c);
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
// stop worker when jenkins slave is deleted or disconnected
GearmanProxy.getInstance().stop(c);
}
@Override
public void onOnline(Computer c, TaskListener listener) throws IOException,
InterruptedException {
// gets called when master goes into online state
// gets called when existing slave re-connects
// gets called when new slave goes into online state
logger.info("---- " + ComputerListenerImpl.class.getName() + ":"
+ " onOnline computer " + c);
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
GearmanProxy gp = GearmanProxy.getInstance();
/*
* Spawn management executor worker if one doesn't exist yet.
* This worker does not need any executors. It only needs
* to work with gearman.
*/
gp.createManagementWorker();
// on creation of new slave
gp.createExecutorWorkersOnNode(c);
}
@Override
public void onTemporarilyOffline(Computer c, OfflineCause cause) {
// fired when master or slave goes into temporary offline state
logger.info("---- " + ComputerListenerImpl.class.getName() + ":"
+ " onTemporarilyOffline computer " + c);
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
// re-register gearman functions on node status change,
GearmanProxy.getInstance().registerJobs();
}
@Override
public void onTemporarilyOnline(Computer c) {
// fired when master or slave goes into temporary online state
logger.info("---- " + ComputerListenerImpl.class.getName() + ":"
+ " onTemporarilyOnline computer " + c);
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
// re-register gearman functions on node status change,
GearmanProxy.getInstance().registerJobs();
}
}

View File

@ -1,33 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
/*
* Constants for the Gearman Plugin
*/
public interface Constants {
/* Defines. */
public static final String GEARMAN_DEFAULT_EXECUTOR_NAME = "anonymous";
public static final boolean GEARMAN_DEFAULT_ENABLE_PLUGIN = false;
public static final String GEARMAN_DEFAULT_TCP_HOST = "127.0.0.1";
public static final int GEARMAN_DEFAULT_TCP_PORT = 4730;
public static final String PLUGIN_LOGGER_NAME = "hudson.plugins.gearman.logger";
}

View File

@ -1,92 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* This is adapted from gearman-java with the following license
*
* Copyright (C) 2009 by Eric Lambert <Eric.Lambert@sun.com>
* Use and distribution licensed under the BSD license. See
* the bsd.txt file in the parent directory for full text.
*/
package hudson.plugins.gearman;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Project;
import java.lang.reflect.Constructor;
import org.gearman.common.Constants;
import org.gearman.worker.DefaultGearmanFunctionFactory;
import org.gearman.worker.GearmanFunction;
import org.slf4j.LoggerFactory;
public class CustomGearmanFunctionFactory extends DefaultGearmanFunctionFactory {
private final AbstractProject<?,?> project;
private final Computer computer;
private final String theClass;
private final String masterName;
private final MyGearmanWorkerImpl worker;
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(
Constants.GEARMAN_WORKER_LOGGER_NAME);
public CustomGearmanFunctionFactory(String functionName, String className,
AbstractProject<?,?> project, Computer computer,
String masterName,
MyGearmanWorkerImpl worker) {
super(functionName, className);
this.theClass = className;
this.project = project;
this.computer = computer;
this.masterName = masterName;
this.worker = worker;
}
@Override
public GearmanFunction getFunction() {
return createFunctionInstance(theClass, project, computer, masterName,
worker);
}
private static GearmanFunction createFunctionInstance(String className, AbstractProject<?,?> project, Computer computer, String masterName, MyGearmanWorkerImpl worker) {
GearmanFunction f = null;
try {
Class<?> c = Class.forName(className);
Constructor<?> con = c.getConstructor(new Class[]{AbstractProject.class, Computer.class, String.class, MyGearmanWorkerImpl.class});
Object o = con.newInstance(new Object[] {project, computer, masterName, worker});
if (o instanceof GearmanFunction) {
f = (GearmanFunction) o;
} else {
LOG.warn("Specified class " + className +
" is not a Gearman Function ");
}
} catch (Exception e) {
LOG.warn("Unable to create instance of " +
"Function: " + className, e);
}
return f;
}
}

View File

@ -1,179 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Label;
import hudson.model.labels.LabelAtom;
import hudson.model.Node;
import hudson.model.Node.Mode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import jenkins.model.Jenkins;
import org.gearman.worker.GearmanFunctionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* This is the thread to run gearman executors
* Executors are used to initiate jenkins builds
*
* @author Khai Do
*
*/
public class ExecutorWorkerThread extends AbstractWorkerThread{
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
private final Computer computer;
private final String masterName;
private HashMap<String,GearmanFunctionFactory> functionMap;
// constructor
public ExecutorWorkerThread(String host, int port, String name,
Computer computer, String masterName,
AvailabilityMonitor availability) {
super(host, port, name, availability);
this.computer = computer;
this.masterName = masterName;
}
@Override
protected void initWorker() {
availability.unlock(worker);
super.initWorker();
this.functionMap = new HashMap<String,GearmanFunctionFactory>();
}
/**
* Register gearman functions on this computer. This will unregister all
* functions before registering new functions. Works for free-style
* and maven projects but does not work for multi-config projects
*
* How functions are registered:
* - If the project has no label then we register the project with all
* computers
*
* build:pep8 on precise-123
* build:pep8 on oneiric-456
*
* - If the project contains one label then we register with the computer
* that contains the corresponding label. Labels with '&&' is
* considered just one label
*
* build:pep8:precise on precise-123
* build:pep8 on precise-123
* build:pep8:precise on precise-129
* build:pep8 on precise-129
*
* - If the project contains multiple labels separated by '||' then
* we register with the computers that contain the corresponding labels
*
* build:pep8:precise on precise-123
* build:pep8 on precise-123
* build:pep8:precise on precise-129
* build:pep8 on precise-129
* build:pep8:oneiric on oneiric-456
* build:pep8 on oneiric-456
* build:pep8:oneiric on oneiric-459
* build:pep8 on oneiric-459
*
*/
@Override
public void registerJobs() {
if (worker == null || functionMap == null) {
// We haven't been initialized yet; the run method will call this again
return;
}
HashMap<String,GearmanFunctionFactory> newFunctionMap = new HashMap<String,GearmanFunctionFactory>();
if (!computer.isOffline()) {
Node node = computer.getNode();
List<AbstractProject> allProjects = Jenkins.getActiveInstance().getAllItems(AbstractProject.class);
for (AbstractProject<?, ?> project : allProjects) {
if (project.isDisabled()) { // ignore all disabled projects
continue;
}
String projectName = project.getName();
Label label = project.getAssignedLabel();
if (label == null) { // project has no label -> so register
// "build:projectName" on all non exclusive nodes
if (node.getMode() != Mode.EXCLUSIVE) {
String jobFunctionName = "build:" + projectName;
newFunctionMap.put(jobFunctionName, new CustomGearmanFunctionFactory(
jobFunctionName, StartJobWorker.class.getName(),
project, computer, this.masterName, worker));
}
} else { // register "build:$projectName:$label" if this
// node matches a node from the project label
Set<Node> projectLabelNodes = label.getNodes();
Set<LabelAtom> projectLabelAtoms = label.listAtoms();
Set<LabelAtom> nodeLabelAtoms = node.getAssignedLabels();
// Get the intersection of label atoms for the project and the current node
Set<LabelAtom> nodeProjectLabelAtoms = new HashSet<LabelAtom>(projectLabelAtoms);
nodeProjectLabelAtoms.retainAll(nodeLabelAtoms);
// Register functions iff the current node is in
// the list of nodes for the project's label
if (projectLabelNodes.contains(node)) {
String jobFunctionName = "build:" + projectName;
// register without label (i.e. "build:$projectName")
newFunctionMap.put(jobFunctionName, new CustomGearmanFunctionFactory(
jobFunctionName, StartJobWorker.class.getName(),
project, computer, this.masterName, worker));
// iterate over the intersection of project and node labels
for (LabelAtom labelAtom : nodeProjectLabelAtoms) {
jobFunctionName = "build:" + projectName
+ ":" + labelAtom.getDisplayName();
// register with label (i.e. "build:$projectName:$label")
newFunctionMap.put(jobFunctionName, new CustomGearmanFunctionFactory(
jobFunctionName, StartJobWorker.class.getName(),
project, computer, this.masterName, worker));
}
}
}
}
}
if (!newFunctionMap.keySet().equals(functionMap.keySet())) {
functionMap = newFunctionMap;
Set<GearmanFunctionFactory> functionSet = new HashSet<GearmanFunctionFactory>(functionMap.values());
updateJobs(functionSet);
}
}
public synchronized Computer getComputer() {
return computer;
}
}

View File

@ -1,215 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.Extension;
import hudson.model.Descriptor;
import hudson.util.FormValidation;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.servlet.ServletException;
import jenkins.model.GlobalConfiguration;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
/**
* This class is used to set the global configuration for the gearman-plugin It
* is also used to enable/disable the gearman plugin.
*
* @author Khai Do
*/
@Extension
public class GearmanPluginConfig extends GlobalConfiguration {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
private boolean enablePlugin; // config to enable and disable plugin
private String host; // gearman server host
private int port; // gearman server port
/**
* Constructor.
*/
public GearmanPluginConfig() {
load();
}
public static GearmanPluginConfig get() {
return GlobalConfiguration.all().get(GearmanPluginConfig.class);
}
/*
* This method runs when user clicks Test Connection button.
*
* @return message indicating whether connection test passed or failed
*/
public FormValidation doTestConnection(
@QueryParameter("host") final String host,
@QueryParameter("port") final int port) throws IOException,
ServletException {
if (connectionIsAvailable(host, port, 5000)) {
return FormValidation.ok("Success");
} else {
return FormValidation.error("Failed: Unable to Connect");
}
}
/*
* This method runs when user saves the configuration form
*/
@Override
public boolean configure(StaplerRequest req, JSONObject json)
throws Descriptor.FormException {
// save current plugin config so we can compare to new user settings
String prevHost = this.host;
int prevPort = this.port;
boolean prevEnablePlugin = this.enablePlugin;
// get the new gearman plugin configs from jenkins config page settings
enablePlugin = json.getBoolean("enablePlugin");
host = json.getString("host");
port = json.getInt("port");
if (!enablePlugin && prevEnablePlugin) { // gearman-plugin goes from ON to OFF state
GearmanProxy.getInstance().stopAll();
} else if (enablePlugin && !prevEnablePlugin) { // gearman-plugin goes from OFF to ON state
// check for a valid connection to server
if (!connectionIsAvailable(host, port, 5000)) {
enablePlugin = false;
throw new FormException("Unable to connect to Gearman server. "
+ "Please check the server connection settings and retry.",
"host");
}
// run workers
GearmanProxy.getInstance().initWorkers();
} else if (enablePlugin && prevEnablePlugin) { // gearman-plugin stays in the ON state
// update connection for a plugin config change
if (!host.equals(prevHost) || port != prevPort) {
// stop the workers on the current connected
GearmanProxy.getInstance().stopAll();
// check for a valid connection to server
if (!connectionIsAvailable(host, port, 5000)) {
enablePlugin = false;
throw new FormException("Unable to connect to Gearman server. "
+ "Please check the server connection settings and retry.",
"host");
}
// run workers with new connection
GearmanProxy.getInstance().initWorkers();
}
}
req.bindJSON(this, json);
save();
return true;
}
/**
* This method returns true if the global configuration says we should
* enable the plugin.
*/
public boolean enablePlugin() {
return Objects.firstNonNull(enablePlugin, Constants.GEARMAN_DEFAULT_ENABLE_PLUGIN);
}
/**
* This method returns the value from the server host text box
*/
public String getHost() {
return Objects.firstNonNull(host, Constants.GEARMAN_DEFAULT_TCP_HOST);
}
/**
* This method returns the value from the server port text box
*/
public int getPort() {
if (port == 0){ // Change default value
return Constants.GEARMAN_DEFAULT_TCP_PORT;
} else {
return port;
}
}
/*
* This method checks whether a connection is open and available
* on $host:$port
*
* @param host
* the host name
*
* @param port
* the host port
*
* @param timeout
* the timeout (milliseconds) to try the connection
*
* @return boolean
* true if a socket connection can be established otherwise false
*/
private boolean connectionIsAvailable(String host, int port,
int timeout) {
InetSocketAddress endPoint = new InetSocketAddress(host, port);
Socket socket = new Socket();
if (endPoint.isUnresolved()) {
System.out.println("Failure " + endPoint);
} else {
try {
socket.connect(endPoint, timeout);
logger.info("Connection Success: " + endPoint);
return true;
} catch (Exception e) {
logger.info("Connection Failure: " + endPoint + " message: "
+ e.getClass().getSimpleName() + " - " + e.getMessage());
} finally {
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
logger.info(e.getMessage());
}
}
}
}
return false;
}
}

View File

@ -1,109 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Run;
import hudson.security.ACL;
import java.io.IOException;
import jenkins.model.Jenkins;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.SecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class contains some useful utilities for this plugin
*
* @author Khai Do
*/
public class GearmanPluginUtil {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
/*
* This method returns the real computer name. Master computer
* by default has an empty string for the name. But you
* need to use "master" to tell jenkins to do stuff,
* namely like schedule a build.
*
* @param Computer
* The computer to lookup
*
* @return
* "master" for the master computer or assigned name of the slave computer
*/
public static String getRealName(Computer computer) {
if (Jenkins.getActiveInstance().getComputer("") == computer) {
return "master";
} else {
return computer.getName();
}
}
/**
* Function to finds the build with the unique build id.
*
* @param jobName
* The jenkins job or project name
* @param buildNumber
* The jenkins build number
* @return
* the build Run if found, otherwise return null
*/
public static Run<?,?> findBuild(String jobName, int buildNumber) {
SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM);
try {
AbstractProject<?,?> project = Jenkins.getActiveInstance().getItemByFullName(jobName, AbstractProject.class);
if (project != null){
Run<?,?> run = project.getBuildByNumber(buildNumber);
if (run != null) {
return run;
}
}
return null;
} finally {
SecurityContextHolder.setContext(oldContext);
}
}
/**
* Sets description of the build
*
* @param build
* Build to set the description of
* @param description
* New build description
*/
public static void setBuildDescription(Run build, String description) throws IOException {
SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM);
try {
build.setDescription(description);
} finally {
SecurityContextHolder.setContext(oldContext);
}
}
}

View File

@ -1,346 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Computer;
import hudson.model.Node;
import hudson.model.Run;
import hudson.model.Queue;
import hudson.model.queue.CauseOfBlockage;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import jenkins.model.Jenkins;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is used to startup and shutdown the gearman workers.
* It is also used to keep gearman plugin state info.
*
* @author Khai Do
*/
public class GearmanProxy {
private static GearmanProxy gearmanProxy;
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
// handles to gearman workers
private final List<ExecutorWorkerThread> gewtHandles;
private final List<ManagementWorkerThread> gmwtHandles;
private final String masterName;
// Singleton instance
public static synchronized GearmanProxy getInstance() {
if (gearmanProxy == null) {
gearmanProxy = new GearmanProxy();
}
return gearmanProxy;
}
// constructor
private GearmanProxy() {
gewtHandles = Collections.synchronizedList(new ArrayList<ExecutorWorkerThread>());
gmwtHandles = Collections.synchronizedList(new ArrayList<ManagementWorkerThread>());
Computer master = null;
String hostname = Constants.GEARMAN_DEFAULT_EXECUTOR_NAME;
// query Jenkins for master's name
try {
master = Jenkins.getActiveInstance().getComputer("");
hostname = master.getHostName();
} catch (Exception e) {
logger.warn("Exception while getting hostname", e);
}
// master node may not be enabled so get masterName from system
if (master == null) {
try {
hostname = java.net.InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
logger.warn("Exception while getting hostname", e);
}
}
masterName = hostname;
}
/*
* This method is for unit tests only.
*/
protected void testResetHandles() {
gmwtHandles.clear();
gewtHandles.clear();
}
/*
* This method initializes the gearman workers.
*/
public void initWorkers() {
/*
* Purpose here is to create a 1:1 mapping of 'gearman worker':'jenkins
* executor' then use the gearman worker to execute builds on that
* jenkins nodes
*/
/*
* Spawn management executor worker. This worker does not need any
* executors. It only needs to work with gearman.
*/
createManagementWorker();
/*
* Spawn executors for the jenkins master Need to treat the master
* differently than slaves because the master is not the same as a
* slave
*/
// first make sure master is enabled (or has executors)
Node masterNode = null;
try {
masterNode = Jenkins.getActiveInstance().getComputer("").getNode();
} catch (NullPointerException npe) {
logger.info("---- Master is offline");
} catch (Exception e) {
logger.error("Exception while finding master", e);
}
if (masterNode != null) {
Computer computer = masterNode.toComputer();
if (computer != null) {
createExecutorWorkersOnNode(computer);
}
}
/*
* Spawn executors for the jenkins slaves
*/
List<Node> nodes = Jenkins.getActiveInstance().getNodes();
if (!nodes.isEmpty()) {
for (Node node : nodes) {
Computer computer = node.toComputer();
if (computer != null) {
// create a gearman worker for every executor on the slave
createExecutorWorkersOnNode(computer);
}
}
}
logger.info("---- Num of executors running = " + getNumExecutors());
}
/*
* Spawn management executor workers. This worker does not need any
* executors. It only needs to connect to gearman.
*/
public void createManagementWorker() {
ManagementWorkerThread gwt;
synchronized (gmwtHandles) {
if (!gmwtHandles.isEmpty()) {
return;
}
gwt = new ManagementWorkerThread(
GearmanPluginConfig.get().getHost(),
GearmanPluginConfig.get().getPort(),
masterName + "_manager",
masterName, new NoopAvailabilityMonitor());
gmwtHandles.add(gwt);
gwt.start();
}
logger.info("---- Num of executors running = " + getNumExecutors());
}
/*
* Spawn workers for each executor on a node.
*/
public void createExecutorWorkersOnNode(Computer computer) {
// find the computer in the executor workers list
synchronized(gewtHandles) {
for (ExecutorWorkerThread t : gewtHandles) {
if (t.getComputer() == computer) {
logger.info("---- Executor thread already running for " + computer.getName());
return;
}
}
AvailabilityMonitor availability = new NodeAvailabilityMonitor(computer);
int executors = computer.getExecutors().size();
for (int i = 0; i < executors; i++) {
String nodeName = null;
nodeName = GearmanPluginUtil.getRealName(computer);
if (nodeName == "master") {
nodeName = masterName;
}
ExecutorWorkerThread ewt = new ExecutorWorkerThread(
GearmanPluginConfig.get().getHost(),
GearmanPluginConfig.get().getPort(),
nodeName+"_exec-"+Integer.toString(i),
computer, masterName, availability);
ewt.start();
gewtHandles.add(ewt);
}
}
logger.info("---- Num of executors running = " + getNumExecutors());
}
/*
* This method stops all gearman workers
*/
public void stopAll() {
// stop gearman executors
List<AbstractWorkerThread> stopHandles;
synchronized(gewtHandles) {
stopHandles = new ArrayList<AbstractWorkerThread>(gewtHandles);
gewtHandles.clear();
}
for (AbstractWorkerThread wt : stopHandles) { // stop executors
wt.stop();
}
synchronized(gmwtHandles) {
stopHandles = new ArrayList<AbstractWorkerThread>(gmwtHandles);
gmwtHandles.clear();
}
for (AbstractWorkerThread wt : stopHandles) { // stop executors
wt.stop();
}
logger.info("---- Num of executors running = " + getNumExecutors());
}
/*
* This method stops all threads on the gewtHandles list that
* is used to service the jenkins slave/computer
*
*
* @param Node
* The Computer to stop
*
*/
public void stop(Computer computer) {
logger.info("---- Stop computer " + computer);
List<ExecutorWorkerThread> workers = new ArrayList<ExecutorWorkerThread>();
synchronized(gewtHandles) {
// find the computer in the executor workers list and stop it
for (Iterator<ExecutorWorkerThread> it = gewtHandles.iterator(); it.hasNext(); ) {
ExecutorWorkerThread t = it.next();
if (t.getComputer() == computer) {
workers.add(t);
it.remove();
}
}
}
for (ExecutorWorkerThread t : workers) {
t.stop();
}
logger.info("---- Num of executors running = " + getNumExecutors());
}
/*
* This method returns the total number of gearman executor threads
*/
public int getNumExecutors() {
return gmwtHandles.size() + gewtHandles.size();
}
public void onBuildFinalized(Run r) {
Computer computer = r.getExecutor().getOwner();
// A build just finished, so let the AvailabilityMonitor
// associated with its node wake up any workers who may be
// waiting for the lock.
AvailabilityMonitor availability = null;
synchronized(gewtHandles) {
for (ExecutorWorkerThread t : gewtHandles) {
if (t.getComputer() == computer) {
availability = t.getAvailability();
}
}
}
if (availability != null) {
availability.wake();
}
}
public AvailabilityMonitor getAvailabilityMonitor(Computer computer) {
synchronized (gewtHandles) {
for (ExecutorWorkerThread t : gewtHandles) {
if (t.getComputer() == computer) {
return t.getAvailability();
}
}
}
return null;
}
public CauseOfBlockage canTake(Node node,
Queue.BuildableItem item) {
// Ask the AvailabilityMonitor for this node if it's okay to
// run this build.
ExecutorWorkerThread workerThread = null;
synchronized(gewtHandles) {
Computer computer = node.toComputer();
for (ExecutorWorkerThread t : gewtHandles) {
if (t.getComputer() == computer) {
workerThread = t;
break;
}
}
}
if (workerThread != null) {
if (workerThread.getAvailability().canTake(item)) {
return null;
} else {
return new CauseOfBlockage.BecauseNodeIsBusy(node);
}
}
return null;
}
public void registerJobs() {
synchronized(gewtHandles) {
for (ExecutorWorkerThread worker : gewtHandles) {
worker.registerJobs();
}
}
}
}

View File

@ -1,83 +0,0 @@
/*
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.Extension;
import hudson.model.Item;
import hudson.model.listeners.ItemListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* This handles events for generic items in Jenkins. We also extended
* the SaveableListener to catch any events that this one misses.
*/
@Extension
public class ItemListenerImpl extends ItemListener {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
@Override
public void onCopied(Item src, Item item) {
// Called after a new job is created by copying from an existing job
registerJobs();
}
@Override
public void onRenamed(Item item, String oldName, String newName) {
// Called after a job is renamed
registerJobs();
}
@Override
public void onLoaded() {
registerJobs();
}
@Override
public void onCreated(Item item) {
registerJobs();
}
@Override
public void onUpdated(Item item) {
registerJobs();
}
@Override
public void onDeleted(Item item) {
registerJobs();
}
@Override
public void onLocationChanged(Item item, String oldFullName, String newFullName) {
registerJobs();
}
// register gearman functions
private void registerJobs() {
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
GearmanProxy.getInstance().registerJobs();
}
}

View File

@ -1,75 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import java.util.HashSet;
import java.util.Set;
import org.gearman.worker.DefaultGearmanFunctionFactory;
import org.gearman.worker.GearmanFunctionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a thread to run gearman management worker
*
* @author Khai Do
*/
public class ManagementWorkerThread extends AbstractWorkerThread{
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
private boolean registered = false;
private final String masterName;
public ManagementWorkerThread(String host, int port, String name, String masterName, AvailabilityMonitor availability){
super(host, port, name, availability);
this.masterName = masterName;
}
/**
* Register gearman functions on this executor. This will unregister all
* functions before registering new functions.
*
* This executor only registers one function "stop:$hostname".
*
*/
@Override
public void registerJobs(){
if (worker == null) {
// We haven't been initialized yet; the run method will call this again
return;
}
if (!registered) {
Set<GearmanFunctionFactory> functionSet = new HashSet<GearmanFunctionFactory>();
functionSet.add(new DefaultGearmanFunctionFactory("stop:"+masterName,
StopJobWorker.class.getName()));
functionSet.add(new DefaultGearmanFunctionFactory("set_description:"+masterName,
SetDescriptionWorker.class.getName()));
updateJobs(functionSet);
registered = true;
}
}
}

View File

@ -1,660 +0,0 @@
/*
*
* Copyright 2013 OpenStack Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* This is adapted from gearman-java with the following license
*
* Copyright (C) 2013 by Eric Lambert <eric.d.lambert@gmail.com>
* Use and distribution licensed under the BSD license. See
* the COPYING file in the parent directory for full text.
*/
package hudson.plugins.gearman;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import org.gearman.common.Constants;
import org.gearman.common.GearmanException;
import org.gearman.common.GearmanJobServerConnection;
import org.gearman.common.GearmanJobServerIpConnectionFactory;
import org.gearman.common.GearmanJobServerSession;
import org.gearman.common.GearmanNIOJobServerConnectionFactory;
import org.gearman.common.GearmanPacket;
import org.gearman.common.GearmanPacket.DataComponentName;
import org.gearman.common.GearmanPacketImpl;
import org.gearman.common.GearmanPacketMagic;
import org.gearman.common.GearmanPacketType;
import org.gearman.common.GearmanServerResponseHandler;
import org.gearman.common.GearmanSessionEvent;
import org.gearman.common.GearmanSessionEventHandler;
import org.gearman.common.GearmanTask;
import org.gearman.worker.DefaultGearmanFunctionFactory;
import org.gearman.worker.GearmanFunction;
import org.gearman.worker.GearmanFunctionFactory;
import org.gearman.worker.GearmanWorker;
import org.gearman.util.ByteUtils;
import org.slf4j.LoggerFactory;
public class MyGearmanWorkerImpl implements GearmanSessionEventHandler {
static public enum State {
IDLE, RUNNING, SHUTTINGDOWN
}
private static final String DESCRIPION_PREFIX = "GearmanWorker";
private ConcurrentLinkedQueue<GearmanSessionEvent> eventList = null;
private Selector ioAvailable = null;
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(
Constants.GEARMAN_WORKER_LOGGER_NAME);
private String id;
private Map<String, FunctionDefinition> functionMap;
private State state;
private ExecutorService executorService;
private GearmanJobServerSession session = null;
private final GearmanJobServerIpConnectionFactory connFactory = new GearmanNIOJobServerConnectionFactory();
private volatile boolean jobUniqueIdRequired = false;
private FunctionRegistry functionRegistry;
private AvailabilityMonitor availability;
class GrabJobEventHandler implements GearmanServerResponseHandler {
private final GearmanJobServerSession session;
private boolean isDone = false;
GrabJobEventHandler(GearmanJobServerSession session) {
super();
this.session = session;
}
public void handleEvent(GearmanPacket event) throws GearmanException {
handleSessionEvent(new GearmanSessionEvent(event, session));
isDone = true;
}
public boolean isDone() {
return isDone;
}
}
static class FunctionDefinition {
private final long timeout;
private final GearmanFunctionFactory factory;
FunctionDefinition(long timeout, GearmanFunctionFactory factory) {
this.timeout = timeout;
this.factory = factory;
}
long getTimeout() {
return timeout;
}
GearmanFunctionFactory getFactory() {
return factory;
}
}
class FunctionRegistry {
private Set<GearmanFunctionFactory> functions;
private boolean updated = false;
FunctionRegistry() {
functions = new HashSet<GearmanFunctionFactory>();
}
public synchronized Set<GearmanFunctionFactory> getFunctions(){
if (updated) {
updated = false;
return functions;
} else {
return null;
}
}
public synchronized void setFunctions(Set<GearmanFunctionFactory> functions){
this.functions = functions;
this.updated = true;
}
public synchronized void setUpdated(boolean updated) {
this.updated = updated;
}
}
public void reconnect() {
LOG.info("---- Worker " + this + " starting reconnect for " + session.toString());
// In case we held the availability lock earlier, release it.
availability.unlock(this);
try {
session.initSession(ioAvailable, this);
if (id != null) {
sendToAll(new GearmanPacketImpl(GearmanPacketMagic.REQ,
GearmanPacketType.SET_CLIENT_ID,
ByteUtils.toUTF8Bytes(id)));
}
// Reset events so that we don't process events from the old
// connection.
eventList = new ConcurrentLinkedQueue<GearmanSessionEvent>();
// this will cause a grab-job event
functionRegistry.setUpdated(true);
// Make sure we reset the function list
functionMap.clear();
} catch (IOException e) {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
LOG.warn("---- Worker " + this + " interrupted while reconnecting", e);
return;
}
}
LOG.info("---- Worker " + this + " ending reconnect for " + session.toString());
}
public MyGearmanWorkerImpl(AvailabilityMonitor availability) {
this (null, availability);
}
public MyGearmanWorkerImpl(ExecutorService executorService,
AvailabilityMonitor availability) {
this.availability = availability;
eventList = new ConcurrentLinkedQueue<GearmanSessionEvent>();
id = DESCRIPION_PREFIX + ":" + Thread.currentThread().getId();
functionMap = new HashMap<String, FunctionDefinition>();
state = State.IDLE;
this.executorService = executorService;
functionRegistry = new FunctionRegistry();
try {
ioAvailable = Selector.open();
} catch (IOException ioe) {
LOG.warn("---- Worker " + this + " failed to open IO selector", ioe);
}
}
@Override
public String toString() {
return id;
}
public void setFunctions(Set<GearmanFunctionFactory> functions) {
LOG.info("---- Worker " + this + " registering " + functions.size() + " functions");
functionRegistry.setFunctions(functions);
ioAvailable.wakeup();
}
/**
* This is a small lie -- it only returns the functions it has been
* instructed to register, not the ones it has actually gotton around
* to registering. This is mostly here for tests.
**/
public Set getRegisteredFunctions() {
Set<String> ret = new HashSet<String>();
Set<GearmanFunctionFactory> functions = functionRegistry.getFunctions();
if (functions == null) {
return ret;
}
for (GearmanFunctionFactory factory: functions) {
ret.add(factory.getFunctionName());
}
return ret;
}
private void registerFunctions() throws IOException {
Set<GearmanFunctionFactory> functions = functionRegistry.getFunctions();
if (functions == null) {
return;
}
HashMap<String, FunctionDefinition> newFunctionMap = new HashMap<String, FunctionDefinition>();
// If we have no previous data then reset abilities to be sure the
// gearman server has no stale data that we don't know about.
// Or if we have no functions anymore just reset everything, we don't
// need a CANT_DO per lost function.
if (functions.isEmpty() || functionMap.isEmpty()) {
sendToAll(new GearmanPacketImpl(GearmanPacketMagic.REQ,
GearmanPacketType.RESET_ABILITIES, new byte[0]));
session.driveSessionIO();
LOG.debug("---- Worker " + this + " reset functions");
if (!isRunning()) {
// Ensure we start from scratch on reconnection.
functionMap.clear();
return;
}
}
// Now only update if we have data to update.
if (!functions.isEmpty()) {
for (GearmanFunctionFactory factory: functions) {
FunctionDefinition def = new FunctionDefinition(0, factory);
newFunctionMap.put(factory.getFunctionName(), def);
if (!functionMap.containsKey(factory.getFunctionName())) {
sendToAll(generateCanDoPacket(def));
session.driveSessionIO();
if (!isRunning()) {
// Ensure we start from scratch on reconnection.
functionMap.clear();
return;
}
LOG.debug("---- Worker " + this + " registered function " +
factory.getFunctionName());
}
functionMap.remove(factory.getFunctionName());
}
for (FunctionDefinition def: functionMap.values()) {
sendToAll(generateCantDoPacket(def));
session.driveSessionIO();
if (!isRunning()) {
// Ensure we start from scratch on reconnection.
functionMap.clear();
return;
}
LOG.debug("---- Worker " + this + " unregistered function " +
def.getFactory().getFunctionName());
}
}
functionMap = newFunctionMap;
GearmanSessionEvent nextEvent = eventList.peek();
if (nextEvent == null ||
nextEvent.getPacket().getPacketType() != GearmanPacketType.NOOP) {
// Simulate a NOOP packet which will kick off a GRAB_JOB cycle
// if we're sleeping. If we get a real NOOP in the mean time,
// it should be fine because GearmanJobServerSession ignores a
// NOOP if PRE_SLEEP is not on the stack.
GearmanPacket p = new GearmanPacketImpl(GearmanPacketMagic.RES,
GearmanPacketType.NOOP, new byte[0]);
GearmanSessionEvent event = new GearmanSessionEvent(p, session);
session.handleSessionEvent(event);
}
}
public void enqueueNoopEvent() {
// Simulate a NOOP packet which will kick off a GRAB_JOB cycle.
// This unconditionally enqueues the NOOP which will send a GRAB_JOB
// and should only be used when you know you need to send a GRAB_JOB.
// Cases like worker start, post function run, post failure.
GearmanPacket p = new GearmanPacketImpl(GearmanPacketMagic.RES,
GearmanPacketType.NOOP, new byte[0]);
GearmanSessionEvent event = new GearmanSessionEvent(p, session);
enqueueEvent(event);
}
public void work() {
GearmanSessionEvent event = null;
GearmanFunction function = null;
LOG.info("---- Worker " + this + " starting work");
if (!state.equals(State.IDLE)) {
throw new IllegalStateException("Can not call work while worker " +
"is running or shutting down");
}
state = State.RUNNING;
// When we first start working we will already be initialized so must
// enqueue a Noop event to trigger GRAB_JOB here.
enqueueNoopEvent();
while (isRunning()) {
LOG.debug("---- Worker " + this + " top of run loop");
if (!session.isInitialized()) {
LOG.debug("---- Worker " + this + " run loop reconnect");
reconnect();
enqueueNoopEvent();
// Restart loop to check we connected.
continue;
}
try {
LOG.debug("---- Worker " + this + " run loop register functions");
registerFunctions();
} catch (IOException io) {
LOG.warn("---- Worker " + this + " receieved IOException while" +
" registering functions", io);
session.closeSession();
continue;
}
if (!isRunning() || !session.isInitialized()) continue;
event = eventList.poll();
function = processSessionEvent(event);
if (!isRunning() || !session.isInitialized()) continue;
// For the time being we will execute the jobs synchronously
// in the future, I expect to change this.
if (function != null) {
LOG.info("---- Worker " + this + " executing function");
submitFunction(function);
// Send another grab_job on the next loop
enqueueNoopEvent();
// Skip IO as submitFunction drives the IO for function
// running.
continue;
}
if (!isRunning() || !session.isInitialized()) continue;
// Run IO, select waiting for ability to read and/or write
// then read and/or write.
int interestOps = SelectionKey.OP_READ;
if (session.sessionHasDataToWrite()) {
interestOps |= SelectionKey.OP_WRITE;
}
session.getSelectionKey().interestOps(interestOps);
try {
ioAvailable.select();
} catch (IOException io) {
LOG.warn("---- Worker " + this + " receieved IOException while" +
" selecting for IO", io);
session.closeSession();
continue;
}
if (ioAvailable.selectedKeys().contains(session.getSelectionKey())) {
LOG.debug("---- Worker " + this + " received input in run loop");
if (!session.isInitialized()) {
LOG.debug("---- Worker " + this + " session is no longer initialized");
continue;
}
try {
session.driveSessionIO();
} catch (IOException io) {
LOG.warn("---- Worker " + this + " received IOException while driving" +
" IO on session " + session, io);
session.closeSession();
continue;
}
}
LOG.debug("---- Worker " + this + " run loop finished driving session io");
}
shutDownWorker(true);
}
private void sendGrabJob(GearmanJobServerSession s) throws InterruptedException {
// If we can get the lock, this will prevent other workers and
// Jenkins itself from scheduling builds on this node. If we
// can not get the lock, this will wait for it.
availability.lock(this);
GearmanTask grabJobTask = new GearmanTask(
new GrabJobEventHandler(s),
new GearmanPacketImpl(GearmanPacketMagic.REQ,
getGrabJobPacketType(), new byte[0]));
s.submitTask(grabJobTask);
}
public void handleSessionEvent(GearmanSessionEvent event)
throws IllegalArgumentException, IllegalStateException {
enqueueEvent(event);
}
public void enqueueEvent(GearmanSessionEvent event) {
// Enqueue in a thread safe manner. Events will
// be pulled off and processed serially in this workers
// main thread.
eventList.add(event);
}
private GearmanFunction processSessionEvent(GearmanSessionEvent event)
throws IllegalArgumentException, IllegalStateException {
if (event != null) {
GearmanPacket p = event.getPacket();
GearmanJobServerSession s = event.getSession();
GearmanPacketType t = p.getPacketType();
LOG.debug("---- Worker " + this + " handling session event" +
" ( Session = " + s + " Event = " + t + " )");
switch (t) {
case JOB_ASSIGN:
//TODO Figure out what the right behavior is if JobUUIDRequired was false when we submitted but is now true
LOG.info("---- Worker " + this + " received job assignment");
return addNewJob(event);
case JOB_ASSIGN_UNIQ:
//TODO Figure out what the right behavior is if JobUUIDRequired was true when we submitted but is now false
LOG.info("---- Worker " + this + " received unique job assignment");
return addNewJob(event);
case NOOP:
LOG.debug("---- Worker " + this + " sending grab job after wakeup");
try {
sendGrabJob(s);
} catch (InterruptedException e) {
LOG.warn("---- Worker " + this + " interrupted while waiting for okay to send " +
"grab job", e);
}
break;
case NO_JOB:
// We didn't get a job, so allow other workers or
// Jenkins to schedule on this node.
availability.unlock(this);
LOG.debug("---- Worker " + this + " sending pre sleep after no_job");
GearmanTask preSleepTask = new GearmanTask(new GrabJobEventHandler(s),
new GearmanPacketImpl(GearmanPacketMagic.REQ,
GearmanPacketType.PRE_SLEEP, new byte[0]));
s.submitTask(preSleepTask);
break;
case ECHO_RES:
break;
case OPTION_RES:
break;
case ERROR:
s.closeSession();
break;
default:
LOG.warn("---- Worker " + this + " received unknown packet type " + t +
" from session " + s + "; closing connection");
s.closeSession();
}
}
return null;
}
public boolean addServer(String host, int port) {
return addServer(connFactory.createConnection(host, port));
}
public boolean addServer(GearmanJobServerConnection conn)
throws IllegalArgumentException, IllegalStateException {
if (conn == null) {
throw new IllegalArgumentException("Connection can not be null");
}
if (session != null) {
return true;
}
session = new GearmanJobServerSession(conn);
reconnect();
LOG.debug("---- Worker " + this + " added server " + conn);
return true;
}
public void setWorkerID(String id) throws IllegalArgumentException {
if (id == null) {
throw new IllegalArgumentException("Worker ID may not be null");
}
this.id = id;
if (session.isInitialized()) {
sendToAll(new GearmanPacketImpl(GearmanPacketMagic.REQ,
GearmanPacketType.SET_CLIENT_ID,
ByteUtils.toUTF8Bytes(id)));
}
}
public String getWorkerID() {
return id;
}
public void stop() {
state = State.SHUTTINGDOWN;
}
public List<Exception> shutdown() {
return shutDownWorker(false);
}
public boolean isRunning() {
return state.equals(State.RUNNING);
}
public void setJobUniqueIdRequired(boolean requiresJobUUID) {
jobUniqueIdRequired = requiresJobUUID;
}
public boolean isJobUniqueIdRequired() {
return jobUniqueIdRequired;
}
private GearmanPacket generateCanDoPacket(FunctionDefinition def) {
GearmanPacketType pt = GearmanPacketType.CAN_DO;
byte[] data = ByteUtils.toUTF8Bytes(def.getFactory().getFunctionName());
return new GearmanPacketImpl(GearmanPacketMagic.REQ, pt, data);
}
private GearmanPacket generateCantDoPacket(FunctionDefinition def) {
GearmanPacketType pt = GearmanPacketType.CANT_DO;
byte[] data = ByteUtils.toUTF8Bytes(def.getFactory().getFunctionName());
return new GearmanPacketImpl(GearmanPacketMagic.REQ, pt, data);
}
private void sendToAll(GearmanPacket p) {
sendToAll(null, p);
}
private void sendToAll(GearmanServerResponseHandler handler, GearmanPacket p) {
GearmanTask gsr = new GearmanTask(handler, p);
session.submitTask(gsr);
}
/*
* For the time being this will always return an empty list of
* exceptions because closeSession does not throw an exception
*/
private List<Exception> shutDownWorker(boolean completeTasks) {
LOG.info("---- Worker " + this + " commencing shutdown");
ArrayList<Exception> exceptions = new ArrayList<Exception>();
// This gives any jobs in flight a chance to complete
if (executorService != null) {
if (completeTasks) {
executorService.shutdown();
} else {
executorService.shutdownNow();
}
}
session.closeSession();
try {
ioAvailable.close();
} catch (IOException ioe) {
LOG.warn("---- Worker " + this + " encountered IOException while closing selector: ", ioe);
}
state = State.IDLE;
LOG.info("---- Worker " + this + " completed shutdown");
return exceptions;
}
private GearmanFunction addNewJob(GearmanSessionEvent event) {
byte[] handle, data, functionNameBytes, unique;
GearmanPacket p = event.getPacket();
String functionName;
handle = p.getDataComponentValue(
GearmanPacket.DataComponentName.JOB_HANDLE);
functionNameBytes = p.getDataComponentValue(
GearmanPacket.DataComponentName.FUNCTION_NAME);
data = p.getDataComponentValue(
GearmanPacket.DataComponentName.DATA);
unique = p.getDataComponentValue(DataComponentName.UNIQUE_ID);
functionName = ByteUtils.fromUTF8Bytes(functionNameBytes);
FunctionDefinition def = functionMap.get(functionName);
if (def == null) {
GearmanTask gsr = new GearmanTask(
new GearmanPacketImpl(GearmanPacketMagic.REQ,
GearmanPacketType.WORK_FAIL, handle));
session.submitTask(gsr);
availability.unlock(this);
enqueueNoopEvent();
} else {
GearmanFunction function = def.getFactory().getFunction();
function.setData(data);
function.setJobHandle(handle);
function.registerEventListener(session);
if (unique != null && unique.length > 0) {
function.setUniqueId(unique);
}
return function;
}
return null;
}
private void submitFunction(GearmanFunction fun) {
try {
if (executorService == null) {
fun.call();
} else {
executorService.submit(fun);
}
// We should have submitted either a WORK_EXCEPTION, COMPLETE,
// or FAIL; make sure it gets sent.
session.driveSessionIO();
} catch (IOException io) {
LOG.warn("---- Worker " + this + " receieved IOException while" +
" running function",io);
session.closeSession();
} catch (Exception e) {
LOG.warn("---- Worker " + this + " exception while executing function " + fun.getName(), e);
}
// Unlock the monitor for this worker
availability.unlock(this);
}
private GearmanPacketType getGrabJobPacketType() {
if (jobUniqueIdRequired) {
return GearmanPacketType.GRAB_JOB_UNIQ;
}
return GearmanPacketType.GRAB_JOB;
}
}

View File

@ -1,65 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Label;
import hudson.model.labels.LabelAssignmentAction;
import hudson.model.labels.LabelAtom;
import hudson.model.queue.SubTask;
/**
* Action to send jenkins build to a specific node
*
* @author Khai Do
*/
public class NodeAssignmentAction implements LabelAssignmentAction {
LabelAtom labelAtom;
public NodeAssignmentAction(String label) {
this.labelAtom = new LabelAtom(label);
}
@Override
public String getIconFileName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getDisplayName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getUrlName() {
// TODO Auto-generated method stub
return null;
}
@Override
public Label getAssignedLabel(SubTask task) {
// TODO Auto-generated method stub
return labelAtom;
}
}

View File

@ -1,144 +0,0 @@
/*
*
* Copyright 2013 OpenStack Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import jenkins.model.Jenkins;
import hudson.model.Queue;
import hudson.model.Computer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NodeAvailabilityMonitor implements AvailabilityMonitor {
private final Queue queue;
private final Jenkins jenkins;
private final Computer computer;
private MyGearmanWorkerImpl workerHoldingLock = null;
private String expectedUUID = null;
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
NodeAvailabilityMonitor(Computer computer)
{
this.computer = computer;
queue = Queue.getInstance();
jenkins = Jenkins.getActiveInstance();
}
public Computer getComputer() {
return computer;
}
public void lock(MyGearmanWorkerImpl worker)
throws InterruptedException
{
logger.debug("AvailabilityMonitor lock request: " + worker);
while (true) {
boolean busy = false;
// Synchronize on the Jenkins queue so that Jenkins is
// unable to schedule builds while we try to acquire the
// lock.
synchronized(queue) {
if (workerHoldingLock == null) {
if (computer.countIdle() == 0) {
// If there are no idle executors, we can not
// schedule a build.
busy = true;
} else if (jenkins.isQuietingDown()) {
busy = true;
} else {
logger.debug("AvailabilityMonitor got lock: " + worker);
workerHoldingLock = worker;
return;
}
} else {
busy = true;
}
}
if (busy) {
synchronized(this) {
// We get synchronous notification when a
// build finishes, but there are lots of other
// reasons circumstances could change (adding
// an executor, canceling shutdown, etc), so
// we slowly busy wait to cover all those
// reasons.
this.wait(5000);
}
}
}
}
public void unlock(MyGearmanWorkerImpl worker) {
logger.debug("AvailabilityMonitor unlock request: " + worker);
synchronized(queue) {
if (workerHoldingLock == worker) {
workerHoldingLock = null;
expectedUUID = null;
logger.debug("AvailabilityMonitor unlocked: " + worker);
} else {
logger.debug("Worker does not own AvailabilityMonitor lock: " +
worker);
}
}
wake();
}
public void wake() {
// Called when we know circumstances may have changed in a way
// that may allow someone to get the lock.
logger.debug("AvailabilityMonitor wake request");
synchronized(this) {
logger.debug("AvailabilityMonitor woken");
notifyAll();
}
}
public void expectUUID(String UUID) {
// The Gearman worker which holds the lock is about to
// schedule this build, so when Jenkins asks to run it, say
// "yes".
if (expectedUUID != null) {
logger.error("AvailabilityMonitor told to expect UUID " +
UUID + "while already expecting " + expectedUUID);
}
expectedUUID = UUID;
}
public boolean canTake(Queue.BuildableItem item)
{
// Jenkins calls this from within the scheduler maintenance
// function (while owning the queue monitor). If we are
// locked, only allow the build we are expecting to run.
logger.debug("AvailabilityMonitor canTake request for " +
workerHoldingLock);
NodeParametersAction param = item.getAction(NodeParametersAction.class);
if (param != null) {
logger.debug("AvailabilityMonitor canTake request for UUID " +
param.getUuid() + " expecting " + expectedUUID);
if (expectedUUID == param.getUuid()) {
return true;
}
}
return (workerHoldingLock == null);
}
}

View File

@ -1,56 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import java.util.List;
import hudson.model.ParameterValue;
import hudson.model.ParametersAction;
/**
* Action to send parameters to a jenkins build.
*
* @author Khai Do
*/
public class NodeParametersAction extends ParametersAction {
String id; // the id used to track the build job
public NodeParametersAction(List<ParameterValue> parameters) {
this(parameters, "");
}
public NodeParametersAction(List<ParameterValue> parameters, String id) {
super(parameters);
this.id = id;
}
public String getUuid() {
return id;
}
public void setUuid(String uuid) {
this.id = uuid;
}
}

View File

@ -1,40 +0,0 @@
/*
*
* Copyright 2013 OpenStack Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Queue;
public class NoopAvailabilityMonitor implements AvailabilityMonitor {
public void lock(MyGearmanWorkerImpl worker) {
}
public void unlock(MyGearmanWorkerImpl worker) {
}
public void wake() {
}
public void expectUUID(String UUID) {
}
public boolean canTake(Queue.BuildableItem item)
{
return (true);
}
}

View File

@ -1,50 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
* Copyright 2013 OpenStack Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.Extension;
import hudson.model.Node;
import hudson.model.Queue;
import hudson.model.queue.QueueTaskDispatcher;
import hudson.model.queue.CauseOfBlockage;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Extension
public class QueueTaskDispatcherImpl extends QueueTaskDispatcher {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
@Override
public CauseOfBlockage canTake(Node node,
Queue.BuildableItem item) {
// update only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return null;
}
return GearmanProxy.getInstance().canTake(node, item);
}
}

View File

@ -1,50 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
* Copyright 2013 OpenStack Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.Extension;
import hudson.model.TaskListener;
import hudson.model.Run;
import hudson.model.listeners.RunListener;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Update gearman workers when node changes
*/
@Extension
public class RunListenerImpl extends RunListener<Run> {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
@Override
public void onFinalized(Run r) {
// update only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
GearmanProxy.getInstance().onBuildFinalized(r);
}
}

View File

@ -1,58 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.Extension;
import hudson.XmlFile;
import hudson.model.Saveable;
import hudson.model.AbstractProject;
import hudson.model.listeners.SaveableListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Using the SaveableListener is required as a work around because
* the itemListener.onUpdate event does not fire on changes to
* project updates using the Jenkins REST API
* Bug: https://issues.jenkins-ci.org/browse/JENKINS-25175
*/
@Extension
public class SaveableListenerImpl extends SaveableListener {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
@Override
// This works but is NOT good because this event is a catch all
// for just about any change that happens in Jenkins. This event
// also doesn't provide much detail on what has changed.
public void onChange(Saveable o, XmlFile file) {
// update functions only when gearman-plugin is enabled
if (!GearmanPluginConfig.get().enablePlugin()) {
return;
}
// only look for changes to projects, specifically for project
// label changes. Node changes are handled in ComputerListenerImpl
if (o instanceof AbstractProject) {
GearmanProxy.getInstance().registerJobs();
}
}
}

View File

@ -1,104 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Run;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.gearman.client.GearmanJobResult;
import org.gearman.client.GearmanJobResultImpl;
import org.gearman.worker.AbstractGearmanFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* This is a gearman function to set a jenkins build
* description
*
*
* @author Khai Do
*/
public class SetDescriptionWorker extends AbstractGearmanFunction {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
/*
* The Gearman Function
* @see org.gearman.worker.AbstractGearmanFunction#executeFunction()
*/
@Override
public GearmanJobResult executeFunction() {
// check job results
boolean jobResult = false;
String jobResultMsg = "";
String decodedData;
// decode json
try {
decodedData = new String((byte[]) this.data, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Unsupported encoding exception in argument");
}
// convert parameters passed in from client to hash map
Gson gson = new Gson();
Map<String, String> data = gson.fromJson(decodedData,
new TypeToken<Map<String, String>>() {
}.getType());
// get build description
String buildDescription = data.get("html_description");
// get build id
String jobName = data.get("name");
String buildNumber = data.get("number");
if (!jobName.isEmpty() && !buildNumber.isEmpty()) {
// find build then update its description
Run<?,?> build = GearmanPluginUtil.findBuild(jobName, Integer.parseInt(buildNumber));
if (build != null) {
try {
GearmanPluginUtil.setBuildDescription(build, buildDescription);
} catch (IOException e) {
throw new IllegalArgumentException("Unable to set description for " +
jobName + ": " + buildNumber);
}
jobResultMsg = "Description for Jenkins build " +buildNumber+" was updated to " + buildDescription;
jobResult = true;
} else {
throw new IllegalArgumentException("Cannot find build number " +
buildNumber);
}
} else {
throw new IllegalArgumentException("Build id is invalid or not specified");
}
GearmanJobResult gjr = new GearmanJobResultImpl(this.jobHandle, jobResult,
jobResultMsg.getBytes(), null, null, 0, 0);
return gjr;
}
}

View File

@ -1,253 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Action;
import hudson.model.ParameterValue;
import hudson.model.Result;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Cause;
import hudson.model.Computer;
import hudson.model.Hudson;
import hudson.model.Queue;
import hudson.model.labels.LabelAtom;
import hudson.model.Node;
import hudson.model.TextParameterValue;
import hudson.model.queue.QueueTaskFuture;
import hudson.slaves.OfflineCause;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.gearman.client.GearmanIOEventListener;
import org.gearman.client.GearmanJobResult;
import org.gearman.client.GearmanJobResultImpl;
import org.gearman.common.GearmanJobServerSession;
import org.gearman.worker.AbstractGearmanFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* This is a gearman function that will start jenkins builds
*
* Assumptions: When this function is created it has an associated
* computer and project. The build will start a jenkins build
* on its assigned assigned project and computer and pass along
* all of the parameters from the client.
*
* @author Khai Do
*/
public class StartJobWorker extends AbstractGearmanFunction {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
Computer computer;
AbstractProject<?, ?> project;
String masterName;
MyGearmanWorkerImpl worker;
public StartJobWorker(AbstractProject<?, ?> project, Computer computer, String masterName,
MyGearmanWorkerImpl worker) {
this.project = project;
this.computer = computer;
this.masterName = masterName;
this.worker = worker;
}
private String buildStatusData(AbstractBuild<?, ?> build) {
Hudson hudson = Hudson.getInstance();
AbstractProject<?, ?> project = build.getProject();
Map data = new HashMap<String, String>();
data.put("name", project.getName());
data.put("number", build.getNumber());
data.put("manager", masterName);
data.put("worker", this.worker.getWorkerID());
String rootUrl = Hudson.getInstance().getRootUrl();
if (rootUrl != null) {
data.put("url", rootUrl + build.getUrl());
}
Result result = build.getResult();
if (result != null) {
data.put("result", result.toString());
}
ArrayList<String> nodeLabels = new ArrayList<String>();
Node node = build.getBuiltOn();
if (node != null) {
Set<LabelAtom> nodeLabelAtoms = node.getAssignedLabels();
for (LabelAtom labelAtom : nodeLabelAtoms) {
nodeLabels.add(labelAtom.getDisplayName());
}
}
data.put("node_labels", nodeLabels);
data.put("node_name", node.getNodeName());
Gson gson = new Gson();
return gson.toJson(data);
}
/*
* The Gearman Function
* @see org.gearman.worker.AbstractGearmanFunction#executeFunction()
*/
@Override
public GearmanJobResult executeFunction() {
try {
return safeExecuteFunction();
} catch (Exception inner) {
RuntimeException outer = new RuntimeException(inner);
throw outer;
}
}
private GearmanJobResult safeExecuteFunction()
throws Exception
{
// decode the uniqueId from the client
String decodedUniqueId = null;
if (this.uniqueId != null) {
decodedUniqueId = new String(this.uniqueId, "UTF-8");
}
// create new parameter objects to pass to jenkins build
List<ParameterValue> buildParams = new ArrayList<ParameterValue>();
String decodedData = null;
boolean offlineWhenComplete = false;
if (this.data != null) {
// decode the data from the client
decodedData = new String((byte[]) this.data, "UTF-8");
// convert parameters passed in from client to hash map
Gson gson = new Gson();
Map<String, String> inParams = gson.fromJson(decodedData,
new TypeToken<Map<String, String>>() {
}.getType());
// set build parameters that were passed in from client
for (Map.Entry<String, String> entry : inParams.entrySet()) {
buildParams.add(new TextParameterValue(entry.getKey(), entry.getValue()));
}
String offline = inParams.get("OFFLINE_NODE_WHEN_COMPLETE");
if (offline != null) {
if (offline.equals("1") || offline.equals("true") ||
offline.equals("True") || offline.equals("TRUE")) {
offlineWhenComplete = true;
}
}
}
/*
* make this node build this project with unique id and build params from the client
*/
String runNodeName = GearmanPluginUtil.getRealName(computer);
// create action to run on a specified computer
Action runNode = new NodeAssignmentAction(runNodeName);
// create action for parameters
Action params = new NodeParametersAction(buildParams, decodedUniqueId);
Action [] actions = {runNode, params};
AvailabilityMonitor availability =
GearmanProxy.getInstance().getAvailabilityMonitor(computer);
availability.expectUUID(decodedUniqueId);
// schedule jenkins to build project
logger.info("---- Worker " + this.worker + " scheduling " +
project.getName()+" build #" +
project.getNextBuildNumber()+" on " + runNodeName
+ " with UUID " + decodedUniqueId + " and build params " + buildParams);
QueueTaskFuture<?> future = project.scheduleBuild2(0, new Cause.UserIdCause(), actions);
// check build and pass results back to client
String jobData;
try {
// This is a hack that relies on implementation knowledge. In
// order to actually send a WORK_STATUS packet before the
// completion of work, we need to directly drive the session
// IO, which requires a session object. We happen to know
// that's what our event listener is.
GearmanJobServerSession sess = null;
for (GearmanIOEventListener listener : listeners) {
if (listener instanceof GearmanJobServerSession) {
sess = (GearmanJobServerSession)listener;
}
}
// wait for start of build
Queue.Executable exec = future.getStartCondition().get();
AbstractBuild<?, ?> currBuild = (AbstractBuild<?, ?>) exec;
if (!offlineWhenComplete) {
// Unlock the monitor for this worker
availability.unlock(worker);
}
long now = new Date().getTime();
int duration = (int) (now - currBuild.getStartTimeInMillis());
int estimatedDuration = (int) currBuild.getEstimatedDuration();
jobData = buildStatusData(currBuild);
sendData(jobData.getBytes());
sess.driveSessionIO();
sendStatus(estimatedDuration, duration);
sess.driveSessionIO();
exec = future.get();
jobData = buildStatusData(currBuild);
} finally {
if (offlineWhenComplete) {
if (computer == null) {
logger.error("---- Worker " + this.worker + " has no " +
"computer while trying to take node offline.");
} else {
logger.info("---- Worker " + this.worker + " setting " +
"node offline.");
computer.setTemporarilyOffline(true,
new OfflineCause.ByCLI("Offline due to Gearman request"));
}
}
}
// return result to client
GearmanJobResult gjr = new GearmanJobResultImpl(
this.jobHandle, true,
jobData.getBytes(), "".getBytes(),
"".getBytes(), 0, 0);
return gjr;
}
}

View File

@ -1,104 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Run;
import hudson.model.Executor;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.gearman.client.GearmanJobResult;
import org.gearman.client.GearmanJobResultImpl;
import org.gearman.worker.AbstractGearmanFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* This is a gearman function that will cancel/abort jenkins builds
*
* @author Khai Do
*/
public class StopJobWorker extends AbstractGearmanFunction {
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
/*
* The Gearman Function
* @see org.gearman.worker.AbstractGearmanFunction#executeFunction()
*/
@Override
public GearmanJobResult executeFunction() {
// check job results
boolean jobResult = false;
String jobResultMsg = "";
String decodedData;
// decode json
try {
decodedData = new String((byte[]) this.data, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Unsupported encoding exception in argument");
}
// convert parameters passed in from client to hash map
Gson gson = new Gson();
Map<String, String> data = gson.fromJson(decodedData,
new TypeToken<Map<String, String>>() {
}.getType());
// get build id
String jobName = data.get("name");
String buildNumber = data.get("number");
if (jobName.isEmpty() || buildNumber.isEmpty()) {
throw new IllegalArgumentException("Build id is invalid or not specified");
}
// Abort running jenkins build that contain matching uuid
Run<?,?> build = GearmanPluginUtil.findBuild(jobName, Integer.parseInt(buildNumber));
if (build != null) {
if (build.isBuilding()) {
Executor executor = build.getExecutor();
// abort the running jenkins build
if (!executor.isInterrupted()) {
executor.interrupt();
logger.info("---- Aborting build : " +
jobName + ": " + buildNumber);
jobResult = true;
}
} else {
logger.info("---- Request to abourt non-building build : " +
jobName + ": " + buildNumber);
}
} else {
throw new IllegalArgumentException("Cannot find build " +
jobName + ": " + buildNumber);
}
GearmanJobResult gjr = new GearmanJobResultImpl(this.jobHandle, jobResult,
jobResultMsg.getBytes(), null, null, 0, 0);
return gjr;
}
}

View File

@ -1,81 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman.example;
import java.util.UUID;
import org.gearman.client.GearmanClient;
import org.gearman.client.GearmanClientImpl;
import org.gearman.client.GearmanJob;
import org.gearman.client.GearmanJobImpl;
import org.gearman.client.GearmanJobResult;
import org.gearman.common.GearmanNIOJobServerConnection;
import org.gearman.util.ByteUtils;
/**
* A java example of how to start a jenkins job using a Gearman client
*
* @author Khai Do
*/
public class StartJobClient {
/**
* @param args
*/
public static void main(String[] args) {
// setup connection settings
String host = "127.0.0.1";
int port = 4730;
// setup job parameters
String function = "build:pep8:precise";
String uniqueId = UUID.randomUUID().toString();
String params = "{param1:red, param2:white, param3:blue}";
// connect client to server
GearmanClient client = new GearmanClientImpl();
GearmanNIOJobServerConnection conn = new GearmanNIOJobServerConnection(host, port);
client.addJobServer(conn);
// send job request
byte[] data = ByteUtils.toUTF8Bytes(params);
GearmanJob job = GearmanJobImpl.createJob(function, data, uniqueId);
client.submit(job);
// get results
String value = "";
GearmanJobResult res = null;
try {
res = job.get();
value = ByteUtils.fromUTF8Bytes(res.getResults());
System.out.println("Job Result: "+value);
} catch (Exception e) {
e.printStackTrace();
}
// close client
client.shutdown();
}
}

View File

@ -1,17 +0,0 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:section title="Gearman Plugin Config">
<f:entry title="Gearman Server Host" field="host">
<f:textbox value="${descriptor.host()}" clazz="required"/>
</f:entry>
<f:entry title="Gearman Server Port" field="port">
<f:number value="${descriptor.port()}" clazz="required number"/>
</f:entry>
<f:validateButton
title="${%Test Connection}" progress="${%Testing...}"
method="testConnection" with="host,port"/>
<f:entry title="Enable Gearman" field="enablePlugin"
description="Select to enable Gearman plugin, Unselect to disable">
<f:checkbox checked="${descriptor.enablePlugin()}"/>
</f:entry>
</f:section>
</j:jelly>

View File

@ -1,5 +0,0 @@
<div>
<p>
Select then press save to start the Gearman workers.
</p>
</div>

View File

@ -1,5 +0,0 @@
<div>
<p>
Set the Gearman Server's host name, something like 'localhost', '127.0.0.1' or 'server.domain.com'
</p>
</div>

View File

@ -1,5 +0,0 @@
<div>
<p>
Set the Gearman server port. By default the Gearman server's port typically set to 4730
</p>
</div>

View File

@ -1,3 +0,0 @@
<div>
This plugin uses Gearman to support multiple Jenkins masters.
</div>

View File

@ -1,71 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.gearman.common.GearmanNIOJobServerConnection;
import org.gearman.worker.GearmanWorker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PrepareForTest;
/**
* Test for the {@link AbstractWorkerThread} class.
*
* @author Khai Do
*/
@PrepareForTest(GearmanWorker.class)
public class AbstractWorkerThreadTest {
/**
*/
@Before
public void setUp() {
GearmanWorker gearmanWorker = mock(GearmanWorker.class);
GearmanNIOJobServerConnection conn = new GearmanNIOJobServerConnection("localhost", 4730);
doNothing().when(gearmanWorker).work();
when(gearmanWorker.addServer(conn)).thenReturn(true);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testNamedThread() {
AbstractWorkerThread fakeWorker = new FakeWorkerThread("GearmanServer", 4730, "faker", null);
assertEquals("faker", fakeWorker.getName());
}
@Test
public void testStartStopThread() {
AbstractWorkerThread fakeWorker = new FakeWorkerThread("GearmanServer", 4730, "faker", null);
fakeWorker.start();
assertTrue(fakeWorker.isAlive());
fakeWorker.stop();
assertFalse(fakeWorker.isAlive());
}
}

View File

@ -1,244 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.maven.MavenModuleSet;
import hudson.model.Node.Mode;
import hudson.model.Project;
import hudson.model.labels.LabelAtom;
import hudson.slaves.DumbSlave;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.jvnet.hudson.test.HudsonTestCase;
/**
* Test for the {@link ExecutorWorkerThread} class.
*
* @author Khai Do
*/
public class ExecutorWorkerThreadTest extends HudsonTestCase {
DumbSlave slave = null;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
slave = createOnlineSlave(new LabelAtom("oneiric-10"));
// poll to make sure test slave is online before continuing
long timeoutExpiredMs = System.currentTimeMillis() + 3000;
while (true) {
if (slave.getChannel() != null) {
break;
}
this.wait(timeoutExpiredMs - System.currentTimeMillis());
if (System.currentTimeMillis() >= timeoutExpiredMs) {
fail("Could not start test slave");
}
}
slave.setLabelString("ubuntu gcc python-2.4 linux");
}
@Override
@After
public void tearDown() throws Exception {
hudson.removeNode(slave);
super.tearDown();
}
/*
* This test verifies that gearman functions are correctly registered for a
* project that contains a single label matching a label on the slave node
*/
@Test
public void testRegisterJobs_ProjectSingleLabel() throws Exception {
Project<?, ?> lemon = createFreeStyleProject("lemon");
lemon.setAssignedLabel(new LabelAtom("linux"));
AbstractWorkerThread oneiric = new ExecutorWorkerThread("GearmanServer", 4730, "MyWorker", slave.toComputer(), "master", new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(2, functions.size());
assertTrue(functions.contains("build:lemon"));
assertTrue(functions.contains("build:lemon:linux"));
}
/*
* This test verifies that no gearman functions are registered
* for projects that contain labels that do not match labels on a slave node
*/
@Test
public void testRegisterJobs_ProjectInvalidLabel() throws Exception {
Project<?, ?> lemon = createFreeStyleProject("lemon");
lemon.setAssignedLabel(new LabelAtom("bogus"));
AbstractWorkerThread oneiric = new ExecutorWorkerThread("GearmanServer", 4730, "MyWorker", slave.toComputer(), "master", new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(0, functions.size());
}
/*
* This test verifies that gearman functions get correctly registered for a
* project has no labels and slave is set to normal mode (i.e. 'Utilize this
* slave as much as possible')
*/
@Test
public void testRegisterJobs_ProjectNoLabel() throws Exception {
Project<?, ?> lemon = createFreeStyleProject("lemon");
AbstractWorkerThread oneiric = new ExecutorWorkerThread(
"GearmanServer",
4730,
"MyWorker",
slave.toComputer(),
"master",
new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(1, functions.size());
assertTrue(functions.contains("build:lemon"));
}
/*
* This test verifies that a gearman function does not get registered for
* a project that has no label and slave is set to exclusive mode
* (i.e. 'leave this machine for tied jobs only')
*/
@Test
public void testRegisterJobs_ProjectNoLabel_Exclusive() throws Exception {
Project<?, ?> lemon = createFreeStyleProject("lemon");
DumbSlave exclusive_slave = createOnlineSlave(new LabelAtom("foo"));
exclusive_slave.setMode(Mode.EXCLUSIVE);
AbstractWorkerThread oneiric = new ExecutorWorkerThread(
"GearmanServer",
4730,
"MyWorker",
exclusive_slave.toComputer(),
"master",
new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(0, functions.size());
}
/*
* This test verifies that no gearman functions are registered
* for disabled projects.
*/
@Test
public void testRegisterJobs_ProjectDisabled() throws Exception {
Project<?, ?> lemon = createFreeStyleProject("lemon");
lemon.setAssignedLabel(new LabelAtom("linux"));
lemon.disable();
AbstractWorkerThread oneiric = new ExecutorWorkerThread("GearmanServer", 4730, "MyWorker", slave.toComputer(), "master", new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(0, functions.size());
}
/*
* This test verifies that no gearman functions are registered
* for slaves nodes that are offline.
*/
@Test
public void testRegisterJobs_SlaveOffline() throws Exception {
DumbSlave offlineSlave = createSlave(new LabelAtom("oneiric-10"));
offlineSlave.setLabelString("ubuntu gcc python-2.4 linux");
Project<?, ?> lemon = createFreeStyleProject("lemon");
lemon.setAssignedLabel(new LabelAtom("linux"));
AbstractWorkerThread oneiric = new ExecutorWorkerThread("GearmanServer", 4730, "MyWorker", offlineSlave.toComputer(), "master", new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(0, functions.size());
}
/*
* This test verifies that gearman functions is correctly registered
* for maven projects
*/
@Test
public void testRegisterJobs_MavenProject() throws Exception {
MavenModuleSet lemon = createMavenProject("lemon");
lemon.setAssignedLabel(new LabelAtom("linux"));
AbstractWorkerThread oneiric = new ExecutorWorkerThread("GearmanServer", 4730, "MyWorker", slave.toComputer(), "master", new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(2, functions.size());
assertTrue(functions.contains("build:lemon"));
assertTrue(functions.contains("build:lemon:linux"));
}
/*
* This test verifies that gearman functions are correctly registered for a
* project that contains a label that has a negate operator
*/
@Test
public void testRegisterJobs_ProjectNotLabel() throws Exception {
Project<?, ?> lemon = createFreeStyleProject("lemon");
lemon.setAssignedLabel(new LabelAtom("!linux"));
AbstractWorkerThread oneiric = new ExecutorWorkerThread("GearmanServer", 4730, "MyWorker", slave.toComputer(), "master", new NoopAvailabilityMonitor());
oneiric.testInitWorker();
oneiric.registerJobs();
Set<String> functions = oneiric.worker.getRegisteredFunctions();
assertEquals(0, functions.size());
}
}

View File

@ -1,57 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* This a fake worker which is only used for testing
*
* @author Khai Do
*
*/
public class FakeWorkerThread extends AbstractWorkerThread{
private static final Logger logger = LoggerFactory
.getLogger(Constants.PLUGIN_LOGGER_NAME);
public FakeWorkerThread(String host, int port, String name,
AvailabilityMonitor availability) {
super(host, port, name, availability);
}
/**
* Fake registerJobs
*/
@Override
public void registerJobs() {
}
/**
* Fake run
*/
@Override
public void run() {
}
}

View File

@ -1,75 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import jenkins.model.Jenkins;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
/**
* Test for the {@link GearmanPluginConfig} class.
*
* @author Khai Do
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(Jenkins.class)
public class GearmanPluginConfigTest {
private GearmanPluginConfig gpc;
/**
*/
@Before
public void setUp() {
Jenkins jenkins = mock(Jenkins.class);
PowerMockito.mockStatic(Jenkins.class);
when(Jenkins.getActiveInstance()).thenReturn(jenkins);
gpc = new GearmanPluginConfig();
}
@After
public void tearDown() throws Exception {
}
@Test
public void testDefaultGearmanHost() {
assertEquals(Constants.GEARMAN_DEFAULT_TCP_HOST, gpc.getHost());
}
@Test
public void testDefaultGearmanPort() {
assertEquals(Constants.GEARMAN_DEFAULT_TCP_PORT, gpc.getPort());
}
@Test
public void testDefaultLaunchWorker() {
assertEquals(Constants.GEARMAN_DEFAULT_ENABLE_PLUGIN,
gpc.enablePlugin());
}
}

View File

@ -1,52 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.model.Computer;
import hudson.slaves.DumbSlave;
import jenkins.model.Jenkins;
import org.junit.Test;
import org.jvnet.hudson.test.HudsonTestCase;
/**
* Test for the {@link GearmanPluginUtil} class.
*
* @author Khai Do
*/
public class GearmanPluginUtilTest extends HudsonTestCase {
@Test
public void testGetRealNameSlave() throws Exception {
DumbSlave slave = createOnlineSlave();
// createOnlineSlave sets the slave name to slave0. Do not change
// this with setNodeName as the name is supposed to be immutable
// except when cloning a preexisting slave.
assertEquals("slave0", GearmanPluginUtil.getRealName(slave.toComputer()));
hudson.removeNode(slave);
}
@Test
public void testGetRealNameMaster() throws Exception {
assertEquals("master", GearmanPluginUtil.getRealName(Jenkins.getActiveInstance().getComputer("")));
}
}

View File

@ -1,94 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import hudson.slaves.DumbSlave;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.jvnet.hudson.test.HudsonTestCase;
/**
* Test for the {@link ExecutorWorkerThread} class.
*
* @author Khai Do
*/
public class GearmanProxyTest extends HudsonTestCase {
GearmanProxy gp;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
gp = GearmanProxy.getInstance();
}
@Override
@After
public void tearDown() throws Exception {
gp.testResetHandles();
super.tearDown();
}
@Test
public void testCreateManagementWorker() {
assertEquals(0, gp.getNumExecutors());
gp.createManagementWorker();
// mgmt: 1 master
assertEquals(1, gp.getNumExecutors());
// assertTrue(gp.getGmwtHandles().get(0).isAlive());
}
@Test
public void testCreateExecutorWorkersOnNode() throws Exception {
DumbSlave slave = createSlave();
assertEquals(0, gp.getNumExecutors());
gp.createExecutorWorkersOnNode(slave.toComputer());
// exec: 1 master
assertEquals(1, gp.getNumExecutors());
}
@Test
public void testInitWorkers() {
gp.initWorkers();
// exec: 1 slave, 1 master + mgmnt: 1
assertEquals(3, gp.getNumExecutors());
}
@Test
public void testInitWorkers2() throws Exception {
DumbSlave slave = createSlave();
gp.initWorkers();
// exec: 2 slaves, 1 master + mgmnt: 1
assertEquals(4, gp.getNumExecutors());
}
}

View File

@ -1,75 +0,0 @@
/*
*
* Copyright 2013 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hudson.plugins.gearman;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Set;
import org.gearman.common.GearmanNIOJobServerConnection;
import org.gearman.worker.GearmanWorker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PrepareForTest;
/**
* Test for the {@link ManagementWorkerThread} class.
*
* @author Khai Do
*/
@PrepareForTest(GearmanWorker.class)
public class ManagementWorkerThreadTest {
/**
*/
@Before
public void setUp() {
GearmanWorker gearmanWorker = mock(GearmanWorker.class);
GearmanNIOJobServerConnection conn = new GearmanNIOJobServerConnection("localhost", 4730);
doNothing().when(gearmanWorker).work();
when(gearmanWorker.addServer(conn)).thenReturn(true);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testRegisterJobs() {
AbstractWorkerThread manager = new ManagementWorkerThread("GearmanServer", 4730,
"master_manager", "master", new NoopAvailabilityMonitor());
manager.testInitWorker();
manager.registerJobs();
Set<String> functions = manager.worker.getRegisteredFunctions();
assertEquals("set_description:master", functions.toArray()[0]);
assertEquals("stop:master", functions.toArray()[1]);
}
@Test
public void testManagerId() {
AbstractWorkerThread manager = new ManagementWorkerThread("GearmanServer", 4730,
"master_manager", "master", new NoopAvailabilityMonitor());
assertEquals("master_manager", manager.getName());
}
}

View File

@ -1,32 +0,0 @@
#!/bin/bash -ex
#
# This is a script that helps us version build artifacts. It retrieves
# git info and generates version strings.
#
# Source:
# http://git.openstack.org/cgit/openstack-infra/project-config/tree/jenkins/scripts/version-properties.sh
#
# get version info from scm
SCM_TAG=$(git describe --abbrev=0 --tags) || true
SCM_SHA=$(git rev-parse --short HEAD) || true
# assumes format is like this '0.0.4-2-g135721c'
COMMITS_SINCE_TAG=$(git describe | awk '{split($0,a,"-"); print a[2]}') || true
# just use git sha if there is no tag yet.
if [[ "${SCM_TAG}" == "" ]]; then
SCM_TAG=$SCM_SHA
fi
# General build version should be something like '0.0.4.3.d4ee90c'
# Release build version should be something like '0.0.5'
if [[ "${COMMITS_SINCE_TAG}" == "" ]]; then
PROJECT_VER=$SCM_TAG
else
PROJECT_VER="$SCM_TAG.$COMMITS_SINCE_TAG.$SCM_SHA";
fi
echo "SCM_SHA=$SCM_SHA" >version.properties
echo "PROJECT_VER=$PROJECT_VER" >>version.properties
echo "COMMITS_SINCE_TAG=$COMMITS_SINCE_TAG" >>version.properties