Last active
July 6, 2020 09:12
-
-
Save michaelsauter/6b1f70eb3a6d544de0198fcd08b4ed83 to your computer and use it in GitHub Desktop.
Jenkinsfile.example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
odsComponentPipeline( | |
imageStreamTag: 'ods/jenkins-agent-base:3.x' | |
) { | |
odsComponentStageImportOpenShiftImageOrElse(context) { | |
stage('Build') { | |
sh './gradlew build' | |
} | |
odsComponentStageBuildOpenShiftImage(context) | |
} | |
odsComponentStageRolloutOpenShiftDeployment(context) | |
withOpenShiftCluster('https://api.abc.com', 'foo-cd-cluster-abc-sa-credentials') { | |
odsComponentStageImportOpenShiftImage(context, [imagePullerSecret: 'xyz-image-puller']) | |
odsComponentStageRolloutOpenShiftDeployment(context) | |
} | |
} | |
// Three new methods to implement: | |
// Check if image is in a namespace from which it can be promoted. | |
// First, it searches for eligible namespaces by making use of a new pipeline option, 'imagePromotion', | |
// which defaults to ['dev->test', 'test->prod']. For example, if the target environment is 'test', | |
// eligible namespaces to promote from are 'dev' and 'test' (as the current namespace is always eligible). | |
// When an image for the commit we checked out exists in an eligible namespace, we call | |
// odsComponentStagePromoteImage. If the image does not exist, we execute the given closure. | |
odsComponentStageImportOpenShiftImageOrElse(IContext context, Map config = [:], Closure block) | |
// Promote image from namespace given in config. The config map takes an image name, a namespace | |
// to pull from, and optionally the name of an image puller secret. If that is given, that secret | |
// is read and an image pull across clusters is performed using the credentials in the secret. | |
odsComponentStageImportOpenShiftImage(IContext context, Map config = [:]) | |
// Log into cluster identified by apiUrl using the credentials from serviceAccountCredentialsId, | |
// then execute given closure. The closure is wrapped in try/catch/finally, and in the finally | |
// block we log back into the current cluster. | |
withOpenShiftCluster(String apiUrl, String serviceAccountCredentialsId, Closure block) | |
// Advantages over current approach: | |
// - Images are promoted instead of rebuilt if the commit SHAs did not change. | |
// This requires to use 'git merge --ff-only' when merging (which is actually desirable anyway, | |
// as it prevents "loosing" commits in production) | |
// - Production namespace can be on another cluster | |
// - Multiple production namespaces on different clusters are possible |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.ods.component.IContext | |
import org.ods.services.OpenShiftService | |
import org.ods.util.PipelineSteps | |
@SuppressWarnings('UnusedMethodParameter') | |
def call(IContext context, Map config = [:], Closure block) { | |
if (!config.apiUrl) { | |
error('''Param 'apiUrl' is required''') | |
} | |
if (!config.credentialsId) { | |
error('''Param 'credentialsId' is required''') | |
} | |
def steps = new PipelineSteps(this) | |
def currentApiUrl = OpenShiftService.getApiUrl(steps) | |
withCredentials([ | |
usernamePassword( | |
credentialsId: config.credentialsId, | |
usernameVariable: 'OPENSHIFT_API_USER', | |
passwordVariable: 'OPENSHIFT_API_TOKEN' | |
) | |
]) { | |
def occuredException | |
try { | |
OpenShiftService.loginToExternalCluster( | |
steps, config.apiUrl, OPENSHIFT_API_TOKEN | |
) | |
block() | |
} catch (ex) { | |
occuredException = ex | |
} finally { | |
def tokenFile = '/var/run/secrets/kubernetes.io/serviceaccount/token' | |
OpenShiftService.loginToExternalCluster( | |
steps, currentApiUrl, readFile(tokenFile) | |
) | |
} | |
if (occuredException) { | |
throw occuredException | |
} | |
} | |
} |
Thanks for reviewing.
- We already have the import commands in the
OpenShiftService
and they work, so no need to use skopeo (though that certainly would also work) String apiUrl, String serviceAccountCredentialsId
give you the credentials of the "target cluster". the credentials / repo URL for the "source cluster" are stored inside a secret in the target cluster, which is referenced by the optionimagePullerSecret
.- Good point about the naming. I think that it should actually be named something ending in
OpenShiftCluster
now. So maybewithOpenShiftCluster
? I would not useOdsCluster
as no ODS needs to be installed in the target cluster, and I didn't useodsComponent
as a prefix as it is pretty general - the method could be used in any context really.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Looks good! I saw an older blog entry about this topic where they used skopeo (at the very end of the article) but I think it should be able to work just with 'oc', right?
Did I understood the flow correctly?: in odsOnCluster we log into the cluster2 and pull the image from cluster1 and promote + deploy the image there. Wouldn't we need URL and secrets to login into cluster2 AND repo-URL + sa secret of cluster1 to pull the image from cluster1 while being logged into cluster2? Not sure if this is completly covered in your description and method heads or if I got this wrong?
minor thing: should odsOnCluster not rather be named odsComponentWithCluster, odsWithCluster or withOdsCluster?