diff --git a/Makefile b/Makefile index b76a4dd1d..5cb36f290 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,8 @@ export GO111MODULE:=on PKGNAME=harmony VERSION=2.3.5 RPMBUILD=$(HOME)/rpmbuild +DEBBUILD=$(HOME)/debbuild +SHELL := bash .PHONY: all help libs exe race trace-pointer debug debug-kill test test-go test-api test-api-attach linux_static deb rpm_init rpm_build rpm @@ -84,11 +86,25 @@ arm_static: bash ./scripts/go_executable_build.sh -a arm64 -s git checkout go.mod -deb: rpm - fpm -s dir -t deb -n $(PKGNAME) -v $(VERSION)-$(COMMIT) --prefix /usr/local bin/harmony - fpm -s pleaserun -t deb -n $(PKGNAME)-service -v $(VERSION) /usr/local/bin/harmony - -rpm_init: bin/harmony +deb_init: + rm -rf $(DEBBUILD) + mkdir -p $(DEBBUILD)/$(PKGNAME)-$(VERSION)/{etc/systemd/system,usr/sbin,etc/sysctl.d,etc/harmony} + cp -f bin/harmony $(DEBBUILD)/$(PKGNAME)-$(VERSION)/usr/sbin/ + bin/harmony dumpconfig $(DEBBUILD)/$(PKGNAME)-$(VERSION)/etc/harmony/harmony.conf + cp -f scripts/package/rclone.conf $(DEBBUILD)/$(PKGNAME)-$(VERSION)/etc/harmony/ + cp -f scripts/package/harmony.service $(DEBBUILD)/$(PKGNAME)-$(VERSION)/etc/systemd/system/ + cp -f scripts/package/harmony-setup.sh $(DEBBUILD)/$(PKGNAME)-$(VERSION)/usr/sbin/ + cp -f scripts/package/harmony-rclone.sh $(DEBBUILD)/$(PKGNAME)-$(VERSION)/usr/sbin/ + cp -f scripts/package/harmony-sysctl.conf $(DEBBUILD)/$(PKGNAME)-$(VERSION)/etc/sysctl.d/99-harmony.conf + cp -r scripts/package/deb/DEBIAN $(DEBBUILD)/$(PKGNAME)-$(VERSION) + VER=$(VERSION) scripts/package/templater.sh scripts/package/deb/DEBIAN/control > $(DEBBUILD)/$(PKGNAME)-$(VERSION)/DEBIAN/control + +deb_build: + (cd $(DEBBUILD); dpkg-deb --build $(PKGNAME)-$(VERSION)/) + +deb: deb_init deb_build + +rpm_init: rm -rf $(RPMBUILD) mkdir -p $(RPMBUILD)/{SOURCES,SPECS,BUILD,RPMS,BUILDROOT,SRPMS} mkdir -p $(RPMBUILD)/SOURCES/$(PKGNAME)-$(VERSION) @@ -99,10 +115,10 @@ rpm_init: bin/harmony cp -f scripts/package/harmony-rclone.sh $(RPMBUILD)/SOURCES/$(PKGNAME)-$(VERSION) cp -f scripts/package/rclone.conf $(RPMBUILD)/SOURCES/$(PKGNAME)-$(VERSION) cp -f scripts/package/harmony-sysctl.conf $(RPMBUILD)/SOURCES/$(PKGNAME)-$(VERSION) - cp -f scripts/package/rpm/harmony.spec $(RPMBUILD)/SPECS + VER=$(VERSION) scripts/package/templater.sh scripts/package/rpm/harmony.spec > $(RPMBUILD)/SPECS/harmony.spec (cd $(RPMBUILD)/SOURCES; tar cvf $(PKGNAME)-$(VERSION).tar $(PKGNAME)-$(VERSION)) rpm_build: - rpmbuild --target x86_64 -bb scripts/package/rpm/harmony.spec + rpmbuild --target x86_64 -bb $(RPMBUILD)/SPECS/harmony.spec rpm: rpm_init rpm_build diff --git a/scripts/package/deb/DEBIAN/conffiles b/scripts/package/deb/DEBIAN/conffiles new file mode 100644 index 000000000..3421cfc40 --- /dev/null +++ b/scripts/package/deb/DEBIAN/conffiles @@ -0,0 +1,4 @@ +/etc/harmony/harmony.conf +/etc/harmony/rclone.conf +/etc/sysctl.d/99-harmony.conf +/etc/systemd/system/harmony.service diff --git a/scripts/package/deb/DEBIAN/control b/scripts/package/deb/DEBIAN/control new file mode 100644 index 000000000..805e021b1 --- /dev/null +++ b/scripts/package/deb/DEBIAN/control @@ -0,0 +1,13 @@ +{{VER=2.0.0}} +Package: harmony +Version: {{ VER }} +License: MIT +Vendor: Harmony blockchain +Architecture: amd64 +Source: https://github.com/harmony-one/harmony +Maintainer: Leo Chen +Section: net +Priority: extra +Homepage: https://harmony.one +Description: Harmony is a sharded, fast finality, low fee, PoS public blockchain. This package contains the validator node program for harmony blockchain. +Build-Dep: dh-systemd diff --git a/scripts/package/deb/DEBIAN/debian-binary b/scripts/package/deb/DEBIAN/debian-binary new file mode 100644 index 000000000..cd5ac039d --- /dev/null +++ b/scripts/package/deb/DEBIAN/debian-binary @@ -0,0 +1 @@ +2.0 diff --git a/scripts/package/deb/DEBIAN/postinst b/scripts/package/deb/DEBIAN/postinst new file mode 100755 index 000000000..39e8221c5 --- /dev/null +++ b/scripts/package/deb/DEBIAN/postinst @@ -0,0 +1,40 @@ +#!/bin/sh + +set -e + +after_install() { + : +} + +after_upgrade() { + : +# systemctl restart harmony +} + + +# Setup system users and groups +addgroup --quiet --system harmony +adduser --quiet --system --ingroup harmony --gecos "harmony validator account" harmony + +if [ "${1}" = "configure" -a -z "${2}" ] || \ + [ "${1}" = "abort-remove" ] +then + # "after install" here + # "abort-remove" happens when the pre-removal script failed. + # In that case, this script, which should be idemptoent, is run + # to ensure a clean roll-back of the removal. + after_install +elif [ "${1}" = "configure" -a -n "${2}" ] +then + upgradeFromVersion="${2}" + # "after upgrade" here + # NOTE: This slot is also used when deb packages are removed, + # but their config files aren't, but a newer version of the + # package is installed later, called "Config-Files" state. + # basically, that still looks a _lot_ like an upgrade to me. + after_upgrade "${2}" +elif echo "${1}" | grep -E -q "(abort|fail)" +then + echo "Failed to install before the post-installation script was run." >&2 + exit 1 +fi diff --git a/scripts/package/deb/DEBIAN/postrm b/scripts/package/deb/DEBIAN/postrm new file mode 100755 index 000000000..1b88a21c8 --- /dev/null +++ b/scripts/package/deb/DEBIAN/postrm @@ -0,0 +1,44 @@ +#!/bin/sh +after_remove() { + : + #rm -rf /data/harmony/latest + #rm -rf /data/harmony/.dht* + #rm -rf /data/harmony/transactions.rlp +} + +after_purge() { + : +} + +dummy() { + : +} + + +if [ "${1}" = "remove" -o "${1}" = "abort-install" ] +then + # "after remove" goes here + # "abort-install" happens when the pre-installation script failed. + # In that case, this script, which should be idemptoent, is run + # to ensure a clean roll-back of the installation. + after_remove +elif [ "${1}" = "purge" -a -z "${2}" ] +then + # like "on remove", but executes after dpkg deletes config files + # 'apt-get purge' runs 'on remove' section, then this section. + # There is no equivalent in RPM or ARCH. + after_purge +elif [ "${1}" = "upgrade" ] +then + # This represents the case where the old package's postrm is called after + # the 'preinst' script is called. + # We should ignore this and just use 'preinst upgrade' and + # 'postinst configure'. The newly installed package should do the + # upgrade, not the uninstalled one, since it can't anticipate what new + # things it will have to do to upgrade for the new version. + dummy +elif echo "${1}" | grep -E -q '(fail|abort)' +then + echo "Failed to install before the post-removal script was run." >&2 + exit 1 +fi diff --git a/scripts/package/deb/DEBIAN/preinst b/scripts/package/deb/DEBIAN/preinst new file mode 100755 index 000000000..cf11183a9 --- /dev/null +++ b/scripts/package/deb/DEBIAN/preinst @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +before_install() { + : +} + +before_upgrade() { + : +} + +if [ "${1}" = "install" -a -z "${2}" ] +then + before_install +elif [ "${1}" = "upgrade" -a -n "${2}" ] +then + upgradeFromVersion="${2}" + before_upgrade "${upgradeFromVersion}" +elif [ "${1}" = "install" -a -n "${2}" ] +then + upgradeFromVersion="${2}" + # Executed when a package is removed but its config files aren't, + # and a new version is installed. + # Looks a _lot_ like an upgrade case, I say we just execute the + # same "before upgrade" script as in the previous case + before_upgrade "${upgradeFromVersion}" +elif echo "${1}" | grep -E -q '(fail|abort)' +then + echo "Failed to install before the pre-installation script was run." >&2 + exit 1 +fi diff --git a/scripts/package/deb/DEBIAN/prerm b/scripts/package/deb/DEBIAN/prerm new file mode 100755 index 000000000..6f41586b4 --- /dev/null +++ b/scripts/package/deb/DEBIAN/prerm @@ -0,0 +1,29 @@ +#!/bin/sh + +set -e + +before_remove() { + : +} + +dummy() { + : +} + +if [ "${1}" = "remove" -a -z "${2}" ] +then + # "before remove" goes here + before_remove +elif [ "${1}" = "upgrade" ] +then + # Executed before the old version is removed + # upon upgrade. + # We should generally not do anything here. The newly installed package + # should do the upgrade, not the uninstalled one, since it can't anticipate + # what new things it will have to do to upgrade for the new version. + dummy +elif echo "${1}" | grep -E -q "(fail|abort)" +then + echo "Failed to install before the pre-removal script was run." >&2 + exit 1 +fi diff --git a/scripts/package/deb/build.sh b/scripts/package/deb/build.sh new file mode 100755 index 000000000..e81795c53 --- /dev/null +++ b/scripts/package/deb/build.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +if [ $# != 1 ]; then + echo "$0 version" + exit +fi + +VERSION=$1 + +fpm -s dir -t deb -n harmony -p harmony_VERSION_ARCH.deb -C harmony-${VERSION} \ + -v "$VERSION" \ + --license "MIT" \ + --vendor "Harmony Blockchain" \ + --category "net" \ + --no-depends \ + --no-auto-depends \ + --directories /etc/harmony \ + --directories /data/harmony \ + --architecture x86_64 \ + --maintainer "Leo Chen " \ + --description "Harmony is a sharded, fast finality, low fee, PoS public blockchain.\nThis package contains the validator node program for harmony blockchain." \ + --url "https://harmony.one" \ + --before-install scripts/preinst \ + --after-install scripts/postinst \ + --before-remove scripts/prerm \ + --after-remove scripts/postrm \ + --before-upgrade scripts/preup \ + --after-upgrade scripts/postup \ + --deb-changelog scripts/changelog \ + --deb-systemd-restart-after-upgrade diff --git a/scripts/package/deb/changelog b/scripts/package/deb/changelog new file mode 100644 index 000000000..103f4cd56 --- /dev/null +++ b/scripts/package/deb/changelog @@ -0,0 +1 @@ +1.0 init harmony debian package diff --git a/scripts/package/harmony-rclone.sh b/scripts/package/harmony-rclone.sh old mode 100644 new mode 100755 diff --git a/scripts/package/harmony-setup.sh b/scripts/package/harmony-setup.sh index b2d07ffb6..c9588c4af 100755 --- a/scripts/package/harmony-setup.sh +++ b/scripts/package/harmony-setup.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash ME=$(basename "$0") -CONFIG=/etc/harmony/harmony.cfg +CONFIG=/etc/harmony/harmony.conf VER=v1.0 function usage() { diff --git a/scripts/package/harmony.service b/scripts/package/harmony.service index 2f7934274..30a7a5a21 100644 --- a/scripts/package/harmony.service +++ b/scripts/package/harmony.service @@ -7,8 +7,9 @@ Type=simple Restart=on-failure RestartSec=1 User=harmony -WorkingDirectory=/data/harmony -ExecStart=/usr/local/sbin/harmony -c /etc/harmony/harmony.conf +Group=harmony +WorkingDirectory=~ +ExecStart=/usr/sbin/harmony -c /etc/harmony/harmony.conf StandardError=syslog SyslogIdentifier=harmony StartLimitInterval=0 diff --git a/scripts/package/rpm/harmony.spec b/scripts/package/rpm/harmony.spec index 856d49d15..757bf1fa6 100644 --- a/scripts/package/rpm/harmony.spec +++ b/scripts/package/rpm/harmony.spec @@ -1,11 +1,11 @@ +{{VER=2.0.0}} # SPEC file overview: # https://docs.fedoraproject.org/en-US/quick-docs/creating-rpm-packages/#con_rpm-spec-file-overview # Fedora packaging guidelines: # https://docs.fedoraproject.org/en-US/packaging-guidelines/ - Name: harmony -Version: 2.3.5 +Version: {{ VER }} Release: 0 Summary: harmony blockchain validator node program @@ -14,12 +14,9 @@ URL: https://harmony.one Source0: %{name}-%{version}.tar BuildArch: x86_64 Packager: Leo Chen -Provides: /bin/sh Requires(pre): shadow-utils Requires: systemd-rpm-macros -BuildRoot: ~/rpmbuild/ - %description Harmony is a sharded, fast finality, low fee, PoS public blockchain. This package contains the validator node program for harmony blockchain. @@ -39,23 +36,23 @@ exit 0 %pre getent group harmony >/dev/null || groupadd -r harmony getent passwd harmony >/dev/null || \ - useradd -r -g harmony -d /data/harmony -m -s /sbin/nologin \ + useradd -r -g harmony -d /home/harmony -m -s /sbin/nologin \ -c "Harmony validator node account" harmony -mkdir -p /data/harmony/.hmy/blskeys -mkdir -p /data/harmony/.config/rclone -chown -R harmony.harmony /data/harmony +mkdir -p /home/harmony/.hmy/blskeys +mkdir -p /home/harmony/.config/rclone +chown -R harmony.harmony /home/harmony exit 0 %install -install -m 0755 -d ${RPM_BUILD_ROOT}/usr/local/sbin ${RPM_BUILD_ROOT}/etc/systemd/system ${RPM_BUILD_ROOT}/etc/sysctl.d ${RPM_BUILD_ROOT}/etc/harmony -install -m 0755 -d ${RPM_BUILD_ROOT}/data/harmony/.config/rclone -install -m 0755 harmony ${RPM_BUILD_ROOT}/usr/local/sbin/ -install -m 0755 harmony-setup.sh ${RPM_BUILD_ROOT}/usr/local/sbin/ -install -m 0755 harmony-rclone.sh ${RPM_BUILD_ROOT}/usr/local/sbin/ -install -m 0644 rclone.conf ${RPM_BUILD_ROOT}/data/harmony/.config/rclone/ +install -m 0755 -d ${RPM_BUILD_ROOT}/usr/sbin ${RPM_BUILD_ROOT}/etc/systemd/system ${RPM_BUILD_ROOT}/etc/sysctl.d ${RPM_BUILD_ROOT}/etc/harmony +install -m 0755 -d ${RPM_BUILD_ROOT}/home/harmony/.config/rclone +install -m 0755 harmony ${RPM_BUILD_ROOT}/usr/sbin/ +install -m 0755 harmony-setup.sh ${RPM_BUILD_ROOT}/usr/sbin/ +install -m 0755 harmony-rclone.sh ${RPM_BUILD_ROOT}/usr/sbin/ install -m 0644 harmony.service ${RPM_BUILD_ROOT}/etc/systemd/system/ -install -m 0644 harmony-sysctl.conf ${RPM_BUILD_ROOT}/etc/sysctl.d/ +install -m 0644 harmony-sysctl.conf ${RPM_BUILD_ROOT}/etc/sysctl.d/99-harmony.conf +install -m 0644 rclone.conf ${RPM_BUILD_ROOT}/etc/harmony/ install -m 0644 harmony.conf ${RPM_BUILD_ROOT}/etc/harmony/ exit 0 @@ -70,13 +67,14 @@ exit 0 %systemd_postun_with_restart ${name}.service %files -/usr/local/sbin/harmony -/usr/local/sbin/harmony-setup.sh -/usr/local/sbin/harmony-rclone.sh -/etc/sysctl.d/harmony-sysctl.conf +/usr/sbin/harmony +/usr/sbin/harmony-setup.sh +/usr/sbin/harmony-rclone.sh +/etc/sysctl.d/99-harmony.conf /etc/systemd/system/harmony.service /etc/harmony/harmony.conf -/data/harmony/.config/rclone +/etc/harmony/rclone.conf +/home/harmony/.config/rclone %doc %license diff --git a/scripts/package/templater.sh b/scripts/package/templater.sh new file mode 100755 index 000000000..2bdb4ede4 --- /dev/null +++ b/scripts/package/templater.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# Replaces all {{VAR}} by the $VAR value in a template file and outputs it +# Use with -h to output all variables +# curtesy of https://github.com/lavoiesl/bash-templater/blob/master/templater.sh + +if [[ ! -f "$1" ]]; then + echo "Usage: VAR=value $0 template" >&2 + exit 1 +fi + +template="$1" +vars=$(grep -oE '\{\{\s*[A-Za-z0-9_]+\s*\}\}' "$template" | sort | uniq | sed -e 's/^{{//' -e 's/}}$//') + +if [[ -z "$vars" ]]; then + echo "Warning: No variable was found in $template, syntax is {{VAR}}" >&2 +fi + +var_value() { + var="${1}" + eval echo \$"${var}" +} + +## +# Escape custom characters in a string +# Example: escape "ab'\c" '\' "'" ===> ab\'\\c +# +function escape_chars() { + local content="${1}" + shift + + for char in "$@"; do + content="${content//${char}/\\${char}}" + done + + echo "${content}" +} + +function echo_var() { + local var="${1}" + local content="${2}" + local escaped="$(escape_chars "${content}" "\\" '"')" + + echo "${var}=\"${escaped}\"" +} + +declare -a replaces +replaces=() + +# Reads default values defined as {{VAR=value}} and delete those lines +# There are evaluated, so you can do {{PATH=$HOME}} or {{PATH=`pwd`}} +# You can even reference variables defined in the template before +defaults=$(grep -oE '^\{\{[A-Za-z0-9_]+=.+\}\}$' "${template}" | sed -e 's/^{{//' -e 's/}}$//') +IFS=$'\n' +for default in $defaults; do + var=$(echo "${default}" | grep -oE "^[A-Za-z0-9_]+") + current="$(var_value "${var}")" + + # Replace only if var is not set + if [[ -n "$current" ]]; then + eval "$(echo_var "${var}" "${current}")" + else + eval "${default}" + fi + + # remove define line + replaces+=("-e") + replaces+=("/^{{${var}=/d") + vars="${vars} ${var}" +done + +vars="$(echo "${vars}" | tr " " "\n" | sort | uniq)" + +if [[ "$2" = "-h" ]]; then + for var in $vars; do + value="$(var_value "${var}")" + echo_var "${var}" "${value}" + done + exit 0 +fi + +# Replace all {{VAR}} by $VAR value +for var in $vars; do + value="$(var_value "${var}")" + if [[ -z "$value" ]]; then + echo "Warning: $var is not defined and no default is set, replacing by empty" >&2 + fi + + # Escape slashes + value="$(escape_chars "${value}" "\\" '/' ' ')"; + replaces+=("-e") + replaces+=("s/{{\s*${var}\s*}}/${value}/g") +done + +sed "${replaces[@]}" "${template}"