├── .gitignore ├── LICENSE ├── aggregator ├── pom.xml └── src │ └── main │ └── resources │ └── index.jelly ├── arquillian-steps ├── pom.xml ├── readme.md └── src │ └── main │ ├── java │ └── io │ │ └── fabric8 │ │ └── kubernetes │ │ └── pipeline │ │ └── arquillian │ │ └── cube │ │ └── kubernetes │ │ ├── AbstractSessionManagerStep.java │ │ ├── AbstractSessionManagerStepExecution.java │ │ ├── AbstractStep.java │ │ ├── AbstractStepExecution.java │ │ ├── CreateEnvironmentStep.java │ │ ├── CreateEnvironmentStepExecution.java │ │ ├── CubeDSL.java │ │ ├── EmptyDependencyResolver.java │ │ ├── GetNamespaceStep.java │ │ ├── GetNamespaceStepExecution.java │ │ ├── InNamespaceStep.java │ │ ├── InNamespaceStepExecution.java │ │ ├── InSessionStep.java │ │ ├── InSessionStepExecution.java │ │ ├── MapAnnotationProvider.java │ │ ├── MapLabelProvider.java │ │ ├── NamespaceDestructionCallback.java │ │ ├── NamespaceExpander.java │ │ ├── SessionManagerStopCallback.java │ │ └── StreamLogger.java │ └── resources │ ├── index.jelly │ └── io │ └── fabric8 │ └── kubernetes │ └── pipeline │ └── arquillian │ └── cube │ └── kubernetes │ ├── CreateEnvironmentSessionStep │ ├── config.jelly │ └── help-name.html │ ├── Cube.groovy │ ├── InNamespaceStep │ ├── config.jelly │ └── help-name.html │ └── InSessionStep │ ├── config.jelly │ └── help-name.html ├── circle.yml ├── core ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── fabric8 │ │ └── workflow │ │ └── core │ │ ├── ClassWhiteList.java │ │ └── Constants.java │ └── test │ └── java │ ├── io │ └── fabric8 │ │ └── kubernetes │ │ └── pipeline │ │ └── KubernetesTestUtil.java │ └── org │ └── jvnet │ └── hudson │ └── test │ └── JenkinsRuleNonLocalhost.java ├── devops-steps ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── fabric8 │ │ │ └── kubernetes │ │ │ └── pipeline │ │ │ └── devops │ │ │ ├── ApplyStep.java │ │ │ ├── ApplyStepExecution.java │ │ │ ├── ApproveReceivedEventStep.java │ │ │ ├── ApproveReceivedEventStepExecution.java │ │ │ ├── ApproveRequestedEventStep.java │ │ │ ├── ApproveRequestedEventStepExecution.java │ │ │ ├── CreateEventStep.java │ │ │ ├── CreateEventStepExecution.java │ │ │ ├── EnvironmentRollout.java │ │ │ ├── KubernetesClientRef.java │ │ │ ├── ServiceResourceUtil.java │ │ │ ├── elasticsearch │ │ │ ├── ApprovalEventDTO.java │ │ │ ├── BuildDTO.java │ │ │ ├── BuildListener.java │ │ │ ├── CauseDTO.java │ │ │ ├── DTOSupport.java │ │ │ ├── DeploymentEventDTO.java │ │ │ ├── ElasticsearchClient.java │ │ │ └── JsonUtils.java │ │ │ └── git │ │ │ ├── GitConfig.java │ │ │ ├── GitInfoCallback.java │ │ │ └── RepositoryListenerCallback.java │ └── resources │ │ └── io │ │ └── fabric8 │ │ └── kubernetes │ │ └── pipeline │ │ └── devops │ │ └── environmentAnnotations.properties │ └── test │ ├── java │ └── io │ │ └── fabric8 │ │ └── kubernetes │ │ └── pipeline │ │ └── devops │ │ ├── ApplyTest.java │ │ ├── ServiceResourceUtilTest.java │ │ └── elasticsearch │ │ ├── BaseSendEvent.java │ │ ├── BuildEvent.java │ │ ├── CreateApprovalEvent.java │ │ ├── DeploymentEvent.java │ │ └── UpdateApprovalEvent.java │ └── resources │ ├── kubernetesJsonWithRegistry.json │ ├── kubernetesJsonWithoutRegistry.json │ └── services │ ├── invalidservice1.yaml │ ├── invalidservice2.yaml │ ├── invalidservice3.yaml │ ├── validservice3.yaml │ └── validservice4.yaml ├── doc └── scc-example.json ├── header.txt ├── kubernetes-steps ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── fabric8 │ │ │ └── kubernetes │ │ │ └── pipeline │ │ │ ├── AbstractDockerStep.java │ │ │ ├── BuildImageStep.java │ │ │ ├── BuildImageStepExecution.java │ │ │ ├── KubernetesDSL.java │ │ │ ├── KubernetesFacade.java │ │ │ ├── PodExecDecorator.java │ │ │ ├── PodExecProc.java │ │ │ ├── PodWatcher.java │ │ │ ├── PushImageStep.java │ │ │ ├── PushImageStepExecution.java │ │ │ ├── TagImageStep.java │ │ │ ├── TagImageStepExecution.java │ │ │ ├── WithPodStep.java │ │ │ └── WithPodStepExecution.java │ └── resources │ │ ├── META-INF │ │ └── hudson.remoting.ClassFilter │ │ ├── index.jelly │ │ └── io │ │ └── fabric8 │ │ └── kubernetes │ │ └── pipeline │ │ ├── BuildImageStep │ │ ├── config.jelly │ │ ├── help-email.html │ │ ├── help-name.html │ │ ├── help-password.html │ │ ├── help-path.html │ │ ├── help-rm.html │ │ ├── help-timeout.html │ │ ├── help-username.html │ │ └── help.html │ │ ├── Kubernetes.groovy │ │ ├── KubernetesDSL │ │ └── help.jelly │ │ ├── PushImageStep │ │ ├── config.jelly │ │ ├── help-email.html │ │ ├── help-name.html │ │ ├── help-password.html │ │ ├── help-registry.html │ │ ├── help-timeout.html │ │ ├── help-username.html │ │ └── help.html │ │ ├── TagImageStep │ │ ├── config.jelly │ │ ├── help-email.html │ │ ├── help-name.html │ │ ├── help-password.html │ │ ├── help-repo.html │ │ ├── help-tag.html │ │ ├── help-username.html │ │ └── help.html │ │ └── WithPodStep │ │ ├── config.jelly │ │ ├── help-inheritFrom.html │ │ ├── help-nodeSelector.html │ │ └── help-serviceAccount.html │ └── test │ ├── java │ └── io │ │ └── fabric8 │ │ └── kubernetes │ │ └── pipeline │ │ └── KubernetesPipelineTest.java │ └── resources │ ├── arquillian.xml │ └── io │ └── fabric8 │ └── kubernetes │ └── pipeline │ └── simpleMaven.groovy ├── pom.xml └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Maven template 3 | target/ 4 | work/ 5 | pom.xml.tag 6 | pom.xml.releaseBackup 7 | pom.xml.versionsBackup 8 | pom.xml.next 9 | release.properties 10 | dependency-reduced-pom.xml 11 | buildNumber.properties 12 | .mvn/timing.properties 13 | 14 | 15 | ### Java template 16 | *.class 17 | 18 | # Mobile Tools for Java (J2ME) 19 | .mtj.tmp/ 20 | 21 | # Package Files # 22 | *.jar 23 | *.war 24 | *.ear 25 | 26 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 27 | hs_err_pid* 28 | 29 | 30 | ### JetBrains template 31 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 32 | 33 | *.iml 34 | 35 | ## Directory-based project format: 36 | .idea/ 37 | # if you remove the above rule, at least ignore the following: 38 | 39 | # User-specific stuff: 40 | # .idea/workspace.xml 41 | # .idea/tasks.xml 42 | # .idea/dictionaries 43 | 44 | # Sensitive or high-churn files: 45 | # .idea/dataSources.ids 46 | # .idea/dataSources.xml 47 | # .idea/sqlDataSources.xml 48 | # .idea/dynamic.xml 49 | # .idea/uiDesigner.xml 50 | 51 | # Gradle: 52 | # .idea/gradle.xml 53 | # .idea/libraries 54 | 55 | # Mongo Explorer plugin: 56 | # .idea/mongoSettings.xml 57 | 58 | ## File-based project format: 59 | *.ipr 60 | *.iws 61 | 62 | ## Plugin-specific files: 63 | 64 | # IntelliJ 65 | /out/ 66 | 67 | # mpeltonen/sbt-idea plugin 68 | .idea_modules/ 69 | 70 | # JIRA plugin 71 | atlassian-ide-plugin.xml 72 | 73 | # Crashlytics plugin (for Android Studio and IntelliJ) 74 | com_crashlytics_export_strings.xml 75 | crashlytics.properties 76 | crashlytics-build.properties 77 | 78 | .DS_Store 79 | .classpath 80 | .project 81 | velocity.log 82 | .settings 83 | -------------------------------------------------------------------------------- /aggregator/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | Collects all Fabric8 Workflow Plugins into One. 4 |
-------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/AbstractSessionManagerStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import java.io.Serializable; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | public abstract class AbstractSessionManagerStep extends AbstractStep implements Serializable { 24 | 25 | private static final long serialVersionUID = 5588861066775717487L; 26 | 27 | private static final long DEFAULT_WAIT_TIMEOUT = 5*60*1000; 28 | 29 | protected final String name; 30 | protected final String prefix; 31 | 32 | protected final Map labels; 33 | protected final Map annotations; 34 | 35 | protected final Map scriptEnvironmentVariables; 36 | protected final String environmentSetupScriptUrl; 37 | protected final String environmentTeardownScriptUrl; 38 | 39 | protected final String environmentConfigUrl; 40 | protected final List environmentDependencies; 41 | 42 | 43 | protected final Long waitTimeout; 44 | protected final List waitForServiceList; 45 | 46 | protected final Boolean namespaceLazyCreateEnabled; 47 | protected final Boolean namespaceCleanupEnabled; 48 | protected final Boolean namespaceDestroyEnabled; 49 | 50 | public AbstractSessionManagerStep(String cloud, String name, String prefix, Map labels, Map annotations, Map scriptEnvironmentVariables, String environmentSetupScriptUrl, String environmentTeardownScriptUrl, String environmentConfigUrl, List environmentDependencies, Long waitTimeout, List waitForServiceList, Boolean namespaceLazyCreateEnabled, Boolean namespaceCleanupEnabled, Boolean namespaceDestroyEnabled) { 51 | super(cloud); 52 | this.name = name; 53 | this.prefix = prefix; 54 | this.labels = labels; 55 | this.annotations = annotations; 56 | this.scriptEnvironmentVariables = scriptEnvironmentVariables; 57 | this.environmentSetupScriptUrl = environmentSetupScriptUrl; 58 | this.environmentTeardownScriptUrl = environmentTeardownScriptUrl; 59 | this.environmentConfigUrl = environmentConfigUrl; 60 | this.environmentDependencies = environmentDependencies; 61 | this.waitTimeout = waitTimeout != null ? waitTimeout : DEFAULT_WAIT_TIMEOUT; 62 | this.waitForServiceList = waitForServiceList; 63 | this.namespaceLazyCreateEnabled = namespaceLazyCreateEnabled != null ? namespaceLazyCreateEnabled : true; 64 | this.namespaceCleanupEnabled = namespaceCleanupEnabled; 65 | this.namespaceDestroyEnabled = namespaceDestroyEnabled; 66 | } 67 | 68 | public String getName() { 69 | return name; 70 | } 71 | 72 | public String getPrefix() { 73 | return prefix; 74 | } 75 | 76 | public Map getLabels() { 77 | return labels; 78 | } 79 | 80 | public Map getAnnotations() { 81 | return annotations; 82 | } 83 | 84 | public Map getScriptEnvironmentVariables() { 85 | return scriptEnvironmentVariables; 86 | } 87 | 88 | public String getEnvironmentSetupScriptUrl() { 89 | return environmentSetupScriptUrl; 90 | } 91 | 92 | public String getEnvironmentTeardownScriptUrl() { 93 | return environmentTeardownScriptUrl; 94 | } 95 | 96 | public String getEnvironmentConfigUrl() { 97 | return environmentConfigUrl; 98 | } 99 | 100 | public List getEnvironmentDependencies() { 101 | return environmentDependencies; 102 | } 103 | 104 | public Long getWaitTimeout() { 105 | return waitTimeout; 106 | } 107 | 108 | public List getWaitForServiceList() { 109 | return waitForServiceList; 110 | } 111 | 112 | public Boolean isNamespaceLazyCreateEnabled() { 113 | return namespaceLazyCreateEnabled; 114 | } 115 | 116 | 117 | public Boolean isNamespaceCleanupEnabled() { 118 | return namespaceCleanupEnabled; 119 | } 120 | 121 | public Boolean isNamespaceDestroyEnabled() { 122 | return namespaceDestroyEnabled; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/AbstractStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import com.google.common.base.Strings; 20 | 21 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 22 | import org.jenkinsci.plugins.workflow.steps.Step; 23 | import org.jenkinsci.plugins.workflow.steps.StepContext; 24 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 25 | import org.kohsuke.stapler.DataBoundConstructor; 26 | 27 | import java.io.Serializable; 28 | 29 | public abstract class AbstractStep extends Step implements Serializable { 30 | 31 | private static final long serialVersionUID = 5588861066775717487L; 32 | 33 | protected final String cloud; 34 | 35 | public AbstractStep(String cloud) { 36 | this.cloud = Strings.isNullOrEmpty(cloud) ? "kubernetes" : cloud; 37 | } 38 | 39 | public String getCloud() { 40 | return cloud; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/AbstractStepExecution.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.apache.commons.lang3.RandomStringUtils; 4 | import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud; 5 | import org.csanchez.jenkins.plugins.kubernetes.pipeline.NamespaceAction; 6 | import java.util.logging.Logger; 7 | 8 | import hudson.AbortException; 9 | import hudson.model.Run; 10 | import hudson.slaves.Cloud; 11 | import io.fabric8.kubernetes.client.utils.Utils; 12 | import io.fabric8.kubernetes.clnt.v2_5.DefaultKubernetesClient; 13 | import io.fabric8.kubernetes.clnt.v2_5.KubernetesClient; 14 | import io.fabric8.kubernetes.clnt.v2_5.utils.Serialization; 15 | import jenkins.model.Jenkins; 16 | import org.jenkinsci.plugins.workflow.steps.StepContext; 17 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 18 | 19 | public abstract class AbstractStepExecution extends StepExecution { 20 | 21 | private static final transient String NAME_FORMAT = "%s-%s"; 22 | private static final transient String DEFAULT_PREFIX = "temp"; 23 | private static final transient String RANDOM_CHARACTERS = "bcdfghjklmnpqrstvwxz0123456789"; 24 | 25 | protected static final transient Logger LOGGER = Logger.getLogger(InSessionStepExecution.class.getName()); 26 | 27 | abstract S getStep(); 28 | 29 | AbstractStepExecution(StepContext context) { 30 | super(context); 31 | } 32 | 33 | /** 34 | * Obtains a {@link KubernetesClient} either from the configured {@link Cloud} or a default instance. 35 | * @return 36 | * @throws AbortException 37 | */ 38 | protected KubernetesClient getKubernetesClient() throws AbortException { 39 | 40 | Cloud cloud = Jenkins.getInstance().getCloud(getStep().getCloud()); 41 | if (cloud == null) { 42 | LOGGER.warning("Cloud does not exist: [" + getStep().getCloud() + "]. Falling back to default KubernetesClient."); 43 | } else if (!(cloud instanceof KubernetesCloud)) { 44 | LOGGER.warning("Cloud is not a Kubernetes cloud: [" + getStep().getCloud() + "]. Falling back to default KubernetesClient."); 45 | } else { 46 | KubernetesCloud kubernetesCloud = (KubernetesCloud) cloud; 47 | try { 48 | String json = Serialization.asJson(kubernetesCloud.connect().getConfiguration()); 49 | return DefaultKubernetesClient.fromConfig(json); 50 | } catch (Throwable t) { 51 | LOGGER.warning("Could not connect to cloud: [" + getStep().getCloud() + "]. Falling back to default KubernetesClient."); 52 | } 53 | } 54 | return new DefaultKubernetesClient(); 55 | } 56 | 57 | 58 | /** 59 | * Generates a unique identifier for the arquillian session. 60 | * @return 61 | */ 62 | protected String generateSessionId() { 63 | return RandomStringUtils.random(5, RANDOM_CHARACTERS); 64 | } 65 | 66 | /** 67 | * Generates a namespace id/name if one has not been explicitly specified. 68 | * If no name or prefix is specified, it will try to determine a namespace based on the enclosing elements. 69 | * Finally it will fallback to generating one using the default prefix. 70 | * 71 | * @param name A fixed namespace name. 72 | * @param prefix The prefix to use. 73 | * @param sessionId The id of the session. 74 | * @return The name if not null or empty, else prefix-sessionId. 75 | */ 76 | protected String generateNamespaceId(String name, String prefix, String sessionId) { 77 | if (Utils.isNotNullOrEmpty(name)) { 78 | return name; 79 | } else if (Utils.isNotNullOrEmpty(prefix)) { 80 | return String.format(NAME_FORMAT, prefix, sessionId); 81 | } 82 | 83 | NamespaceAction namespaceAction = getNamespaceAction(); 84 | if (namespaceAction != null && Utils.isNotNullOrEmpty(namespaceAction.getNamespace())) { 85 | return namespaceAction.getNamespace(); 86 | } 87 | 88 | return String.format(NAME_FORMAT, DEFAULT_PREFIX, sessionId); 89 | } 90 | 91 | 92 | /** 93 | * Lookup namespace that is already defined in the current build. 94 | * @return The {@link NamespaceAction}. 95 | */ 96 | protected NamespaceAction getNamespaceAction() { 97 | try { 98 | return new NamespaceAction(getContext().get(Run.class)); 99 | } catch (Throwable t) { 100 | return null; 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/CreateEnvironmentStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 20 | import org.jenkinsci.plugins.workflow.steps.StepContext; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | 24 | import java.io.Serializable; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | import hudson.Extension; 29 | 30 | public class CreateEnvironmentStep extends AbstractSessionManagerStep implements Serializable { 31 | 32 | private static final long serialVersionUID = 5588861066775717487L; 33 | 34 | @DataBoundConstructor 35 | public CreateEnvironmentStep(String cloud, String name, String prefix, Map labels, Map annotations, Map scriptEnvironmentVariables, String environmentSetupScriptUrl, String environmentTeardownScriptUrl, String environmentConfigUrl, List environmentDependencies, Long waitTimeout, List waitForServiceList, Boolean namespaceLazyCreateEnabled, Boolean namespaceCleanupEnabled, Boolean namespaceDestroyEnabled) { 36 | super(cloud, name, prefix, labels, annotations, scriptEnvironmentVariables, environmentSetupScriptUrl, environmentTeardownScriptUrl, environmentConfigUrl, environmentDependencies, waitTimeout, waitForServiceList, namespaceLazyCreateEnabled, namespaceCleanupEnabled, namespaceDestroyEnabled); 37 | } 38 | 39 | @Override 40 | public StepExecution start(StepContext context) throws Exception { 41 | return new CreateEnvironmentStepExecution(this, context); 42 | } 43 | 44 | @Extension 45 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 46 | 47 | public DescriptorImpl() { 48 | super(CreateEnvironmentStepExecution.class); 49 | } 50 | 51 | public DescriptorImpl(Class executionType) { 52 | super(executionType); 53 | } 54 | 55 | @Override 56 | public String getFunctionName() { 57 | return "createEnvironment"; 58 | } 59 | 60 | @Override 61 | public String getDisplayName() { 62 | return "Creates the testing environment. Locates, installs and waits for installed resources to become ready"; 63 | } 64 | 65 | @Override 66 | public boolean takesImplicitBlockArgument() { 67 | return false; 68 | } 69 | 70 | @Override 71 | public boolean isAdvanced() { 72 | return true; 73 | } 74 | 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/CreateEnvironmentStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.arquillian.cube.kubernetes.impl.SessionManager; 20 | import org.jenkinsci.plugins.workflow.steps.StepContext; 21 | 22 | import javax.inject.Inject; 23 | 24 | public class CreateEnvironmentStepExecution extends AbstractSessionManagerStepExecution { 25 | 26 | private CreateEnvironmentStep step; 27 | 28 | CreateEnvironmentStepExecution(CreateEnvironmentStep step, StepContext context) { 29 | super(context); 30 | this.step = step; 31 | } 32 | 33 | @Override 34 | public boolean onStart(SessionManager sessionManager) { 35 | try { 36 | sessionManager.createEnvironment(session); 37 | getContext().onSuccess(true); 38 | } catch (Throwable t) { 39 | getContext().onFailure(t); 40 | } 41 | return true; 42 | } 43 | 44 | @Override 45 | public void onStop(SessionManager sessionManager) { 46 | sessionManager.stop(); 47 | } 48 | 49 | 50 | @Override 51 | CreateEnvironmentStep getStep() { 52 | return step; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/CubeDSL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import groovy.lang.Binding; 20 | 21 | import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; 22 | import org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar; 23 | import org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate; 24 | import org.csanchez.jenkins.plugins.kubernetes.PodEnvVar; 25 | import org.jenkinsci.plugins.workflow.cps.CpsScript; 26 | import org.jenkinsci.plugins.workflow.cps.GlobalVariable; 27 | 28 | import java.io.IOException; 29 | import java.net.URL; 30 | import java.util.ArrayList; 31 | import java.util.Collection; 32 | import java.util.Collections; 33 | import java.util.HashMap; 34 | import java.util.HashSet; 35 | import java.util.concurrent.Callable; 36 | 37 | import javax.annotation.Nonnull; 38 | 39 | import hudson.Extension; 40 | import io.fabric8.kubernetes.api.model.PodTemplate; 41 | import io.fabric8.workflow.core.ClassWhiteList; 42 | 43 | @Extension 44 | public class CubeDSL extends GlobalVariable { 45 | 46 | private static final String CUBE = "cube"; 47 | 48 | @Nonnull 49 | @Override 50 | public String getName() { 51 | return CUBE; 52 | } 53 | 54 | @Nonnull 55 | @Override 56 | public Object getValue(CpsScript script) throws Exception { 57 | Binding binding = script.getBinding(); 58 | Object kubernetes; 59 | if (binding.hasVariable(getName())) { 60 | kubernetes = binding.getVariable(getName()); 61 | } else { 62 | // Note that if this were a method rather than a constructor, we would need to mark it @NonCPS lest it throw CpsCallableInvocation. 63 | kubernetes = CubeDSL.class.getClassLoader().loadClass("io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes.Cube").getConstructor(CpsScript.class).newInstance(script); 64 | binding.setVariable(getName(), kubernetes); 65 | } 66 | return kubernetes; 67 | } 68 | 69 | 70 | @Extension 71 | public static class PlugiWhiteList extends ClassWhiteList { 72 | public PlugiWhiteList() throws IOException { 73 | super(ScriptBytecodeAdapter.class, 74 | URL.class, 75 | ArrayList.class, Collection.class, HashMap.class, HashSet.class, Collections.class, 76 | Callable.class); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/EmptyDependencyResolver.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.arquillian.cube.kubernetes.api.DependencyResolver; 4 | import org.arquillian.cube.kubernetes.api.Session; 5 | 6 | import java.io.IOException; 7 | import java.net.URL; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | public class EmptyDependencyResolver implements DependencyResolver { 12 | 13 | @Override 14 | public List resolve(Session session) throws IOException { 15 | return Collections.emptyList(); 16 | } 17 | 18 | @Override 19 | public DependencyResolver toImmutable() { 20 | return this; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/GetNamespaceStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | 24 | import java.io.Serializable; 25 | 26 | import hudson.Extension; 27 | 28 | public class GetNamespaceStep extends AbstractStepImpl implements Serializable { 29 | 30 | private static final long serialVersionUID = 5588861066775717487L; 31 | 32 | private final String fallbackNamespace; 33 | 34 | @DataBoundConstructor 35 | public GetNamespaceStep(String fallbackNamespace) { 36 | this.fallbackNamespace = fallbackNamespace; 37 | } 38 | 39 | public String getFallbackNamespace() { 40 | return fallbackNamespace; 41 | } 42 | 43 | @Extension 44 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 45 | 46 | public DescriptorImpl() { 47 | super(GetNamespaceStepExecution.class); 48 | } 49 | 50 | public DescriptorImpl(Class executionType) { 51 | super(executionType); 52 | } 53 | 54 | @Override 55 | public String getFunctionName() { 56 | return "currentNamespace"; 57 | } 58 | 59 | @Override 60 | public String getDisplayName() { 61 | return "Returns the current namespace"; 62 | } 63 | 64 | @Override 65 | public boolean takesImplicitBlockArgument() { 66 | return true; 67 | } 68 | 69 | @Override 70 | public boolean isAdvanced() { 71 | return true; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/GetNamespaceStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.csanchez.jenkins.plugins.kubernetes.pipeline.NamespaceAction; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution; 21 | 22 | import javax.inject.Inject; 23 | 24 | import hudson.FilePath; 25 | import hudson.model.Run; 26 | import io.fabric8.kubernetes.client.Config; 27 | import io.fabric8.kubernetes.client.utils.Utils; 28 | 29 | 30 | public class GetNamespaceStepExecution extends AbstractSynchronousStepExecution { 31 | 32 | @Inject 33 | GetNamespaceStep step; 34 | 35 | @Override 36 | protected String run() throws Exception { 37 | String namespace = null; 38 | try { 39 | FilePath workspace = getContext().get(FilePath.class); 40 | namespace = workspace.child(Config.KUBERNETES_NAMESPACE_PATH).readToString(); 41 | if (Utils.isNotNullOrEmpty(namespace)) { 42 | return namespace; 43 | } 44 | } catch (Throwable t) { 45 | //it might be executed outside of a `node` block in which case, we want to ignore. 46 | } 47 | 48 | NamespaceAction namespaceAction = new NamespaceAction(getContext().get(Run.class)); 49 | namespace = namespaceAction.getNamespace(); 50 | 51 | if (Utils.isNotNullOrEmpty(namespace)) { 52 | return namespace; 53 | } 54 | return step.getFallbackNamespace(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InNamespaceStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 20 | import org.jenkinsci.plugins.workflow.steps.StepContext; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | 24 | import java.io.Serializable; 25 | import java.util.Map; 26 | 27 | import hudson.Extension; 28 | 29 | public class InNamespaceStep extends AbstractStep implements Serializable { 30 | 31 | private static final long serialVersionUID = 5588861066775717487L; 32 | 33 | private final String name; 34 | private final String prefix; 35 | 36 | private final Map labels; 37 | private final Map annotations; 38 | 39 | private final Boolean namespaceLazyCreateEnabled; 40 | private final Boolean namespaceDestroyEnabled; 41 | 42 | @DataBoundConstructor 43 | public InNamespaceStep(String cloud, String name, String prefix, Map labels, Map annotations, Boolean namespaceLazyCreateEnabled, Boolean namespaceDestroyEnabled) { 44 | super(cloud); 45 | this.name = name; 46 | this.prefix = prefix; 47 | this.labels = labels; 48 | this.annotations = annotations; 49 | 50 | this.namespaceLazyCreateEnabled = namespaceLazyCreateEnabled != null ? namespaceLazyCreateEnabled : true; 51 | this.namespaceDestroyEnabled = namespaceDestroyEnabled != null ? namespaceDestroyEnabled : true; 52 | } 53 | 54 | public String getName() { 55 | return name; 56 | } 57 | 58 | public String getPrefix() { 59 | return prefix; 60 | } 61 | 62 | public Map getLabels() { 63 | return labels; 64 | } 65 | 66 | public Map getAnnotations() { 67 | return annotations; 68 | } 69 | 70 | public Boolean isNamespaceLazyCreateEnabled() { 71 | return namespaceLazyCreateEnabled; 72 | } 73 | 74 | public Boolean isNamespaceDestroyEnabled() { 75 | return namespaceDestroyEnabled; 76 | } 77 | 78 | @Override 79 | public StepExecution start(StepContext context) throws Exception { 80 | return new InNamespaceStepExecution(this, context); 81 | } 82 | 83 | @Extension 84 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 85 | 86 | public DescriptorImpl() { 87 | super(InNamespaceStepExecution.class); 88 | } 89 | 90 | public DescriptorImpl(Class executionType) { 91 | super(executionType); 92 | } 93 | 94 | @Override 95 | public String getFunctionName() { 96 | return "inNamespace"; 97 | } 98 | 99 | @Override 100 | public String getDisplayName() { 101 | return "Run build steps inside an arquillian cube kubernetes managed namespace"; 102 | } 103 | 104 | @Override 105 | public boolean takesImplicitBlockArgument() { 106 | return true; 107 | } 108 | 109 | @Override 110 | public boolean isAdvanced() { 111 | return true; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InNamespaceStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.arquillian.cube.kubernetes.api.Configuration; 20 | import org.arquillian.cube.kubernetes.api.LabelProvider; 21 | import org.arquillian.cube.kubernetes.api.NamespaceService; 22 | import org.arquillian.cube.kubernetes.impl.DefaultConfigurationBuilder; 23 | import org.arquillian.cube.kubernetes.impl.namespace.DefaultNamespaceService; 24 | import org.arquillian.cube.openshift.impl.namespace.OpenshiftNamespaceService; 25 | import org.csanchez.jenkins.plugins.kubernetes.pipeline.NamespaceAction; 26 | import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander; 27 | 28 | import hudson.model.Run; 29 | import hudson.model.TaskListener; 30 | import io.fabric8.kubernetes.clnt.v2_5.KubernetesClient; 31 | import io.fabric8.openshift.clnt.v2_5.OpenShiftClient; 32 | import org.jenkinsci.plugins.workflow.steps.StepContext; 33 | 34 | 35 | public class InNamespaceStepExecution extends AbstractStepExecution { 36 | 37 | private InNamespaceStep step; 38 | 39 | private String sessionId; 40 | private String namespace; 41 | private transient KubernetesClient client; 42 | private transient NamespaceService namespaceService; 43 | private transient Configuration configuration; 44 | 45 | private boolean isOpenshift; 46 | 47 | 48 | InNamespaceStepExecution(InNamespaceStep step, StepContext context) { 49 | super(context); 50 | this.step = step; 51 | } 52 | 53 | @Override 54 | public boolean start() throws Exception { 55 | TaskListener listener = getContext().get(TaskListener.class); 56 | NamespaceAction namespaceAction = new NamespaceAction(getContext().get(Run.class)); 57 | 58 | sessionId = generateSessionId(); 59 | namespace = generateNamespaceId(step.getName(), step.getPrefix(), sessionId); 60 | 61 | client = getKubernetesClient(); 62 | isOpenshift = client.isAdaptable(OpenShiftClient.class); 63 | 64 | configuration = new DefaultConfigurationBuilder() 65 | .withNamespace(namespace) 66 | .withNamespaceLazyCreateEnabled(step.isNamespaceLazyCreateEnabled()) 67 | .withNamespaceDestroyEnabled(step.isNamespaceDestroyEnabled()) 68 | .withMasterUrl(client.getMasterUrl()) 69 | .build(); 70 | 71 | StreamLogger logger = new StreamLogger(listener.getLogger()); 72 | LabelProvider labelProvider = new MapLabelProvider(step.getLabels()); 73 | 74 | namespaceService = isOpenshift 75 | ? new OpenshiftNamespaceService.ImmutableOpenshiftNamespaceService(client, configuration, labelProvider, logger) 76 | : new DefaultNamespaceService.ImmutableNamespaceService(client, configuration, labelProvider, logger); 77 | 78 | 79 | if (!namespaceService.exists(namespace) && configuration.isNamespaceLazyCreateEnabled()) { 80 | namespaceService.create(namespace); 81 | } 82 | namespaceAction.push(namespace); 83 | 84 | getContext().newBodyInvoker(). 85 | withContext(EnvironmentExpander.merge(getContext().get(EnvironmentExpander.class), new NamespaceExpander(namespace))). 86 | withCallback(new NamespaceDestructionCallback(namespace, configuration, namespaceService, namespaceAction)). 87 | start(); 88 | 89 | return false; 90 | } 91 | 92 | @Override 93 | public void stop(Throwable cause) throws Exception { 94 | if (configuration.isNamespaceDestroyEnabled()) { 95 | namespaceService.destroy(namespace); 96 | } 97 | String ns = new NamespaceAction(getContext().get(Run.class)).pop(); 98 | } 99 | 100 | 101 | @Override 102 | InNamespaceStep getStep() { 103 | return step; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InSessionStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 20 | import org.jenkinsci.plugins.workflow.steps.StepContext; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | 24 | import java.io.Serializable; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | import hudson.Extension; 29 | 30 | public class InSessionStep extends AbstractSessionManagerStep implements Serializable { 31 | 32 | private static final long serialVersionUID = 5588861066775717487L; 33 | 34 | @DataBoundConstructor 35 | public InSessionStep(String cloud, String name, String prefix, Map labels, Map annotations, Map scriptEnvironmentVariables, String environmentSetupScriptUrl, String environmentTeardownScriptUrl, String environmentConfigUrl, List environmentDependencies, Long waitTimeout, List waitForServiceList, Boolean namespaceLazyCreateEnabled, Boolean namespaceCleanupEnabled, Boolean namespaceDestroyEnabled) { 36 | super(cloud, name, prefix, labels, annotations, scriptEnvironmentVariables, environmentSetupScriptUrl, environmentTeardownScriptUrl, environmentConfigUrl, environmentDependencies, waitTimeout, waitForServiceList, namespaceLazyCreateEnabled, namespaceCleanupEnabled, namespaceDestroyEnabled); 37 | } 38 | 39 | @Override 40 | public StepExecution start(StepContext context) throws Exception { 41 | return new InSessionStepExecution(this, context); 42 | } 43 | 44 | 45 | @Extension 46 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 47 | 48 | public DescriptorImpl() { 49 | super(InSessionStepExecution.class); 50 | } 51 | 52 | public DescriptorImpl(Class executionType) { 53 | super(executionType); 54 | } 55 | 56 | @Override 57 | public String getFunctionName() { 58 | return "inSession"; 59 | } 60 | 61 | @Override 62 | public String getDisplayName() { 63 | return "Run build steps inside an Arquillian Cube Kubernetes Session"; 64 | } 65 | 66 | @Override 67 | public boolean takesImplicitBlockArgument() { 68 | return true; 69 | } 70 | 71 | @Override 72 | public boolean isAdvanced() { 73 | return true; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InSessionStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 18 | 19 | import org.arquillian.cube.kubernetes.impl.SessionManager; 20 | import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander; 21 | import org.jenkinsci.plugins.workflow.steps.StepContext; 22 | 23 | public class InSessionStepExecution extends AbstractSessionManagerStepExecution { 24 | 25 | private InSessionStep step; 26 | 27 | InSessionStepExecution(InSessionStep step, StepContext context) { 28 | super(context); 29 | this.step = step; 30 | } 31 | 32 | @Override 33 | public boolean onStart(SessionManager sessionManager) throws Exception { 34 | sessionManager.start(); 35 | 36 | getContext().newBodyInvoker(). 37 | withContext(EnvironmentExpander.merge(getContext().get(EnvironmentExpander.class), new NamespaceExpander(session.getNamespace()))). 38 | withCallback(new SessionManagerStopCallback(sessionManager)). 39 | start(); 40 | 41 | return false; 42 | } 43 | 44 | @Override 45 | public void onStop(SessionManager sessionManager) { 46 | sessionManager.stop(); 47 | } 48 | 49 | @Override 50 | public InSessionStep getStep() { 51 | return step; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/MapAnnotationProvider.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.arquillian.cube.kubernetes.api.AnnotationProvider; 4 | import org.arquillian.cube.kubernetes.impl.annotation.DefaultAnnotationProvider; 5 | 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class MapAnnotationProvider implements AnnotationProvider { 11 | 12 | private final Map provided; 13 | private final AnnotationProvider delegate; 14 | 15 | public MapAnnotationProvider(Map provided) { 16 | this(provided, new DefaultAnnotationProvider()); 17 | } 18 | 19 | public MapAnnotationProvider(Map provided, AnnotationProvider delegate) { 20 | this.provided = provided != null ? provided : Collections.emptyMap(); 21 | this.delegate = delegate; 22 | } 23 | 24 | @Override 25 | public Map create(String sessionId, String status) { 26 | Map map = new HashMap<>(provided); 27 | if (delegate != null) { 28 | map.putAll(delegate.create(sessionId, status)); 29 | } 30 | return map; 31 | } 32 | 33 | @Override 34 | public AnnotationProvider toImmutable() { 35 | return this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/MapLabelProvider.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.arquillian.cube.kubernetes.api.LabelProvider; 4 | import org.arquillian.cube.kubernetes.impl.label.DefaultLabelProvider; 5 | 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class MapLabelProvider implements LabelProvider { 11 | 12 | private final Map provided; 13 | private final LabelProvider delegate; 14 | 15 | public MapLabelProvider(Map provided) { 16 | this(provided, null); 17 | } 18 | 19 | public MapLabelProvider(Map provided, LabelProvider delegate) { 20 | this.provided = provided != null ? provided : Collections.emptyMap(); 21 | this.delegate = delegate; 22 | } 23 | 24 | @Override 25 | public Map getLabels() { 26 | Map map = new HashMap<>(provided); 27 | if (delegate != null) { 28 | map.putAll(delegate.getLabels()); 29 | } 30 | return map; 31 | } 32 | 33 | @Override 34 | public LabelProvider toImmutable() { 35 | return this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/NamespaceDestructionCallback.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.arquillian.cube.kubernetes.api.Configuration; 4 | import org.arquillian.cube.kubernetes.api.NamespaceService; 5 | import org.csanchez.jenkins.plugins.kubernetes.pipeline.NamespaceAction; 6 | import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback; 7 | import org.jenkinsci.plugins.workflow.steps.StepContext; 8 | 9 | public class NamespaceDestructionCallback extends BodyExecutionCallback.TailCall { 10 | 11 | private final String namespace; 12 | private final transient Configuration configuration; 13 | private final transient NamespaceService namespaceService; 14 | private final transient NamespaceAction namespaceAction; 15 | 16 | NamespaceDestructionCallback(String namespace, Configuration configuration, NamespaceService namespaceService, NamespaceAction namespaceAction) { 17 | this.namespace = namespace; 18 | this.configuration = configuration; 19 | this.namespaceService = namespaceService; 20 | this.namespaceAction = namespaceAction; 21 | } 22 | 23 | @Override 24 | protected void finished(StepContext context) throws Exception { 25 | if (configuration.isNamespaceDestroyEnabled()) { 26 | namespaceService.destroy(namespace); 27 | } 28 | String ns = namespaceAction.pop(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/NamespaceExpander.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander; 4 | 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import hudson.EnvVars; 10 | 11 | final class NamespaceExpander extends EnvironmentExpander { 12 | 13 | private static final long serialVersionUID = 1; 14 | private static final String KUBERNETES_NAMESPACE = "KUBERNETES_NAMESPACE"; 15 | 16 | private final Map overrides; 17 | 18 | NamespaceExpander(String namespace) { 19 | this.overrides = new HashMap<>(); 20 | this.overrides.put(KUBERNETES_NAMESPACE, namespace); 21 | } 22 | 23 | @Override 24 | public void expand(EnvVars env) throws IOException, InterruptedException { 25 | env.overrideAll(overrides); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/SessionManagerStopCallback.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.arquillian.cube.kubernetes.impl.SessionManager; 4 | import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback; 5 | import org.jenkinsci.plugins.workflow.steps.StepContext; 6 | 7 | public class SessionManagerStopCallback extends BodyExecutionCallback.TailCall { 8 | 9 | private final transient SessionManager sessionManager; 10 | 11 | public SessionManagerStopCallback(SessionManager sessionManager) { 12 | this.sessionManager = sessionManager; 13 | } 14 | 15 | 16 | 17 | @Override 18 | protected void finished(StepContext context) throws Exception { 19 | sessionManager.stop(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/java/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/StreamLogger.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.arquillian.cube.kubernetes; 2 | 3 | import org.arquillian.cube.kubernetes.api.Logger; 4 | 5 | import java.io.PrintStream; 6 | import java.text.DateFormat; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | public class StreamLogger implements Logger { 11 | 12 | private final String INFO = "[INFO]"; 13 | private final String ERROR = "[ERROR]"; 14 | private final String WARNING = "[WARNING]"; 15 | private final String STATUS = "[STATUS]"; 16 | 17 | private final String LOGGING_FORMAT = "%s %s: %s"; 18 | private final DateFormat DATE_FORMAT = new SimpleDateFormat("dd MM yyyy - HH:mm"); 19 | 20 | private final PrintStream stream; 21 | 22 | public StreamLogger(PrintStream stream) { 23 | this.stream = stream; 24 | } 25 | 26 | @Override 27 | public void info(String s) { 28 | stream.println(String.format(LOGGING_FORMAT, INFO, DATE_FORMAT.format(new Date()), s)); 29 | } 30 | 31 | @Override 32 | public void warn(String s) { 33 | stream.println(String.format(LOGGING_FORMAT, WARNING, DATE_FORMAT.format(new Date()), s)); 34 | } 35 | 36 | @Override 37 | public void error(String s) { 38 | stream.println(String.format(LOGGING_FORMAT, ERROR, DATE_FORMAT.format(new Date()), s)); 39 | } 40 | 41 | @Override 42 | public void status(String s) { 43 | stream.println(String.format(LOGGING_FORMAT, STATUS, DATE_FORMAT.format(new Date()), s)); 44 | } 45 | 46 | @Override 47 | public org.arquillian.cube.kubernetes.api.Logger toImmutable() { 48 | return null; 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | Creates an arquillian-cube-kubernetes session for executing tests 5 |
6 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/CreateEnvironmentSessionStep/config.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/CreateEnvironmentSessionStep/help-name.html: -------------------------------------------------------------------------------- 1 | The name of the namespace/project to use/create. -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InNamespaceStep/config.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InNamespaceStep/help-name.html: -------------------------------------------------------------------------------- 1 | The name of the namespace/project to use/create. -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InSessionStep/config.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /arquillian-steps/src/main/resources/io/fabric8/kubernetes/pipeline/arquillian/cube/kubernetes/InSessionStep/help-name.html: -------------------------------------------------------------------------------- 1 | The name of the namespace/project to use/create. -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | override: 3 | - mvn install -DskipTests -U 4 | test: 5 | post: 6 | - mkdir -p $CIRCLE_TEST_REPORTS/junit/ 7 | - find . -type f -regex ".*/target/.*-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \; -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | kubernetes-pipeline-project 21 | io.fabric8 22 | 1.7-SNAPSHOT 23 | 24 | 4.0.0 25 | 26 | io.fabric8.pipeline 27 | kubernetes-pipeline-core 28 | jar 29 | Kubernetes :: Pipeline :: Core 30 | https://wiki.jenkins-ci.org/display/JENKINS/Kubernetes+Pipeline+Plugin 31 | 32 | 33 | 34 | org.jenkins-ci.plugins 35 | script-security 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-jar-plugin 44 | 3.0.2 45 | 46 | 47 | 48 | test-jar 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /core/src/main/java/io/fabric8/workflow/core/ClassWhiteList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.workflow.core; 18 | 19 | import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.EnumeratingWhitelist; 20 | 21 | import java.lang.reflect.Constructor; 22 | import java.lang.reflect.Field; 23 | import java.lang.reflect.Method; 24 | import java.lang.reflect.Modifier; 25 | import java.util.ArrayList; 26 | import java.util.HashSet; 27 | import java.util.List; 28 | import java.util.Set; 29 | 30 | public class ClassWhiteList extends EnumeratingWhitelist { 31 | 32 | private final Class[] classes; 33 | private final List methodSignatures = new ArrayList<>(); 34 | private final List newSignatures = new ArrayList<>(); 35 | private final List staticMethodSignatures = new ArrayList<>(); 36 | private final List fieldSignatures = new ArrayList<>(); 37 | private final List staticFieldSignatures = new ArrayList<>(); 38 | 39 | private final Set processed = new HashSet<>(); 40 | 41 | public ClassWhiteList( List classes) { 42 | this(classes.toArray(new Class[classes.size()])); 43 | } 44 | 45 | public ClassWhiteList(Class... classes) { 46 | this.classes = classes; 47 | load(); 48 | } 49 | 50 | private void load() { 51 | try { 52 | for (Class c : classes) { 53 | processClass(c); 54 | } 55 | } catch (Throwable t) { 56 | throw new RuntimeException(t); 57 | } 58 | } 59 | 60 | private void processClass(Class clazz) { 61 | if (clazz != null && !processed.contains(clazz)) { 62 | //Constructors 63 | for (Constructor ctor : clazz.getDeclaredConstructors()) { 64 | newSignatures.add(new NewSignature(clazz, ctor.getParameterTypes())); 65 | } 66 | 67 | for (Method method : clazz.getDeclaredMethods()) { 68 | MethodSignature methodSignature = new MethodSignature(clazz, method.getName(), method.getParameterTypes()); 69 | if (Modifier.isStatic(method.getModifiers())) { 70 | staticMethodSignatures.add(methodSignature); 71 | } else { 72 | methodSignatures.add(methodSignature); 73 | } 74 | } 75 | 76 | for (Field field : clazz.getDeclaredFields()) { 77 | FieldSignature fieldSignature = new FieldSignature(field.getType(), field.getName()); 78 | if (Modifier.isStatic(field.getModifiers())) { 79 | staticFieldSignatures.add(fieldSignature); 80 | } else { 81 | fieldSignatures.add(fieldSignature); 82 | } 83 | } 84 | processed.add(clazz); 85 | processClass(clazz.getSuperclass()); 86 | for (Class iface :clazz.getInterfaces()) { 87 | processClass(iface); 88 | } 89 | } 90 | } 91 | 92 | 93 | @Override 94 | protected List methodSignatures() { 95 | return methodSignatures; 96 | } 97 | 98 | @Override 99 | protected List newSignatures() { 100 | return newSignatures; 101 | } 102 | 103 | @Override 104 | protected List staticMethodSignatures() { 105 | return staticMethodSignatures; 106 | } 107 | 108 | @Override 109 | protected List fieldSignatures() { 110 | return fieldSignatures; 111 | } 112 | 113 | @Override 114 | protected List staticFieldSignatures() { 115 | return staticFieldSignatures; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /core/src/main/java/io/fabric8/workflow/core/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.workflow.core; 18 | 19 | public class Constants { 20 | public static final String RUNNING_PHASE = "Running"; 21 | public static final String SUCCEEDED_PHASE = "Succeeded"; 22 | public static final String FAILED_PHASE = "Failed"; 23 | public static final String SPACE = " "; 24 | public static final String SEMICOLN = ";"; 25 | public static final String EMPTY = ""; 26 | public static final String EXIT = "exit"; 27 | public static final String NEWLINE = "\n"; 28 | public static final String UTF_8 = "UTF-8"; 29 | 30 | public static final String VOLUME_PREFIX = "volume-"; 31 | 32 | public static final char CTRL_C = '\u0003'; 33 | 34 | public static final String DOCKER_IGNORE = ".dockerignore"; 35 | public static final String DEFAULT_DOCKER_REGISTRY = "DEFAULT_DOCKER_REGISTRY"; 36 | public static final String FABRIC8_DOCKER_REGISTRY_SERVICE_HOST = "FABRIC8_DOCKER_REGISTRY_SERVICE_HOST"; 37 | public static final String FABRIC8_DOCKER_REGISTRY_SERVICE_PORT = "FABRIC8_DOCKER_REGISTRY_SERVICE_PORT"; 38 | public static final String OPENSHIFT_DOCKER_REGISTRY_SERVICE_HOST = "DOCKER_REGISTRY_SERVICE_HOST"; 39 | public static final String OPENSHIFT_DOCKER_REGISTRY_SERVICE_PORT = "DOCKER_REGISTRY_SERVICE_PORT"; 40 | public static final String EXTERNAL_DOCKER_REGISTRY_URL = "external-docker-registry-url"; 41 | public static final String USERS_PIPELINE_CONFIGMAP_NAME = "fabric8-pipelines"; 42 | 43 | public static final String HOSTNAME = "HOSTNAME"; 44 | public static final String KUBERNETES_HOSTNAME = "kubernetes.io/hostname"; 45 | 46 | public static final String JOB_NAME = "JOB_NAME"; 47 | 48 | public static final String[] DEFAULT_IGNORE_PATTERNS = {DOCKER_IGNORE, ".git", ".git/*"}; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /core/src/test/java/io/fabric8/kubernetes/pipeline/KubernetesTestUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2016, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package io.fabric8.kubernetes.pipeline; 25 | 26 | import org.junit.Assume; 27 | 28 | import java.io.ByteArrayOutputStream; 29 | import java.io.IOException; 30 | import java.net.MalformedURLException; 31 | import java.net.URL; 32 | import java.util.logging.Level; 33 | import java.util.logging.Logger; 34 | 35 | import hudson.EnvVars; 36 | import hudson.Launcher; 37 | import hudson.util.StreamTaskListener; 38 | 39 | import static org.hamcrest.Matchers.isEmptyOrNullString; 40 | import static org.hamcrest.Matchers.not; 41 | 42 | public class KubernetesTestUtil { 43 | 44 | private static final Logger LOGGER = Logger.getLogger(KubernetesTestUtil.class.getName()); 45 | 46 | private static final String[] MINIKUBE_COMMANDS = new String[] { "minikube", "/usr/local/bin/minikube" }; 47 | private static String ip = null; 48 | 49 | public static URL miniKubeUrl() { 50 | try { 51 | return new URL("https", miniKubeIp(), 8443, ""); 52 | } catch (MalformedURLException e) { 53 | throw new RuntimeException(e); 54 | } 55 | } 56 | 57 | public static String miniKubeIp() { 58 | if (ip == null) { 59 | for (String cmd : MINIKUBE_COMMANDS) { 60 | String s = miniKubeIp(new Launcher.LocalLauncher(StreamTaskListener.NULL), cmd); 61 | if (s != null) { 62 | ip = s.trim(); 63 | LOGGER.log(Level.INFO, "Using minikube at {0}", ip); 64 | return ip; 65 | } 66 | } 67 | LOGGER.warning("Minikube was not found or is stopped"); 68 | ip = ""; 69 | } 70 | return ip; 71 | } 72 | 73 | private static String miniKubeIp(Launcher.LocalLauncher localLauncher, String cmd) { 74 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 75 | try { 76 | localLauncher.decorateByEnv(new EnvVars("PATH", System.getenv("PATH") + ":/usr/local/bin")).launch() 77 | .cmds(cmd, "ip").stdout(baos).join(); 78 | String stdout = baos.toString().trim(); 79 | 80 | // leave last line only, ie. when a new version is available it will print some info message 81 | int i = stdout.lastIndexOf("\n"); 82 | String s; 83 | if (i > 0) { 84 | s = stdout.substring(i); 85 | } else { 86 | s = stdout; 87 | } 88 | // check that we got an ip and is valid 89 | new URL("http://" + s); 90 | return s; 91 | 92 | } catch (InterruptedException | IOException x) { 93 | return null; 94 | } 95 | } 96 | 97 | public static void assumeMiniKube() throws Exception { 98 | Assume.assumeThat("MiniKube working", miniKubeIp(), not(isEmptyOrNullString())); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /core/src/test/java/org/jvnet/hudson/test/JenkinsRuleNonLocalhost.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2016, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jvnet.hudson.test; 26 | 27 | import org.eclipse.jetty.server.HttpConfiguration; 28 | import org.eclipse.jetty.server.HttpConnectionFactory; 29 | import org.eclipse.jetty.server.Server; 30 | import org.eclipse.jetty.server.ServerConnector; 31 | import org.eclipse.jetty.webapp.Configuration; 32 | import org.eclipse.jetty.webapp.WebAppContext; 33 | import org.eclipse.jetty.webapp.WebXmlConfiguration; 34 | 35 | import java.util.concurrent.LinkedBlockingQueue; 36 | import java.util.concurrent.ThreadFactory; 37 | import java.util.concurrent.ThreadPoolExecutor; 38 | import java.util.concurrent.TimeUnit; 39 | import java.util.logging.Level; 40 | import java.util.logging.Logger; 41 | 42 | import javax.servlet.ServletContext; 43 | 44 | /** 45 | * @author Carlos Sanchez 46 | * 47 | */ 48 | public class JenkinsRuleNonLocalhost extends JenkinsRule { 49 | private static final Logger LOGGER = Logger.getLogger(JenkinsRuleNonLocalhost.class.getName()); 50 | 51 | private static final String HOST = System.getProperty("connectorHost", "0.0.0.0"); 52 | 53 | /** 54 | * Prepares a webapp hosting environment to get {@link ServletContext} implementation 55 | * that we need for testing. 56 | */ 57 | protected ServletContext createWebServer() throws Exception { 58 | server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(),new ThreadFactory() { 59 | public Thread newThread(Runnable r) { 60 | Thread t = new Thread(r); 61 | t.setName("Jetty Thread Pool"); 62 | return t; 63 | } 64 | }))); 65 | 66 | WebAppContext context = new WebAppContext(WarExploder.getExplodedDir().getPath(), contextPath); 67 | context.setClassLoader(getClass().getClassLoader()); 68 | context.setConfigurations(new Configuration[]{new WebXmlConfiguration()}); 69 | context.addBean(new NoListenerConfiguration(context)); 70 | server.setHandler(context); 71 | context.getSecurityHandler().setLoginService(configureUserRealm()); 72 | context.setResourceBase(WarExploder.getExplodedDir().getPath()); 73 | 74 | ServerConnector connector = new ServerConnector(server); 75 | HttpConfiguration config = connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration(); 76 | // use a bigger buffer as Stapler traces can get pretty large on deeply nested URL 77 | config.setRequestHeaderSize(12 * 1024); 78 | connector.setHost(HOST); 79 | if (System.getProperty("port")!=null) 80 | connector.setPort(Integer.parseInt(System.getProperty("port"))); 81 | 82 | server.addConnector(connector); 83 | server.start(); 84 | 85 | localPort = connector.getLocalPort(); 86 | LOGGER.log(Level.INFO, "Running on {0}", getURL()); 87 | 88 | return context.getServletContext(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /devops-steps/readme.md: -------------------------------------------------------------------------------- 1 | DevOps Steps 2 | ------------- 3 | 4 | ## Applying Kubernetes Configuration 5 | 6 | You can apply Kubernetes resources in order to create and update pods, services, replication controllers, lists and openshift templates. When running on openshift it will also create routes so that services are exposed. 7 | 8 | Apply changes by passing the JSON formatted resource and the required environment. If the environment does not exist then a new namespace is created with the environment name. 9 | 10 | The KubernetesApply step will enrich Pod or Replication Controller manifests, adding the platform default docker registry if no `registry` parameter set. 11 | 12 | 13 | node { 14 | def rc = getKubernetesJson { 15 | port = 8080 16 | label = 'node' 17 | icon = 'https://cdn.rawgit.com/fabric8io/fabric8/dc05040/website/src/images/logos/nodejs.svg' 18 | version = newVersion 19 | } 20 | 21 | kubernetesApply(file: rc, environment: 'my-cool-app-staging', registry: 'myexternalregistry.io:5000') 22 | } 23 | 24 | __NOTE__ By default [DeploymentEvent](https://github.com/fabric8io/kubernetes-pipeline/blob/master/src/main/java/io/fabric8/kubernetes/workflow/elasticsearch/DeploymentEvent.java) are sent to elasticsearch (if running in the same namespace) when a pod or replication controller is deployed. 25 | 26 | ### Waiting for resources to become ready 27 | 28 | When applying the kubernetes configuration, you have the option to wait until they become ready. 29 | You can set the option `readinessTimeout` that specifies the amount of milliseconds we should wait until everything is in ready state (this applies only to resources that makes sense, e.g. Pods, ReplicaSets, ReplicationControllers, Deployments, DeploymentConfigs etc). 30 | If `readinessTimeout` is set to a positive value, then `kubernetesApply` will wait until the resource are ready or the specified amount of time has elapsed. In the later case an Exception will be thrown. 31 | 32 | ## Working with Elasticsearch 33 | 34 | 35 | ### Create 36 | You can create events in elasticsearch providing it is running in the current namespace with a Kubernetes service name of `elasticsearch`. The fabric8 logging template does exactly this. 37 | 38 | 39 | node { 40 | def event = '{"user" : "rawlingsj","post_date" : "2016-01-30T13:29:36+00:00","project" : "my-cool-project"}' 41 | 42 | createEvent(json: event, index: 'myindex') 43 | } 44 | 45 | __NOTE__ The default elasticsearch index used is `pipeline` if no index property is set. For more information see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#docs-index_ 46 | 47 | 48 | ### Approve Events 49 | You can send and update approve events in elasticsearch 50 | 51 | 52 | node{ 53 | def id = approveRequestedEvent(app: 'test app', environment: 'staging') 54 | 55 | try { 56 | input id: 'Proceed', message: 'Continue?' 57 | } catch (err) { 58 | 59 | approveReceivedEvent(id: id, approved: false) 60 | throw err 61 | } 62 | approveReceivedEvent(id: id, approved: true) 63 | 64 | } 65 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/ApproveReceivedEventStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import hudson.Extension; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 21 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 22 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 23 | import org.kohsuke.stapler.DataBoundConstructor; 24 | 25 | public class ApproveReceivedEventStep extends AbstractStepImpl { 26 | 27 | private final String id; 28 | private final Boolean approved; 29 | 30 | @DataBoundConstructor 31 | public ApproveReceivedEventStep(String id, Boolean approved) { 32 | this.id = id; 33 | this.approved = approved; 34 | } 35 | 36 | public String getId() { 37 | return id; 38 | } 39 | 40 | public Boolean getApproved() { 41 | return approved; 42 | } 43 | 44 | @Extension 45 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 46 | 47 | public DescriptorImpl() { 48 | super(ApproveReceivedEventStepExecution.class); 49 | } 50 | 51 | public DescriptorImpl(Class executionType) { 52 | super(executionType); 53 | } 54 | 55 | @Override 56 | public String getFunctionName() { 57 | return "approveReceivedEvent"; 58 | } 59 | 60 | @Override 61 | public String getDisplayName() { 62 | return "Updates an Approve event in Elasticsearch"; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/ApproveReceivedEventStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import hudson.AbortException; 21 | import hudson.model.TaskListener; 22 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.ApprovalEventDTO; 23 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.ElasticsearchClient; 24 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.JsonUtils; 25 | import io.fabric8.utils.Strings; 26 | import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution; 27 | import org.jenkinsci.plugins.workflow.steps.StepContextParameter; 28 | 29 | import javax.inject.Inject; 30 | import java.util.Date; 31 | 32 | 33 | public class ApproveReceivedEventStepExecution extends AbstractSynchronousStepExecution{ 34 | 35 | @Inject 36 | private transient ApproveReceivedEventStep step; 37 | 38 | @StepContextParameter 39 | private transient TaskListener listener; 40 | 41 | private ObjectMapper mapper = JsonUtils.createObjectMapper(); 42 | 43 | private final String OK = "OK"; 44 | 45 | @Override 46 | public String run() throws Exception { 47 | 48 | if (step.getApproved() == null) { 49 | throw new AbortException("No Approved boolean set"); 50 | } 51 | 52 | if (Strings.isNullOrBlank(step.getId())) { 53 | // if we dont have an id to update ignore the request as it's likely elasticsearch isn't running 54 | listener.getLogger().println("No approve event id found. Skipping approval event update request"); 55 | return OK; 56 | } 57 | ApprovalEventDTO approval = new ApprovalEventDTO(); 58 | approval.setApproved(step.getApproved()); 59 | approval.setReceivedTime(new Date()); 60 | 61 | String json = mapper.writeValueAsString(approval); 62 | 63 | Boolean success = ElasticsearchClient.updateEvent(step.getId(), json, ElasticsearchClient.APPROVE, listener); 64 | if (!success){ 65 | throw new AbortException("Error updating Approve event id ["+step.getId()+"]"); 66 | } 67 | 68 | return OK; 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/ApproveRequestedEventStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import hudson.Extension; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 21 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 22 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 23 | import org.kohsuke.stapler.DataBoundConstructor; 24 | 25 | public class ApproveRequestedEventStep extends AbstractStepImpl { 26 | 27 | private final String app; 28 | private final String environment; 29 | 30 | @DataBoundConstructor 31 | public ApproveRequestedEventStep(String app, String environment){ 32 | this.app = app; 33 | this.environment = environment; 34 | } 35 | 36 | public String getApp() { 37 | return app; 38 | } 39 | 40 | public String getEnvironment() { 41 | return environment; 42 | } 43 | 44 | @Extension 45 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 46 | 47 | public DescriptorImpl() { 48 | super(ApproveRequestedEventStepExecution.class); 49 | } 50 | 51 | public DescriptorImpl(Class executionType) { 52 | super(executionType); 53 | } 54 | 55 | @Override 56 | public String getFunctionName() { 57 | return "approveRequestedEvent"; 58 | } 59 | 60 | @Override 61 | public String getDisplayName() { 62 | return "Creates an Approve requested event in Elasticsearch"; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/ApproveRequestedEventStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import hudson.AbortException; 21 | import hudson.model.TaskListener; 22 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.ApprovalEventDTO; 23 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.ElasticsearchClient; 24 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.JsonUtils; 25 | import io.fabric8.utils.Strings; 26 | import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution; 27 | import org.jenkinsci.plugins.workflow.steps.StepContextParameter; 28 | 29 | import javax.inject.Inject; 30 | import java.util.Date; 31 | 32 | 33 | public class ApproveRequestedEventStepExecution extends AbstractSynchronousStepExecution{ 34 | 35 | @Inject 36 | private transient ApproveRequestedEventStep step; 37 | 38 | @StepContextParameter 39 | private transient TaskListener listener; 40 | 41 | private ObjectMapper mapper = JsonUtils.createObjectMapper(); 42 | 43 | @Override 44 | public String run() throws Exception { 45 | 46 | if (Strings.isNullOrBlank(step.getApp())) { 47 | throw new AbortException("No App name provided"); 48 | } 49 | 50 | if (Strings.isNullOrBlank(step.getEnvironment())) { 51 | throw new AbortException("No environment name provided"); 52 | } 53 | ApprovalEventDTO approval = new ApprovalEventDTO(); 54 | approval.setApp(step.getApp()); 55 | approval.setEnvironment(step.getEnvironment()); 56 | approval.setRequestedTime(new Date()); 57 | 58 | String json = mapper.writeValueAsString(approval); 59 | 60 | return ElasticsearchClient.createEvent(json, ElasticsearchClient.APPROVE, listener); 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/CreateEventStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import hudson.Extension; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 21 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 22 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 23 | import org.kohsuke.stapler.DataBoundConstructor; 24 | 25 | public class CreateEventStep extends AbstractStepImpl { 26 | 27 | private final String json; 28 | 29 | private String index = "pipeline"; 30 | 31 | @DataBoundConstructor 32 | public CreateEventStep(String json, String index){ 33 | this.json = json; 34 | if (index != null) this.index = index; 35 | } 36 | 37 | public String getJson() { 38 | return json; 39 | } 40 | 41 | public String getIndex() { 42 | return index; 43 | } 44 | 45 | @Extension 46 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 47 | 48 | public DescriptorImpl() { 49 | super(CreateEventStepExecution.class); 50 | } 51 | 52 | public DescriptorImpl(Class executionType) { 53 | super(executionType); 54 | } 55 | 56 | @Override 57 | public String getFunctionName() { 58 | return "createEvent"; 59 | } 60 | 61 | @Override 62 | public String getDisplayName() { 63 | return "Creates a JSON payload event in Elasticsearch"; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/CreateEventStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import hudson.AbortException; 21 | import hudson.model.TaskListener; 22 | import io.fabric8.kubernetes.pipeline.devops.elasticsearch.ElasticsearchClient; 23 | import io.fabric8.utils.Strings; 24 | import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution; 25 | import org.jenkinsci.plugins.workflow.steps.StepContextParameter; 26 | 27 | import javax.inject.Inject; 28 | 29 | 30 | public class CreateEventStepExecution extends AbstractSynchronousStepExecution{ 31 | 32 | @Inject 33 | private transient CreateEventStep step; 34 | 35 | @StepContextParameter 36 | private transient TaskListener listener; 37 | 38 | @Override 39 | public String run() throws Exception { 40 | 41 | String json = step.getJson(); 42 | String index = step.getIndex(); 43 | 44 | if (Strings.isNullOrBlank(json)) { 45 | throw new AbortException("No JSON payload found"); 46 | } 47 | // validate JSON structure 48 | ObjectMapper objectMapper = new ObjectMapper(); 49 | objectMapper.readTree(json); 50 | 51 | String id = ElasticsearchClient.createEvent(json, index, listener); 52 | if (Strings.isNullOrBlank(id)){ 53 | throw new AbortException("Error creating event in elasticsearch"); 54 | } 55 | 56 | return id; 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/EnvironmentRollout.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | *

9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | *

11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | 21 | import java.util.Map; 22 | 23 | /** 24 | * The YAML structure to store the service URLs and deployment versions for an environment 25 | */ 26 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 27 | public class EnvironmentRollout { 28 | private final String environmentName; 29 | private final Map serviceUrls; 30 | private final Map deploymentVersions; 31 | 32 | public EnvironmentRollout(String environmentName, Map serviceUrls, Map deploymentVersions) { 33 | this.environmentName = environmentName; 34 | this.serviceUrls = serviceUrls; 35 | this.deploymentVersions = deploymentVersions; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "EnvironmentRollout{" + 41 | "environmentName='" + environmentName + '\'' + 42 | ", serviceUrls=" + serviceUrls + 43 | ", deploymentVersions=" + deploymentVersions + 44 | '}'; 45 | } 46 | 47 | public String getEnvironmentName() { 48 | return environmentName; 49 | } 50 | 51 | public Map getServiceUrls() { 52 | return serviceUrls; 53 | } 54 | 55 | public Map getDeploymentVersions() { 56 | return deploymentVersions; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/KubernetesClientRef.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.devops; 2 | 3 | import io.fabric8.kubernetes.client.DefaultKubernetesClient; 4 | import io.fabric8.kubernetes.client.KubernetesClient; 5 | 6 | public class KubernetesClientRef { 7 | 8 | private static KubernetesClient kubernetesClient; 9 | 10 | public static synchronized KubernetesClient get() { 11 | if (kubernetesClient == null) { 12 | kubernetesClient = create(); 13 | } 14 | return kubernetesClient; 15 | } 16 | 17 | public static synchronized void close() { 18 | if (kubernetesClient == null) { 19 | return; 20 | } 21 | kubernetesClient.close(); 22 | kubernetesClient = null; 23 | } 24 | 25 | 26 | public static synchronized KubernetesClient create() { 27 | return new DefaultKubernetesClient(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/ServiceResourceUtil.java: -------------------------------------------------------------------------------- 1 | package io.fabric8.kubernetes.pipeline.devops; 2 | 3 | import io.fabric8.kubernetes.api.model.HasMetadata; 4 | import io.fabric8.kubernetes.api.model.Service; 5 | import io.fabric8.openshift.api.model.Route; 6 | 7 | import java.io.Serializable; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.function.Function; 11 | import java.util.function.Predicate; 12 | import java.util.regex.Pattern; 13 | import java.util.stream.Collectors; 14 | 15 | public class ServiceResourceUtil implements Serializable { 16 | 17 | private static final String SERVICE_NAME_REGEX = "[a-z]([-a-z0-9]*[a-z0-9])?"; 18 | public static final int SERVICE_NAME_MAX_LENGTH = 58; 19 | public static final String SERVICE_NAME_PREFIX = "svc-"; 20 | public static final String K8S_PIPELINE_SERVICE_PATCH = "K8S_PIPELINE_SERVICE_PATCH"; 21 | 22 | private final Function resourceKeyMapper = (r) -> r.getMetadata().getName(); 23 | 24 | public void patchServiceName(Set entities) { 25 | if(isPatchingDisabled()) { 26 | return; 27 | } 28 | 29 | Map services = patchServiceIfInvalidName(entities); 30 | Map routes = patchRouteWithService(entities, services); 31 | 32 | replace(services, entities); 33 | replace(routes, entities); 34 | } 35 | 36 | private boolean isPatchingDisabled() { 37 | return System.getenv(K8S_PIPELINE_SERVICE_PATCH) == null || 38 | System.getenv(K8S_PIPELINE_SERVICE_PATCH).isEmpty() || 39 | !System.getenv("K8S_PIPELINE_SERVICE_PATCH").equalsIgnoreCase("enabled"); 40 | } 41 | 42 | private Map patchServiceIfInvalidName(Set resources) { 43 | 44 | Predicate invalidService = (r) -> r instanceof Service && hasInvalidDNS((Service) r); 45 | Function patchedService = (r) -> sanitizeServiceName((Service) r); 46 | 47 | Map patchedServices = resources.stream() 48 | .filter(invalidService) 49 | .collect(Collectors.toMap(resourceKeyMapper, patchedService)); 50 | 51 | return patchedServices; 52 | } 53 | 54 | private Map patchRouteWithService(Set resources, Map services) { 55 | 56 | Predicate routeToUpdate = (r) -> r instanceof Route && services.get(serviceNameFromRoute((Route) r)) != null; 57 | Function patchedRoute = (r) -> updateRoute((Route) r, services.get(serviceNameFromRoute((Route) r))); 58 | 59 | Map patchedRoutes = resources.stream() 60 | .filter(routeToUpdate) 61 | .collect(Collectors.toMap(resourceKeyMapper, patchedRoute)); 62 | 63 | return patchedRoutes; 64 | } 65 | 66 | public boolean hasInvalidDNS(Service service) { 67 | if (service.getMetadata() != null && service.getMetadata().getName() != null) 68 | return !(Pattern.matches(SERVICE_NAME_REGEX, service.getMetadata().getName())); 69 | else 70 | return false; 71 | } 72 | 73 | private Service sanitizeServiceName(Service service) { 74 | String serviceName = service.getMetadata().getName(); 75 | service.getMetadata().setName(SERVICE_NAME_PREFIX + truncate(serviceName).toLowerCase()); 76 | return service; 77 | } 78 | 79 | private String serviceNameFromRoute(Route route) { 80 | if(route.getSpec() != null && route.getSpec().getTo() != null && route.getSpec().getTo().getKind().equals("Service")) { 81 | return route.getSpec().getTo().getName(); 82 | } else { 83 | return null; 84 | } 85 | } 86 | 87 | private Route updateRoute(Route route, Service service) { 88 | route.getSpec().getTo().setName(service.getMetadata().getName()); 89 | return route; 90 | } 91 | 92 | private String truncate(String name) { 93 | if (name.length() > SERVICE_NAME_MAX_LENGTH) { 94 | return name.substring(0, SERVICE_NAME_MAX_LENGTH); 95 | } else { 96 | return name; 97 | } 98 | } 99 | 100 | private void replace(Map patchedResources, Set originalResources) { 101 | 102 | originalResources = originalResources.stream() 103 | .filter(r -> patchedResources.get(r.getMetadata().getName()) == null) 104 | .collect(Collectors.toSet()); 105 | 106 | originalResources.addAll(patchedResources 107 | .entrySet().stream() 108 | .map(Map.Entry::getValue) 109 | .collect(Collectors.toSet())); 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/ApprovalEventDTO.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import java.util.Date; 20 | 21 | /** 22 | * Pipeline approval. 23 | */ 24 | public class ApprovalEventDTO extends DTOSupport { 25 | private Date timestamp = new Date(); 26 | private String app; 27 | private String environment; 28 | private Boolean approved; 29 | private Date requestedTime; 30 | private Date receivedTime; 31 | 32 | public ApprovalEventDTO() { 33 | } 34 | 35 | public ApprovalEventDTO(Date timestamp, String app, String environment, Boolean approved, Date requestedTime, Date receivedTime) { 36 | this.timestamp = timestamp; 37 | this.app = app; 38 | this.environment = environment; 39 | this.approved = approved; 40 | this.requestedTime = requestedTime; 41 | this.receivedTime = receivedTime; 42 | } 43 | 44 | public Date getTimestamp() { 45 | return timestamp; 46 | } 47 | 48 | public void setTimestamp(Date timestamp) { 49 | this.timestamp = timestamp; 50 | } 51 | 52 | public String getApp() { 53 | return app; 54 | } 55 | 56 | public void setApp(String app) { 57 | this.app = app; 58 | } 59 | 60 | public String getEnvironment() { 61 | return environment; 62 | } 63 | 64 | public void setEnvironment(String environment) { 65 | this.environment = environment; 66 | } 67 | 68 | public Boolean getApproved() { 69 | return approved; 70 | } 71 | 72 | public void setApproved(Boolean approved) { 73 | this.approved = approved; 74 | } 75 | 76 | public Date getRequestedTime() { 77 | return requestedTime; 78 | } 79 | 80 | public void setRequestedTime(Date requestedTime) { 81 | this.requestedTime = requestedTime; 82 | } 83 | 84 | public Date getReceivedTime() { 85 | return receivedTime; 86 | } 87 | 88 | public void setReceivedTime(Date receivedTime) { 89 | this.receivedTime = receivedTime; 90 | } 91 | 92 | 93 | @java.lang.Override 94 | public java.lang.String toString() { 95 | return "ApprovalEventDTO{" + 96 | "timestamp=" + timestamp + 97 | ", app='" + app + '\'' + 98 | ", environment='" + environment + '\'' + 99 | ", approved=" + approved + 100 | ", requestedTime=" + requestedTime + 101 | ", receivedTime=" + receivedTime + 102 | '}'; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/BuildDTO.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Date; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | /** 25 | * Jenkins build. 26 | */ 27 | public class BuildDTO extends DTOSupport { 28 | private Date timestamp; 29 | private int buildNumber; 30 | private String app; 31 | private String buildResult; 32 | private Date startTime; 33 | private long duration; 34 | private Map envVars; 35 | private String buildUrl; 36 | private List causes = new ArrayList<>(); 37 | 38 | public BuildDTO() { 39 | } 40 | 41 | public BuildDTO(Date timestamp, int buildNumber, String app, String buildResult, Date startTime, long duration, Map envVars) { 42 | this.timestamp = timestamp; 43 | this.buildNumber = buildNumber; 44 | this.app = app; 45 | this.buildResult = buildResult; 46 | this.startTime = startTime; 47 | this.duration = duration; 48 | this.envVars = envVars; 49 | } 50 | 51 | public void addCause(CauseDTO cause) { 52 | if (causes == null) { 53 | causes = new ArrayList<>(); 54 | } 55 | causes.add(cause); 56 | } 57 | 58 | public String getApp() { 59 | return app; 60 | } 61 | 62 | public void setApp(String app) { 63 | this.app = app; 64 | } 65 | 66 | public int getBuildNumber() { 67 | return buildNumber; 68 | } 69 | 70 | public void setBuildNumber(int buildNumber) { 71 | this.buildNumber = buildNumber; 72 | } 73 | 74 | public String getBuildResult() { 75 | return buildResult; 76 | } 77 | 78 | public void setBuildResult(String buildResult) { 79 | this.buildResult = buildResult; 80 | } 81 | 82 | public Date getStartTime() { 83 | return startTime; 84 | } 85 | 86 | public void setStartTime(Date startTime) { 87 | this.startTime = startTime; 88 | } 89 | 90 | public long getDuration() { 91 | return duration; 92 | } 93 | 94 | public void setDuration(long duration) { 95 | this.duration = duration; 96 | } 97 | 98 | public Map getEnvVars() { 99 | return envVars; 100 | } 101 | 102 | public void setEnvVars(Map environment) { 103 | this.envVars = environment; 104 | } 105 | 106 | public Date getTimestamp() { 107 | return timestamp; 108 | } 109 | 110 | public void setTimestamp(Date timestamp) { 111 | this.timestamp = timestamp; 112 | } 113 | 114 | @Override 115 | public String toString() { 116 | return "Build{" + 117 | "@timestamp" + timestamp + 118 | ", number=" + buildNumber + 119 | ", jobName='" + app + '\'' + 120 | ", result='" + buildResult + '\'' + 121 | ", startTime=" + startTime + 122 | ", duration=" + duration + 123 | ", envVars=" + envVars + 124 | '}'; 125 | } 126 | 127 | public void setBuildUrl(String buildUrl) { 128 | this.buildUrl = buildUrl; 129 | } 130 | 131 | public String getBuildUrl() { 132 | return buildUrl; 133 | } 134 | 135 | public List getCauses() { 136 | return causes; 137 | } 138 | 139 | public void setCauses(List causes) { 140 | this.causes = causes; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/BuildListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import hudson.EnvVars; 21 | import hudson.Extension; 22 | import hudson.model.Cause; 23 | import hudson.model.Job; 24 | import hudson.model.Result; 25 | import hudson.model.Run; 26 | import hudson.model.TaskListener; 27 | import hudson.model.listeners.RunListener; 28 | 29 | import java.io.IOException; 30 | import java.util.ArrayList; 31 | import java.util.Calendar; 32 | import java.util.Date; 33 | import java.util.HashMap; 34 | import java.util.List; 35 | import java.util.Map; 36 | import java.util.logging.Level; 37 | import java.util.logging.Logger; 38 | 39 | /** 40 | * Send Jenkins build information to Elasticsearch. 41 | */ 42 | @Extension 43 | public class BuildListener extends RunListener { 44 | private static final Logger LOG = Logger.getLogger(BuildListener.class.getName()); 45 | private ObjectMapper mapper = JsonUtils.createObjectMapper(); 46 | 47 | public BuildListener() { 48 | } 49 | 50 | @Override 51 | public synchronized void onCompleted(Run run, TaskListener listener) { 52 | final BuildDTO build = createBuild(run, listener); 53 | try { 54 | String json = mapper.writeValueAsString(build); 55 | ElasticsearchClient.createEvent(json, "build", listener); 56 | } catch (Exception e) { 57 | LOG.log(Level.SEVERE, "Error when sending build data: " + build, e); 58 | } 59 | } 60 | 61 | private BuildDTO createBuild(Run run, TaskListener listener) { 62 | final Job job = run.getParent(); 63 | 64 | EnvVars environment = null; 65 | try { 66 | environment = run.getEnvironment(listener); 67 | } catch (IOException e) { 68 | LOG.log(Level.WARNING, "Error getting environment", e); 69 | } catch (InterruptedException e) { 70 | LOG.log(Level.WARNING, "Error getting environment", e); 71 | } 72 | 73 | // ES doesnt like '.' in env var key names so replace any with '_' 74 | Map changeMap = new HashMap<>(); 75 | List oldKeys = new ArrayList<>(); 76 | 77 | for (String key :environment.keySet()) { 78 | if (key.contains(".")){ 79 | oldKeys.add(key); 80 | String value = environment.get(key, ""); 81 | changeMap.put(key.replace(".", "_"), value); 82 | } 83 | } 84 | for (String key:oldKeys){ 85 | environment.remove(key); 86 | } 87 | for (Map.Entryentry:changeMap.entrySet()){ 88 | environment.put(entry.getKey(),entry.getValue()); 89 | } 90 | 91 | 92 | final BuildDTO build = new BuildDTO(); 93 | 94 | long duration = System.currentTimeMillis() - run.getStartTimeInMillis(); 95 | build.setDuration(duration); 96 | 97 | build.setApp(job.getFullName()); 98 | Result result = run.getResult(); 99 | if (result != null) { 100 | build.setBuildResult(result.toString()); 101 | } 102 | build.setStartTime(new Date(run.getStartTimeInMillis())); 103 | build.setBuildNumber(run.getNumber()); 104 | build.setEnvVars(environment); 105 | Calendar timestamp = run.getTimestamp(); 106 | if (timestamp != null) { 107 | build.setTimestamp(timestamp.getTime()); 108 | } 109 | build.setBuildUrl(run.getUrl()); 110 | List causes = run.getCauses(); 111 | for (Cause cause : causes) { 112 | CauseDTO causeDTO = new CauseDTO(cause); 113 | if (causeDTO != null) { 114 | build.addCause(causeDTO); 115 | } 116 | } 117 | return build; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/CauseDTO.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 17 | 18 | import hudson.model.Cause; 19 | 20 | /** 21 | */ 22 | public class CauseDTO extends DTOSupport { 23 | private String shortDescription; 24 | private String remoteAddr; 25 | private String remoteNote; 26 | private String userName; 27 | private String userId; 28 | private String upstreamProject; 29 | private String upstreamUrl; 30 | 31 | public CauseDTO() { 32 | } 33 | 34 | public CauseDTO(Cause cause) { 35 | this.shortDescription = cause.getShortDescription(); 36 | if (cause instanceof Cause.UserIdCause) { 37 | Cause.UserIdCause userIdCause = (Cause.UserIdCause) cause; 38 | this.userId = userIdCause.getUserId(); 39 | this.userName = userIdCause.getUserName(); 40 | } else if (cause instanceof Cause.RemoteCause) { 41 | Cause.RemoteCause remoteCause = (Cause.RemoteCause) cause; 42 | this.remoteAddr = remoteCause.getAddr(); 43 | this.remoteNote = remoteCause.getNote(); 44 | } else if (cause instanceof Cause.UpstreamCause) { 45 | Cause.UpstreamCause upstreamCause = (Cause.UpstreamCause) cause; 46 | this.upstreamProject = upstreamCause.getUpstreamProject(); 47 | this.upstreamUrl = upstreamCause.getUpstreamUrl(); 48 | 49 | } 50 | } 51 | 52 | public String getRemoteAddr() { 53 | return remoteAddr; 54 | } 55 | 56 | public void setRemoteAddr(String remoteAddr) { 57 | this.remoteAddr = remoteAddr; 58 | } 59 | 60 | public String getRemoteNote() { 61 | return remoteNote; 62 | } 63 | 64 | public void setRemoteNote(String remoteNote) { 65 | this.remoteNote = remoteNote; 66 | } 67 | 68 | public String getShortDescription() { 69 | return shortDescription; 70 | } 71 | 72 | public void setShortDescription(String shortDescription) { 73 | this.shortDescription = shortDescription; 74 | } 75 | 76 | public String getUpstreamProject() { 77 | return upstreamProject; 78 | } 79 | 80 | public void setUpstreamProject(String upstreamProject) { 81 | this.upstreamProject = upstreamProject; 82 | } 83 | 84 | public String getUpstreamUrl() { 85 | return upstreamUrl; 86 | } 87 | 88 | public void setUpstreamUrl(String upstreamUrl) { 89 | this.upstreamUrl = upstreamUrl; 90 | } 91 | 92 | public String getUserId() { 93 | return userId; 94 | } 95 | 96 | public void setUserId(String userId) { 97 | this.userId = userId; 98 | } 99 | 100 | public String getUserName() { 101 | return userName; 102 | } 103 | 104 | public void setUserName(String userName) { 105 | this.userName = userName; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/DTOSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 17 | 18 | import com.fasterxml.jackson.annotation.JsonInclude; 19 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 20 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 21 | 22 | /** 23 | */ 24 | @JsonNaming(value = PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 25 | @JsonInclude(JsonInclude.Include.NON_NULL) 26 | public abstract class DTOSupport { 27 | 28 | } 29 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/DeploymentEventDTO.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import java.io.Serializable; 20 | import java.util.Date; 21 | 22 | public class DeploymentEventDTO extends DTOSupport implements Serializable { 23 | private String author; 24 | private String app; 25 | private String commit; 26 | private String namespace; 27 | private String environment; 28 | private String resource; 29 | private String version; 30 | private Date timestamp = new Date(); 31 | 32 | public String getAuthor() { 33 | return author; 34 | } 35 | 36 | public void setAuthor(String author) { 37 | this.author = author; 38 | } 39 | 40 | public String getApp() { 41 | return app; 42 | } 43 | 44 | public void setApp(String app) { 45 | this.app = app; 46 | } 47 | 48 | public String getCommit() { 49 | return commit; 50 | } 51 | 52 | public void setCommit(String commit) { 53 | this.commit = commit; 54 | } 55 | 56 | public String getEnvironment() { 57 | return environment; 58 | } 59 | 60 | public void setEnvironment(String environment) { 61 | this.environment = environment; 62 | } 63 | 64 | public String getResource() { 65 | return resource; 66 | } 67 | 68 | public void setResource(String resource) { 69 | this.resource = resource; 70 | } 71 | 72 | public String getVersion() { 73 | return version; 74 | } 75 | 76 | public void setVersion(String version) { 77 | this.version = version; 78 | } 79 | 80 | public Date getTimestamp() { 81 | return timestamp; 82 | } 83 | 84 | public void setTimestamp(Date timestamp) { 85 | this.timestamp = timestamp; 86 | } 87 | 88 | public String getNamespace() { 89 | return namespace; 90 | } 91 | 92 | public void setNamespace(String namespace) { 93 | this.namespace = namespace; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/JsonUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 17 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; 19 | import com.fasterxml.jackson.databind.SerializationFeature; 20 | 21 | /** 22 | */ 23 | public class JsonUtils { 24 | public static ObjectMapper createObjectMapper() { 25 | ObjectMapper mapper = new ObjectMapper(); 26 | mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 27 | return mapper; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/git/GitConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.git; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | 21 | import java.io.Serializable; 22 | 23 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 24 | public class GitConfig implements Serializable { 25 | 26 | private String branch; 27 | private String commit; 28 | private String author; 29 | 30 | public GitConfig() { 31 | } 32 | 33 | public String getBranch() { 34 | return branch; 35 | } 36 | 37 | public void setBranch(String branch) { 38 | this.branch = branch; 39 | } 40 | 41 | public String getCommit() { 42 | return commit; 43 | } 44 | 45 | public void setCommit(String commit) { 46 | this.commit = commit; 47 | } 48 | 49 | public String getAuthor() { return author; } 50 | 51 | public void setAuthor(String author) { this.author = author; } 52 | } 53 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/git/GitInfoCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.git; 18 | 19 | import hudson.model.TaskListener; 20 | import hudson.remoting.VirtualChannel; 21 | import org.eclipse.jgit.api.Git; 22 | import org.eclipse.jgit.api.errors.GitAPIException; 23 | import org.eclipse.jgit.lib.Repository; 24 | import org.eclipse.jgit.revwalk.RevCommit; 25 | 26 | import java.io.IOException; 27 | 28 | /** 29 | * Callback method that retrieves Git information from the current workspace git repository 30 | */ 31 | public class GitInfoCallback extends RepositoryListenerCallback { 32 | 33 | /** 34 | * Constructor for GitInfoCallback 35 | * @param listener The TaskListener 36 | */ 37 | public GitInfoCallback(TaskListener listener) { 38 | super(listener); 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | @Override 45 | public GitConfig invoke(Repository repository, VirtualChannel channel) throws IOException, InterruptedException { 46 | 47 | Git git = new Git(repository); 48 | Iterable log; 49 | try { 50 | log = git.log().call(); 51 | } catch (GitAPIException e) { 52 | listener.error("Unable to get git log: " + e); 53 | GitConfig config = new GitConfig(); 54 | config.setAuthor("UNKNOWN"); 55 | config.setCommit("UNKNOWN"); 56 | config.setBranch("UNKNOWN"); 57 | return config; 58 | } 59 | 60 | RevCommit commit = log.iterator().next(); 61 | 62 | GitConfig config = new GitConfig(); 63 | config.setAuthor(commit.getCommitterIdent().getName()); 64 | config.setCommit(commit.getId().getName()); 65 | config.setBranch(repository.getBranch()); 66 | 67 | return config; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /devops-steps/src/main/java/io/fabric8/kubernetes/pipeline/devops/git/RepositoryListenerCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.git; 18 | 19 | import hudson.model.TaskListener; 20 | import hudson.remoting.VirtualChannel; 21 | import org.eclipse.jgit.lib.Repository; 22 | import org.jenkinsci.plugins.gitclient.RepositoryCallback; 23 | 24 | import java.io.IOException; 25 | 26 | /** 27 | * RepositoryCallback that keeps track of the TaskListener 28 | * @param Return type of the Callback 29 | */ 30 | public abstract class RepositoryListenerCallback implements RepositoryCallback { 31 | 32 | /** 33 | * The TaskListener for use in invoke 34 | */ 35 | public final TaskListener listener; 36 | 37 | /** 38 | * Constructor for a RepositoryListenerAwareCallback 39 | * @param listener The TaskListener 40 | */ 41 | public RepositoryListenerCallback(TaskListener listener) { 42 | this.listener = listener; 43 | } 44 | 45 | /** 46 | * {@inheritDoc } 47 | */ 48 | @Override 49 | public abstract T invoke(Repository repo, VirtualChannel channel) throws IOException, InterruptedException; 50 | } -------------------------------------------------------------------------------- /devops-steps/src/main/resources/io/fabric8/kubernetes/pipeline/devops/environmentAnnotations.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015 Original Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # maps environment variables to annotations 18 | 19 | BUILD_ID = fabric8.io/build-id 20 | BUILD_URL = fabric8.io/build-url 21 | 22 | GIT_COMMIT = fabric8.io/git-commit 23 | GIT_URL = fabric8.io/git-url 24 | GIT_BRANCH = fabric8.io/git-branch 25 | -------------------------------------------------------------------------------- /devops-steps/src/test/java/io/fabric8/kubernetes/pipeline/devops/ApplyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops; 18 | 19 | import io.fabric8.kubernetes.api.KubernetesHelper; 20 | import io.fabric8.kubernetes.api.model.HasMetadata; 21 | import io.fabric8.kubernetes.api.model.ReplicationController; 22 | import io.fabric8.kubernetes.internal.HasMetadataComparator; 23 | import org.apache.commons.io.FileUtils; 24 | import org.junit.Test; 25 | 26 | import java.io.File; 27 | import java.util.Set; 28 | import java.util.TreeSet; 29 | 30 | import static org.junit.Assert.assertEquals; 31 | import static org.junit.Assert.assertFalse; 32 | import static org.junit.Assert.assertTrue; 33 | 34 | public class ApplyTest { 35 | 36 | @Test 37 | public void testAddRegistryToImageNameIfNotPresent() throws Exception { 38 | 39 | String json = FileUtils.readFileToString( 40 | new File(this.getClass().getResource("/kubernetesJsonWithoutRegistry.json").toURI())); 41 | 42 | String registry = "MY-REGISTRY:5000"; 43 | String expectedImageName = registry+"/TEST_NS/my-test-image:TEST-1.0"; 44 | testAddRegistryToImageName(json, registry, expectedImageName); 45 | } 46 | 47 | @Test 48 | public void testRegistryNotAddedIfAlreadyPresent() throws Exception { 49 | String json = FileUtils.readFileToString( 50 | new File(this.getClass().getResource("/kubernetesJsonWithRegistry.json").toURI())); 51 | 52 | String registry = "MY-REGISTRY:5000"; 53 | String expectedImageName = "myexternalregistry.io:5000/TEST_NS/my-test-image:TEST-1.0"; 54 | testAddRegistryToImageName(json, registry, expectedImageName); 55 | 56 | } 57 | 58 | @Test 59 | public void testImageNameWithRegistry(){ 60 | String imageName = "myexternalregistry.io:5000/TEST_NS/my-test-image:TEST-1.0"; 61 | assertTrue(ApplyStepExecution.hasRegistry(imageName)); 62 | } 63 | 64 | @Test 65 | public void testImageNameWithoutRegistry(){ 66 | String imageName = "TEST_NS/my-test-image:TEST-1.0"; 67 | assertFalse(ApplyStepExecution.hasRegistry(imageName)); 68 | } 69 | 70 | @Test 71 | public void testImageNameWithRegistryWithoutTag(){ 72 | String imageName = "myexternalregistry.io:5000/TEST_NS/my-test-image"; 73 | assertTrue(ApplyStepExecution.hasRegistry(imageName)); 74 | } 75 | 76 | @Test 77 | public void testImageNameWithoutRegistryWithoutTag(){ 78 | String imageName = "TEST_NS/my-test-image"; 79 | assertFalse(ApplyStepExecution.hasRegistry(imageName)); 80 | } 81 | 82 | 83 | private void testAddRegistryToImageName(String json, String registry, String expectedImageName) throws Exception { 84 | Set entities = new TreeSet<>(new HasMetadataComparator()); 85 | Object dto = KubernetesHelper.loadJson(json); 86 | 87 | entities.addAll(KubernetesHelper.toItemList(dto)); 88 | 89 | ApplyStepExecution execution = new ApplyStepExecution(); 90 | execution.addRegistryToImageNameIfNotPresent(entities, registry); 91 | 92 | boolean matched = false; 93 | for (HasMetadata entity : entities) { 94 | if (entity instanceof ReplicationController){ 95 | assertEquals(expectedImageName, ((ReplicationController) entity).getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); 96 | matched = true; 97 | } 98 | } 99 | assertTrue(matched); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /devops-steps/src/test/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/BaseSendEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | 20 | import com.fasterxml.jackson.databind.ObjectMapper; 21 | import hudson.model.StreamBuildListener; 22 | 23 | import java.nio.charset.Charset; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | 27 | public class BaseSendEvent { 28 | private static final Logger LOG = Logger.getLogger(BuildListener.class.getName()); 29 | 30 | /** 31 | * Java main to test creating events in elasticsearch. Set the following ENV VARS to point to a local ES running in OpenShift 32 | * 33 | * PIPELINE_ELASTICSEARCH_HOST=elasticsearch.vagrant.f8 34 | * ELASTICSEARCH_SERVICE_PORT=80 35 | * 36 | * @param event to send to elasticsearch 37 | */ 38 | public static void send (DTOSupport event, String type){ 39 | 40 | hudson.model.BuildListener listener = new StreamBuildListener(System.out, Charset.defaultCharset()); 41 | try { 42 | ObjectMapper mapper = JsonUtils.createObjectMapper(); 43 | String json = mapper.writeValueAsString(event); 44 | String id = ElasticsearchClient.createEvent(json, type , listener); 45 | listener.getLogger().println("Added events id: " + id); 46 | } catch (Exception e) { 47 | LOG.log(Level.SEVERE, "Error when sending build data: " + event, e); 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /devops-steps/src/test/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/BuildEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import java.util.*; 20 | 21 | public class BuildEvent extends BaseSendEvent{ 22 | 23 | /** 24 | * Java main to test creating events in elasticsearch. Set the following ENV VARS to point to a local ES running in OpenShift 25 | * 26 | * PIPELINE_ELASTICSEARCH_HOST=elasticsearch.vagrant.f8 27 | * ELASTICSEARCH_SERVICE_PORT=80 28 | */ 29 | public static void main(String[] args) { 30 | final BuildDTO buildEvent = createTestBuildEvent(); 31 | send(buildEvent, "build"); 32 | } 33 | 34 | private static BuildDTO createTestBuildEvent(){ 35 | BuildDTO event = new BuildDTO(); 36 | Map environment = new HashMap<>(); 37 | environment.put("BUILD_DISPLAY_NAME","#1"); 38 | environment.put("BUILD_ID","1"); 39 | environment.put("BUILD_NUMBER","1"); 40 | environment.put("BUILD_TAG","jenkins-jr-int3-1"); 41 | environment.put("CLASSPATH",""); 42 | environment.put("HUDSON_HOME","/var/jenkins_home"); 43 | environment.put("HUDSON_SERVER_COOKIE","de93f00fb246988e"); 44 | environment.put("JENKINS_HOME","/var/jenkins_home"); 45 | environment.put("JENKINS_SERVER_COOKIE","de93f00fb246988e"); 46 | environment.put("JOB_NAME","jr-int3"); 47 | 48 | CauseDTO cause = new CauseDTO(); 49 | cause.setUserId("annonymous"); 50 | cause.setShortDescription("Started by user anonymous"); 51 | List causeDTOList = Collections.singletonList(cause); 52 | 53 | event.setTimestamp(new Date()); 54 | event.setStartTime(new Date()); 55 | event.setBuildResult("SUCCESS"); 56 | event.setEnvVars(environment); 57 | event.setApp("mytestapp"); 58 | event.setCauses(causeDTOList); 59 | 60 | return event; 61 | } 62 | } -------------------------------------------------------------------------------- /devops-steps/src/test/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/CreateApprovalEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import java.util.Date; 20 | 21 | public class CreateApprovalEvent extends BaseSendEvent { 22 | 23 | /** 24 | * Java main to test creating events in elasticsearch. Set the following ENV VARS to point to a local ES running in OpenShift 25 | * 26 | * PIPELINE_ELASTICSEARCH_HOST=elasticsearch.vagrant.f8 27 | * ELASTICSEARCH_SERVICE_PORT=80 28 | */ 29 | public static void main(String[] args) { 30 | final ApprovalEventDTO approval = createTestApprovalEvent(); 31 | send(approval, ElasticsearchClient.APPROVE); 32 | } 33 | 34 | private static ApprovalEventDTO createTestApprovalEvent(){ 35 | ApprovalEventDTO event = new ApprovalEventDTO(); 36 | event.setEnvironment("test"); 37 | event.setApp("mytestapp"); 38 | event.setRequestedTime(new Date()); 39 | 40 | return event; 41 | } 42 | } -------------------------------------------------------------------------------- /devops-steps/src/test/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/DeploymentEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | import java.util.*; 20 | 21 | public class DeploymentEvent extends BaseSendEvent { 22 | 23 | /** 24 | * Java main to test creating events in elasticsearch. Set the following ENV VARS to point to a local ES running in OpenShift 25 | * 26 | * PIPELINE_ELASTICSEARCH_HOST=elasticsearch.vagrant.f8 27 | * ELASTICSEARCH_SERVICE_PORT=80 28 | */ 29 | public static void main(String[] args) { 30 | final DeploymentEventDTO build = createTestDeploymentEvent(); 31 | send(build, ElasticsearchClient.DEPLOYMENT); 32 | } 33 | 34 | private static DeploymentEventDTO createTestDeploymentEvent(){ 35 | DeploymentEventDTO event = new DeploymentEventDTO(); 36 | 37 | event.setTimestamp(new Date()); 38 | event.setEnvironment("test-staging"); 39 | event.setApp("mytestapp"); 40 | event.setAuthor("tester"); 41 | event.setCommit("1234abcd"); 42 | event.setNamespace("test-namespace"); 43 | event.setResource("pod"); 44 | event.setVersion("123"); 45 | 46 | return event; 47 | } 48 | } -------------------------------------------------------------------------------- /devops-steps/src/test/java/io/fabric8/kubernetes/pipeline/devops/elasticsearch/UpdateApprovalEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline.devops.elasticsearch; 18 | 19 | 20 | import com.fasterxml.jackson.databind.ObjectMapper; 21 | import hudson.model.StreamBuildListener; 22 | 23 | import java.nio.charset.Charset; 24 | import java.util.Date; 25 | import java.util.logging.Level; 26 | import java.util.logging.Logger; 27 | 28 | import static junit.framework.TestCase.assertTrue; 29 | 30 | public class UpdateApprovalEvent { 31 | private static final Logger LOG = Logger.getLogger(BuildListener.class.getName()); 32 | 33 | /** 34 | * Java main to test updating events in elasticsearch. Set the following ENV VARS to point to a local ES running in OpenShift 35 | * 36 | * PIPELINE_ELASTICSEARCH_HOST=elasticsearch.vagrant.f8 37 | * ELASTICSEARCH_SERVICE_PORT=80 38 | */ 39 | public static void main(String[] args) { 40 | final ApprovalEventDTO approval = createTestApprovalEvent(); 41 | hudson.model.BuildListener listener = new StreamBuildListener(System.out, Charset.defaultCharset()); 42 | try { 43 | ObjectMapper mapper = JsonUtils.createObjectMapper(); 44 | String json = mapper.writeValueAsString(approval); 45 | boolean success = ElasticsearchClient.updateEvent("AVVy4MSZ_YLNT2M2J-83", json, ElasticsearchClient.APPROVE , listener); 46 | assertTrue(success); 47 | } catch (Exception e) { 48 | LOG.log(Level.SEVERE, "Error when updating event: " + approval, e); 49 | } 50 | } 51 | 52 | private static ApprovalEventDTO createTestApprovalEvent(){ 53 | ApprovalEventDTO event = new ApprovalEventDTO(); 54 | event.setApproved(true); 55 | event.setReceivedTime(new Date()); 56 | return event; 57 | } 58 | } -------------------------------------------------------------------------------- /devops-steps/src/test/resources/kubernetesJsonWithRegistry.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion" : "v1", 3 | "kind" : "Template", 4 | "labels" : { }, 5 | "metadata" : { 6 | "annotations" : { 7 | "description" : "test example", 8 | "fabric8.my-test-image/iconUrl" : "test-icon", 9 | "fabric8.my-test-image/summary" : "A nodeJS example" 10 | }, 11 | "labels" : { }, 12 | "name" : "my-test-image" 13 | }, 14 | "objects" : [{ 15 | "kind": "Service", 16 | "apiVersion": "v1", 17 | "metadata": { 18 | "name": "my-test-image", 19 | "creationTimestamp": null, 20 | "labels": { 21 | "component": "my-test-image", 22 | "container": "test", 23 | "group": "quickstarts", 24 | "project": "my-test-image", 25 | "provider": "fabric8", 26 | "version": "TEST-1.0" 27 | }, 28 | "annotations": { 29 | "prometheus.io/port": "1111", 30 | "prometheus.io/scheme": "http", 31 | "prometheus.io/scrape": "true" 32 | } 33 | }, 34 | "spec": { 35 | "ports": [ 36 | { 37 | "protocol": "TCP", 38 | "port": 80, 39 | "targetPort": 1111 40 | } 41 | ], 42 | "selector": { 43 | "component": "my-test-image", 44 | "container": "test", 45 | "group": "quickstarts", 46 | "project": "my-test-image", 47 | "provider": "fabric8", 48 | "version": "TEST-1.0" 49 | }, 50 | "type": "ClusterIP", 51 | "sessionAffinity": "None" 52 | }, 53 | "status": { 54 | "loadBalancer": {} 55 | } 56 | }, 57 | { 58 | "kind": "ReplicationController", 59 | "apiVersion": "v1", 60 | "metadata": { 61 | "name": "my-test-image", 62 | "generation": 1, 63 | "creationTimestamp": null, 64 | "labels": { 65 | "component": "my-test-image", 66 | "container": "test", 67 | "group": "quickstarts", 68 | "project": "my-test-image", 69 | "provider": "fabric8", 70 | "version": "TEST-1.0" 71 | } 72 | }, 73 | "spec": { 74 | "replicas": 1, 75 | "selector": { 76 | "component": "my-test-image", 77 | "container": "test", 78 | "group": "quickstarts", 79 | "project": "my-test-image", 80 | "provider": "fabric8", 81 | "version": "TEST-1.0" 82 | }, 83 | "template": { 84 | "metadata": { 85 | "creationTimestamp": null, 86 | "labels": { 87 | "component": "my-test-image", 88 | "container": "test", 89 | "group": "quickstarts", 90 | "project": "my-test-image", 91 | "provider": "fabric8", 92 | "version": "TEST-1.0" 93 | } 94 | }, 95 | "spec": { 96 | "volumes": [ 97 | { 98 | "name": "nginx-conf", 99 | "configMap": { 100 | "name": "nginx-registry-config" 101 | } 102 | } 103 | ], 104 | "containers": [ 105 | { 106 | "name": "my-test-image", 107 | "image": "myexternalregistry.io:5000/TEST_NS/my-test-image:TEST-1.0", 108 | "ports": [ 109 | { 110 | "name": "web", 111 | "containerPort": 1111, 112 | "protocol": "TCP" 113 | } 114 | ], 115 | "volumeMounts": [ 116 | { 117 | "name": "nginx-conf", 118 | "mountPath": "/etc/nginx/conf.d" 119 | } 120 | ], 121 | "env": [ 122 | { 123 | "name": "KUBERNETES_NAMESPACE", 124 | "valueFrom": { 125 | "fieldRef": { 126 | "apiVersion": "v1", 127 | "fieldPath": "metadata.namespace" 128 | } 129 | } 130 | } 131 | ], 132 | "resources": {}, 133 | "terminationMessagePath": "/dev/termination-log", 134 | "imagePullPolicy": "IfNotPresent", 135 | "securityContext": {} 136 | } 137 | ], 138 | "restartPolicy": "Always", 139 | "terminationGracePeriodSeconds": 30, 140 | "dnsPolicy": "ClusterFirst", 141 | "securityContext": {} 142 | } 143 | } 144 | }, 145 | "status": { 146 | "replicas": 0 147 | } 148 | }]} 149 | -------------------------------------------------------------------------------- /devops-steps/src/test/resources/kubernetesJsonWithoutRegistry.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion" : "v1", 3 | "kind" : "Template", 4 | "labels" : { }, 5 | "metadata" : { 6 | "annotations" : { 7 | "description" : "test example", 8 | "fabric8.my-test-image/iconUrl" : "test-icon", 9 | "fabric8.my-test-image/summary" : "A nodeJS example" 10 | }, 11 | "labels" : { }, 12 | "name" : "my-test-image" 13 | }, 14 | "objects" : [{ 15 | "kind": "Service", 16 | "apiVersion": "v1", 17 | "metadata": { 18 | "name": "my-test-image", 19 | "creationTimestamp": null, 20 | "labels": { 21 | "component": "my-test-image", 22 | "container": "test", 23 | "group": "quickstarts", 24 | "project": "my-test-image", 25 | "provider": "fabric8", 26 | "version": "TEST-1.0" 27 | }, 28 | "annotations": { 29 | "prometheus.io/port": "1111", 30 | "prometheus.io/scheme": "http", 31 | "prometheus.io/scrape": "true" 32 | } 33 | }, 34 | "spec": { 35 | "ports": [ 36 | { 37 | "protocol": "TCP", 38 | "port": 80, 39 | "targetPort": 1111 40 | } 41 | ], 42 | "selector": { 43 | "component": "my-test-image", 44 | "container": "test", 45 | "group": "quickstarts", 46 | "project": "my-test-image", 47 | "provider": "fabric8", 48 | "version": "TEST-1.0" 49 | }, 50 | "type": "ClusterIP", 51 | "sessionAffinity": "None" 52 | }, 53 | "status": { 54 | "loadBalancer": {} 55 | } 56 | }, 57 | { 58 | "kind": "ReplicationController", 59 | "apiVersion": "v1", 60 | "metadata": { 61 | "name": "my-test-image", 62 | "generation": 1, 63 | "creationTimestamp": null, 64 | "labels": { 65 | "component": "my-test-image", 66 | "container": "test", 67 | "group": "quickstarts", 68 | "project": "my-test-image", 69 | "provider": "fabric8", 70 | "version": "TEST-1.0" 71 | } 72 | }, 73 | "spec": { 74 | "replicas": 1, 75 | "selector": { 76 | "component": "my-test-image", 77 | "container": "test", 78 | "group": "quickstarts", 79 | "project": "my-test-image", 80 | "provider": "fabric8", 81 | "version": "TEST-1.0" 82 | }, 83 | "template": { 84 | "metadata": { 85 | "creationTimestamp": null, 86 | "labels": { 87 | "component": "my-test-image", 88 | "container": "test", 89 | "group": "quickstarts", 90 | "project": "my-test-image", 91 | "provider": "fabric8", 92 | "version": "TEST-1.0" 93 | } 94 | }, 95 | "spec": { 96 | "containers": [ 97 | { 98 | "name": "my-test-image", 99 | "image": "TEST_NS/my-test-image:TEST-1.0", 100 | "ports": [ 101 | { 102 | "name": "web", 103 | "containerPort": 1111, 104 | "protocol": "TCP" 105 | } 106 | ], 107 | "env": [ 108 | { 109 | "name": "KUBERNETES_NAMESPACE", 110 | "valueFrom": { 111 | "fieldRef": { 112 | "apiVersion": "v1", 113 | "fieldPath": "metadata.namespace" 114 | } 115 | } 116 | } 117 | ], 118 | "resources": {}, 119 | "terminationMessagePath": "/dev/termination-log", 120 | "imagePullPolicy": "IfNotPresent", 121 | "securityContext": {} 122 | } 123 | ], 124 | "restartPolicy": "Always", 125 | "terminationGracePeriodSeconds": 30, 126 | "dnsPolicy": "ClusterFirst", 127 | "securityContext": {} 128 | } 129 | } 130 | }, 131 | "status": { 132 | "replicas": 0 133 | } 134 | }]} 135 | -------------------------------------------------------------------------------- /devops-steps/src/test/resources/services/invalidservice1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: launchpad-builder 5 | annotations: 6 | description: This template creates a Build Configuration using an S2I builder. 7 | tags: instant-app 8 | objects: 9 | - apiVersion: v1 10 | kind: Service 11 | metadata: 12 | labels: 13 | project: nodejs-rest-http 14 | provider: nodeshift 15 | version: 2.0.0 16 | name: 12Nodejs-rest-http 17 | spec: 18 | ports: 19 | - protocol: TCP 20 | port: 8080 21 | targetPort: 8080 22 | selector: 23 | project: nodejs-rest-http 24 | provider: nodeshift 25 | type: ClusterIP 26 | - apiVersion: v1 27 | kind: Route 28 | metadata: 29 | labels: 30 | project: nodejs-rest-http 31 | provider: nodeshift 32 | version: 2.0.0 33 | name: nodejs-rest-http 34 | spec: 35 | port: 36 | targetPort: 8080 37 | to: 38 | kind: Service 39 | name: 12Nodejs-rest-http -------------------------------------------------------------------------------- /devops-steps/src/test/resources/services/invalidservice2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: launchpad-builder 5 | annotations: 6 | description: This template creates a Build Configuration using an S2I builder. 7 | tags: instant-app 8 | objects: 9 | - apiVersion: v1 10 | kind: Service 11 | metadata: 12 | labels: 13 | project: nodejs-rest-http 14 | provider: nodeshift 15 | version: 2.0.0 16 | name: 12Nodejs-rest-Http12Nodejs-rest-Http12Nodejs-rest-Http12Nodejs-rest-Http12Nodejs-rest-http12Nodejs-rest-Http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http12Nodejs-rest-http 17 | spec: 18 | ports: 19 | - protocol: TCP 20 | port: 8080 21 | targetPort: 8080 22 | selector: 23 | project: nodejs-rest-http 24 | provider: nodeshift 25 | type: ClusterIP -------------------------------------------------------------------------------- /devops-steps/src/test/resources/services/invalidservice3.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: launchpad-builder 5 | annotations: 6 | description: This template creates a Build Configuration using an S2I builder. 7 | tags: instant-app 8 | objects: 9 | - apiVersion: v1 10 | kind: Service 11 | metadata: 12 | labels: 13 | project: nodejs-rest-http 14 | provider: nodeshift 15 | version: 2.0.0 16 | name: 12Nodejs-rest-http 17 | spec: 18 | ports: 19 | - protocol: TCP 20 | port: 8080 21 | targetPort: 8080 22 | selector: 23 | project: nodejs-rest-http 24 | provider: nodeshift 25 | type: ClusterIP 26 | - apiVersion: v1 27 | kind: Route 28 | metadata: 29 | labels: 30 | project: nodejs-rest-http 31 | provider: nodeshift 32 | version: 2.0.0 33 | name: nodejs-rest-http 34 | spec: 35 | port: 36 | targetPort: 8080 37 | to: 38 | kind: Loadbalancer 39 | name: somelb -------------------------------------------------------------------------------- /devops-steps/src/test/resources/services/validservice3.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: launchpad-builder 5 | annotations: 6 | description: This template creates a Build Configuration using an S2I builder. 7 | tags: instant-app 8 | objects: 9 | - apiVersion: v1 10 | kind: Service 11 | metadata: 12 | labels: 13 | project: nodejs-rest-http 14 | provider: nodeshift 15 | version: 2.0.0 16 | name: nodejs-rest-http 17 | spec: 18 | ports: 19 | - protocol: TCP 20 | port: 8080 21 | targetPort: 8080 22 | selector: 23 | project: nodejs-rest-http 24 | provider: nodeshift 25 | type: ClusterIP 26 | - apiVersion: v1 27 | kind: Route 28 | metadata: 29 | labels: 30 | project: nodejs-rest-http 31 | provider: nodeshift 32 | version: 2.0.0 33 | name: nodejs-rest-http 34 | spec: 35 | port: 36 | targetPort: 8080 37 | to: 38 | kind: Service 39 | name: nodejs-rest-http 40 | - apiVersion: v1 41 | kind: ImageStream 42 | metadata: 43 | name: runtime 44 | spec: 45 | tags: 46 | - name: latest 47 | from: 48 | kind: DockerImage 49 | name: 'bucharestgold/centos7-s2i-nodejs:10.x' 50 | - apiVersion: v1 51 | kind: BuildConfig 52 | metadata: 53 | name: nodejs-rest-http 54 | spec: 55 | output: 56 | to: 57 | kind: ImageStreamTag 58 | name: 'nodejs-rest-http:latest' 59 | postCommit: {} 60 | resources: {} 61 | source: 62 | git: 63 | uri: '${SOURCE_REPOSITORY_URL}' 64 | ref: '${SOURCE_REPOSITORY_REF}' 65 | type: Git 66 | strategy: 67 | type: Source 68 | sourceStrategy: 69 | from: 70 | kind: ImageStreamTag 71 | name: 'runtime:latest' 72 | incremental: true 73 | triggers: 74 | - github: 75 | secret: '${GITHUB_WEBHOOK_SECRET}' 76 | type: GitHub 77 | - type: ConfigChange 78 | - imageChange: {} 79 | type: ImageChange 80 | status: 81 | lastVersion: 0 -------------------------------------------------------------------------------- /devops-steps/src/test/resources/services/validservice4.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: launchpad-builder 5 | annotations: 6 | description: This template creates a Build Configuration using an S2I builder. 7 | tags: instant-app 8 | objects: 9 | - apiVersion: v1 10 | kind: Route 11 | metadata: 12 | labels: 13 | project: nodejs-rest-http 14 | provider: nodeshift 15 | version: 2.0.0 16 | name: nodejs-rest-http 17 | spec: 18 | port: 19 | targetPort: 8080 20 | to: 21 | kind: Service 22 | name: nodejs-rest-http 23 | - apiVersion: v1 24 | kind: ImageStream 25 | metadata: 26 | name: runtime 27 | spec: 28 | tags: 29 | - name: latest 30 | from: 31 | kind: DockerImage 32 | name: 'bucharestgold/centos7-s2i-nodejs:10.x' 33 | - apiVersion: v1 34 | kind: BuildConfig 35 | metadata: 36 | name: nodejs-rest-http 37 | spec: 38 | output: 39 | to: 40 | kind: ImageStreamTag 41 | name: 'nodejs-rest-http:latest' 42 | postCommit: {} 43 | resources: {} 44 | source: 45 | git: 46 | uri: '${SOURCE_REPOSITORY_URL}' 47 | ref: '${SOURCE_REPOSITORY_REF}' 48 | type: Git 49 | strategy: 50 | type: Source 51 | sourceStrategy: 52 | from: 53 | kind: ImageStreamTag 54 | name: 'runtime:latest' 55 | incremental: true 56 | triggers: 57 | - github: 58 | secret: '${GITHUB_WEBHOOK_SECRET}' 59 | type: GitHub 60 | - type: ConfigChange 61 | - imageChange: {} 62 | type: ImageChange 63 | status: 64 | lastVersion: 0 -------------------------------------------------------------------------------- /doc/scc-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "SecurityContextConstraints", 3 | "apiVersion": "v1", 4 | "metadata": { 5 | "name": "example" 6 | }, 7 | "priority": null, 8 | "allowPrivilegedContainer": true, 9 | "allowedCapabilities": null, 10 | "allowHostDirVolumePlugin": true, 11 | "allowHostNetwork": true, 12 | "allowHostPorts": true, 13 | "allowHostPID": false, 14 | "allowHostIPC": false, 15 | "seLinuxContext": { 16 | "type": "RunAsAny" 17 | }, 18 | "runAsUser": { 19 | "type": "RunAsAny" 20 | }, 21 | "supplementalGroups": { 22 | "type": "RunAsAny" 23 | }, 24 | "fsGroup": { 25 | "type": "RunAsAny" 26 | }, 27 | "users": [ 28 | "system:serviceaccount:default:myserviceaccount", 29 | "myuser" 30 | ], 31 | "groups": [ 32 | "system:cluster-admins", 33 | "system:nodes" 34 | ] 35 | } -------------------------------------------------------------------------------- /header.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) ${project.inceptionYear} ${owner} 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/AbstractDockerStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import io.fabric8.docker.api.model.AuthConfig; 20 | import io.fabric8.docker.client.Config; 21 | import io.fabric8.docker.client.ConfigBuilder; 22 | import io.fabric8.docker.client.utils.Utils; 23 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 24 | import org.kohsuke.stapler.DataBoundSetter; 25 | 26 | import java.io.Serializable; 27 | 28 | public class AbstractDockerStep extends AbstractStepImpl implements Serializable { 29 | 30 | private static final long serialVersionUID = -9155746436499494358L; 31 | 32 | private final String name; 33 | 34 | private String username; 35 | private String password; 36 | private String email; 37 | 38 | public AbstractDockerStep(String name) { 39 | this.name = name; 40 | 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public String getUsername() { 48 | return username; 49 | } 50 | 51 | @DataBoundSetter 52 | public void setUsername(String username) { 53 | this.username = username; 54 | } 55 | 56 | public String getPassword() { 57 | return password; 58 | } 59 | 60 | @DataBoundSetter 61 | public void setPassword(String password) { 62 | this.password = password; 63 | } 64 | 65 | public String getEmail() { 66 | return email; 67 | } 68 | 69 | @DataBoundSetter 70 | public void setEmail(String email) { 71 | this.email = email; 72 | } 73 | 74 | public Config getDockerConfig() { 75 | Config config = new ConfigBuilder().build(); 76 | AuthConfig fallbackAuthConfig = config.getAuthConfigs().get(Config.DOCKER_AUTH_FALLBACK_KEY); 77 | if (Utils.isNotNullOrEmpty(username)) { 78 | fallbackAuthConfig.setUsername(username); 79 | } 80 | 81 | if (Utils.isNotNullOrEmpty(password)) { 82 | fallbackAuthConfig.setPassword(password); 83 | } 84 | 85 | if (Utils.isNotNullOrEmpty(email)) { 86 | fallbackAuthConfig.setEmail(email); 87 | } 88 | return config; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/BuildImageStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import hudson.Extension; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | import org.kohsuke.stapler.DataBoundSetter; 24 | 25 | import java.io.Serializable; 26 | import java.util.ArrayList; 27 | 28 | public class BuildImageStep extends AbstractDockerStep implements Serializable { 29 | 30 | private static final long serialVersionUID = 1851294902925088301L; 31 | 32 | private Boolean rm; 33 | private String path; 34 | private long timeout = 600000L; 35 | private ArrayList ignorePatterns = new ArrayList(); 36 | 37 | @DataBoundConstructor 38 | public BuildImageStep(String name) { 39 | super(name); 40 | } 41 | 42 | public Boolean getRm() { 43 | return rm; 44 | } 45 | 46 | @DataBoundSetter 47 | public void setRm(Boolean rm) { 48 | this.rm = rm; 49 | } 50 | 51 | public String getPath() { 52 | return path; 53 | } 54 | 55 | @DataBoundSetter 56 | public void setPath(String path) { 57 | this.path = path; 58 | } 59 | 60 | public long getTimeout() { 61 | return timeout; 62 | } 63 | 64 | @DataBoundSetter 65 | public void setTimeout(long timeout) { 66 | this.timeout = timeout; 67 | } 68 | 69 | public ArrayList getIgnorePatterns() { 70 | return ignorePatterns; 71 | } 72 | 73 | @DataBoundSetter 74 | public void setIgnorePatterns(ArrayList ignorePatterns) { 75 | this.ignorePatterns = ignorePatterns; 76 | } 77 | 78 | @Extension 79 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 80 | 81 | public DescriptorImpl() { 82 | super(BuildImageStepExecution.class); 83 | } 84 | 85 | public DescriptorImpl(Class executionType) { 86 | super(executionType); 87 | } 88 | 89 | @Override 90 | public String getFunctionName() { 91 | return "buildImage"; 92 | } 93 | 94 | @Override 95 | public String getDisplayName() { 96 | return "Builds a Docker Image"; 97 | } 98 | 99 | @Override 100 | public boolean takesImplicitBlockArgument() { 101 | return false; 102 | } 103 | 104 | @Override 105 | public boolean isAdvanced() { 106 | return true; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/KubernetesDSL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import groovy.lang.Binding; 20 | import hudson.Extension; 21 | import io.fabric8.kubernetes.api.model.PodTemplate; 22 | import io.fabric8.workflow.core.ClassWhiteList; 23 | import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; 24 | import org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar; 25 | import org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate; 26 | import org.csanchez.jenkins.plugins.kubernetes.PodEnvVar; 27 | import org.jenkinsci.plugins.workflow.cps.CpsScript; 28 | import org.jenkinsci.plugins.workflow.cps.GlobalVariable; 29 | 30 | import javax.annotation.Nonnull; 31 | import java.io.IOException; 32 | import java.util.ArrayList; 33 | import java.util.Collection; 34 | import java.util.Collections; 35 | import java.util.HashMap; 36 | import java.util.HashSet; 37 | import java.util.concurrent.Callable; 38 | 39 | @Extension 40 | public class KubernetesDSL extends GlobalVariable { 41 | 42 | private static final String KUBERNETES = "kubernetes"; 43 | 44 | @Nonnull 45 | @Override 46 | public String getName() { 47 | return KUBERNETES; 48 | } 49 | 50 | @Nonnull 51 | @Override 52 | public Object getValue(CpsScript script) throws Exception { 53 | Binding binding = script.getBinding(); 54 | Object kubernetes; 55 | if (binding.hasVariable(getName())) { 56 | kubernetes = binding.getVariable(getName()); 57 | } else { 58 | // Note that if this were a method rather than a constructor, we would need to mark it @NonCPS lest it throw CpsCallableInvocation. 59 | kubernetes = script.getClass().getClassLoader().loadClass("io.fabric8.kubernetes.pipeline.Kubernetes").getConstructor(CpsScript.class).newInstance(script); 60 | binding.setVariable(getName(), kubernetes); 61 | } 62 | return kubernetes; 63 | } 64 | 65 | 66 | @Extension 67 | public static class PlugiWhiteList extends ClassWhiteList { 68 | public PlugiWhiteList() throws IOException { 69 | super(ScriptBytecodeAdapter.class, 70 | PodTemplate.class, ContainerTemplate.class, PodEnvVar.class, ContainerEnvVar.class, 71 | ArrayList.class, Collection.class, HashMap.class, HashSet.class, Collections.class, 72 | Callable.class); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/PodExecDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import hudson.Launcher; 20 | import hudson.LauncherDecorator; 21 | import hudson.Proc; 22 | import hudson.model.Node; 23 | import io.fabric8.kubernetes.client.dsl.ExecWatch; 24 | 25 | import java.io.IOException; 26 | import java.io.Serializable; 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.concurrent.CountDownLatch; 31 | import java.util.concurrent.atomic.AtomicBoolean; 32 | 33 | public class PodExecDecorator extends LauncherDecorator implements Serializable { 34 | 35 | private final transient KubernetesFacade kubernetes; 36 | private final transient String name; 37 | private final transient String containerName; 38 | private final transient AtomicBoolean alive; 39 | private final transient CountDownLatch started; 40 | private final transient CountDownLatch finished; 41 | 42 | public PodExecDecorator(KubernetesFacade kubernetes, String name, String containerName, AtomicBoolean alive, CountDownLatch started, CountDownLatch finished) { 43 | this.kubernetes = kubernetes; 44 | this.name = name; 45 | this.alive = alive; 46 | this.started = started; 47 | this.finished = finished; 48 | this.containerName = containerName; 49 | } 50 | 51 | @Override 52 | public Launcher decorate(final Launcher launcher, Node node) { 53 | return new Launcher.DecoratedLauncher(launcher) { 54 | @Override 55 | public Proc launch(ProcStarter starter) throws IOException { 56 | AtomicBoolean processAlive = new AtomicBoolean(false); 57 | CountDownLatch processStarted = new CountDownLatch(1); 58 | CountDownLatch processFinished = new CountDownLatch(1); 59 | 60 | ExecWatch execWatch = kubernetes.exec(name, containerName, processAlive, processStarted, processFinished, launcher.getListener().getLogger(), 61 | getCommands(starter) 62 | ); 63 | return new PodExecProc(name, processAlive, processFinished, execWatch); 64 | } 65 | 66 | @Override 67 | public void kill(Map modelEnvVars) throws IOException, InterruptedException { 68 | kubernetes.deletePod(name); 69 | } 70 | }; 71 | } 72 | 73 | static String[] getCommands(Launcher.ProcStarter starter) { 74 | List allCommands = new ArrayList(); 75 | 76 | boolean first = true; 77 | for (String cmd : starter.cmds()) { 78 | if (first && "nohup".equals(cmd)) { 79 | first = false; 80 | continue; 81 | } 82 | //I shouldn't been doing that, but clearly the script that is passed to us is wrong? 83 | allCommands.add(cmd.replaceAll("\\$\\$", "\\$")); 84 | } 85 | return allCommands.toArray(new String[allCommands.size()]); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/PodExecProc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import hudson.Proc; 20 | import io.fabric8.kubernetes.client.dsl.ExecWatch; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | import java.util.concurrent.CountDownLatch; 26 | import java.util.concurrent.atomic.AtomicBoolean; 27 | 28 | import static io.fabric8.workflow.core.Constants.CTRL_C; 29 | import static io.fabric8.workflow.core.Constants.EXIT; 30 | import static io.fabric8.workflow.core.Constants.NEWLINE; 31 | import static io.fabric8.workflow.core.Constants.UTF_8; 32 | 33 | public class PodExecProc extends Proc { 34 | 35 | private final String podName; 36 | private final AtomicBoolean alive; 37 | private final CountDownLatch finished; 38 | private final ExecWatch watch; 39 | 40 | public PodExecProc(String podName, AtomicBoolean alive, CountDownLatch finished, ExecWatch watch) { 41 | this.podName = podName; 42 | this.watch = watch; 43 | this.alive = alive; 44 | this.finished = finished; 45 | } 46 | 47 | @Override 48 | public boolean isAlive() throws IOException, InterruptedException { 49 | return alive.get(); 50 | } 51 | 52 | @Override 53 | public void kill() throws IOException, InterruptedException { 54 | //What we actually do is send a ctrl-c to the current process and then exit the shell. 55 | watch.getInput().write(CTRL_C); 56 | watch.getInput().write(EXIT.getBytes(UTF_8)); 57 | watch.getInput().write(NEWLINE.getBytes(UTF_8)); 58 | watch.getInput().flush(); 59 | } 60 | 61 | @Override 62 | public int join() throws IOException, InterruptedException { 63 | finished.await(); 64 | return 1; 65 | } 66 | 67 | @Override 68 | public InputStream getStdout() { 69 | return watch.getOutput(); 70 | } 71 | 72 | @Override 73 | public InputStream getStderr() { 74 | return watch.getOutput(); 75 | } 76 | 77 | @Override 78 | public OutputStream getStdin() { 79 | return watch.getInput(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/PodWatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import io.fabric8.kubernetes.api.model.Pod; 20 | import io.fabric8.kubernetes.api.model.Status; 21 | import io.fabric8.kubernetes.client.KubernetesClientException; 22 | import io.fabric8.kubernetes.client.Watcher; 23 | 24 | import java.util.concurrent.Callable; 25 | import java.util.concurrent.CountDownLatch; 26 | import java.util.concurrent.atomic.AtomicBoolean; 27 | 28 | import static io.fabric8.kubernetes.pipeline.KubernetesFacade.isPodCompleted; 29 | import static io.fabric8.kubernetes.pipeline.KubernetesFacade.isPodRunning; 30 | 31 | public class PodWatcher implements Watcher { 32 | 33 | private final AtomicBoolean alive; 34 | private final CountDownLatch started; 35 | private final CountDownLatch finisied; 36 | private final Callable onCompletion; 37 | 38 | public PodWatcher(AtomicBoolean alive, CountDownLatch running, CountDownLatch finisied, Callable onCompletion) { 39 | this.alive = alive; 40 | this.started = running; 41 | this.finisied = finisied; 42 | this.onCompletion = onCompletion; 43 | } 44 | 45 | @Override 46 | public void eventReceived(Action action, Pod pod) { 47 | if (isPodRunning(pod)) { 48 | alive.set(true); 49 | started.countDown(); 50 | } 51 | 52 | switch (action) { 53 | case ADDED: 54 | case MODIFIED: 55 | case ERROR: 56 | if (isPodCompleted(pod)) { 57 | finisied.countDown(); 58 | callCompletionCallback(); 59 | } 60 | break; 61 | case DELETED: 62 | finisied.countDown(); 63 | } 64 | } 65 | 66 | @Override 67 | public void onClose(KubernetesClientException e) { 68 | finisied.countDown(); 69 | callCompletionCallback(); 70 | } 71 | 72 | private void callCompletionCallback() { 73 | if (onCompletion != null) { 74 | try { 75 | onCompletion.call(); 76 | } catch (Throwable t) { 77 | //ignore 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/PushImageStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import hudson.Extension; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | import org.kohsuke.stapler.DataBoundSetter; 24 | 25 | import java.io.Serializable; 26 | 27 | public class PushImageStep extends AbstractDockerStep implements Serializable { 28 | 29 | private static final long serialVersionUID = -6633237919456764764L; 30 | 31 | private String tag; 32 | private String registry; 33 | private long timeout = 600000L; 34 | 35 | @DataBoundConstructor 36 | public PushImageStep(String name) { 37 | super(name); 38 | } 39 | 40 | public String getTag() { 41 | return tag; 42 | } 43 | 44 | @DataBoundSetter 45 | public void setTag(String tag) { 46 | this.tag = tag; 47 | } 48 | 49 | public String getRegistry() { 50 | return registry; 51 | } 52 | 53 | @DataBoundSetter 54 | public void setRegistry(String registry) { 55 | this.registry = registry; 56 | } 57 | 58 | public long getTimeout() { 59 | return timeout; 60 | } 61 | 62 | @DataBoundSetter 63 | public void setTimeout(long timeout) { 64 | this.timeout = timeout; 65 | } 66 | 67 | 68 | @Extension 69 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 70 | 71 | public DescriptorImpl() { 72 | super(PushImageStepExecution.class); 73 | } 74 | 75 | public DescriptorImpl(Class executionType) { 76 | super(executionType); 77 | } 78 | 79 | @Override 80 | public String getFunctionName() { 81 | return "pushImage"; 82 | } 83 | 84 | @Override 85 | public String getDisplayName() { 86 | return "Pushes a Docker Image"; 87 | } 88 | 89 | @Override 90 | public boolean takesImplicitBlockArgument() { 91 | return false; 92 | } 93 | 94 | @Override 95 | public boolean isAdvanced() { 96 | return true; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/TagImageStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import hudson.Extension; 20 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 21 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 22 | import org.kohsuke.stapler.DataBoundConstructor; 23 | import org.kohsuke.stapler.DataBoundSetter; 24 | 25 | import java.io.Serializable; 26 | 27 | public class TagImageStep extends AbstractDockerStep implements Serializable { 28 | 29 | private static final long serialVersionUID = -7095902323448215913L; 30 | 31 | private final String tag; 32 | private String repo; 33 | private Boolean force; 34 | 35 | @DataBoundConstructor 36 | public TagImageStep(String name, String tag) { 37 | super(name); 38 | this.tag = tag; 39 | this.repo = name; 40 | } 41 | 42 | public String getTag() { 43 | return tag; 44 | } 45 | 46 | public String getRepo() { 47 | return repo; 48 | } 49 | 50 | @DataBoundSetter 51 | public void setRepo(String repo) { 52 | this.repo = repo; 53 | } 54 | 55 | public Boolean getForce() { 56 | return force; 57 | } 58 | 59 | @DataBoundSetter 60 | public void setForce(Boolean force) { 61 | this.force = force; 62 | } 63 | 64 | @Extension 65 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 66 | 67 | public DescriptorImpl() { 68 | super(TagImageStepExecution.class); 69 | } 70 | 71 | public DescriptorImpl(Class executionType) { 72 | super(executionType); 73 | } 74 | 75 | @Override 76 | public String getFunctionName() { 77 | return "tagImage"; 78 | } 79 | 80 | @Override 81 | public String getDisplayName() { 82 | return "Tags a Docker Image"; 83 | } 84 | 85 | @Override 86 | public boolean takesImplicitBlockArgument() { 87 | return false; 88 | } 89 | 90 | @Override 91 | public boolean isAdvanced() { 92 | return true; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/TagImageStepExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import com.google.inject.Inject; 20 | import hudson.FilePath; 21 | import hudson.model.TaskListener; 22 | import io.fabric8.docker.client.DefaultDockerClient; 23 | import io.fabric8.docker.client.DockerClient; 24 | import jenkins.security.MasterToSlaveCallable; 25 | import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution; 26 | import org.jenkinsci.plugins.workflow.steps.StepContextParameter; 27 | 28 | public class TagImageStepExecution extends AbstractSynchronousStepExecution { 29 | 30 | @Inject 31 | private TagImageStep step; 32 | 33 | @StepContextParameter 34 | private TaskListener listener; 35 | 36 | @StepContextParameter 37 | private FilePath workspace; 38 | 39 | @Override 40 | protected Boolean run() throws Exception { 41 | return workspace.getChannel().call(new MasterToSlaveCallable() { 42 | @Override 43 | public Boolean call() throws Exception { 44 | try (DockerClient client = new DefaultDockerClient(step.getDockerConfig())) { 45 | listener.getLogger().println("Tagging image:" + step.getName() + " with tag:" + step.getTag() + "."); 46 | return client.image() 47 | .withName(step.getName()).tag() 48 | .inRepository(step.getRepo()) 49 | .force(step.getForce()) 50 | .withTagName(step.getTag()); 51 | } 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/java/io/fabric8/kubernetes/pipeline/WithPodStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Original Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.kubernetes.pipeline; 18 | 19 | import com.google.common.base.Strings; 20 | 21 | import hudson.Extension; 22 | 23 | import org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate; 24 | import org.csanchez.jenkins.plugins.kubernetes.PodEnvVar; 25 | import org.csanchez.jenkins.plugins.kubernetes.volumes.PodVolume; 26 | import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; 27 | import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; 28 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 29 | import org.kohsuke.stapler.DataBoundConstructor; 30 | 31 | import java.io.Serializable; 32 | import java.util.ArrayList; 33 | import java.util.Collections; 34 | import java.util.List; 35 | import java.util.Map; 36 | 37 | @Deprecated //No longer needed as we delegate to the kubernetes-plugin. 38 | public class WithPodStep extends AbstractStepImpl implements Serializable { 39 | 40 | private static final long serialVersionUID = 5588861066775717487L; 41 | 42 | private final String name; 43 | 44 | private final List containers; 45 | private final transient List envVars; 46 | private final List volumes; 47 | private final Map labels; 48 | 49 | private final String serviceAccount; 50 | private final String nodeSelector; 51 | private final String workingDir; 52 | 53 | @DataBoundConstructor 54 | public WithPodStep(String name, List containers, Map envVars, List volumes, String serviceAccount, String nodeSelector, String workingDir, Map labels) { 55 | this.name = name; 56 | this.containers = containers != null ? containers : Collections.emptyList(); 57 | this.envVars = envVars != null ? asPodEnvars(envVars) : Collections.emptyList(); 58 | this.volumes = volumes != null ? volumes : Collections.emptyList(); 59 | this.serviceAccount = serviceAccount; 60 | this.nodeSelector = nodeSelector; 61 | this.workingDir = Strings.isNullOrEmpty(workingDir) ? ContainerTemplate.DEFAULT_WORKING_DIR : workingDir; 62 | this.labels = labels != null ? labels : Collections.emptyMap(); 63 | } 64 | 65 | public String getName() { 66 | return name; 67 | } 68 | 69 | public List getContainers() { 70 | return containers; 71 | } 72 | 73 | public List getEnvVars() { 74 | return envVars; 75 | } 76 | 77 | public List getVolumes() { 78 | return volumes; 79 | } 80 | 81 | public String getServiceAccount() { 82 | return serviceAccount; 83 | } 84 | 85 | public String getNodeSelector() { 86 | return nodeSelector; 87 | } 88 | 89 | public Map getLabels() { return labels; } 90 | 91 | public String getWorkingDir() { 92 | return workingDir; 93 | } 94 | 95 | 96 | private List asPodEnvars(Map map) { 97 | List result = new ArrayList<>(); 98 | for (Map.Entry entry : map.entrySet()) { 99 | result.add(new PodEnvVar(entry.getKey(), entry.getValue())); 100 | } 101 | return result; 102 | } 103 | 104 | @Extension 105 | public static class DescriptorImpl extends AbstractStepDescriptorImpl { 106 | 107 | public DescriptorImpl() { 108 | super(WithPodStepExecution.class); 109 | } 110 | 111 | public DescriptorImpl(Class executionType) { 112 | super(executionType); 113 | } 114 | 115 | @Override 116 | public String getFunctionName() { 117 | return "withPod"; 118 | } 119 | 120 | @Override 121 | public String getDisplayName() { 122 | return "Run build steps in a MyPod"; 123 | } 124 | 125 | @Override 126 | public boolean takesImplicitBlockArgument() { 127 | return true; 128 | } 129 | 130 | @Override 131 | public boolean isAdvanced() { 132 | return true; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/META-INF/hudson.remoting.ClassFilter: -------------------------------------------------------------------------------- 1 | io.fabric8.docker.api.model.ImageInspect 2 | io.fabric8.docker.api.model.Config 3 | io.fabric8.docker.api.model.GraphDriverData 4 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | Builds and uses Docker images and Kubernetes Pods. 5 |
6 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-email.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | This email will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-name.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The name of the docker image. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-password.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | This password will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-path.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The path of the folder that contains the docker image. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-rm.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | Flag to remove intermediate layers. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-timeout.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The amount of time to wait for the build to complete. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help-username.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | This username will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/BuildImageStep/help.html: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 | Builds a docker image. 19 |
20 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/KubernetesDSL/help.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 | The kubernetes variable offers convenient access to Kubernetes and Docker related functions from a Workflow script. 6 |

7 |

8 | Methods needing a slave will implicitly run a node {…} block if you have not wrapped them in one. 9 | It is a good idea to enclose a block of steps which should all run on the same node in such a block yourself. 10 |

11 |

12 | If you are using Kubernetes build pods, then you must ensure that node {…} should be able to share its workspace. 13 | This requires that the node is exposing the workspace as hostPath volume mount. 14 |

15 |
16 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help-email.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | This email will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help-name.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The name of the docker image. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help-password.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | This password will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help-registry.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | Explicitly specify a remote registry if not present in the image repository. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help-timeout.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The amount of time to wait for the push to complete. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help-username.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | This username will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/PushImageStep/help.html: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 | Pushes a docker image to a docker registry. 19 |
20 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help-email.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | This email will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help-name.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The name of the docker image. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help-password.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | This password will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help-repo.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The image repository in which the tag will be created. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help-tag.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | The tag. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help-username.html: -------------------------------------------------------------------------------- 1 | The 16 | 17 | This username will be used in the fallback docker auth config object, that will be used if matching configuration is found for the registry. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/TagImageStep/help.html: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 | Tags a docker image. 19 |
20 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/WithPodStep/config.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/WithPodStep/help-inheritFrom.html: -------------------------------------------------------------------------------- 1 | A podTemplate may or may not inherit from an existing template. This means that the podTemplate will inherit node selector, service account, image pull secrets, containerTemplates and volumes from the template it inheritsFrom. 2 | 3 | Service account and Node selector when are overridden completely substitute any possible value found on the 'parent'. 4 | 5 | Container templates that are added to the podTemplate, that has a matching containerTemplate (a containerTemplate with the same name) in the 'parent' template, will inherit the configuration of the parent containerTemplate. 6 | If no matching containerTemplate is found, the template is added as is. 7 | 8 | Volume inheritance works exactly as Container templates. 9 | 10 | Image Pull Secrets** are combined (all secrets defined both on 'parent' and 'current' template are used). -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/WithPodStep/help-nodeSelector.html: -------------------------------------------------------------------------------- 1 | Specify which nodes the pod should operate on by providing a comma separated list of node labels: 2 | `label1=value1,label2=value2`. -------------------------------------------------------------------------------- /kubernetes-steps/src/main/resources/io/fabric8/kubernetes/pipeline/WithPodStep/help-serviceAccount.html: -------------------------------------------------------------------------------- 1 | The service account to use. -------------------------------------------------------------------------------- /kubernetes-steps/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | true 9 | kubernetes-pipeline-test 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /kubernetes-steps/src/test/resources/io/fabric8/kubernetes/pipeline/simpleMaven.groovy: -------------------------------------------------------------------------------- 1 | kubernetes.pod('buildpod').withName('maven').withImage('maven:3.3.9').inside { 2 | sh 'mvn -version' 3 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Kubernetes Pipeline 2 | ------------------- 3 | 4 | Kubernetes Pipeline is Jenkins plugin which extends [Jenkins Pipeline](https://github.com/jenkinsci/pipeline-plugin) to allow building and testing inside Kubernetes Pods reusing kubernetes features like pods, build images, service accounts, volumes and secrets while providing an elastic slave pool (each build runs in new pods). 5 | 6 | ## Features 7 | 8 | ### Kubernetes Steps 9 | 10 | - Build steps inside Kubernetes Pods 11 | - Service Accounts 12 | - Volumes 13 | - Secrets 14 | - Building, Pushing and using Docker Images 15 | 16 | ### DevOps Steps 17 | - Apply Kubernetes JSON 18 | - Interaction with ElasticSearch 19 | 20 | ### Arquillian Steps 21 | - Create temporary namespaces for testing 22 | - Install everything you need for end to end testing 23 | 24 | ### Aggregator 25 | An aggregator plugin for all the above. 26 | 27 | ### Further Reading 28 | - [Kubernetes Steps](kubernetes-steps/readme.md) 29 | - [DevOps Steps](devops-steps/readme.md) --------------------------------------------------------------------------------