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

                                                                  
                                         
                    





                                          
 
                                                              
 



                                            
 
                            
 

                            
 
                                                                































                                                                                                
 
           
                




                                             
     
 


                                  
 
            
                                               
     
 
                                               
 


                                                                               

                                               
             

                                              

                                                
                                           
            

                                                     



                                                       



                                                  
            
                                             
     
 
                                                                                              
     
 


                                                                            
               
                                                                  







                                                                        

                                                                           
 
                     
             

                                







                                                                                                        
                                                           
                              
                                                                                 
                                                                        
                                                                           









                                                                                         


                                                      
 
                       


                                 












                                                                                                  
                                                           







                                                                          
                  
                                   
                                                                 
                                                
 


                        

                                               


                           


                                                                                                                              

                                                         
 






                                                                                               
 

                                           
                                                                     




                                                                                                             
                                        






                                                                                   
 


                                           






                                                                                  
 

                                           
                                                                
 

                                           
                                                           
 
     
                                                             

                                        
                                                                

                                                
                                                                
                                                                  

                                                
                                                       

                                                                  
                                                                    

                                                
                                 











                                                                                                                      
                                                                                                          

                                      



                                       
# 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_BOOT     ?= ansible-dracut
ANSIBLE_DIR_PROV     ?= ansible-roles-prov
HASHER               ?= sha256sum
SHELL                := /usr/bin/env bash
BUILDS               := builds

ARCH                 := $(shell uname -m | sed 's/i686/i386/')

AVAILABLE_BUILDERS   := QEMU
BUILDER_QEMU_EXE     := qemu-system-$(ARCH)
BUILDER_QEMU_NAME    := qemu
BUILDER_QEMU_PROV    := $(BUILDER_QEMU_NAME)

BUILDERS             := qemu

override BUILDER     := qemu
override PROVISIONER := qemu

# The packer templates, detected as *.json (excluding base.json)
TEMPLATES :=        $(patsubst %/,%,$(dir $(wildcard */base.pkrvars.hcl)))

# The provisioning flavors, detected as ansible-<flavor>/setup-<flavor>.yml
# Find all paths beginnig with "ansible-" and and save this suffix in PATTERNS
PATTERNS :=         $(patsubst ansible-%, %, $(wildcard ansible-*))
# Extract <flavor> from ansible-<flavor>/setup-<flavor>.yml using PATTERNS as <flavor>
FLAVORS :=          $(foreach p, $(PATTERNS), \
                        $(patsubst ansible-$(p)/setup-$(p).yml, $(p), \
                            $(wildcard ansible-$(p)/setup-$(p).yml)))
# Extra flavor from variable ANSIBLE_DIR_PROV, using pattern ANSIBLE_DIR_PROV/setup-<flavor>.yml
FLAVORS +=          $(patsubst $(ANSIBLE_DIR_PROV)/setup-%.yml,%, \
                        $(wildcard $(ANSIBLE_DIR_PROV)/setup-*.yml))
FLAVORS :=          $(strip $(FLAVORS))

BASETARGETS :=      $(strip $(foreach t, $(TEMPLATES), $(t)/base))
PROVTARGETS :=      $(strip $(foreach t, $(TEMPLATES), \
                            $(foreach f, $(FLAVORS), $(t)/$(f))))
PROVIMAGES :=       $(strip $(foreach f, $(FLAVORS), \
                            $(foreach t, $(TEMPLATES), $(t)/$(f): %/$(f): %/base)))
REPROVTARGETS :=    $(strip $(foreach t, $(TEMPLATES), \
                                $(foreach f, $(FLAVORS), \
                                    $(filter-out $(t)/$(f).latest, \
                                        $(wildcard $(t)/$(f).*)))))
COMPRESSPOSSIBLE := $(foreach t, $(TEMPLATES), \
                        $(foreach f, $(FLAVORS), $(wildcard $(t)/$(f).*)))
COMPRESSTARGETS :=  $(foreach p, $(COMPRESSPOSSIBLE), $(p)/compress)
BOOTTARGETS :=      $(foreach t, $(TEMPLATES), $(t)/base/boot)
BOOTTARGETS +=      $(foreach p, $(PROVTARGETS), $(p)/boot)
BOOTTARGETS :=      $(strip $(BOOTTARGETS))
CURBOOTTARGETS :=   $(foreach p, $(REPROVTARGETS), $(p)/boot)
BASERMTARGETS :=    $(foreach t, $(BASETARGETS),  rm/$(t))
PROVRMTARGETS :=    $(foreach t, $(REPROVTARGETS),  rm/$(t))

ifdef DEBUG
    VERBOSE := 1
    ifeq ($(DEBUG),STEP)
        override PACKER_OPTS += -debug
    else
        override PACKER_OPTS += -on-error=ask
    endif
endif

ifdef FORCE
    override PACKER_OPTS += -force
endif

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

override PACKER_OPTS += -warn-on-undeclared-var

# 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")

ifdef VERBOSE
    $(info timestamp:            $(TIMESTAMP))
    $(info )
    $(info packer: executable:   $(PACKER))
    $(info packer: options:      $(PACKER_OPTS))
    $(info hasher:               $(HASHER))
    $(info )
    $(info ansible: boot:        $(ANSIBLE_DIR_BOOT))
    $(info ansible: flavors:     $(FLAVORS))
    $(info )
    $(info builder: available:   $(AVAILABLE_BUILDERS))
    $(info builder: chosen:      $(BUILDER))
    $(info )
    $(info targets: base:        $(BASETARGETS))
    $(info targets: boot:        $(BOOTTARGETS))
    $(info targets: provision:   $(PROVTARGETS))
    $(info targets: reprovision: $(REPROVTARGETS))
    $(info )
    override PACKER := PACKER_LOG=1 $(PACKER)
endif

.PHONY: help clean_except_last clean_bases clean_all clean_failed backinglock $(REPROVTARGETS)
help:

# Creating base images. When DRACUT_INIT is specified, the dracut module
# repository will be initially cloned and its required components (dnbd3,
# xmount, libxmount-qemu) will be pre-build to accelerate subsequent builds.
$(BASETARGETS):
	$(info ** Building template '$(@D)' using '$(BUILDER)' **)
	$(eval INIT_TAG := $(if $(DRACUT_INIT), install, untagged))
	$(PACKER) build -only=base.$(BUILDER).ansible \
		$(PACKER_OPTS) \
		-var-file=$(@D)/base.pkrvars.hcl \
		-var http_dir=$(@D)/http \
		-var output_directory=$(BUILDS)/$(@D)/base \
		-var playbook_file=$(ANSIBLE_DIR_BOOT)/slx-builder.yml \
		-var vm_name=$(@D) \
		./
	$(HASHER) $(BUILDS)/$(@D)/base/$(@D) >$(BUILDS)/$(@D)/base/CHECKSUM

# Provisioning images
$(PROVIMAGES)

$(PROVTARGETS) $(REPROVTARGETS):
	$(eval FLAVOR := 			$(basename $(@F)))
	$(eval ANSIBLE_DIR_PROV :=	$(if ansible-$(FLAVOR)/setup-$(FLAVOR).yml,\
									ansible-$(FLAVOR)))
	$(eval VERSION := 			$(if $(suffix $(@)), $(subst .,,$(suffix $(@))), 0))
	$(eval BASE_IMAGE :=		$(if $(wildcard $(BUILDS)/$(@)/$(@D)-$(FLAVOR)),\
									$(BUILDS)/$(@)/$(@D)-$(FLAVOR),\
									$(BUILDS)/$(@D)/base/$(@D)))
	$(eval BUILD_DIR :=		 	$(BUILDS)/$(@D)/$(FLAVOR).$(TIMESTAMP))
	$(info ** Provisioning '$(@D)' with '$(FLAVOR)' **)
	@mkdir -p $(BUILD_DIR)
	@cp -r `readlink -f $(ANSIBLE_DIR_PROV)` $(BUILD_DIR)/$(ANSIBLE_DIR_PROV)
	@ln -sfn $(FLAVOR).$(TIMESTAMP) $(BUILDS)/$(@D)/$(FLAVOR).latest
	@ln -sfr $(BUILD_DIR) $(dir $(BASE_IMAGE))/$(TIMESTAMP).backinglock
	@-cp -r $(BUILDS)/$@/$(ANSIBLE_DIR_PROV) $(BUILD_DIR)
	@-cp -r $(BUILDS)/$@/$(ANSIBLE_DIR_PROV).* $(BUILD_DIR)
	$(PACKER) build -only=flavor.$(BUILDER).ansible \
		$(PACKER_OPTS) \
		-var disk_image=true \
		-var iso_url=$(BASE_IMAGE) \
		-var iso_checksum=file:$(dir $(BASE_IMAGE))CHECKSUM \
		-var output_directory=$(BUILD_DIR)/image \
		-var playbook_file=$(BUILD_DIR)/$(ANSIBLE_DIR_PROV)/setup-$(FLAVOR).yml \
		-var vm_name=$(@D)-$(FLAVOR) \
		./
	$(HASHER) $(BUILD_DIR)/image/$(@D)-$(FLAVOR) \
		>$(BUILD_DIR)/image/CHECKSUM

# Generating boot files
$(BOOTTARGETS): %/boot: %

$(BOOTTARGETS) $(CURBOOTTARGETS):
	$(eval FLAVOR := 	$(notdir $(@D)))
	$(eval BASE := 		$(patsubst %/, %, $(dir $(@D))))
	$(eval BASE_DIR :=	$(if $(filter base, $(notdir $(BUILDS)/$(@D))),\
							,\
							$(if $(wildcard $(BUILDS)/$(@D)/image/.),\
								$(BUILDS)/$(@D),\
								$(BUILDS)/$(@D).$(TIMESTAMP))))
	$(eval BUILD_DIR := $(if $(BASE_DIR)/image,\
							$(BASE_DIR)/image,\
							$(BUILDS)/$(@D)))
	$(eval BUILD_DIR :=	$(if $(filter $(@), $(CURBOOTTARGETS)),\
							$(BASE_DIR)/image,\
							$(BUILD_DIR)))
	$(info ** Generating boot files for '$(BUILD_DIR)')
	$(PACKER) build -only=flavor.$(BUILDER).ansible \
		$(PACKER_OPTS) \
		-var disk_image=true \
		-var iso_url=$(BUILD_DIR)/$(BASE)-$(FLAVOR) \
		-var iso_checksum=file:$(dir $(BUILD_DIR))image/CHECKSUM \
		-var output_directory=$(BUILD_DIR)/tmp \
		-var playbook_file=$(ANSIBLE_DIR_BOOT)/slx-builder.yml \
		-var vm_name=$(BASE)-$(FLAVOR).tmp \
		./
	@mkdir -p $(BUILD_DIR)/boot
	@mv -f $(ANSIBLE_DIR_BOOT)/boot_files/* $(BUILD_DIR)/boot
	$(if $(DEBUG),,@rm -rf $(BUILD_DIR)/tmp)

# Safe removal of images
$(BASERMTARGETS):
rm/%: %/*.backinglock
	$(eval BUILD_DIR := $(subst rm/,,$(@)))
	@rm -rf $(BUILD_DIR)

$(PROVRMTARGETS):
rm/%: %/build/*.backinglock
	$(eval BUILD_DIR := 	$(subst rm/,,$(@))/build)
	$(eval FATHER_BUILD := 	$(dir $(shell qemu-img info $(BUILD_DIR)/rootfs-image | grep "backing file" | cut -d\  -f3-)))
	$(eval BUILD_TIME := 	$(subst .,,$(suffix $(@))))
	@rm -rf $(FATHER_BUILD)/$(BUILD_TIME).backinglock
	@rm -rf $(BUILD_DIR)

%.backinglock: backinglock
	@qemu-img convert -f qcow2 $(@)/build/rootfs-image -O qcow2 $(@)/build/rootfs-image.tmp
	@rm $(@)/build/rootfs-image
	@mv $(@)/build/rootfs-image.tmp $(@)/build/rootfs-image
	@rm $(@)

backinglock:

clean_except_last:
	@-$(foreach template,$(TEMPLATES),\
		$(eval exclusions := $(shell test -d $(template) && \
										find $(template) \
											-maxdepth 1 \
											-type l \
											-print0 \
										| xargs -r -0 -n1 readlink))\
		test -d $(template) && \
			find $(template)/* \
				-maxdepth 0 \
				-type d \
				$(foreach file,$(exclusions),-not -name $(file) ) \
				-not -name base \
				-print0 \
			| xargs -r -0 -n1 rm -rf; )

clean_failed:
	@-$(foreach template,$(TEMPLATES),\
		test -d $(template) && \
			find $(template)/* \
				-maxdepth 0 \
				-type d \
				-not -name base \
				-print0 \
			| xargs -r -0 -n1 -i \
				$(SHELL) -c 'test -d "{}/build" || 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"
	@printf "\n"
	@printf "Base images targets:\n"
	@for T in $(BASETARGETS); do printf "\t%s\n" "$$T"; done
	@printf "\n"
	@printf "Provisioning images targets:\n"
	@for P in $(PROVTARGETS); do printf "\t%s\n" "$$P"; done
	@for P in $(REPROVTARGETS); do printf "\t%s\n" "$$P"; done
	@printf "\n"
	@printf "Generate boot files targets:\n"
	@printf "\t<{base,provisioning}_target>/boot\n"
	@printf "\n"
	@printf "Commiting backing files and Compressing targets:"
	@for C in $(COMPRESSTARGETS); do printf "\t%s\n" "$$C"; done
	@printf "\n"
	@printf "For safely removing targets:\n"
	@printf "\trm/<target>\n"
	@printf "\n"
	@printf "Available options are:\n"
	@printf "\tANSIBLE_DIR_BOOT:\tSet directory with ansible roles for building initramfs (def: ansible-dracut)\n"
	@printf "\tANSIBLE_DIR_PROV:\tSet directory with ansible roles for provisioning (def: ansible-roles-prov)\n"
	@printf "\tDEBUG:\t\t\tEnable debug mode in packer (sets VERBOSE=1)\n"
	@printf "\t\tDEBUG=1\t\tEnable enhanced on-error handling\n"
	@printf "\t\tDEBUG=STEP\tEnable step by step debugging in packer\n"
	@printf "\tFORCE=1:\t\tOverwrite existing builds\n"
	@printf "\tPACKER:\t\t\tSet packer executable (def: packer)\n"
	@printf "\tPACKER_OPTS:\t\tSet packer options\n"
	@printf "\tVERBOSE=1:\t\tEnable verbose output\n"
	@printf "\tWINDOW:\t\t\tDisable headless mode\n"
	@printf "\tPKR_VAR_<VAR>=<VAL>:\tSet a packer variable <VAR>=<VAL>, e.g. PKR_VAR_headless=false\n"
	@printf "\n"
	@printf "Clean targets are:\n"
	@printf "\tclean_except_last\n"
	@printf "\tclean_failed\n"
	@printf "\tclean_bases\n"
	@printf "\tclean_all\n"