summaryrefslogtreecommitdiffstats
path: root/Makefile
blob: 9a10a18c1d612d1677f5038edb899244643e9bad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# 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
ifndef BUILDER
    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

    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


# 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
    PACKER_OPTS += -var='headless=false'

    $(info root password:        $(ROOTPW))
    $(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

HASHER := sha256sum
check_rootpw = $(if $(strip $(ROOTPW)),\
    $(if $1,\
        $(if $(shell echo "$(ROOTPW)" | $(HASHER) --check --quiet $1/base/rootpw.$(HASHER)),\
             $(error ROOTPW password hash does not match $1/base/rootpw.$(HASHER)),\
             ),\
        ),\
    $(error No root password is set, set it as ROOTPW in your environment.) \
)


.PHONY: help clean_except_last clean_bases 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=rootfs-image' \
		-var='output_directory=$(@D)/base' \
		$(@D).json
	@echo "$(ROOTPW)" | $(HASHER) > $(@D)/base/rootpw.$(HASHER)


# Provisioning images
$(PROVTARGETS):
$(foreach flav, $(FLAVORS), %/$(flav)): %/base
	$(call check_rootpw,$(@D))
	$(eval BUILD_DIR := $(@D)/$(@F).$(TIMESTAMP))
	$(info ** Provisioning '$(@D)' with '$(@F)' **)
	@mkdir -p $(BUILD_DIR)
	@cp -r $(ANSIBLE_DIR) $(BUILD_DIR)/$(ANSIBLE_DIR)
	$(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
	@ln -sfn $(@F).$(TIMESTAMP) $(@D)/$(@F).latest


# Generating boot files
$(BOOTTARGETS):
%/boot: %
	$(call check_rootpw,$(@D))
	$(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


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"