hack/release.sh
83a2e92d
 #!/bin/bash
 set -e
ccc39695
 
d9f76993
 # This script looks for bundles built by make.sh, and releases them on a
 # public S3 bucket.
ccc39695
 #
 # Bundles should be available for the VERSION string passed as argument.
 #
d9f76993
 # The correct way to call this script is inside a container built by the
 # official Dockerfile at the root of the Docker source code. The Dockerfile,
 # make.sh and release.sh should all be from the same source code revision.
ccc39695
 
83a2e92d
 set -o pipefail
ccc39695
 
 # Print a usage message and exit.
 usage() {
83a2e92d
 	cat >&2 <<'EOF'
ff30eb96
 To run, I need:
 - to be in a container generated by the Dockerfile at the top of the Docker
   repository;
 - to be provided with the name of an S3 bucket, in environment variable
   AWS_S3_BUCKET;
 - to be provided with AWS credentials for this S3 bucket, in environment
   variables AWS_ACCESS_KEY and AWS_SECRET_KEY;
9c06420b
 - the passphrase to unlock the GPG key which will sign the deb packages
   (passed as environment variable GPG_PASSPHRASE);
ff30eb96
 - a generous amount of good will and nice manners.
 The canonical way to run me is to run the image produced by the Dockerfile: e.g.:"
 
83a2e92d
 docker run -e AWS_S3_BUCKET=get-staging.docker.io \
            -e AWS_ACCESS_KEY=AKI1234... \
            -e AWS_SECRET_KEY=sEs4mE... \
            -e GPG_PASSPHRASE=m0resEs4mE... \
            -i -t -privileged \
            docker ./hack/release.sh
ff30eb96
 EOF
ccc39695
 	exit 1
 }
 
ff30eb96
 [ "$AWS_S3_BUCKET" ] || usage
 [ "$AWS_ACCESS_KEY" ] || usage
 [ "$AWS_SECRET_KEY" ] || usage
9c06420b
 [ "$GPG_PASSPHRASE" ] || usage
83a2e92d
 [ -d /go/src/github.com/dotcloud/docker ] || usage
 cd /go/src/github.com/dotcloud/docker
 [ -x hack/make.sh ] || usage
 
 RELEASE_BUNDLES=(
 	binary
62a81370
 	cross
b3f5973f
 	tgz
83a2e92d
 	ubuntu
 )
 
 if [ "$1" != '--release-regardless-of-test-failure' ]; then
 	RELEASE_BUNDLES=( test "${RELEASE_BUNDLES[@]}" )
 fi
 
 if ! ./hack/make.sh "${RELEASE_BUNDLES[@]}"; then
 	echo >&2
 	echo >&2 'The build or tests appear to have failed.'
 	echo >&2
 	echo >&2 'You, as the release  maintainer, now have a couple options:'
 	echo >&2 '- delay release and fix issues'
 	echo >&2 '- delay release and fix issues'
 	echo >&2 '- did we mention how important this is?  issues need fixing :)'
 	echo >&2
 	echo >&2 'As a final LAST RESORT, you (because only you, the release maintainer,'
 	echo >&2 ' really knows all the hairy problems at hand with the current release'
 	echo >&2 ' issues) may bypass this checking by running this script again with the'
 	echo >&2 ' single argument of "--release-regardless-of-test-failure", which will skip'
 	echo >&2 ' running the test suite, and will only build the binaries and packages.  Please'
 	echo >&2 ' avoid using this if at all possible.'
 	echo >&2
 	echo >&2 'Regardless, we cannot stress enough the scarcity with which this bypass'
 	echo >&2 ' should be used.  If there are release issues, we should always err on the'
 	echo >&2 ' side of caution.'
 	echo >&2
 	exit 1
 fi
ff30eb96
 
 VERSION=$(cat VERSION)
ab4fb9bb
 BUCKET=$AWS_S3_BUCKET
ccc39695
 
 setup_s3() {
 	# Try creating the bucket. Ignore errors (it might already exist).
0469e476
 	s3cmd mb s3://$BUCKET 2>/dev/null || true
ab4fb9bb
 	# Check access to the bucket.
 	# s3cmd has no useful exit status, so we cannot check that.
 	# Instead, we check if it outputs anything on standard output.
 	# (When there are problems, it uses standard error instead.)
 	s3cmd info s3://$BUCKET | grep -q .
0469e476
 	# Make the bucket accessible through website endpoints.
 	s3cmd ws-create --ws-index index --ws-error error s3://$BUCKET
ccc39695
 }
 
 # write_to_s3 uploads the contents of standard input to the specified S3 url.
 write_to_s3() {
 	DEST=$1
 	F=`mktemp`
 	cat > $F
7f1b179c
 	s3cmd --acl-public --mime-type='text/plain' put $F $DEST
ccc39695
 	rm -f $F
 }
 
 s3_url() {
94bf5b00
 	case "$BUCKET" in
 		get.docker.io|test.docker.io)
 			echo "https://$BUCKET"
 			;;
 		*)
b8e7ec1b
 			s3cmd ws-info s3://$BUCKET | awk -v 'FS=: +' '/http:\/\/'$BUCKET'/ { gsub(/\/+$/, "", $2); print $2 }'
94bf5b00
 			;;
 	esac
ccc39695
 }
 
4100e9b7
 release_build() {
 	GOOS=$1
 	GOARCH=$2
 
 	BINARY=bundles/$VERSION/cross/$GOOS/$GOARCH/docker-$VERSION
 	TGZ=bundles/$VERSION/tgz/$GOOS/$GOARCH/docker-$VERSION.tgz
 
 	# we need to map our GOOS and GOARCH to uname values
 	# see https://en.wikipedia.org/wiki/Uname
 	# ie, GOOS=linux -> "uname -s"=Linux
 
 	S3OS=$GOOS
 	case "$S3OS" in
 		darwin)
 			S3OS=Darwin
 			;;
 		freebsd)
 			S3OS=FreeBSD
 			;;
 		linux)
 			S3OS=Linux
 			;;
 		*)
 			echo >&2 "error: can't convert $S3OS to an appropriate value for 'uname -s'"
 			exit 1
 			;;
 	esac
 
 	S3ARCH=$GOARCH
 	case "$S3ARCH" in
 		amd64)
 			S3ARCH=x86_64
 			;;
 		386)
 			S3ARCH=i386
 			;;
 		arm)
 			# GOARCH is fine
 			;;
 		*)
 			echo >&2 "error: can't convert $S3ARCH to an appropriate value for 'uname -m'"
 			exit 1
 			;;
 	esac
 
 	S3DIR=s3://$BUCKET/builds/$S3OS/$S3ARCH
 
 	if [ ! -x "$BINARY" ]; then
 		echo >&2 "error: can't find $BINARY - was it compiled properly?"
 		exit 1
 	fi
 	if [ ! -f "$TGZ" ]; then
 		echo >&2 "error: can't find $TGZ - was it packaged properly?"
 		exit 1
 	fi
 
 	echo "Uploading $BINARY to $S3OS/$S3ARCH/docker-$VERSION"
 	s3cmd --follow-symlinks --preserve --acl-public put $BINARY $S3DIR/docker-$VERSION
 
 	echo "Uploading $TGZ to $S3OS/$S3ARCH/docker-$VERSION.tgz"
 	s3cmd --follow-symlinks --preserve --acl-public put $TGZ $S3DIR/docker-$VERSION.tgz
 
 	if [ -z "$NOLATEST" ]; then
 		echo "Copying $S3OS/$S3ARCH/docker-$VERSION to $S3OS/$S3ARCH/docker-latest"
 		s3cmd --acl-public cp $S3DIR/docker-$VERSION $S3DIR/docker-latest
 
 		echo "Copying $S3OS/$S3ARCH/docker-$VERSION.tgz to $S3OS/$S3ARCH/docker-latest.tgz"
 		s3cmd --acl-public cp $S3DIR/docker-$VERSION.tgz $S3DIR/docker-latest.tgz
 	fi
 }
 
ccc39695
 # Upload the 'ubuntu' bundle to S3:
 # 1. A full APT repository is published at $BUCKET/ubuntu/
f56945d7
 # 2. Instructions for using the APT repository are uploaded at $BUCKET/ubuntu/index
ccc39695
 release_ubuntu() {
83a2e92d
 	[ -e bundles/$VERSION/ubuntu ] || {
 		echo >&2 './hack/make.sh must be run before release_ubuntu'
 		exit 1
 	}
9c06420b
 	# Make sure that we have our keys
 	mkdir -p /.gnupg/
 	s3cmd sync s3://$BUCKET/ubuntu/.gnupg/ /.gnupg/ || true
 	gpg --list-keys releasedocker >/dev/null || {
83a2e92d
 		gpg --gen-key --batch <<EOF
9c06420b
 Key-Type: RSA
 Key-Length: 2048
 Passphrase: $GPG_PASSPHRASE
 Name-Real: Docker Release Tool
 Name-Email: docker@dotcloud.com
 Name-Comment: releasedocker
 Expire-Date: 0
 %commit
 EOF
 	}
 
 	# Sign our packages
 	dpkg-sig -g "--passphrase $GPG_PASSPHRASE" -k releasedocker \
83a2e92d
 		--sign builder bundles/$VERSION/ubuntu/*.deb
9c06420b
 
5b0eaef6
 	# Setup the APT repo
 	APTDIR=bundles/$VERSION/ubuntu/apt
 	mkdir -p $APTDIR/conf $APTDIR/db
 	s3cmd sync s3://$BUCKET/ubuntu/db/ $APTDIR/db/ || true
 	cat > $APTDIR/conf/distributions <<EOF
 Codename: docker
 Components: main
87872006
 Architectures: amd64 i386
5b0eaef6
 EOF
 
 	# Add the DEB package to the APT repo
 	DEBFILE=bundles/$VERSION/ubuntu/lxc-docker*.deb
 	reprepro -b $APTDIR includedeb docker $DEBFILE
 
9c06420b
 	# Sign
83a2e92d
 	for F in $(find $APTDIR -name Release); do
9c06420b
 		gpg -u releasedocker --passphrase $GPG_PASSPHRASE \
 			--armor --sign --detach-sign \
 			--output $F.gpg $F
 	done
 
 	# Upload keys
 	s3cmd sync /.gnupg/ s3://$BUCKET/ubuntu/.gnupg/
 	gpg --armor --export releasedocker > bundles/$VERSION/ubuntu/gpg
 	s3cmd --acl-public put bundles/$VERSION/ubuntu/gpg s3://$BUCKET/gpg
 
 	# Upload repo
 	s3cmd --acl-public sync $APTDIR/ s3://$BUCKET/ubuntu/
f56945d7
 	cat <<EOF | write_to_s3 s3://$BUCKET/ubuntu/index
9c06420b
 # Add the repository to your APT sources
94bf5b00
 echo deb $(s3_url)/ubuntu docker main > /etc/apt/sources.list.d/docker.list
9c06420b
 # Then import the repository key
94bf5b00
 curl $(s3_url)/gpg | apt-key add -
9c06420b
 # Install docker
a8059059
 apt-get update ; apt-get install -y lxc-docker
83a2e92d
 
 #
 # Alternatively, just use the curl-able install.sh script provided at $(s3_url)
 #
ccc39695
 EOF
f56945d7
 
 	# Add redirect at /ubuntu/info for URL-backwards-compatibility
 	rm -rf /tmp/emptyfile && touch /tmp/emptyfile
 	s3cmd --acl-public --add-header='x-amz-website-redirect-location:/ubuntu/' --mime-type='text/plain' put /tmp/emptyfile s3://$BUCKET/ubuntu/info
 
 	echo "APT repository uploaded. Instructions available at $(s3_url)/ubuntu"
ccc39695
 }
 
4100e9b7
 # Upload binaries and tgz files to S3
 release_binaries() {
 	[ -e bundles/$VERSION/cross/linux/amd64/docker-$VERSION ] || {
 		echo >&2 './hack/make.sh must be run before release_binaries'
b3f5973f
 		exit 1
 	}
 
4100e9b7
 	for d in bundles/$VERSION/cross/*/*; do
 		GOARCH="$(basename "$d")"
 		GOOS="$(basename "$(dirname "$d")")"
 		release_build "$GOOS" "$GOARCH"
 	done
b3f5973f
 
4100e9b7
 	# TODO create redirect from builds/*/i686 to builds/*/i386
f56945d7
 
 	cat <<EOF | write_to_s3 s3://$BUCKET/builds/index
ccc39695
 # To install, run the following command as root:
94bf5b00
 curl -O $(s3_url)/builds/Linux/x86_64/docker-$VERSION && chmod +x docker-$VERSION && sudo mv docker-$VERSION /usr/local/bin/docker
ccc39695
 # Then start docker in daemon mode:
 sudo /usr/local/bin/docker -d
 EOF
f56945d7
 
 	# Add redirect at /builds/info for URL-backwards-compatibility
 	rm -rf /tmp/emptyfile && touch /tmp/emptyfile
 	s3cmd --acl-public --add-header='x-amz-website-redirect-location:/builds/' --mime-type='text/plain' put /tmp/emptyfile s3://$BUCKET/builds/info
 
ccc39695
 	if [ -z "$NOLATEST" ]; then
 		echo "Advertising $VERSION on $BUCKET as most recent version"
 		echo $VERSION | write_to_s3 s3://$BUCKET/latest
 	fi
 }
 
0469e476
 # Upload the index script
 release_index() {
94bf5b00
 	sed "s,https://get.docker.io/,$(s3_url)/," hack/install.sh | write_to_s3 s3://$BUCKET/index
0469e476
 }
 
59856a20
 release_test() {
 	if [ -e "bundles/$VERSION/test" ]; then
 		s3cmd --acl-public sync bundles/$VERSION/test/ s3://$BUCKET/test/
 	fi
 }
 
ccc39695
 main() {
 	setup_s3
4100e9b7
 	release_binaries
ccc39695
 	release_ubuntu
0469e476
 	release_index
59856a20
 	release_test
ccc39695
 }
 
 main
4100e9b7
 
 echo
 echo
 echo "Release complete; see $(s3_url)"
 echo