Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added task CreatePod #20

Merged
merged 5 commits into from
Mar 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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