CHECK_NEWS = $(top_srcdir)/autotools/check-news
DOCPP = $(top_srcdir)/autotools/docpp
REPLACE_VARS_SED = autotools/replace_vars.sed
+CONVERT_CONSTANTS = $(top_srcdir)/autotools/convert-constants
-# Note: the variable must be named after the directory + 'dir' suffix
+# Note: these are automake-specific variables, and must be named after
+# the directory + 'dir' suffix
clientdir = $(pkgpythondir)/client
hypervisordir = $(pkgpythondir)/hypervisor
httpdir = $(pkgpythondir)/http
utilsdir = $(pkgpythondir)/utils
toolsdir = $(pkglibdir)/tools
iallocatorsdir = $(pkglibdir)/iallocators
+pytoolsdir = $(pkgpythondir)/tools
docdir = $(datadir)/doc/$(PACKAGE)
# Delete output file if an error occurred while building it
HTOOLS_DIRS = \
htools \
htools/Ganeti \
- htools/Ganeti/HTools
+ htools/Ganeti/HTools \
+ htools/Ganeti/HTools/Program
DIRS = \
autotools \
lib/masterd \
lib/rapi \
lib/server \
+ lib/tools \
lib/utils \
lib/watcher \
man \
BUILDTIME_DIR_AUTOCREATE = \
scripts \
- doc/api \
- doc/coverage
+ $(APIDOC_DIR) \
+ $(APIDOC_PY_DIR) \
+ $(APIDOC_HS_DIR) \
+ $(APIDOC_HS_DIR)/Ganeti $(APIDOC_HS_DIR)/Ganeti/HTools \
+ $(APIDOC_HS_DIR)/Ganeti/HTools/Program \
+ $(COVERAGE_DIR) \
+ $(COVERAGE_PY_DIR) \
+ $(COVERAGE_HS_DIR) \
+ .hpc
BUILDTIME_DIRS = \
$(BUILDTIME_DIR_AUTOCREATE) \
all_dirfiles = $(addsuffix /.dir,$(DIRS) $(BUILDTIME_DIR_AUTOCREATE))
+# some helper vars
+COVERAGE_DIR = doc/coverage
+COVERAGE_PY_DIR = $(COVERAGE_DIR)/py
+COVERAGE_HS_DIR = $(COVERAGE_DIR)/hs
+APIDOC_DIR = doc/api
+APIDOC_PY_DIR = $(APIDOC_DIR)/py
+APIDOC_HS_DIR = $(APIDOC_DIR)/hs
+
MAINTAINERCLEANFILES = \
$(docpng) \
$(maninput) \
epydoc.conf \
autotools/replace_vars.sed \
daemons/daemon-util \
- daemons/ensure-dirs \
daemons/ganeti-cleaner \
devel/upload \
doc/examples/bash_completion \
tools/kvm-ifup \
stamp-srclinks \
$(nodist_pkgpython_PYTHON) \
- $(HALLPROGS) $(HSRCS2)
+ $(HS_ALL_PROGS) $(HS_BUILT_SRCS) \
+ .hpc/*.mix htools/*.tix \
+ doc/hs-lint.html
# BUILT_SOURCES should only be used as a dependency on phony targets. Otherwise
# it'll cause the target to rebuild every time.
lib/server/noded.py \
lib/server/rapi.py
+pytools_PYTHON = \
+ lib/tools/__init__.py \
+ lib/tools/ensure_dirs.py
+
utils_PYTHON = \
lib/utils/__init__.py \
lib/utils/algo.py \
doc/design-2.4.rst \
doc/design-draft.rst \
doc/design-oob.rst \
+ doc/design-cpu-pinning.rst \
doc/design-query2.rst \
+ doc/design-x509-ca.rst \
+ doc/design-http-server.rst \
+ doc/design-impexp2.rst \
+ doc/design-lu-generated-jobs.rst \
+ doc/design-multi-reloc.rst \
+ doc/design-network.rst \
+ doc/design-chained-jobs.rst \
doc/cluster-merge.rst \
doc/design-shared-storage.rst \
doc/devnotes.rst \
doc/upgrade.rst \
doc/walkthrough.rst
-HPROGS = \
- htools/hbal \
+HS_PROGS = \
htools/hscan \
- htools/hail \
- htools/hspace
+ htools/hspace \
+ htools/htools
+HS_BIN_ROLES = hbal
-HALLPROGS = $(HPROGS) htools/test
-HSRCPROGS = $(patsubst %,%.hs,$(HALLPROGS))
+HS_ALL_PROGS = $(HS_PROGS) htools/test
+HS_PROG_SRCS = $(patsubst %,%.hs,$(HS_ALL_PROGS))
# we don't add -Werror by default
HFLAGS = -O -Wall -fwarn-monomorphism-restriction -fwarn-tabs -ihtools
+# extra flags that can be overriden on the command line
HEXTRA =
+# exclude options for coverage reports
+HPCEXCL = --exclude Main --exclude Ganeti.HTools.QC \
+ --exclude Ganeti.Constants \
+ --exclude Ganeti.HTools.Version
-HSRCS = \
+HS_LIB_SRCS = \
htools/Ganeti/HTools/CLI.hs \
htools/Ganeti/HTools/Cluster.hs \
+ htools/Ganeti/HTools/Compat.hs \
htools/Ganeti/HTools/Container.hs \
htools/Ganeti/HTools/ExtLoader.hs \
htools/Ganeti/HTools/Group.hs \
htools/Ganeti/HTools/Text.hs \
htools/Ganeti/HTools/Types.hs \
htools/Ganeti/HTools/Utils.hs \
+ htools/Ganeti/HTools/Program/Hail.hs \
+ htools/Ganeti/HTools/Program/Hbal.hs \
htools/Ganeti/Jobs.hs \
htools/Ganeti/Luxi.hs \
htools/Ganeti/OpCodes.hs
-HSRCS2 = htools/Ganeti/HTools/Version.hs
-HSRCS2IN = $(patsubst %,%.in,$(HSRCS2))
+HS_BUILT_SRCS = htools/Ganeti/HTools/Version.hs htools/Ganeti/Constants.hs
+HS_BUILT_SRCS_IN = $(patsubst %,%.in,$(HS_BUILT_SRCS))
$(RUN_IN_TEMPDIR): | $(all_dirfiles)
scripts/gnt-node \
scripts/gnt-os
-PYTHON_BOOTSTRAP = \
+PYTHON_BOOTSTRAP_SBIN = \
daemons/ganeti-confd \
daemons/ganeti-masterd \
daemons/ganeti-noded \
scripts/gnt-node \
scripts/gnt-os
+PYTHON_BOOTSTRAP = \
+ $(PYTHON_BOOTSTRAP_SBIN) \
+ tools/ensure-dirs
+
qa_scripts = \
qa/ganeti-qa.py \
qa/qa_cluster.py \
qa/qa_utils.py
bin_SCRIPTS =
-iallocators_SCRIPTS =
if WANT_HTOOLS
-bin_SCRIPTS += $(filter-out htools/hail,$(HPROGS))
-iallocators_SCRIPTS += $(filter htools/hail,$(HPROGS))
+bin_SCRIPTS += $(filter-out htools/hail,$(HS_PROGS))
+install-exec-hook:
+ @mkdir_p@ $(DESTDIR)$(iallocatorsdir)
+ $(LN_S) -f $(DESTDIR)$(bindir)/htools \
+ $(DESTDIR)$(iallocatorsdir)/hail
+ for role in $(HS_BIN_ROLES); do \
+ $(LN_S) -f $(DESTDIR)$(bindir)/htools \
+ $(DESTDIR)$(bindir)/$$role ; \
+ done
endif
-$(HALLPROGS): %: %.hs $(HSRCS) $(HSRCS2) Makefile
- BINARY=$(@:htools/%=%); \
- $(GHC) --make \
- $(HFLAGS) $(HEXTRA) $(HTOOLS_NOCURL) \
- -osuf $$BINARY.o -hisuf $$BINARY.hi \
- $@
+$(HS_ALL_PROGS): %: %.hs $(HS_LIB_SRCS) $(HS_BUILT_SRCS) Makefile
+ @if [ -z "$(HTOOLS)" ]; then \
+ echo "Error: htools compilation disabled at configure time" 1>&2 ;\
+ exit 1; \
+ fi
+ @BINARY=$(@:htools/%=%); \
+ if [ "$BINARY" = "test" ] && [ -z "$(GHC_PKG_QUICKCHECK)" ]; then \
+ echo "Error: cannot run unittests without the QuickCheck library (see devnotes.rst)" 1>&2; \
+ exit 1; \
+ fi
+ BINARY=$(@:htools/%=%); $(GHC) --make \
+ $(HFLAGS) $(HEXTRA) \
+ $(HTOOLS_NOCURL) $(HTOOLS_PARALLEL3) \
+ -osuf $$BINARY.o -hisuf $$BINARY.hi $@
+
+# for the htools/test binary, we need to enable profiling/coverage
+htools/test: HEXTRA=-fhpc -Wwarn -fno-warn-missing-signatures \
+ -fno-warn-monomorphism-restriction -fno-warn-orphans \
+ -fno-warn-missing-methods -fno-warn-unused-imports
dist_sbin_SCRIPTS = \
tools/ganeti-listrunner
nodist_sbin_SCRIPTS = \
- $(PYTHON_BOOTSTRAP) \
+ $(PYTHON_BOOTSTRAP_SBIN) \
daemons/ganeti-cleaner
-dist_tools_SCRIPTS = \
+dist_tools_PYTHON = \
tools/burnin \
tools/cfgshell \
tools/cfgupgrade \
tools/setup-ssh \
tools/sanitize-config
+dist_tools_SCRIPTS = \
+ $(dist_tools_PYTHON) \
+ tools/kvm-console-wrapper \
+ tools/xm-console-wrapper
+
pkglib_python_scripts = \
daemons/import-export \
tools/check-cert-expired
+nodist_pkglib_python_scripts = \
+ tools/ensure-dirs
+
pkglib_SCRIPTS = \
daemons/daemon-util \
- daemons/ensure-dirs \
tools/kvm-ifup \
$(pkglib_python_scripts)
+nodist_pkglib_SCRIPTS = \
+ $(nodist_pkglib_python_scripts)
+
EXTRA_DIST = \
NEWS \
UPGRADE \
autotools/check-news \
autotools/check-tar \
autotools/check-version \
+ autotools/convert-constants \
autotools/docpp \
autotools/gen-coverage \
autotools/testrunner \
$(RUN_IN_TEMPDIR) \
daemons/daemon-util.in \
- daemons/ensure-dirs.in \
daemons/ganeti-cleaner.in \
$(pkglib_python_scripts) \
devel/upload.in \
$(maninput) \
qa/qa-sample.json \
$(qa_scripts) \
- $(HSRCS) $(HSRCS2IN) \
- $(HSRCPROGS)
+ $(HS_LIB_SRCS) $(HS_BUILT_SRCS_IN) \
+ $(HS_PROG_SRCS)
man_MANS = \
man/ganeti.7 \
man/hail.1 \
man/hbal.1 \
man/hscan.1 \
- man/hspace.1
+ man/hspace.1 \
+ man/htools.1
manrst = $(patsubst %.1,%.rst,$(patsubst %.7,%.rst,$(patsubst %.8,%.rst,$(man_MANS))))
manhtml = $(patsubst %.rst,%.html,$(manrst))
test/ganeti.runtime_unittest.py \
test/ganeti.serializer_unittest.py \
test/ganeti.ssh_unittest.py \
+ test/ganeti.tools.ensure_dirs_unittest.py \
test/ganeti.uidpool_unittest.py \
test/ganeti.utils.algo_unittest.py \
test/ganeti.utils.filelock_unittest.py \
test/docs_unittest.py \
test/tempfile_fork_unittest.py
+haskell_tests = htools/test
+
dist_TESTS = \
test/check-cert-expired_unittest.bash \
test/daemon-util_unittest.bash \
$(python_tests)
nodist_TESTS =
+if WANT_HTOOLSTESTS
+nodist_TESTS += $(haskell_tests)
+endif
TESTS = $(dist_TESTS) $(nodist_TESTS)
all_python_code = \
$(dist_sbin_SCRIPTS) \
- $(dist_tools_SCRIPTS) \
+ $(dist_tools_PYTHON) \
$(pkglib_python_scripts) \
+ $(nodist_pkglib_python_scripts) \
$(python_tests) \
$(pkgpython_PYTHON) \
$(client_PYTHON) \
$(hypervisor_PYTHON) \
$(rapi_PYTHON) \
$(server_PYTHON) \
+ $(pytools_PYTHON) \
$(http_PYTHON) \
$(confd_PYTHON) \
$(masterd_PYTHON) \
test/ganeti-cleaner_unittest.bash \
test/import-export_unittest.bash \
$(all_python_code) \
- $(HSRCS) $(HSRCPROGS)
+ $(HS_LIB_SRCS) $(HS_PROG_SRCS)
check_python_code = \
$(BUILD_BASH_COMPLETION) \
ganeti \
ganeti/http/server.py \
$(dist_sbin_SCRIPTS) \
- $(dist_tools_SCRIPTS) \
+ $(dist_tools_PYTHON) \
$(pkglib_python_scripts) \
$(BUILD_BASH_COMPLETION) \
$(DOCPP) \
VCSVER=`cat $(abs_top_srcdir)/vcs-version`; \
sed -e "s/%ver%/$$VCSVER/" < $< > $@
+htools/Ganeti/Constants.hs: htools/Ganeti/Constants.hs.in \
+ lib/constants.py lib/_autoconf.py $(CONVERT_CONSTANTS)
+ set -e; \
+ { cat $< ; PYTHONPATH=. $(CONVERT_CONSTANTS); } > $@
+
lib/_autoconf.py: Makefile vcs-version | lib/.dir
set -e; \
VCSVER=`cat $(abs_top_srcdir)/vcs-version`; \
echo "CONFD_USER = '$(CONFD_USER)'"; \
echo "CONFD_GROUP = '$(CONFD_GROUP)'"; \
echo "NODED_USER = '$(NODED_USER)'"; \
+ echo "NODED_GROUP = '$(NODED_GROUP)'"; \
echo "VCS_VERSION = '$$VCSVER'"; \
echo "DISK_SEPARATOR = '$(DISK_SEPARATOR)'"; \
+ if [ "$(HTOOLS)" ]; then \
+ echo "HTOOLS = True"; \
+ else \
+ echo "HTOOLS = False"; \
+ fi; \
} > $@
$(REPLACE_VARS_SED): Makefile
daemons/ganeti-%: MODULE = ganeti.server.$(patsubst ganeti-%,%,$(notdir $@))
daemons/ganeti-watcher: MODULE = ganeti.watcher
scripts/%: MODULE = ganeti.client.$(subst -,_,$(notdir $@))
+tools/ensure-dirs: MODULE = ganeti.tools.ensure_dirs
$(PYTHON_BOOTSTRAP): Makefile | $(all_dirfiles)
test -n "$(MODULE)" || { echo Missing module; exit 1; }
$(CHECK_PYTHON_CODE) $(check_python_code)
$(CHECK_VERSION) $(VERSION) $(top_srcdir)/NEWS
$(CHECK_NEWS) < $(top_srcdir)/NEWS
+ expver=$(VERSION_MAJOR).$(VERSION_MINOR); \
+ if test "`head -n 1 $(top_srcdir)/README`" != "Ganeti $$expver"; then \
+ echo "Incorrect version in README, expected $$expver"; \
+ exit 1; \
+ fi; \
+ if test "`sed -ne '4 p' $(top_srcdir)/doc/iallocator.rst`" != \
+ "Documents Ganeti version $$expver"; then \
+ echo "Incorrect version in iallocator.rst, expected $$expver"; \
+ exit 1; \
+ fi
+
+.PHONY: hs-check
+hs-check: htools/test
+ @rm -f test.tix
+ ./htools/test
.PHONY: lint
lint: $(BUILT_SOURCES)
PYTHONPATH=$(abs_top_srcdir) $(PYLINT) $(LINT_OPTS) \
--rcfile ../pylintrc $(patsubst qa/%.py,%,$(qa_scripts))
+.PHONY: hlint
+hlint: $(HS_BUILT_SRCS)
+ if tty -s; then C="-c"; else C=""; fi; \
+ hlint --report=doc/hs-lint.html $$C htools
+
# a dist hook rule for updating the vcs-version file; this is
# hardcoded due to where it needs to build the file...
dist-hook:
@mkdir_p@ $* && touch $@
.PHONY: apidoc
-apidoc: epydoc.conf $(RUN_IN_TEMPDIR) $(BUILT_SOURCES)
+if WANT_HTOOLSAPIDOC
+apidoc: py-apidoc hs-apidoc
+else
+apidoc: py-apidoc
+endif
+
+.PHONY: py-apidoc
+py-apidoc: epydoc.conf $(RUN_IN_TEMPDIR) $(BUILT_SOURCES)
$(RUN_IN_TEMPDIR) epydoc -v \
--conf $(CURDIR)/epydoc.conf \
- --output $(CURDIR)/doc/api
+ --output $(CURDIR)/$(APIDOC_PY_DIR)
+
+.PHONY: hs-apidoc
+hs-apidoc: $(HS_BUILT_SRCS)
+ @test -n "$(HSCOLOUR)" || \
+ { echo 'HsColour' not found during configure; exit 1; }
+ @test -n "$(HADDOCK)" || \
+ { echo 'haddock' not found during configure; exit 1; }
+ rm -rf $(APIDOC_HS_DIR)/*
+ @mkdir_p@ $(APIDOC_HS_DIR)/Ganeti/HTools/Program
+ $(HSCOLOUR) -print-css > $(APIDOC_HS_DIR)/Ganeti/hscolour.css
+ ln -s ../hscolour.css $(APIDOC_HS_DIR)/Ganeti/HTools/hscolour.css
+ set -e ; \
+ cd htools; \
+ if [ "$(HTOOLS_NOCURL)" ]; \
+ then OPTGHC="--optghc=$(HTOOLS_NOCURL)"; \
+ else OPTGHC=""; \
+ fi; \
+ if [ "$(HTOOLS_PARALLEL3)" ]; \
+ then OPTGHC="$$OPTGHC --optghc=$(HTOOLS_PARALLEL3)"; \
+ fi; \
+ RELSRCS="$(HS_LIB_SRCS:htools/%=%) $(HS_BUILT_SRCS:htools/%=%)"; \
+ for file in $$RELSRCS; do \
+ hfile=`echo $$file|sed 's/\\.hs$$//'`.html; \
+ $(HSCOLOUR) -css -anchor $$file > ../$(APIDOC_HS_DIR)/$$hfile ; \
+ done ; \
+ $(HADDOCK) --odir ../$(APIDOC_HS_DIR) --html --ignore-all-exports -w \
+ -t ganeti-htools -p haddock-prologue \
+ --source-module="%{MODULE/.//}.html" \
+ --source-entity="%{MODULE/.//}.html#%{NAME}" \
+ $$OPTGHC \
+ $(filter-out Ganeti/HTools/ExtLoader.hs,$(HS_LIB_SRCS:htools/%=%))
.PHONY: TAGS
TAGS: $(BUILT_SOURCES)
etags -l python -
.PHONY: coverage
-coverage: $(BUILT_SOURCES) $(python_tests)
+if WANT_HTOOLS
+coverage: py-coverage hs-coverage
+else
+coverage: py-coverage
+endif
+
+.PHONY: py-coverage
+py-coverage: $(BUILT_SOURCES) $(python_tests)
set -e; \
- COVERAGE_FILE=$(CURDIR)/doc/coverage/data \
- TEXT_COVERAGE=$(CURDIR)/doc/coverage/report.txt \
- HTML_COVERAGE=$(CURDIR)/doc/coverage \
+ COVERAGE_FILE=$(CURDIR)/$(COVERAGE_PY_DIR)/data \
+ TEXT_COVERAGE=$(CURDIR)/$(COVERAGE_PY_DIR)/report.txt \
+ HTML_COVERAGE=$(CURDIR)/$(COVERAGE_PY_DIR) \
$(PLAIN_TESTS_ENVIRONMENT) $(abs_top_srcdir)/autotools/gen-coverage \
$(python_tests)
+.PHONY: hs-coverage
+hs-coverage: $(haskell_tests)
+ cd htools && rm -f *.tix *.mix && ./test
+ @mkdir_p@ $(COVERAGE_HS_DIR)
+ hpc markup --destdir=$(COVERAGE_HS_DIR) htools/test $(HPCEXCL)
+ hpc report htools/test $(HPCEXCL)
+ ln -sf hpc_index.html $(COVERAGE_HS_DIR)/index.html
+
+# Special "kind-of-QA" target for htools, needs special setup (all
+# tools compiled with -fhpc)
+.PHONY: live-test
+live-test: all
+ set -e ; \
+ cd htools; \
+ rm -f .hpc; ln -s ../.hpc .hpc; \
+ rm -f *.tix *.mix; \
+ ./live-test.sh; \
+ hpc sum --union $(HPCEXCL) $(addsuffix .tix,$(HS_PROGS:htools/%=%)) \
+ --output=live-test.tix ; \
+ @mkdir_p@ ../$(COVERAGE_HS_DIR) ; \
+ hpc markup --destdir=../$(COVERAGE_HS_DIR) live-test \
+ --srcdir=.. $(HPCEXCL) ; \
+ hpc report --srcdir=.. live-test $(HPCEXCL)
+
commit-check: distcheck lint apidoc
-include ./Makefile.local