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

feat: step to check if a docker image exists #1077

Merged
merged 19 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from 12 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
4 changes: 4 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ execute the following from the directory at the root of this project:

`./mvnw test -Dtest=DummyStepTests`

To run one single test, execute the following from the directory at the root of
this project, separating test name from test file with an `#`:

`./mvnw test -Dtest=DummyStepTests#testName`
mdelapenya marked this conversation as resolved.
Show resolved Hide resolved

To run tests and print additional debug output to the console, use the `-Pdebug`
flag:
Expand Down
146 changes: 146 additions & 0 deletions src/test/groovy/DockerImageExistsStepTests.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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.

import org.junit.Before
import org.junit.Test
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertTrue

class DockerImageExistsStepTests extends ApmBasePipelineTest {

@Override
@Before
void setUp() throws Exception {
super.setUp()
helper.registerAllowedMethod('isInstalled', [Map.class], { return true })
script = loadScript('vars/dockerImageExists.groovy')
}

@Test
void testLinux_DockerIsNotInstalled() throws Exception {
helper.registerAllowedMethod('isInstalled', [Map.class], { return false })
try {
script.call(image: 'hello-world:latest')
} catch(e){
//NOOP
}
printCallStack()
assertTrue(assertMethodCallContainsPattern('error', 'Docker is not installed'))
assertJobStatusFailure()
}

@Test
void testLinux_ImageDoesNotExists() throws Exception {
helper.registerAllowedMethod('cmd', [Map.class], { m ->
if (m.script.contains('docker manifest inspect')) {
return 0
}
return 1
})
def ret = script.call(image: 'hello-world:latest')
printCallStack()
assertTrue(ret)
assertTrue(assertMethodCallContainsPattern('cmd', 'docker images -q hello-world:latest 2>/dev/null'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest does not exist in the Docker host: checking registry'))
assertTrue(assertMethodCallContainsPattern('cmd', 'docker manifest inspect hello-world:latest >/dev/null'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest exists in the Docker registry'))
assertJobStatusSuccess()
}

@Test
void testLinux_ImageExists() throws Exception {
helper.registerAllowedMethod('cmd', [Map.class], { m -> 0 })
def ret = script.call(image: 'hello-world:latest')
printCallStack()
assertTrue(ret)
assertTrue(assertMethodCallContainsPattern('cmd', 'docker images -q hello-world:latest 2>/dev/null'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest exists in the Docker host'))
assertJobStatusSuccess()
}

@Test
void testLinux_NotExists() throws Exception {
helper.registerAllowedMethod('cmd', [Map.class], { m -> 1 })
def ret = script.call(image: 'hello-world:latest')
printCallStack()
assertFalse(ret)
assertTrue(assertMethodCallContainsPattern('cmd', 'docker images -q hello-world:latest 2>/dev/null'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest does not exist in the Docker host: checking registry'))
assertTrue(assertMethodCallContainsPattern('cmd', 'docker manifest inspect hello-world:latest >/dev/null'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest does not exist at all'))
assertJobStatusSuccess()
}

@Test
void testWindows_DockerIsNotInstalled() throws Exception {
helper.registerAllowedMethod('isUnix', [], { false })
helper.registerAllowedMethod('isInstalled', [Map.class], { return false })
try {
script.call(image: 'hello-world:latest')
} catch(e){
//NOOP
}
printCallStack()
assertTrue(assertMethodCallContainsPattern('error', 'Docker is not installed'))
assertJobStatusFailure()
}

@Test
void testWindows_ImageDoesNotExists_Pull() throws Exception {
helper.registerAllowedMethod('isUnix', [], { false })
helper.registerAllowedMethod('cmd', [Map.class], { m ->
if (m.script.contains('docker manifest inspect')) {
return 0
}
return 1
})
def ret = script.call(image: 'hello-world:latest')
printCallStack()
assertTrue(ret)
assertTrue(assertMethodCallContainsPattern('cmd', 'docker images -q hello-world:latest 2>NUL'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest does not exist in the Docker host: checking registry'))
assertTrue(assertMethodCallContainsPattern('cmd', 'docker manifest inspect hello-world:latest >NUL'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest exists in the Docker registry'))
assertJobStatusSuccess()
}

@Test
void testWindows_ImageExists() throws Exception {
helper.registerAllowedMethod('isUnix', [], { false })
helper.registerAllowedMethod('cmd', [Map.class], { m -> 0 })
def ret = script.call(image: 'hello-world:latest')
printCallStack()
assertTrue(ret)
assertTrue(assertMethodCallContainsPattern('cmd', 'docker images -q hello-world:latest 2>NUL'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest exists in the Docker host'))
assertJobStatusSuccess()
}

@Test
void testWindows_NotExists() throws Exception {
helper.registerAllowedMethod('isUnix', [], { false })
helper.registerAllowedMethod('cmd', [Map.class], { m -> 1 })
def ret = script.call(image: 'hello-world:latest')
printCallStack()
assertFalse(ret)
assertTrue(assertMethodCallContainsPattern('cmd', 'docker images -q hello-world:latest 2>NUL'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest does not exist in the Docker host: checking registry'))
assertTrue(assertMethodCallContainsPattern('cmd', 'docker manifest inspect hello-world:latest >NUL'))
assertTrue(assertMethodCallContainsPattern('log', 'hello-world:latest does not exist at all'))
assertJobStatusSuccess()
}
}
9 changes: 9 additions & 0 deletions vars/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,15 @@ Generate the details URL to be added to the GitHub notifications. When possible
* tab: What kind of details links will be used. Enum type: tests, changes, artifacts, pipeline or an `<URL>`). Default `pipeline`.
* isBlueOcean: Whether to use the BlueOcean URLs. Default `false`.

## dockerImageExists
Checks if the given Docker image exists.

```
dockerImageExists(image: 'hello-world:latest')
```

* image: Fully qualified name of the image

## dockerLogin
Login to hub.docker.com with an authentication credentials from a Vault secret.
The vault secret contains `user` and `password` fields with the authentication details.
Expand Down
47 changes: 47 additions & 0 deletions vars/dockerImageExists.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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.

/**
Checks if the given Docker image exists.

whenTrue(dockerImageExists(image: 'hello-world:latest')) {
...
}
*/
def call(Map args = [:]) {
if (!isInstalled(tool: 'docker', flag: '--version')) {
error 'Docker is not installed'
}

def image = args.containsKey('image') ? args.image : error('dockerImageExists: image parameter is required')
mdelapenya marked this conversation as resolved.
Show resolved Hide resolved

def redirectStdout = isUnix() ? '2>/dev/null' : '2>NUL'
if (cmd(returnStatus: true, script: "docker images -q ${image} ${redirectStdout}") == 0) {
mdelapenya marked this conversation as resolved.
Show resolved Hide resolved
log(level: 'DEBUG', text: "${image} exists in the Docker host")
return true
}

redirectStdout = isUnix() ? '>/dev/null' : '>NUL'
log(level: 'DEBUG', text: "${image} does not exist in the Docker host: checking registry")
if (cmd(returnStatus: true, script: "docker manifest inspect ${image} ${redirectStdout}") == 0) {
log(level: 'DEBUG', text: "${image} exists in the Docker registry")
return true
}

log(level: 'DEBUG', text: "${image} does not exist at all")
return false
}
7 changes: 7 additions & 0 deletions vars/dockerImageExists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Checks if the given Docker image exists.

```
dockerImageExists(image: 'hello-world:latest')
```

* image: Fully qualified name of the image