summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Olson <brian.olson@algorand.com>2019-06-11 09:26:39 -0400
committerBrian Olson <brian.olson@algorand.com>2019-06-11 09:26:39 -0400
commitef889726afc4da12d161bfb6936edbe97777f58c (patch)
tree06181a6a6db9fa9812ffd533592f77e38d214fdb
parenta9c28959fbd4e4bd3e2d8c4fa37152d01fdf4274 (diff)
new release build processorigin/bolson/goal2-638-release-build
-rw-r--r--.travis.yml4
-rwxr-xr-xscripts/build/stable.sh6
-rwxr-xr-xscripts/build_deb.sh7
-rwxr-xr-xscripts/build_package.sh9
-rwxr-xr-xscripts/build_packages.sh23
-rwxr-xr-xscripts/build_release.sh149
-rw-r--r--scripts/build_release_centos_docker.sh42
-rw-r--r--scripts/build_release_local.sh77
-rw-r--r--scripts/build_release_setup.sh123
-rwxr-xr-xscripts/build_rpm.sh7
-rw-r--r--scripts/centos-build.Dockerfile6
-rwxr-xr-xscripts/get_latest_go.py91
-rwxr-xr-xscripts/release_deb.sh79
-rwxr-xr-xscripts/reverse_hex_timestamp6
14 files changed, 606 insertions, 23 deletions
diff --git a/.travis.yml b/.travis.yml
index 77526206a..6baae5b47 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,9 +16,9 @@ stages:
- name: build_release
if: branch =~ /^rel\// AND type != pull_request
- name: deploy
- if: branch =~ /^rel\// AND type != pull_request
+ if: branch =~ /^rel\/nightly/ AND type != pull_request
- name: release
- if: branch =~ /^rel\// AND type != pull_request
+ if: branch =~ /^rel\/nightly/ AND type != pull_request
jobs:
include:
diff --git a/scripts/build/stable.sh b/scripts/build/stable.sh
index 1e8923895..e4ad652bd 100755
--- a/scripts/build/stable.sh
+++ b/scripts/build/stable.sh
@@ -39,5 +39,9 @@ git commit -m "Build ${BUILD_NUMBER}"
git push
TAG=rel/stable-$(scripts/compute_build_number.sh -f)
-git tag -a ${TAG} -m "Genesis Timestamp: $(cat ./genesistimestamp.dat)"
+if [ ! -z "${SIGNING_KEY_ADDR}" ]; then
+ git tag -s -u "${SIGNING_KEY_ADDR}" ${TAG} -m "Genesis Timestamp: $(cat ./genesistimestamp.dat)"
+else
+ git tag -a ${TAG} -m "Genesis Timestamp: $(cat ./genesistimestamp.dat)"
+fi
git push origin ${TAG}
diff --git a/scripts/build_deb.sh b/scripts/build_deb.sh
index 6d4116cd5..7c743d0ce 100755
--- a/scripts/build_deb.sh
+++ b/scripts/build_deb.sh
@@ -27,7 +27,12 @@ cd ${REPO_DIR}
echo "Building debian package for '${OS} - ${ARCH}'"
-env GOOS=${OS} GOARCH=${ARCH} scripts/build_prod.sh
+if [ -z "${NO_BUILD}" ]; then
+ env GOOS=${OS} GOARCH=${ARCH} scripts/build_prod.sh
+else
+ echo "already built"
+ true
+fi
VER=$(./scripts/compute_build_number.sh -f)
diff --git a/scripts/build_package.sh b/scripts/build_package.sh
index fe5bfd7f9..e5cd02e8a 100755
--- a/scripts/build_package.sh
+++ b/scripts/build_package.sh
@@ -21,6 +21,8 @@ if [ ! "$#" -eq 3 ]; then
exit 1
fi
+set -x
+
OS=$1
ARCH=$2
PKG_ROOT=$3
@@ -36,7 +38,12 @@ cd ${REPO_DIR}
echo "Building package for '${OS} - ${ARCH}'"
-env GOOS=${OS} GOARCH=${ARCH} scripts/build_prod.sh
+if [ -z "${NO_BUILD}" ]; then
+ env GOOS=${OS} GOARCH=${ARCH} scripts/build_prod.sh
+else
+ echo "already built"
+ true
+fi
if [ $? -ne 0 ]; then
echo 'Error building! Aborting...'
diff --git a/scripts/build_packages.sh b/scripts/build_packages.sh
index 0ec9c89de..adac93ab0 100755
--- a/scripts/build_packages.sh
+++ b/scripts/build_packages.sh
@@ -19,6 +19,8 @@ if [ "$#" -eq 0 ]; then
exit 1
fi
+set -x
+
export GOPATH=$(go env GOPATH)
cd ${GOPATH}/src/github.com/algorand/go-algorand
@@ -47,9 +49,9 @@ export TIMESTAMP=${TIMESTAMP}
# To ensure deterministic availability of testnet (stable) builds, prefix the packages
# with "pending_" so updater will not detect the package before we rename it.
GATE_PREFIX=""
-if [[ "${CHANNEL}" = "stable" || "${CHANNEL}" = "nightly" ]]; then
- GATE_PREFIX="pending_"
-fi
+# if [[ "${CHANNEL}" = "stable" || "${CHANNEL}" = "nightly" ]]; then
+# GATE_PREFIX="pending_"
+# fi
VERSION_COMPONENTS=(${FULLVERSION//\./ })
export BUILDNUMBER=${VERSION_COMPONENTS[2]}
@@ -126,17 +128,7 @@ for var in "${VARIATION_ARRAY[@]}"; do
exit 1
fi
pushd ${DEBTMP}
- tar -zcf ${PKG_ROOT}/${GATE_PREFIX}deb_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.tar.gz *.deb >/dev/null 2>&1
- popd
- fi
-
- # If Linux package, build RPM package as well
- if [ $(scripts/ostype.sh) = "linux" ]; then
- RPMTMP=$(mktemp -d 2>/dev/null || mktemp -d -t "rpmtmp")
- trap "rm -rf ${RPMTMP}" 0
- scripts/build_rpm.sh ${RPMTMP}
- pushd ${RPMTMP}
- tar -zcf ${PKG_ROOT}/${GATE_PREFIX}rpm_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.tar.gz */*.rpm >/dev/null 2>&1
+ cp -p *.deb ${PKG_ROOT}/${GATE_PREFIX}algorand_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.deb
popd
fi
@@ -146,9 +138,6 @@ for var in "${VARIATION_ARRAY[@]}"; do
cp ${PKG_ROOT}/${GATE_PREFIX}node_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.tar.gz ${PKG_ROOT}/${GATE_PREFIX}node_${CHANNEL}-telem_${PKG_NAME}_${FULLVERSION}.tar.gz
cp ${PKG_ROOT}/${GATE_PREFIX}install_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.tar.gz ${PKG_ROOT}/${GATE_PREFIX}install_${CHANNEL}-telem_${PKG_NAME}_${FULLVERSION}.tar.gz
cp ${PKG_ROOT}/${GATE_PREFIX}tools_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.tar.gz ${PKG_ROOT}/${GATE_PREFIX}tools_${CHANNEL}-telem_${PKG_NAME}_${FULLVERSION}.tar.gz
- if [ $(scripts/ostype.sh) = "linux" ]; then
- cp ${PKG_ROOT}/${GATE_PREFIX}deb_${CHANNEL}_${PKG_NAME}_${FULLVERSION}.tar.gz ${PKG_ROOT}/${GATE_PREFIX}deb_${CHANNEL}-telem_${PKG_NAME}_${FULLVERSION}.tar.gz
- fi
fi
done
done
diff --git a/scripts/build_release.sh b/scripts/build_release.sh
new file mode 100755
index 000000000..967cb5d35
--- /dev/null
+++ b/scripts/build_release.sh
@@ -0,0 +1,149 @@
+#!/bin/bash
+#
+# This script needs to be run in a terminal with a human watching to
+# be prompted for GPG key password at a couple points.
+#
+# Externally settable env vars:
+# S3_PREFIX= where to upload build artifacts
+# AWS_EFS_MOUNT= NFS to mount for `aptly` persistent state and scratch storage
+# SIGNING_KEY_ADDR= dev@algorand.com or similar for GPG key
+# RSTAMP= `scripts/reverse_hex_timestamp`
+# AWS_ACCESS_KEY_ID=
+# AWS_SECRET_ACCESS_KEY=
+
+date "+build_release start %Y%m%d_%H%M%S"
+
+set -e
+set -x
+
+if [ -z "${S3_PREFIX}" ]; then
+ S3_PREFIX=s3://algorand-builds
+fi
+
+# persistent storage of repo manager scratch space is on EFS
+if [ ! -z "${AWS_EFS_MOUNT}" ]; then
+ if mount|grep -q /data; then
+ echo /data already mounted
+ else
+ sudo mkdir -p /data
+ sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport "${AWS_EFS_MOUNT}":/ /data
+ # make environment for release_deb.sh
+ sudo mkdir -p /data/_aptly
+ sudo chown -R ${USER} /data/_aptly
+ export APTLY_DIR=/data/_aptly
+ fi
+fi
+
+export GOPATH=${HOME}/go
+export PATH=${HOME}/gpgbin:${GOPATH}/bin:/usr/local/go/bin:${PATH}
+
+cd ${GOPATH}/src/github.com/algorand/go-algorand
+export RELEASE_GENESIS_PROCESS=true
+export TRANSITION_TELEMETRY_BUILDS=true
+PLATFORM=$(./scripts/osarchtype.sh)
+PLATFORM_SPLIT=(${PLATFORM//\// })
+OS=${PLATFORM_SPLIT[0]}
+ARCH=${PLATFORM_SPLIT[1]}
+export BRANCH=rel/stable
+export CHANNEL=$(./scripts/compute_branch_channel.sh ${BRANCH})
+export PKG_ROOT=${HOME}/node_pkg
+export VARIATIONS="base"
+# tell underlying 'build' scripts we already built
+export NO_BUILD=true
+if [ -z "${RSTAMP}" ]; then
+ RSTAMP=$(scripts/reverse_hex_timestamp)
+fi
+
+# Update version file for this build
+BUILD_NUMBER=
+if [ -e buildnumber.dat ]; then
+ BUILD_NUMBER=$(cat ./buildnumber.dat)
+else
+ BUILD_NUMBER=0
+fi
+BUILD_NUMBER=$((${BUILD_NUMBER} + 1))
+echo ${BUILD_NUMBER} > ./buildnumber.dat
+export FULLVERSION=$(./scripts/compute_build_number.sh -f)
+
+
+# Build!
+scripts/configure_dev.sh
+
+make ${GOPATH}/src/github.com/algorand/go-algorand/crypto/lib/libsodium.a
+
+make build
+
+scripts/build_packages.sh "${PLATFORM}"
+
+# Tag Source
+git add -A
+git commit -m "Build ${BUILD_NUMBER}"
+
+TAG=${BRANCH}-${FULLVERSION}
+if [ ! -z "${SIGNING_KEY_ADDR}" ]; then
+ git tag -s -u "${SIGNING_KEY_ADDR}" ${TAG} -m "Genesis Timestamp: $(cat ./genesistimestamp.dat)"
+else
+ git tag -s ${TAG} -m "Genesis Timestamp: $(cat ./genesistimestamp.dat)"
+fi
+git push origin ${TAG}
+
+git archive --prefix=algorand-${FULLVERSION}/ "${TAG}" | gzip > ${PKG_ROOT}/algorand_${CHANNEL}_source_${FULLVERSION}.tar.gz
+
+# Run RPM bulid in Centos7 Docker container
+sg docker "docker build -t algocentosbuild - < scripts/centos-build.Dockerfile"
+
+# cleanup our libsodium build
+if [ -f ${GOPATH}/src/github.com/algorand/go-algorand/crypto/libsodium-fork/Makefile ]; then
+ (cd ${GOPATH}/src/github.com/algorand/go-algorand/crypto/libsodium-fork && make distclean)
+fi
+rm -rf ${GOPATH}/src/github.com/algorand/go-algorand/crypto/lib
+
+# do the RPM build
+sg docker "docker run --mount type=bind,src=${GOPATH}/src,dst=/root/go/src --mount type=bind,src=${HOME},dst=/root/subhome --mount type=bind,src=/usr/local/go,dst=/usr/local/go -a stdout -a stderr algocentosbuild /root/go/src/github.com/algorand/go-algorand/scripts/build_release_centos_docker.sh"
+
+
+# create *.sig gpg signatures
+cd ${PKG_ROOT}
+for i in *.tar.gz *.deb *.rpm; do
+ gpg --detach-sign "${i}"
+done
+HASHFILE=hashes_${CHANNEL}_${OS}_${ARCH}_${FULLVERSION}
+rm -f "${HASHFILE}"
+touch "${HASHFILE}"
+md5sum *.tar.gz *.deb *.rpm >> "${HASHFILE}"
+shasum -a 256 *.tar.gz *.deb *.rpm >> "${HASHFILE}"
+shasum -a 512 *.tar.gz *.deb *.rpm >> "${HASHFILE}"
+gpg --detach-sign "${HASHFILE}"
+gpg --clearsign "${HASHFILE}"
+
+echo RSTAMP=${RSTAMP} > "${HOME}/rstamp"
+aws s3 sync --quiet --exclude dev\* --exclude master\* --exclude nightly\* --exclude stable\* --acl public-read ./ ${S3_PREFIX}/${CHANNEL}/${RSTAMP}_${FULLVERSION}/
+
+# copy .rpm file to intermediate yum repo scratch space, actual publish manually later
+if [ ! -d /data/yumrepo ]; then
+ sudo mkdir -p /data/yumrepo
+ sudo chown ${USER} /data/yumrepo
+fi
+cp -p -n *.rpm *.rpm.sig /data/yumrepo
+
+cd ${HOME}
+STATUSFILE=build_status_${CHANNEL}_${FULLVERSION}
+echo "ami-id:" > "${STATUSFILE}"
+curl --silent http://169.254.169.254/latest/meta-data/ami-id >> "${STATUSFILE}"
+cat <<EOF>>"${STATUSFILE}"
+
+
+dpkg-l:
+EOF
+dpkg -l >>"${STATUSFILE}"
+gpg --clearsign "${STATUSFILE}"
+gzip "${STATUSFILE}.asc"
+aws s3 cp --quiet "${STATUSFILE}.asc.gz" "s3://algorand-devops-misc/buildlog/${RSTAMP}/${STATUSFILE}.asc.gz"
+
+# use aptly to push .deb to its serving repo
+# Leave .deb publishing to manual step after we do more checks on the release artifacts.
+# ${GOPATH}/src/github.com/algorand/go-algorand/scripts/release_deb.sh ${PKG_ROOT}/*deb
+
+# TODO: manually post rpm to repo
+
+date "+build_release finish %Y%m%d_%H%M%S"
diff --git a/scripts/build_release_centos_docker.sh b/scripts/build_release_centos_docker.sh
new file mode 100644
index 000000000..e6f09fa01
--- /dev/null
+++ b/scripts/build_release_centos_docker.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+# build centos rpm from inside docker
+#
+# mount src from outside
+# --mount type=bind,src=${GOPATH}/src,dst=/root/go/src
+#
+# mount golang install from outside
+# --mount type=bind,src=/usr/local/go,dst=/usr/local/go
+#
+# output copied to /root/subhome/node_pkg
+# --mount type=bind,src=${HOME},dst=/root/subhome
+
+set -e
+set -x
+
+export HOME=/root
+mkdir -p ${HOME}/go
+mkdir -p ${HOME}/go/bin
+export GOPATH=${HOME}/go
+export PATH=${GOPATH}/bin:/usr/local/go/bin:${PATH}
+
+go install golang.org/x/lint/golint
+go install github.com/golang/dep/cmd/dep
+go install golang.org/x/tools/cmd/stringer
+go install github.com/go-swagger/go-swagger/cmd/swagger
+
+
+cd ${GOPATH}/src/github.com/algorand/go-algorand
+
+# definitely rebuild libsodium which could link to external C libraries
+if [ -f ${GOPATH}/src/github.com/algorand/go-algorand/crypto/libsodium-fork/Makefile ]; then
+ (cd ${GOPATH}/src/github.com/algorand/go-algorand/crypto/libsodium-fork && make distclean)
+fi
+rm -rf ${GOPATH}/src/github.com/algorand/go-algorand/crypto/lib
+make ${GOPATH}/src/github.com/algorand/go-algorand/crypto/lib/libsodium.a
+
+make build
+
+RPMTMP=$(mktemp -d 2>/dev/null || mktemp -d -t "rpmtmp")
+trap "rm -rf ${RPMTMP}" 0
+scripts/build_rpm.sh ${RPMTMP}
+cp -p ${RPMTMP}/*/*.rpm /root/subhome/node_pkg
diff --git a/scripts/build_release_local.sh b/scripts/build_release_local.sh
new file mode 100644
index 000000000..3e12a8783
--- /dev/null
+++ b/scripts/build_release_local.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+echo "this is a file of commands to copy and paste to run build_release.sh on an AWS EC2 instance"
+exit 1
+
+# use AWS console to create a new t3.large with the latest official Ubuntu 18.04
+
+# ec2 public address here:
+TARGET=
+
+cd ${GOPATH}/src/github.com/algorand/go-algorand
+
+git fetch
+git checkout rel/stable
+git merge origin/rel/stable
+scp -p ${GOPATH}/src/github.com/algorand/go-algorand/scripts/build_release_setup.sh ubuntu@${TARGET}:~/
+
+# upload the latest public key
+GTMPDIR=$(mktemp -d 2>/dev/null || mktemp -d -t "rpmtmp")
+gpg --export --armor -o "${GTMPDIR}/key.gpg" sa@algorand.com
+scp -p "${GTMPDIR}/key.gpg" "ubuntu@${TARGET}:~/key.gpg"
+rm -rf ${GTMPDIR}
+
+ssh -A ubuntu@${TARGET} bash build_release_setup.sh
+
+# setup GPG key forwarding https://wiki.gnupg.org/AgentForwarding
+umask 0077
+mkdir -p ${HOME}/.gnupg
+touch ${HOME}/.gnupg/gpg-agent.conf
+if grep -q extra-socket ${HOME}/.gnupg/gpg-agent.conf; then
+ echo "already have extra-socket"
+else
+ cat <<EOF>>${HOME}/.gnupg/gpg-agent.conf
+extra-socket ${HOME}/.gnupg/S.gpg-agent.extra
+default-cache-ttl 3600
+EOF
+fi
+umask 0002
+
+# this will require your key password, and export a private key file protected by the same password
+
+# warm up your local gpg-agent
+gpg --clearsign
+type some stuff
+^D
+
+
+# TODO: use simpler expression when we can rely on gpg 2.2 on ubuntu >= 18.04
+#REMOTE_GPG_SOCKET=$(ssh ubuntu@${TARGET} gpgconf --list-dir agent-socket)
+REMOTE_GPG_SOCKET=$(ssh ubuntu@${TARGET} "gpgconf --list-dirs|grep agent-socket|awk -F: '{ print \$2 }'")
+LOCAL_GPG_SOCKET=$(gpgconf --list-dir agent-extra-socket)
+ssh -A -R "${REMOTE_GPG_SOCKET}:${LOCAL_GPG_SOCKET}" ubuntu@${TARGET}
+
+# set AWS credentials so we can upload to S3 and connect to EFS
+export AWS_ACCESS_KEY_ID=
+export AWS_SECRET_ACCESS_KEY=
+
+# where we store persistent scratch space for aptly
+export AWS_EFS_MOUNT=
+
+# build_release.sh needs to be run in a terminal with a human watching
+# to be prompted for GPG key password at a couple points.
+# It can still steal the outer terminal from within piping the output to tee. Nifty, huh?
+BUILDTIMESTAMP=$(cat "${HOME}/buildtimestamp")
+(bash "${HOME}/go/src/github.com/algorand/go-algorand/scripts/build_release.sh" 2>&1)|tee -a "buildlog_${BUILDTIMESTAMP}"
+if [ -f "${HOME}/rstamp" ]; then
+ . "${HOME}/rstamp"
+fi
+if [ -z "${RSTAMP}" ]; then
+ RSTAMP=$(${HOME}/go/src/github.com/algorand/go-algorand/scripts/reverse_hex_timestamp)
+fi
+if [ -z "${RSTAMP}" ]; then
+ echo "could not figure out RSTAMP, script must have failed early"
+ exit 1
+fi
+gzip buildlog_*
+aws s3 cp buildlog_*.gz s3://algorand-devops-misc/buildlog/${RSTAMP}/
diff --git a/scripts/build_release_setup.sh b/scripts/build_release_setup.sh
new file mode 100644
index 000000000..9b52d5582
--- /dev/null
+++ b/scripts/build_release_setup.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+#
+# Externally settable env vars:
+# GIT_REPO_PATH= something to `git clone` from
+# GIT_CHECKOUT_LABEL= something to `git checkout` and build from (branch or tag or hash)
+# SIGNING_KEY_ADDR= dev@algorand.com or similar for GPG key
+
+if [ -z "${BUILDTIMESTAMP}" ]; then
+ date "+%Y%m%d_%H%M%S" > "${HOME}/buildtimestamp"
+ BUILDTIMESTAMP=$(cat "${HOME}/buildtimestamp")
+ export BUILDTIMESTAMP
+ echo run "${0}" with output to ${HOME}/buildlog_${BUILDTIMESTAMP}
+ (bash "${0}" 2>&1) | tee ${HOME}/buildlog_${BUILDTIMESTAMP}
+ exit 0
+fi
+
+date "+setup start %Y%m%d_%H%M%S"
+
+set -e
+set -x
+
+if [ -z "${GIT_REPO_PATH}" ]; then
+ GIT_REPO_PATH=git@github.com:algorand/go-algorand.git
+fi
+
+if [ -z "${GIT_CHECKOUT_LABEL}" ]; then
+ GIT_CHECKOUT_LABEL="rel/stable"
+fi
+
+sudo apt-get update
+sudo apt-get upgrade -y
+
+if [ -f /etc/lsb-release ]; then
+ . /etc/lsb-release
+fi
+
+mkdir -p ${HOME}/go
+mkdir -p ${HOME}/gpgbin
+
+if [ "${DISTRIB_ID}" = "Ubuntu" ]; then
+ if [ "${DISTRIB_RELEASE}" = "16.04" ]; then
+ echo "WARNING: Ubuntu 16.04 is DEPRECATED"
+ sudo apt-get install -y autoconf awscli docker.io g++ fakeroot git gnupg2 gpgv2 make nfs-common python3 rpm sqlite3
+ cat <<EOF>${HOME}/gpgbin/gpg
+#!/bin/bash
+exec /usr/bin/gpg2 "\$@"
+EOF
+ cat <<EOF>${HOME}/gpgbin/gpgv
+#!/bin/bash
+exec /usr/bin/gpgv2 "\$@"
+EOF
+ chmod +x ${HOME}/gpgbin/*
+ elif [ "${DISTRIB_RELEASE}" = "18.04" ]; then
+ sudo apt-get install -y autoconf awscli docker.io git gpg nfs-common python3 rpm sqlite3
+ else
+ echo "don't know how to build on Ubuntu ${DISTRIB_RELEASE}"
+ exit 1
+ fi
+else
+ echo "don't know how to build non Ubuntu, /etc/lsb-release[DISTRIB_ID]=${DISTRIB_ID}"
+ exit 1
+fi
+
+export GOPATH=${HOME}/go
+export PATH=${HOME}/gpgbin:${GOPATH}/bin:/usr/local/go/bin:${PATH}
+
+# please keep packages sorted
+
+# This real name and email must precisely match GPG key
+git config --global user.name "Algorand developers"
+git config --global user.email dev@algorand.com
+
+# configure GnuPG to rely on forwarded remote gpg-agent
+umask 0077
+mkdir -p "${HOME}/.gnupg"
+touch "${HOME}/.gnupg/gpg.conf"
+if grep -q no-autostart "${HOME}/.gnupg/gpg.conf"; then
+ echo ""
+else
+ echo "no-autostart" >> "${HOME}/.gnupg/gpg.conf"
+fi
+
+if [ -f "${HOME}/key.gpg" ]; then
+ gpg --import "${HOME}/key.gpg"
+fi
+# we had a tight umask for gpg setup, but need wider for git clone below
+umask 0002
+
+# allow ssh to clobber unix domain sockets for gpg-agent forwarding
+if grep -q ^StreamLocalBindUnlink /etc/ssh/sshd_config; then
+ echo already have StreamLocalBindUnlink sshd config
+else
+ sudo bash -c "echo 'StreamLocalBindUnlink yes' >> /etc/ssh/sshd_config"
+ sudo systemctl restart sshd
+fi
+
+sudo usermod -a -G docker ubuntu
+sg docker "docker pull centos:7"
+
+# Check out
+mkdir -p ${GOPATH}/src/github.com/algorand
+if [ ! -d "${GOPATH}/src/github.com/algorand/go-algorand/.git" ]; then
+ (cd ${GOPATH}/src/github.com/algorand && git clone "${GIT_REPO_PATH}")
+fi
+cd ${GOPATH}/src/github.com/algorand/go-algorand
+git checkout "${GIT_CHECKOUT_LABEL}"
+
+# Install latest Go
+cd $HOME
+# TODO: make a config file in root of repo with single source of truth for Go major-minor version
+if [ ! -e /usr/local/go/bin/go ]; then
+ python3 ${GOPATH}/src/github.com/algorand/go-algorand/scripts/get_latest_go.py --version-prefix=1.12
+ # $HOME will be interpreted by the outer shell to create the string passed to sudo bash
+ sudo bash -c "cd /usr/local && tar zxf ${HOME}/go*.tar.gz"
+fi
+
+cat<<EOF>> "${HOME}/.bashrc"
+export EDITOR=vi
+export GOPATH=\${HOME}/go
+export PATH=\${HOME}/gpgbin:\${GOPATH}/bin:/usr/local/go/bin:\${PATH}
+EOF
+
+date "+setup finish %Y%m%d_%H%M%S"
diff --git a/scripts/build_rpm.sh b/scripts/build_rpm.sh
index 24318e847..2f2991524 100755
--- a/scripts/build_rpm.sh
+++ b/scripts/build_rpm.sh
@@ -19,7 +19,12 @@ cd ${REPO_DIR}
echo "Building RPM package"
-./scripts/build_prod.sh
+if [ -z "${NO_BUILD}" ]; then
+ env GOOS=${OS} GOARCH=${ARCH} scripts/build_prod.sh
+else
+ echo "already built"
+ true
+fi
VER=$(./scripts/compute_build_number.sh -f)
diff --git a/scripts/centos-build.Dockerfile b/scripts/centos-build.Dockerfile
new file mode 100644
index 000000000..310d85222
--- /dev/null
+++ b/scripts/centos-build.Dockerfile
@@ -0,0 +1,6 @@
+FROM centos:7
+WORKDIR /root
+RUN yum install -y epel-release https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
+RUN yum install -y autoconf awscli git gnupg2 nfs-utils python36 sqlite3 boost-devel expect jq libtool gcc-c++ libstdc++-devel libstdc++-static rpmdevtools
+
+ENTRYPOINT ["/bin/bash"]
diff --git a/scripts/get_latest_go.py b/scripts/get_latest_go.py
new file mode 100755
index 000000000..c3b70aa39
--- /dev/null
+++ b/scripts/get_latest_go.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+
+# use just stdlib so we can run with nothing more than `apt-get install -y python3`
+import hashlib
+import http.client
+import json
+import os
+import re
+import shutil
+import subprocess
+import sys
+
+
+version_re = re.compile(r'\D+([0-9][.0-9]+)')
+
+def parseversion(x):
+ m = version_re.match(x)
+ return m.group(1).split('.')
+
+def get():
+ # curl 'https://golang.org/dl/?mode=json'
+ conn = http.client.HTTPSConnection('golang.org')
+ conn.request('GET', '/dl/?mode=json')
+ response = conn.getresponse()
+ jsblob = response.read()
+ # Python <= 3.5 json.loads() doesn't take bytes
+ if isinstance(jsblob, bytes):
+ jsblob = jsblob.decode('utf-8')
+ return json.loads(jsblob)
+
+def loadfile(path):
+ # curl -o golang_dl.json 'https://golang.org/dl/?mode=json'
+ # DRYRUN=1 python3 get_latest_go.py golang_dl.json
+ with open(path) as fin:
+ return json.load(fin)
+
+def main():
+ import argparse
+ ap = argparse.ArgumentParser()
+ ap.add_argument('--json', help='pre-downloaded json from https://golang.org/dl/?mode=json')
+ ap.add_argument('--version-prefix', help='e.g. 1.12 and get the latest 1.12.x')
+ args = ap.parse_args()
+ if args.json:
+ ob = loadfile(args.json)
+ else:
+ ob = get()
+ ob = filter(lambda x: x['stable'], ob)
+ if args.version_prefix:
+ ob = list(ob)
+ filtered_versions = []
+ for v in ob:
+ m = version_re.match(v['version'])
+ if m:
+ version_string = m.group(1)
+ if version_string.startswith(args.version_prefix):
+ filtered_versions.append(v)
+ if not filtered_versions:
+ sys.stderr.write('--version-prefix {!r} filtered out all versions: {!r}\n'.format(args.version_prefix, [v['version'] for v in ob]))
+ sys.exit(1)
+ ob = filtered_versions
+ orderedbyversion = sorted([(parseversion(v['version']),v) for v in ob], reverse=True)
+ newest = orderedbyversion[0][1]
+ files = list(filter(lambda x: x['arch']=='amd64' and x['os']=='linux', newest['files']))
+ fname = files[0]['filename']
+ sha256 = files[0]['sha256']
+ url = 'https://dl.google.com/go/{}'.format(fname)
+
+ # e.g. https://dl.google.com/go/go1.12.5.linux-amd64.tar.gz
+ if os.environ.get('DRYRUN'):
+ sys.stdout.write('curl -L -O {}\n{}\n'.format(url, sha256))
+ else:
+ sys.stdout.write('fetching {}\n'.format(url))
+ subprocess.run(['curl', '-L', '-O', url])
+ fhash = hashlib.sha256()
+ with open(fname, 'rb') as fin:
+ bb = bytearray(64*1024)
+ while True:
+ got = fin.readinto(bb)
+ if got == 0:
+ break
+ fhash.update(bb[:got])
+ dldigest = fhash.hexdigest()
+ if dldigest != sha256:
+ sys.stderr.write('hash mismatch, wanted {} got {}\n'.format(sha256, dldigest))
+ os.unlink(fname)
+ sys.stdout.write('Done\n')
+ return
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/release_deb.sh b/scripts/release_deb.sh
new file mode 100755
index 000000000..ce16cd006
--- /dev/null
+++ b/scripts/release_deb.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# Usage: release_deb.sh *.deb
+#
+# To run on an ephemeral instance, mount AWS EFS somewhere and use it:
+# APTLY_DIR=/large/persistent/filesystem ./release_deb.sh *.deb
+
+
+set -e
+set -x
+
+if [ -z "${APTLY_DIR}" ]; then
+ APTLY_DIR=${HOME}/.aptly
+fi
+
+if [ -z "${APTLY_S3_NAME}" ]; then
+ APTLY_S3_NAME=algorand-releases
+fi
+
+cat <<EOF>${HOME}/.aptly.conf
+{
+ "rootDir": "${APTLY_DIR}",
+ "downloadConcurrency": 4,
+ "downloadSpeedLimit": 0,
+ "architectures": [],
+ "dependencyFollowSuggests": false,
+ "dependencyFollowRecommends": false,
+ "dependencyFollowAllVariants": false,
+ "dependencyFollowSource": false,
+ "dependencyVerboseResolve": false,
+ "gpgDisableSign": false,
+ "gpgDisableVerify": false,
+ "gpgProvider": "gpg",
+ "downloadSourcePackages": false,
+ "skipLegacyPool": true,
+ "ppaDistributorID": "ubuntu",
+ "ppaCodename": "",
+ "skipContentsPublishing": false,
+ "FileSystemPublishEndpoints": {},
+ "S3PublishEndpoints": {
+ "algorand-releases": {
+ "region":"us-east-1",
+ "bucket":"algorand-releases",
+ "acl":"public-read",
+ "prefix":"deb"
+ },
+ "algorand-dev-deb-repo": {
+ "region":"us-east-1",
+ "bucket":"algorand-dev-deb-repo",
+ "acl":"public-read",
+ "prefix":"deb"
+ }
+ },
+ "SwiftPublishEndpoints": {}
+}
+EOF
+
+mkdir -p $GOPATH/src/github.com/aptly-dev
+git clone https://github.com/aptly-dev/aptly $GOPATH/src/github.com/aptly-dev/aptly || true
+(cd $GOPATH/src/github.com/aptly-dev/aptly && git fetch)
+# As of 2019-06-06 release tag v1.3.0 is 2018-May, GnuPG 2 support was added in October but they haven't tagged a new release yet. Hash below seems to work so far.
+(cd $GOPATH/src/github.com/aptly-dev/aptly && git checkout e2d6a53de5ee03814b3fe19a8954a09a5c2969b9)
+(cd $GOPATH/src/github.com/aptly-dev/aptly && make install)
+
+FIRSTTIME=
+if aptly repo create -distribution=stable -component=main algorand; then
+ FIRSTTIME=1
+fi
+aptly repo add algorand "$@"
+SNAPSHOT=algorand-$(date +%Y%m%d_%H%M%S)
+aptly snapshot create ${SNAPSHOT} from repo algorand
+if [ ! -z "${FIRSTTIME}" ]; then
+ echo "first publish"
+ aptly publish snapshot ${SNAPSHOT} "s3:${APTLY_S3_NAME}:"
+else
+ echo "publish snapshot ${SNAPSHOT}"
+ aptly publish switch stable "s3:${APTLY_S3_NAME}:" ${SNAPSHOT}
+fi
+
diff --git a/scripts/reverse_hex_timestamp b/scripts/reverse_hex_timestamp
new file mode 100755
index 000000000..a9f7cd3bc
--- /dev/null
+++ b/scripts/reverse_hex_timestamp
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+# a reverse hex timestamp is useful for putting newest things first in S3 bucket object sort order
+import sys
+import time
+
+sys.stdout.write('{:08x}'.format(0xfffffffff - int(time.time())))