Skip to content

Commit

Permalink
Create a Github Action to run Molecule
Browse files Browse the repository at this point in the history
- Run Molecule in collection support
- Support GIT result as an external varifier
  • Loading branch information
titom73 committed Dec 16, 2020
0 parents commit 015e30b
Show file tree
Hide file tree
Showing 8 changed files with 356 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.retry
*/ansible_collections/*
.ansible*
.cache
requirements.txt
27 changes: 27 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright (c) 2019, Arista Networks
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
126 changes: 126 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/rista-netdevops-community/action-molecule-avd) ![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/avdteam/action-molecule) ![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/avdteam/action-molecule) ![Docker Cloud Automated build](https://img.shields.io/docker/cloud/automated/avdteam/action-molecule) ![Docker Pulls](https://img.shields.io/docker/pulls/avdteam/action-molecule) ![GitHub](https://img.shields.io/github/license/arista-netdevops-community/action-molecule-avd)

# Github Action for Molecule

First GitHub action allows you to run [Molecule](https://molecule.readthedocs.io/en/latest/) using [ansible collection](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) structure.

In addition, this GH action supports GIT status after Molecule execution to help to track unexpected file changes. This check can be enforced and generate a failure if a change is detected.

## Inputs

```yaml
---
molecule_parentdir:
description: Relative path where your molecule folder is.
required: no

molecule_options:
description: |
Supported options:
--debug / --no-debug Enable or disable debug mode. Default is disabled.
-c, --base-config TEXT Path to a base config. If provided Molecule will
load this config first, and deep merge each
scenario's molecule.yml on top.
-e, --env-file TEXT The file to read variables from when rendering
molecule.yml. (.env.yml)
--version Show the version and exit.
--help Show this message and exit.
required: false

molecule_command:
description: |
Supported commands:
check Use the provisioner to perform a Dry-Run...
cleanup Use the provisioner to cleanup any changes...
converge Use the provisioner to configure instances...
create Use the provisioner to start the instances.
dependency Manage the role's dependencies.
destroy Use the provisioner to destroy the instances.
idempotence Use the provisioner to configure the...
init Initialize a new role or scenario.
lint Lint the role.
list Lists status of instances.
login Log in to one instance.
matrix List matrix of steps used to test instances.
prepare Use the provisioner to prepare the instances...
side-effect Use the provisioner to perform side-effects...
syntax Use the provisioner to syntax check the role.
test Test (lint, cleanup, destroy, dependency,...
verify Run automated tests against instances.
required: true
default: 'test'

molecule_args:
description: |
Supported arguments:
--scenario-name foo Targeting a specific scenario.
--driver-name foo Targeting a specific driver.
--all Target all scenarios.
--destroy=always Always destroy instances at the conclusion of a Molecule run.
required: false

pip_file:
description: |
Relative path from `${GITHUB_REPOSITORY}` to install
any requirements prior to run molecule
required: false

check_git:
description: |
Check git status after molecule execution.
Help to track unexpected changes between 2 commits.
required: false

check_git_enforced:
description: |
If set to to true, then exit code is based on git status.
required: false
```
## Usage
To use the action simply create an main.yml (or choose custom *.yml name) in the .github/workflows/ directory.
Basic example:
```yaml
on: push

jobs:
molecule:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Run molecule action
uses: arista-netdevops-community/action-molecule-avd@v1.0
with:
molecule_parentdir: 'ansible_collections/arista/cvp'
molecule_command: 'test'
molecule_args: '--all'
pip_file: 'requirements.txt'
check_git: true
check_git_enforced: false
```
## Local testing
To test action execution locally, configure variables in a file:
```shell
# cat test.env
INPUT_PIP_FILE=requirements.txt
INPUT_MOLECULE_PARENTDIR=/root/ansible_collections/arista/cvp
INPUT_MOLECULE_COMMAND=test
INPUT_MOLECULE_ARGS=--all
```

Then run docker container:

```shell
docker run --rm -it \
-v ${PWD}:/root/ \ # Local content shared with container
-v /var/run/docker.sock:/var/run/docker.sock \ # Docker process required by molecule
--env-file dev.env \ # File with your variables
avdteam/action-molecule:v1.0
```
84 changes: 84 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
name: Ansible Molecule with collection support
description: Run Ansible Molecule with collection support
author: Thomas Grimonet <tgrimonet@arista.com>

branding:
icon: upload
color: green

inputs:
molecule_parentdir:
description: Relative path where your molecule folder is.
required: true
default: '.'

molecule_options:
description: |
Options:
--debug / --no-debug Enable or disable debug mode. Default is disabled.
-c, --base-config TEXT Path to a base config. If provided Molecule will
load this config first, and deep merge each
scenario's molecule.yml on top.
(/home/gofrolist/.config/molecule/config.yml)
-e, --env-file TEXT The file to read variables from when rendering
molecule.yml. (.env.yml)
--version Show the version and exit.
--help Show this message and exit.
required: false

molecule_command:
description: |
Commands:
check Use the provisioner to perform a Dry-Run...
cleanup Use the provisioner to cleanup any changes...
converge Use the provisioner to configure instances...
create Use the provisioner to start the instances.
dependency Manage the role's dependencies.
destroy Use the provisioner to destroy the instances.
idempotence Use the provisioner to configure the...
init Initialize a new role or scenario.
lint Lint the role.
list Lists status of instances.
login Log in to one instance.
matrix List matrix of steps used to test instances.
prepare Use the provisioner to prepare the instances...
side-effect Use the provisioner to perform side-effects...
syntax Use the provisioner to syntax check the role.
test Test (lint, cleanup, destroy, dependency,...
verify Run automated tests against instances.
required: true
default: 'test'

molecule_args:
description: |
Arguments:
--scenario-name foo Targeting a specific scenario.
--driver-name foo Targeting a specific driver.
--all Target all scenarios.
--destroy=always Always destroy instances at the conclusion of a Molecule run.
required: false

pip_file:
description: |
Relative path from `${GITHUB_REPOSITORY}` to install
any requirements prior to run molecule
required: false
default: ''

check_git:
description: |
Check git status after molecule execution.
Help to track unexpected changes between 2 commits.
required: false
default: 'false'

check_git_enforced:
description: |
If set to to true, then exit code is based on git status.
required: false
default: 'false'

runs:
using: docker
image: avdteam/action-molecule:v1.0
21 changes: 21 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM python:3.6-slim
# FROM avdteam/base:3.6

LABEL "maintainer"="Thomas Grimonet <tgrimonet@arista.com>"
LABEL "repository"="https://github.com/titom73/molecule-collection-actions"
LABEL "homepage"="https://github.com/titom73/molecule-collection-actions"

LABEL "com.github.actions.name"="molecule"
LABEL "com.github.actions.description"="Run Ansible Molecule"
LABEL "com.github.actions.icon"="upload"
LABEL "com.github.actions.color"="green"

RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential wget git curl && \
curl -fsSL https://get.docker.com | sh
RUN pip install --upgrade pip molecule molecule-docker
ADD molecule-runner.sh /bin/molecule-runner.sh

WORKDIR /projects

ENTRYPOINT ["sh", "-c", "/bin/molecule-runner.sh"]
22 changes: 22 additions & 0 deletions docker/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
CURRENT_DIR = $(shell pwd)
DOCKER_NAME ?= molecule-actions
DOCKER_BASE ?= titom73
DOCKER_TAG ?= latest
DOCKER_DIR ?= .

.PHONY: help
help: ## Display help message
@grep -E '^[0-9a-zA-Z_-]+\.*[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: build
build: ## Build docker image
docker build -t $(DOCKER_BASE)/$(DOCKER_NAME):$(DOCKER_TAG) $(DOCKER_DIR)

.PHONY: run
run: ## run docker image
docker run --rm -it -v ${PWD}:/projects -v /var/run/docker.sock:/var/run/docker.sock --env-file dev.env $(DOCKER_BASE)/$(DOCKER_NAME):$(DOCKER_TAG)

.PHONY: exec
exec: ## exec docker image
docker run --rm -it \
$(DOCKER_BASE)/$(DOCKER_NAME):$(DOCKER_TAG) ash
7 changes: 7 additions & 0 deletions docker/dev.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

INPUT_PIP_FILE=requirements.txt
INPUT_MOLECULE_PARENTDIR=ansible_collections/arista/avd
INPUT_MOLECULE_COMMAND=test
INPUT_MOLECULE_ARGS=--scenario-name eos_cli_config_gen
INPUT_CHECK_GIT=true
INPUT_CHECK_GIT_ENFORCED=false
64 changes: 64 additions & 0 deletions docker/molecule-runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/bin/sh
#
# Purpose: Molecule runner for github-action
# Author: @titom73
# Date: 2020-12-16
# Version: 1.0
# License: APACHE
# --------------------------------------


# export PATH=$(echo "$PATH" | sed -e 's/:\/home\/avd\/.local\/bin//')
echo "Script running from ${PWD}"

# If user define any requirements file in options, we install them
if [ ${INPUT_PIP_FILE} != '' ] 2> /dev/null && [ -f ${INPUT_PIP_FILE} ]; then
echo 'installing custom requirements file ...'
echo 'PIP file is set to : '${INPUT_PIP_FILE}
# Workaround for https://github.com/ansible/ansible/issues/70348
pip install --upgrade -r ${INPUT_PIP_FILE}
if grep -Fxq 'ansible' "${INPUT_PIP_FILE}"; then
pip install --upgrade --yes ansible
fi
else
pip install --upgrade ansible
fi

export MOLECULE_BIN=$(which molecule)

# Set default value for where to find MOLECULE folder
cd ${INPUT_MOLECULE_PARENTDIR}
echo "Current working dir: $PWD"

# Run Molecule scenario
echo "Running: molecule ${INPUT_MOLECULE_OPTIONS} ${INPUT_MOLECULE_COMMAND} ${INPUT_MOLECULE_ARGS}"
${MOLECULE_BIN} --version
${MOLECULE_BIN} ${INPUT_MOLECULE_OPTIONS} ${INPUT_MOLECULE_COMMAND} ${INPUT_MOLECULE_ARGS}

if [ ${INPUT_CHECK_GIT} = "true" ]; then
git config core.fileMode false
echo " * Run Git Verifier because CHECK_GIT is set to ${INPUT_CHECK_GIT}"
# if git diff-index --quiet HEAD --; then
if [ -n "$(git status --porcelain)" ]; then
# No changes
echo 'Some changes'
echo '------------'
git --no-pager status --short
echo ''
echo 'Diffs are:'
echo '------------'
git --no-pager diff
if [ ${INPUT_CHECK_GIT_ENFORCED} = "true" ]; then
exit 1
else
exit 0
fi
else
# No Changes
echo ' - No change found after running Molecule'
exit 0
fi
exit 0
else
echo " * Git verifier skipped as not set to true"
fi

0 comments on commit 015e30b

Please sign in to comment.