summaryrefslogblamecommitdiffstats
path: root/Makefile
blob: b6d4cb87c46ee65c36393ded7cea59475b8cc1d2 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                                  
                                         
                    

                            
 
                        
 

                                                    
 




                                              
 

                                         
 





                                                                  
 
                                                 
     
 
 
                                                                
                                                                   
 

                                                                                           





                                                                                                      
 
                                      
           
                    
                         
     
 


                                        
 


                                                                               

                                               
 








                                                                               




                                                                                                     



         

                                           
                                           
            

                                              










                                                         
            
     
 
 
                                                    
     
 
 
                      
               


                                                                  
                                             
                                                    
                          
                                                                   
 
 
                     

                                              
                                                     
                                                       

                                                         
                                                      
                                          
                                
                                             

                                                            
                                                 
                                                                  
 
 
                       

               

                                                           

                                          
                                                 

                                                                   
                                                            

                                                                          
                                                      
 
 









                                                                                                               
 



                                                                
 




                                                           
     
                                                             
             
                                    
                                                                
             
                                             
                                                                
             
                                            
                                                       

                                      








                                                                                          
# 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

HASHER      ?= sha256sum

SHELL      := /usr/bin/env bash
ARCH       := $(shell uname -m | sed 's/i686/i386/')

BUILDER_QEMU_EXE        := qemu-system-$(ARCH)
BUILDER_QEMU_NAME       := qemu

BUILDER_VMWARE_EXE      := vmware
BUILDER_VMWARE_NAME     := vmware-iso

BUILDER_VIRTUALBOX_EXE  := virtualbox
BUILDER_VIRTUALBOX_NAME := virtualbox-iso

BUILDERS                := QEMU VMWARE VIRTUALBOX

ifndef BUILDER
    $(foreach cur, $(BUILDERS),\
        $(if $(shell command -v $(BUILDER_$(cur)_EXE)),\
            $(eval AVAILABLE_BUILDERS += $(BUILDER_$(cur)_NAME))))

    BUILDER := $(firstword $(AVAILABLE_BUILDERS))
endif


# 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
    VERBOSE     := 1
    PACKER_OPTS += -debug
endif

ifdef WINDOW
    PACKER_OPTS += -var='headless=false'
endif

# We support parallel Provisioning packer builds.
# To ensure data consistency we save the used ansible roles before executing in
# its own environment, tagged by the current date & time.
TIMESTAMP := $(shell date "+%Y-%m-%d_%H-%M-%S")


# The ROOTPW is only needed for the base, boot and provisioning targets.
# In every other case it must not be checked as it should be possible to call
# help or cleanup without the need of defining the password.
PW_NEEDED := $(filter $(strip $(PROVTARGETS) $(BOOTTARGETS)),$(MAKECMDGOALS))
ifneq ($(PW_NEEDED),)
    ifeq ($(strip $(ROOTPW)),)
        $(error No root password is set, set it as ROOTPW in your environment.)
    else
        $(foreach cur,$(PW_NEEDED),\
            $(eval cur_dir := $(firstword $(subst /, ,$(cur)))/base)\
            $(if $(shell test -d "$(cur_dir)" && echo yes),\
                $(shell echo "$(ROOTPW)" | $(HASHER) --check --status "$(cur_dir)/rootpw.$(HASHER)")\
                $(if $(filter 1,$(.SHELLSTATUS)),\
                    $(error The wrong ROOTPW is set. Please correct it))))
    endif
endif


ifdef VERBOSE
    $(info root password:        $(ROOTPW))
    $(info hasher:               $(HASHER))
    $(info )
    $(info timestamp:            $(TIMESTAMP))
    $(info )
    $(info packer: executable:   $(PACKER))
    $(info packer: options:      $(PACKER_OPTS))
    $(info )
    $(info ansible: directory:   $(ANSIBLE_DIR))
    $(info )
    $(info builder: available:   $(AVAILABLE_BUILDERS))
    $(info builder: chosen:      $(BUILDER))
    $(info )
    $(info targets: base:        $(strip $(BASETARGETS)))
    $(info targets: boot:        $(strip $(BOOTTARGETS)))
    $(info targets: provision:   $(strip $(PROVTARGETS)))
    $(info )
endif


.PHONY: help clean_except_last clean_bases clean_all
help:


# Creating base images
$(BASETARGETS):
	$(info ** Building template '$(@D)' using '$(BUILDER)' **)
	$(PACKER) build -only=$(BUILDER) \
		$(PACKER_OPTS) \
		-var='vm_name=rootfs-image' \
		-var='output_directory=$(@D)/base' \
		$(@D).json
	@echo "$(ROOTPW)" | $(HASHER) > $(@D)/base/rootpw.$(HASHER)


# Provisioning images
$(PROVTARGETS):
$(foreach flav, $(FLAVORS), %/$(flav)): %/base
	$(eval BUILD_DIR := $(@D)/$(@F).$(TIMESTAMP))
	$(info ** Provisioning '$(@D)' with '$(@F)' **)
	@mkdir -p $(BUILD_DIR)
	@cp -r $(ANSIBLE_DIR) $(BUILD_DIR)/$(ANSIBLE_DIR)
	@ln -sfn $(@F).$(TIMESTAMP) $(@D)/$(@F).latest
	$(PACKER) build -only=$(BUILDER) \
		$(PACKER_OPTS) \
		-var='vm_name=rootfs-image' \
		-var='output_directory=$(BUILD_DIR)/build' \
		-var='base_image=$(@D)/base/rootfs-image' \
		-var='playbook=setup-$(@F).yml' \
		$(BUILD_DIR)/$(ANSIBLE_DIR)/run-playbook-only.json


# Generating boot files
$(BOOTTARGETS):
%/boot: %
	$(eval BUILD_DIR := $(@D).$(TIMESTAMP))
	$(info ** Generating boot files for '$(BUILD_DIR)')
	$(PACKER) build -only=$(BUILDER) \
		$(PACKER_OPTS) \
		-var='vm_name=rootfs-image.tmp' \
		-var='output_directory=$(BUILD_DIR)/build/tmp' \
		-var='base_image=$(BUILD_DIR)/build/rootfs-image' \
		-var='playbook=build-dracut-initramfs.yml' \
		$(BUILD_DIR)/$(ANSIBLE_DIR)/run-playbook-only.json
	@mv $(BUILD_DIR)/$(ANSIBLE_DIR)/boot_files $(BUILD_DIR)/build/boot
	$(if $(DEBUG),,@rm -rf $(BUILD_DIR)/build/tmp)


clean_except_last:
	@-$(foreach template,$(TEMPLATES),\
		$(foreach flavor,$(FLAVORS),\
			test -d $(template) && \
				find $(template)/* -maxdepth 0 -type d \
					-not -name base \
					-not -wholename $(template)/$$(readlink $(template)/$(flavor).latest) \
					-print0 | xargs -0 rm -rf \
		);\
	)

clean_bases:
	@-$(foreach template,$(TEMPLATES),\
		test -d $(template) && rm -rf $(template)/base;\
	)

clean_all:
	@-$(foreach template,$(TEMPLATES),\
		test -d $(template) && rm -rf $(template);\
	)

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<{base,provisioning}_target>/boot\n"
	@echo
	@echo "Available options are:"
	@printf "\tANSIBLE_DIR: Set directory with ansible roles   (def: ansible-roles)\n"
	@printf "\tBUILDER:     Set a builder, do not autodetect\n"
	@printf "\tDEBUG:       Enable debug mode in packer        (includes VERBOSE)\n"
	@printf "\tHASHER:      Set wanted hasher                  (def: sha256sum)\n"
	@printf "\tPACKER:      Set packer executable              (def: packer)\n"
	@printf "\tPACKER_OPTS: Set packer options\n"
	@printf "\tROOTPW:      Set root password for output image\n"
	@printf "\tVERBOSE:     Enable verbose output\n"
	@printf "\tWINDOW:      Disable headless mode\n"