Skip to content

Commit

Permalink
Merge pull request #20 from bmuschko/create-pod
Browse files Browse the repository at this point in the history
Added task CreatePod
  • Loading branch information
cdancy authored Mar 18, 2018
2 parents 27c03e2 + 20c8172 commit 8093bbf
Show file tree
Hide file tree
Showing 7 changed files with 434 additions and 11 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ The below table(s) document each of our tasks and their respective `features` in
| Name | `config{}` | `onNext{}` | `response()` |
| --- | --- | --- | --- |
| [ListPods](https://github.com/bmuschko/gradle-kubernetes-plugin/blob/master/src/main/groovy/com/bmuschko/gradle/kubernetes/plugin/tasks/pods/ListPods.groovy) | [MixedOperation](http://static.javadoc.io/io.fabric8/kubernetes-client/3.1.8/io/fabric8/kubernetes/client/dsl/MixedOperation.html) | [Pod](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/Pod.html) | [PodList](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/PodList.html) |
[CreatePod](https://github.com/bmuschko/gradle-kubernetes-plugin/blob/master/src/main/groovy/com/bmuschko/gradle/kubernetes/plugin/tasks/pods/CreatePod.groovy) | [DoneablePod](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/DoneablePod.html) | [Pod](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/Pod.html) | [Pod](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/Pod.html) |
[GetPod](https://github.com/bmuschko/gradle-kubernetes-plugin/blob/master/src/main/groovy/com/bmuschko/gradle/kubernetes/plugin/tasks/pods/GetPod.groovy) | [N/A]() | [Pod](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/Pod.html) | [Pod](http://static.javadoc.io/io.fabric8/kubernetes-model/2.0.8/io/fabric8/kubernetes/api/model/Pod.html) |
[DeletePod](https://github.com/bmuschko/gradle-kubernetes-plugin/blob/master/src/main/groovy/com/bmuschko/gradle/kubernetes/plugin/tasks/pods/DeletePod.groovy) | [N/A]() | [Boolean](https://docs.oracle.com/javase/7/docs/api/java/lang/Boolean.html) | [Boolean](https://docs.oracle.com/javase/7/docs/api/java/lang/Boolean.html) |

Expand Down Expand Up @@ -239,7 +240,8 @@ task getNamespace(type: GetNamespace) {

The [functionalTests](https://github.com/bmuschko/gradle-kubernetes-plugin/tree/master/src/functionalTest/groovy/com/bmuschko/gradle/kubernetes/plugin/tasks) provide many examples that you can use for inspiration within your own code. If there are any questions about how to use a given feature feel free to open an issue and just ask.

## Additional Resources
## Kubernetes Resources
* [Kubernetes Client](https://github.com/fabric8io/kubernetes-client)
* [Kubernetes Setup](https://kubernetes.io/docs/setup/pick-right-solution/)
* [Release Process](https://github.com/bmuschko/gradle-kubernetes-plugin/blob/master/docs/RELEASE_PROCESS.md)
* [Reasons Kubernetes deployments fail: Part 1](https://kukulinski.com/10-most-common-reasons-kubernetes-deployments-fail-part-1/)
* [Reasons Kubernetes deployments fail: Part 2](https://kukulinski.com/10-most-common-reasons-kubernetes-deployments-fail-part-2/)
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ abstract class AbstractFunctionalTest extends Specification {
@Rule
TemporaryFolder temporaryFolder = new TemporaryFolder()

File defaultPodFile = new File(loadResource('/pods/nginx-pod.yaml').getFile())
File projectDir
File buildFile

Expand Down Expand Up @@ -141,4 +142,29 @@ abstract class AbstractFunctionalTest extends Specification {

return count;
}

// load an arbitrary file from classpath resource
public static URL loadResource(String resourcePath) {
this.getClass().getResource(resourcePath)
}

/**
* Copy and replace an arbitrary number of tokens in a given file. If no
* tokens are found then file is more/less just copied to new destination.
*
* @param source the source file we will replace tokens in
* @param destination the destination file we will write
* @param tokensToReplaceWithValues map where key=token-to-replace, value=value-to-replace-with
*/
public static void copyAndReplaceTokensInFile(File source, File destination, def tokensToReplaceWithValues = [:]) {
destination.withWriter { dest ->
source.eachLine { line ->
def localLine = line
tokensToReplaceWithValues.each { k, v ->
localLine = localLine.replaceAll(k, String.valueOf(v))
}
dest << localLine + System.getProperty('line.separator')
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.bmuschko.gradle.kubernetes.plugin.tasks.pods

import com.bmuschko.gradle.kubernetes.plugin.AbstractFunctionalTest
import org.gradle.testkit.runner.BuildResult

/**
*
* All functional tests for the `CreatePod` task.
*
*/
class CreatePodFunctionalTest extends AbstractFunctionalTest {

def defaultNamespace = 'default'

def "Create pod and execute reactive-streams"() {

def randomPod = randomString()

buildFile << """
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.CreatePod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.GetPod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.DeletePod
import java.util.concurrent.TimeUnit
task createPod(type: CreatePod) {
pod = "${randomPod}"
namespace = "${defaultNamespace}"
withLabels = ['name' : "${randomPod}-label"]
addContainer('nginx-container', 'nginx', 'IfNotPresent', 80, null)
onError { exc ->
logger.quiet "$SHOULD_NOT_REACH_HERE: exception=\${exc}"
}
onNext { output ->
logger.quiet "$SHOULD_REACH_HERE: next=\${output}"
}
onComplete {
logger.quiet '$ON_COMPLETE_REACHED'
}
doLast {
if (response()) {
logger.quiet '$RESPONSE_SET_MESSAGE'
}
}
}
task getPod(type: GetPod, dependsOn: createPod){
pod = "${randomPod}"
namespace = "${defaultNamespace}"
retry {
withDelay(30, TimeUnit.SECONDS)
withMaxRetries(6)
}
}
task deletePod(type: DeletePod){
pod = "${randomPod}"
namespace = "${defaultNamespace}"
gracePeriod = 5000
}
task workflow(dependsOn: getPod) {
finalizedBy deletePod
}
"""

when:
BuildResult result = build('workflow')

then:
result.output.contains('Creating pod...')
result.output.contains('Getting pod...')
result.output.contains('Deleting pod...')
result.output.contains(RESPONSE_SET_MESSAGE)
result.output.contains(SHOULD_REACH_HERE)
result.output.contains(ON_COMPLETE_REACHED)
!result.output.contains(SHOULD_NOT_REACH_HERE)
}

def "Create pod and execute reactive-streams with config"() {

def randomPod = randomString()

buildFile << """
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.CreatePod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.GetPod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.DeletePod
import java.util.concurrent.TimeUnit
task createPod(type: CreatePod) {
def labels = ['name' : "${randomPod}-label"]
config {
editOrNewMetadata()
.withName("${randomPod}")
.withNamespace("${defaultNamespace}")
.withLabels(labels)
.endMetadata()
}
addContainer('nginx-container', 'nginx', 'IfNotPresent', 80, null)
onError { exc ->
logger.quiet "$SHOULD_NOT_REACH_HERE: exception=\${exc}"
}
onNext { output ->
logger.quiet "$SHOULD_REACH_HERE: next=\${output}"
}
onComplete {
logger.quiet '$ON_COMPLETE_REACHED'
}
doLast {
if (response()) {
logger.quiet '$RESPONSE_SET_MESSAGE'
}
}
}
task getPod(type: GetPod, dependsOn: createPod){
pod = "${randomPod}"
namespace = "${defaultNamespace}"
retry {
withDelay(30, TimeUnit.SECONDS)
withMaxRetries(6)
}
}
task deletePod(type: DeletePod){
pod = "${randomPod}"
namespace = "${defaultNamespace}"
gracePeriod = 5000
}
task workflow(dependsOn: getPod) {
finalizedBy deletePod
}
"""

when:
BuildResult result = build('workflow')

then:
result.output.contains('Creating pod...')
result.output.contains('Getting pod...')
result.output.contains('Deleting pod...')
result.output.contains(RESPONSE_SET_MESSAGE)
result.output.contains(SHOULD_REACH_HERE)
result.output.contains(ON_COMPLETE_REACHED)
!result.output.contains(SHOULD_NOT_REACH_HERE)
}

def "Create pod from resource"() {

def randomPod = randomString()
def tokenMap = ['POD_NAME' : randomPod,
'CONTAINER_NAME' : "${randomPod}-container",
'PORT' : 80]
def destinationFile = new File(projectDir, 'temp-nginx-pod.yaml')
copyAndReplaceTokensInFile(defaultPodFile, destinationFile, tokenMap)

buildFile << """
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.CreatePod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.GetPod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.DeletePod
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.ListPods
import java.util.concurrent.TimeUnit
task createPod(type: CreatePod) {
resource = project.file("${destinationFile.path}")
namespace = "${defaultNamespace}"
onError { exc ->
logger.quiet "$SHOULD_NOT_REACH_HERE: exception=\${exc}"
}
onNext { output ->
logger.quiet "$SHOULD_REACH_HERE: next=\${output}"
}
onComplete {
logger.quiet '$ON_COMPLETE_REACHED'
}
doLast {
if (response()) {
logger.quiet '$RESPONSE_SET_MESSAGE'
}
}
}
task getPod(type: GetPod, dependsOn: createPod){
pod = "${randomPod}"
namespace = "${defaultNamespace}"
retry {
withDelay(30, TimeUnit.SECONDS)
withMaxRetries(6)
}
}
task listPods(type: ListPods, dependsOn: getPod) {
onError { exc ->
logger.quiet "$SHOULD_NOT_REACH_HERE: exception=\${exc}"
}
onNext { output ->
if (output.getMetadata().getName() == "${randomPod}") {
logger.quiet 'Found our POD'
}
}
}
task deletePod(type: DeletePod){
pod = "${randomPod}"
namespace = "${defaultNamespace}"
gracePeriod = 5000
}
task workflow(dependsOn: listPods) {
finalizedBy deletePod
}
"""

when:
BuildResult result = build('workflow')

then:
result.output.contains('Creating pod...')
result.output.contains('Getting pod...')
result.output.contains('Deleting pod...')
result.output.contains('Listing pods...')
result.output.contains('Found our POD')
result.output.contains(RESPONSE_SET_MESSAGE)
result.output.contains(SHOULD_REACH_HERE)
result.output.contains(ON_COMPLETE_REACHED)
!result.output.contains(SHOULD_NOT_REACH_HERE)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import org.gradle.testkit.runner.BuildResult
*
*/
class ListPodsFunctionalTest extends AbstractFunctionalTest {
/*

def "List pods, execute reactive-streams, with no config"() {
buildFile << """
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.ListPods
Expand Down Expand Up @@ -100,7 +100,7 @@ class ListPodsFunctionalTest extends AbstractFunctionalTest {
result.output.contains(ON_COMPLETE_REACHED)
result.output.contains(RESPONSE_SET_MESSAGE)
}
*/

def "List non-existent pods with config"() {
buildFile << """
import com.bmuschko.gradle.kubernetes.plugin.tasks.pods.ListPods
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
name: POD_NAME
labels:
name: nginx
name: nginx-label
spec:
containers:
- name: nginx
- name: CONTAINER_NAME
image: nginx
ports:
- containerPort: 80
- containerPort: PORT
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ trait CommonFunctions {
* @param args arguments to pass to potential method
* @return the output, or potentially new Object, created from calling the method
*/
def invokeMethod(final AtomicReference<Object> objectToInvoke, final String methodName, final Object... args) {
def static invokeMethod(final AtomicReference<Object> objectToInvoke, final String methodName, final Object... args) {
if (args != null) {
def localObject = objectToInvoke.get()
def metaMethod = localObject.metaClass.getMetaMethod(methodName, args)
Expand All @@ -69,14 +69,22 @@ trait CommonFunctions {
* @param methodName name of method to find and invoke
* @return the output, or potentially new Object, created from calling the method
*/
def invokeMethod(final AtomicReference<Object> objectToInvoke, final String methodName) {
def static invokeMethod(final AtomicReference<Object> objectToInvoke, final String methodName) {
invokeMethod(objectToInvoke, methodName, EMPTY_OBJECT_ARRAY)
}

/**
* Wrap an arbitrary Object in an AtomicReference
*/
def wrapAtomic(Object obj) {
def static wrapAtomic(Object obj) {
new AtomicReference<Object>(obj)
}

/**
* Random String prepended with, by default, the token `gkp-`
* which is shorthand for `gradle-kubernetes-plugin`.
*/
def static String randomString(def prependWith = 'gkp-') {
prependWith + UUID.randomUUID().toString().replaceAll("-", "")
}
}
Loading

0 comments on commit 8093bbf

Please sign in to comment.