You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
17 KiB
Makefile

################################################################################
# includes
################################################################################
# Not sure why this was needed. Without this dummy target the include was
# causing the `check-%` target to get hit.
check-defined.mk: ;@:
include common/makefiles/check-defined.mk
################################################################################
# end includes
################################################################################
################################################################################
# environment variables
################################################################################
# The location of the ansible inventory file.
INVENTORY ?= inventory
# Variables for some of the common docker images we use for tests.
UBUNTU_20_04_DOCKER_IMAGE ?= docker.shnee.net/docker-hub/library/ubuntu:20.04
UBUNTU_22_04_DOCKER_IMAGE ?= docker.shnee.net/docker-hub/library/ubuntu:22.04
MOLECULE_DOCKER_IMAGES ?= $(UBUNTU_22_04_DOCKER_IMAGE)
# The number of platforms to run a molecule scenario in parallel. This means
# that if MOLECULE_DOCKER_IMAGES is set to 'ubi7 ubi8 fedora' and
# CONCURRENT_MOLECULE_PLATFORMS is set to 2, then the firt iteration of the
# scenarion will be run with 'ubi7 ubi8' and a second iteration will be run with
# 'fedora'.
CONCURRENT_MOLECULE_PLATFORMS ?= 999
# This variable will hold a subset of MOLECULE_DOCKER_IMAGES that holds the
# platforms to be used for the current iteration of the molecule scenario.
CURRENT_MOLECULE_PLATFORMS ?=
# You can set this to a file containing the password for your vaults so you
# don't have to enter the password in everytime. This variable should not be
# committed with a value.
VAULT_PASSWD_FILE ?=
ifdef VAULT_PASSWD_FILE
VAULT_PASSWD_ENV = ANSIBLE_VAULT_PASSWORD_FILE=$(VAULT_PASSWD_FILE)
endif
REPO_ENV_VARS ?=
ENV_VARS = PY_COLORS=1 \
ANSIBLE_FORCE_COLOR=1 \
MOLECULE_PLATFORMS="$(call molecule-platforms)" \
$(VAULT_PASSWD_ENV) \
$(REPO_ENV_VARS)
# This target can be used to set environment variables in your local
# environment. Run this to set the necessary environment variables:
# eval $(make -s env-vars)
#
# TODO VAULT_PASSWD_ENV and REPO_ENV_VARS can't be handled like the other
# environment variables. For VAULT_PASSWD_ENV you have to conditionally do
# the 'export' if the variable is defined. For REPO_ENV_VARS you have to
# iterate over each key-value pairs in the variable.
.PHONY: env-vars
env-vars:
$(ENV_VARS) sh -c 'printf "\n\
export PY_COLORS=$$PY_COLORS\n\
export ANSIBLE_FORCE_COLOR=$$ANSIBLE_FORCE_COLOR\n\
export MOLECULE_PLATFORMS=\"$$MOLECULE_PLATFORMS\"\n\
"'
# TODO update comment
# The pip packages to install when doing offline pypi installs.
PIP_PKGS ?= ansible ansible-lint docker
# This makefile will attempt to use sudo when needed. In case you're running on
# a system without sudo go and unset this variable.
#
# The '-i' flag is really only needed to use the SCL sandbox stuff, but it
# doesn't hurt to leave it on all the time?
SUDO ?= sudo -i
ROLE_NAME ?= $(shell basename $$PWD | sed 's/_/-/g')
################################################################################
# end environment variables
################################################################################
# The URL to use for libvirt.
# TODO REM don't commit this specific qemu host.
# LIBVIRT_DEFAULT_URI ?= qemu:///system
LIBVIRT_DEFAULT_URI ?= qemu+ssh://shnee@rita/system
VIRSH ?= virsh --connect $(LIBVIRT_DEFAULT_URI)
################################################################################
# functions
################################################################################
run-molecule = $(ENV_VARS) LIBVIRT_DEFAULT_URI=$(LIBVIRT_DEFAULT_URI) \
MOLECULE_DOCKER_IMAGE=$(MSS_CI_DOCKER_IMAGE) \
molecule $1 -s $2 $(DEBUG_ARGS)
# This returns a json formatted string to be used as a value for the `platforms`
# field in a `molecule.yml` docker scenario.
molecule-platforms = $(shell \
printf "[ " && \
for image in $(MOLECULE_DOCKER_IMAGES); do \
printf $(call docker-image-to-molecule-platform-json,$$image)", "; \
done | sed 's/, $$//' && \
printf " ]" \
)
get-num-of-molecule-docker-images = $(shell \
echo $(MOLECULE_DOCKER_IMAGES) | wc --word)
get-num-of-molecule-iterations = $(shell \
echo $$(( ( $(call get-num-of-molecule-docker-images) / \
$(CONCURRENT_MOLECULE_PLATFORMS) ) + \
( ( $(call get-num-of-molecule-docker-images) % \
$(CONCURRENT_MOLECULE_PLATFORMS) ) != 0 ) )))
# TODO relies on 'iter' being set by caller.
get-current-molecule-platforms = \
export START=$$(( $(CONCURRENT_MOLECULE_PLATFORMS) * $$iter )) && \
export STOP=$$(( $$START + $(CONCURRENT_MOLECULE_PLATFORMS) )) && \
export INDEX=0 && \
export CURR_PLATFORMS="" && \
for image in $(MOLECULE_DOCKER_IMAGES); do \
if [ $$INDEX -ge $$START ] && [ $$INDEX -lt $$STOP ]; then \
CURR_PLATFORMS="$${CURR_PLATFORMS}$$image " ; \
fi ; \
INDEX=$$(( $$INDEX+1 )) ; \
done && \
echo $$CURR_PLATFORMS
# Returns a json formatted string representing a molecule platform. This
# function takes a single parameter that is the docker images to be used. This
# function derives the 'name' field from the docker image. It strips the path
# and tag to give it a name, ie. github/user/cool-image:tag becomes
# 'cool-image'.
#
# NOTE: Single quotes are fine when the string is loaded by ansible, however, if
# the string is to be used in a jinja template combined with the from_json
# filter then you must use double quotes. To ensure that the double quotes
# persist you have to do alot of escaping. Each single quote needs to be
# replaced by `\\\\\"'.
# TODO REM this isn't good enough, we probably need to incorporate the tag in
# the name as well.
docker-image-to-molecule-platform-json = \
"{ 'name': '$(ROLE_NAME)-molecule-$(call \
molecule-platform-to-image-name-sed-command,$1)', \
'image': '$1', \
'pre_build_image': true }"
molecule-platform-to-image-name-sed-command = $$( echo $1 | \
sed 's/^.*\///' | sed 's/:.*$$//' )
run-molecule-per-docker-image = \
for image in $(MOLECULE_DOCKER_IMAGES) ; do \
$(call run-molecule,$1,$2,$$image) ; done
get-scenarios = \
$(shell find molecule -name molecule.yml | \
sed 's/molecule\/\([^\/]*\).*/\1/g')
scenario-targets = \
$(shell export PREFIXES="test- create- destroy- converge- verify- \
idempotence- check-" && \
for prefix in $$PREFIXES ; do \
for scen in $(SCENARIOS) ; do \
echo $$prefix$$scen ; done ; done && \
export PREFIXES="login- list-snapshots- apply-snapshot- \
revert-snapshot- list-current-snapshot- \
delete-snapshot-" && \
for prefix in $$PREFIXES ; do \
for scen in $(VAGRANT_SCENARIOS) ; do \
echo $$prefix$$scen ; done ; done )
scenario-targets-wrapped = \
$(shell echo $(call scenario-targets) | \
fmt -w 79 | \
sed 's/\(.\)\?$$/\1:/g' )
print-scenario-targets:
@echo $(call scenario-targets) | \
sed 's/ /\n/g' | \
awk '{ print $$1 ":" }'
print-scenario-targets-wrapped:
@echo $(call scenario-targets) | \
fmt -w 79 | \
sed 's/\(.\)\?$$/\1:/g'
# Returns the molecule driver used by the passed in scenario, ie.
# $(call get-driver,default)
# returns: docker
get-driver = \
$(shell molecule list -f plain 2> /dev/null | \
grep "^\([-[:alnum:]]\+\s\+\)\{3\}$1" | \
awk '{ print $$2 }' )
get-driver-scenarios = \
$(shell $(ENV_VARS) molecule list -f plain 2> /dev/null | \
grep "^\([-[:alnum:]]\+\s\+\)$1" | \
awk '{ print $$4 }' | \
sort | \
uniq)
get-scenario-molecule-yaml-file = $(shell echo molecule/$1/molecule.yml)
get-scenario-platforms = \
$(shell cat $(call get-scenario-molecule-yaml-file,$1) | \
yq '.platforms[] | .name' | \
sed 's/"//g' )
get-scenario-first-platform = \
$(shell echo $(call get-scenario-platforms,$1) | \
awk '{print $$1}' )
list-scenario-snapshots = \
$(shell echo $(call get-scenario-platforms,$1) | \
awk '{ print "$(VIRSH) snapshot-list --tree $1_" $$1 }' )
space-separated-list-to-json-string-array = \
$(shell echo $1 | \
sed 's/\(\S\+\)/"\1"/g' | \
sed 's/ /, /g' | \
awk '{ print "[ " $$0 " ]" }' )
define driver-scenario-check
@export SCEN=$1 && \
export EXP_DRIVER=$2 && \
export DRIVER=$(call get-driver,$1) && \
if ! [ $$DRIVER == $$EXP_DRIVER ]; then \
echo "ERROR: Expecting driver $$EXP_DRIVER, but scenario $$SCEN uses $$DRIVER."; \
exit 1; \
fi
endef
define get-vm-name
$(shell $(call driver-scenario-check,$1,vagrant) && \
echo $1_$2 )
endef
################################################################################
# End Functions
################################################################################
SCENARIOS := $(call get-scenarios)
VAGRANT_SCENARIOS := $(call get-driver-scenarios,vagrant)
DRIVER=
DEBUG_ARGS =
################################################################################
# Targets
################################################################################
list-scenarios:
@echo $(SCENARIOS)
# TODO This can probably be changed to '--debug' flag to molecule.
# TODO this also only works with molecule because of the '--'
debug:
$(eval DEBUG_ARGS=-- -vvv)
################################################################################
# Run multiple tests at once.
################################################################################
.PHONY: test test-all test-all-docker test-all-ec2 test-all-vagrant
test: test-all
test-all: test-all-docker test-all-ec2 test-all-vagrant
test-all-docker:
for scenario in $(call get-driver-scenarios,docker) ; do \
$(MAKE) test-$$scenario ; done
test-all-ec2:
for scenario in $(call get-driver-scenarios,ec2) ; do \
$(MAKE) test-$$scenario ; done
test-all-vagrant:
for scenario in $(call get-driver-scenarios,vagrant) ; do \
$(MAKE) test-$$scenario ; done
################################################################################
# End Run multiple tests at once.
################################################################################
lint:
$(ENV_VARS) molecule lint
verify-scenario-%:
@# If the '%' is not in $(SCENARIOS) then this is not a valid scenario,
@# therefore we exit with an error message.
@export FOUND=0 && \
for scen in $(SCENARIOS) ; do \
if [ $$scen == $* ]; then \
export FOUND=1 ; fi ; done && \
if [ $$FOUND == 0 ]; then \
echo "ERROR: $* is not a valid scenario. Valid scenarios are: \
$(SCENARIOS)"; \
exit 1 ; fi
test-%: verify-scenario-%
# $(call run-molecule,test,$*)
@for (( iter=0; \
iter<$(call get-num-of-molecule-iterations); \
iter++ )); do \
make MOLECULE_DOCKER_IMAGES="$$($(call get-current-molecule-platforms))" iter-test-$*; \
if [ $$? != 0 ]; then \
exit 1; \
fi \
done
iter-test-%: verify-scenario-%
$(call run-molecule,test,$*)
create-%: verify-scenario-%
$(call run-molecule,create,$*)
converge-%: verify-scenario-%
$(call run-molecule,converge,$*)
idempotence-%: verify-scenario-%
$(call run-molecule,idempotence,$*)
check-%: verify-scenario-%
$(call run-molecule,check,$*)
verify-%: verify-scenario-%
$(call run-molecule,verify,$*)
destroy-%: verify-scenario-%
$(call run-molecule,destroy,$*)
status:
$(ENV_VARS) molecule list
list-vms:
$(VIRSH) list
login-%: verify-scenario-%
@$(call driver-scenario-check,$*,vagrant)
molecule login -s $*
list-snapshots-%: verify-scenario-%
$(call driver-scenario-check,$*,vagrant)
$(call list-scenario-snapshots,$*)
list-current-snapshot-%: verify-scenario-%
$(call driver-scenario-check,$*,vagrant)
$(VIRSH) snapshot-info --current \
$*_$(call get-scenario-first-platform,$*)
# TODO It looks like apply, revert, and delete could be combined.
apply-snapshot-%: verify-scenario-%
@$(call driver-scenario-check,$*,vagrant)
@if [ -z "$(SNAP_NAME)" ]; then \
echo "ERROR: You must define both SNAP_NAME when running \
apply-snapshot. Got SNAP_NAME: $(SNAP_NAME)."; \
exit 1; \
fi
for host in $(call get-scenario-platforms,$*) ; do \
$(VIRSH) snapshot-create-as $*_$$host $(SNAP_NAME) \"$(SNAP_DESC)\"; \
done
revert-snapshot-%: verify-scenario-%
@$(call driver-scenario-check,$*,vagrant)
@if [ -z "$(SNAP_NAME)" ]; then \
echo "ERROR: You must define both SNAP_NAME when running \
apply-snapshot. Got SNAP_NAME: $(SNAP_NAME)."; \
exit 1; \
fi
for host in $(call get-scenario-platforms,$*) ; do \
$(VIRSH) snapshot-revert $*_$$host $(SNAP_NAME) ; \
done
delete-snapshot-%: verify-scenario-%
@$(call driver-scenario-check,$*,vagrant)
@if [ -z "$(SNAP_NAME)" ]; then \
echo "ERROR: You must define both SNAP_NAME when running \
apply-snapshot. Got SNAP_NAME: $(SNAP_NAME)."; \
exit 1; \
fi
for host in $(call get-scenario-platforms,$*) ; do \
$(VIRSH) snapshot-delete $*_$$host $(SNAP_NAME) ; \
done
# TODO REM these are realyl just the const for templates.
ANSIBLE_CONST_ARGS ?= all \
-i localhost, \
-m template \
--connection=local
# TODO make a target that updates all files that make generates to update all of
# those files.
# TODO Combine all these simple templates into a single function.
# TODO had to comment this out. Does this target run evrytime?
Makefile: common/templates/template-disclaimer.j2
Makefile: common/makefiles/templates/main-repo-makefile.j2
$(eval TEMPLATE_FILES = \
$(call space-separated-list-to-json-string-array,$^))
export TARGETS=$$(echo $(call scenario-targets) | \
fmt -w 79 | \
sed 's/\(.\)\?$$/\1:/g' ) && \
ansible $(ANSIBLE_CONST_ARGS) \
-e '{template_files: $(TEMPLATE_FILES)}' \
-e "template_disclaimer={{ \
lookup('ansible.builtin.template', \
'common/templates/template-disclaimer.j2') }}" \
-e 'generated_make_targets="'"$$TARGETS"'"' \
-a "src=$< dest=$(PWD)/$@"
cat $@
ansible.cfg: common/templates/template-disclaimer.j2
ansible.cfg: common/templates/default-ansible.cfg.j2
$(eval TEMPLATE_FILES = \
$(call space-separated-list-to-json-string-array,$^))
ansible $(ANSIBLE_CONST_ARGS) \
-e '{template_files: $(TEMPLATE_FILES)}' \
-e "template_disclaimer={{ \
lookup('ansible.builtin.template', \
'common/templates/template-disclaimer.j2') }}" \
-a "src=$< dest=$(PWD)/$@"
cat $@
.ansible-lint: common/templates/template-disclaimer.j2
.ansible-lint: common/templates/default-ansible-lint.j2
$(eval TEMPLATE_FILES = \
$(call space-separated-list-to-json-string-array,$^))
ansible $(ANSIBLE_CONST_ARGS) \
-e '{template_files: $(TEMPLATE_FILES)}' \
-e "template_disclaimer={{ \
lookup('ansible.builtin.template', \
'common/templates/template-disclaimer.j2') }}" \
-a "src=$< dest=$(PWD)/$@"
cat $@
.yamllint: common/templates/template-disclaimer.j2
.yamllint: common/templates/default-yamllint.j2
$(eval TEMPLATE_FILES = \
$(call space-separated-list-to-json-string-array,$^))
ansible $(ANSIBLE_CONST_ARGS) \
-e '{template_files: $(TEMPLATE_FILES)}' \
-e "template_disclaimer={{ \
lookup('ansible.builtin.template', \
'common/templates/template-disclaimer.j2') }}" \
-a "src=$< dest=$(PWD)/$@"
cat $@
README.md: common/templates/template-disclaimer.j2
README.md: common/templates/role-testing.txt
README.md: docs/templates/README.md.j2
$(eval TEMPLATE_FILES = \
$(call space-separated-list-to-json-string-array,$^))
export COMMON_TEST_DOCS="$$(cat common/templates/role-testing.txt)" && \
ansible $(ANSIBLE_CONST_ARGS) \
-e "common_test_docs=\"$$COMMON_TEST_DOCS\"" \
-e '{template_files: $(TEMPLATE_FILES)}' \
-e "template_disclaimer={{ \
lookup('ansible.builtin.template', \
'common/templates/template-disclaimer.j2') }}" \
-a "src=$< dest=$(PWD)/$@"
cat $@
.PHONY: help
help:
@echo "TODO This help is still a WIP it\'s missing targets."
@echo ""
@echo "test - Runs all scenarios (tests)"
@echo "test-all-docker - Run all the scenarios that use the docker driver."
@echo "test-all-ec2 - Run all the scenarios that use the EC2 driver."
@echo "test-all-vagrant - Run all the scenarios that use the vagrant driver. These"
@echo " scenarios require that the user has a KVM/qemu hypervisor"
@echo " installed."
# TODO I dont remember if this is still needed.
.SUFFIXES: