# Simple Makefile to build base VM images using packer and ansible
# TODO
# * support ssh as user instead of root
# * testing target
PACKER = packer
ANSIBLE_DIR = ansible-roles
# check which hypervisors are available
ifeq ($(shell which qemu-system-$(shell uname -m | sed 's/i686/i386/') 2>&1 > /dev/null && echo $$?), 0)
AVAILABLE_BUILDERS += qemu
endif
ifeq ($(shell which virtualbox 2>&1 > /dev/null && echo $$?), 0)
AVAILABLE_BUILDERS += virtualbox-iso
endif
ifeq ($(shell which vmplayer 2>&1 > /dev/null && echo $$?), 0)
AVAILABLE_BUILDERS += vmware-iso
endif
ifndef BUILDER
$(info # BUILDER not set, using default builder: $(DEFAULT_BUILDER))
$(info # Detected builders: $(AVAILABLE_BUILDERS))
$(info )
BUILDER := $(firstword $(AVAILABLE_BUILDERS))
endif
##
# Templates and flavors detection
##
# The packer templates, detected as *.json (excluding base.json)
TEMPLATES := $(basename $(filter-out base.json,$(wildcard *.json)))
# The provisioning flavors, detected as ansible-roles/setup-<flavor>.yml
FLAVORS := $(patsubst $(ANSIBLE_DIR)/setup-%.yml,%, $(wildcard $(ANSIBLE_DIR)/setup-*.yml))
BASETARGETS := $(foreach template, $(TEMPLATES), $(template)/base)
PROVTARGETS := $(foreach template, $(TEMPLATES), $(foreach flavor, $(FLAVORS), $(template)/$(flavor)))
BOOTTARGETS := $(foreach template, $(TEMPLATES), $(template)/base/boot)
BOOTTARGETS += $(foreach prov, $(PROVTARGETS), $(prov)/boot)
PACKER_OPTS := -var-file=base.json
ifdef DEBUG
PACKER_OPTS += -debug
PACKER_OPTS += -var='headless=false'
endif
check_rootpw = $(if $(strip $(ROOTPW)),,$(error No root password is set, set it as ROOTPW in your environment.))
.PHONY: all help clean
all: help
##
# Creating base images
##
$(BASETARGETS):
$(call check_rootpw)
$(info ** Building template '$(@D)' using '$(BUILDER)' **)
$(PACKER) build -only=$(BUILDER) \
$(PACKER_OPTS) \
-var='vm_name=$(@D)' \
$(@D).json
@test -f output-$(@D)-$(BUILDER)/$(@D) || false
@-test -d $(@D)/base && rm -rf $(@D)/base
@-mkdir $(@D)
@mv output-$(@D)-$(BUILDER) $(@D)/base
@mv $(@D)/base/$(@D) $(@D)/base/image
@echo "** Success **"
##
# Provisioning images
##
# This should still only use base images
$(PROVTARGETS):
$(foreach flav, $(FLAVORS), %/$(flav)): %/base
$(call check_rootpw)
$(info ** Provisioning '$(@D)' with '$(@F)' **)
$(PACKER) build -only=$(BUILDER) \
$(PACKER_OPTS) \
-var='vm_name=$(@F)' \
-var='image_dir=$(@D)' \
-var='image_name=base/image' \
-var='playbook=setup-$(@F).yml' \
$(ANSIBLE_DIR)/run-playbook-only.json
@test -f output-$(@D)/$(@F) || false
@-test -d $(@D)/$(@F) && rm -rf $(@D)/$(@F)
@-mkdir $(@D)/$(@F)
@mv output-$(@D)/$(@F) $(@D)/$(@F)/image
@rmdir output-$(@D)
@echo "** Success **"
##
# Generating boot files
##
# This should use provisioned image
$(BOOTTARGETS):
%/boot: %
$(call check_rootpw)
$(info ** Generating boot files for '$(patsubst %/,%,$(dir $(@D))):$(notdir $(@D))' **)
$(PACKER) build -only=$(BUILDER) \
$(PACKER_OPTS) \
-var='vm_name=$(notdir $(@D)).tmp' \
-var='image_dir=$(patsubst %/,%,$(dir $(@D)))/$(notdir $(@D))' \
-var='image_name=image' \
-var='playbook=build-dracut-initramfs.yml' \
$(ANSIBLE_DIR)/run-playbook-only.json
@test -f $(ANSIBLE_DIR)/boot_files/initramfs || false
@-test -d $(patsubst %/,%,$(dir $(@D)))/$(notdir $(@D))/boot && \
rm -rf $(patsubst %/,%,$(dir $(@D)))/$(notdir $(@D))/boot
@mv $(ANSIBLE_DIR)/boot_files $(patsubst %/,%,$(dir $(@D)))/$(notdir $(@D))/boot
ifndef DEBUG
@rm -rf output-$(patsubst %/,%,$(dir $(@D)))/
endif
@echo "** Success **"
help:
@printf "Usage:\n\tmake <template>/<flavor>[/boot]\n"
@echo
@echo "Base images targets:"
@(for T in $(BASETARGETS); do printf "\t%s\n" "$$T"; done)
@echo
@echo "Provisioning images targets: "
@(for P in $(PROVTARGETS); do printf "\t%s\n" "$$P"; done)
@echo
@echo "Generate boot files targets:"
@printf "\t<provisioning_target>/boot\n"
# The builds are directories named after the template name
clean:
-$(foreach build_dir,$(TEMPLATES),test -d $(build_dir) && rm -rf $(build_dir);)