github.com/damirazo/docker@v1.9.0/hack/release.sh (about) 1 #!/usr/bin/env bash 2 set -e 3 4 # This script looks for bundles built by make.sh, and releases them on a 5 # public S3 bucket. 6 # 7 # Bundles should be available for the VERSION string passed as argument. 8 # 9 # The correct way to call this script is inside a container built by the 10 # official Dockerfile at the root of the Docker source code. The Dockerfile, 11 # make.sh and release.sh should all be from the same source code revision. 12 13 set -o pipefail 14 15 # Print a usage message and exit. 16 usage() { 17 cat >&2 <<'EOF' 18 To run, I need: 19 - to be in a container generated by the Dockerfile at the top of the Docker 20 repository; 21 - to be provided with the location of an S3 bucket and path, in 22 environment variables AWS_S3_BUCKET and AWS_S3_BUCKET_PATH (default: ''); 23 - to be provided with AWS credentials for this S3 bucket, in environment 24 variables AWS_ACCESS_KEY and AWS_SECRET_KEY; 25 - the passphrase to unlock the GPG key specified by the optional environment 26 variable GPG_KEYID (default: releasedocker) which will sign the deb 27 packages (passed as environment variable GPG_PASSPHRASE); 28 - a generous amount of good will and nice manners. 29 The canonical way to run me is to run the image produced by the Dockerfile: e.g.:" 30 31 docker run -e AWS_S3_BUCKET=test.docker.com \ 32 -e AWS_ACCESS_KEY=... \ 33 -e AWS_SECRET_KEY=... \ 34 -e GPG_PASSPHRASE=... \ 35 -i -t --privileged \ 36 docker ./hack/release.sh 37 EOF 38 exit 1 39 } 40 41 [ "$AWS_S3_BUCKET" ] || usage 42 [ "$AWS_ACCESS_KEY" ] || usage 43 [ "$AWS_SECRET_KEY" ] || usage 44 [ "$GPG_PASSPHRASE" ] || usage 45 : ${GPG_KEYID:=releasedocker} 46 [ -d /go/src/github.com/docker/docker ] || usage 47 cd /go/src/github.com/docker/docker 48 [ -x hack/make.sh ] || usage 49 50 RELEASE_BUNDLES=( 51 binary 52 cross 53 tgz 54 ubuntu 55 ) 56 57 if [ "$1" != '--release-regardless-of-test-failure' ]; then 58 RELEASE_BUNDLES=( 59 test-unit 60 "${RELEASE_BUNDLES[@]}" 61 test-integration-cli 62 ) 63 fi 64 65 VERSION=$(< VERSION) 66 BUCKET=$AWS_S3_BUCKET 67 BUCKET_PATH=$BUCKET 68 [[ -n "$AWS_S3_BUCKET_PATH" ]] && BUCKET_PATH+=/$AWS_S3_BUCKET_PATH 69 70 if command -v git &> /dev/null && git rev-parse &> /dev/null; then 71 if [ -n "$(git status --porcelain --untracked-files=no)" ]; then 72 echo "You cannot run the release script on a repo with uncommitted changes" 73 usage 74 fi 75 fi 76 77 # These are the 2 keys we've used to sign the deb's 78 # release (get.docker.com) 79 # GPG_KEY="36A1D7869245C8950F966E92D8576A8BA88D21E9" 80 # test (test.docker.com) 81 # GPG_KEY="740B314AE3941731B942C66ADF4FD13717AAD7D6" 82 83 setup_s3() { 84 echo "Setting up S3" 85 # Try creating the bucket. Ignore errors (it might already exist). 86 s3cmd mb "s3://$BUCKET" 2>/dev/null || true 87 # Check access to the bucket. 88 # s3cmd has no useful exit status, so we cannot check that. 89 # Instead, we check if it outputs anything on standard output. 90 # (When there are problems, it uses standard error instead.) 91 s3cmd info "s3://$BUCKET" | grep -q . 92 # Make the bucket accessible through website endpoints. 93 s3cmd ws-create --ws-index index --ws-error error "s3://$BUCKET" 94 } 95 96 # write_to_s3 uploads the contents of standard input to the specified S3 url. 97 write_to_s3() { 98 DEST=$1 99 F=`mktemp` 100 cat > "$F" 101 s3cmd --acl-public --mime-type='text/plain' put "$F" "$DEST" 102 rm -f "$F" 103 } 104 105 s3_url() { 106 case "$BUCKET" in 107 get.docker.com|test.docker.com|experimental.docker.com) 108 echo "https://$BUCKET_PATH" 109 ;; 110 *) 111 BASE_URL=$( s3cmd ws-info s3://$BUCKET | awk -v 'FS=: +' '/http:\/\/'$BUCKET'/ { gsub(/\/+$/, "", $2); print $2 }' ) 112 if [[ -n "$AWS_S3_BUCKET_PATH" ]] ; then 113 echo "$BASE_URL/$AWS_S3_BUCKET_PATH" 114 else 115 echo "$BASE_URL" 116 fi 117 ;; 118 esac 119 } 120 121 build_all() { 122 echo "Building release" 123 if ! ./hack/make.sh "${RELEASE_BUNDLES[@]}"; then 124 echo >&2 125 echo >&2 'The build or tests appear to have failed.' 126 echo >&2 127 echo >&2 'You, as the release maintainer, now have a couple options:' 128 echo >&2 '- delay release and fix issues' 129 echo >&2 '- delay release and fix issues' 130 echo >&2 '- did we mention how important this is? issues need fixing :)' 131 echo >&2 132 echo >&2 'As a final LAST RESORT, you (because only you, the release maintainer,' 133 echo >&2 ' really knows all the hairy problems at hand with the current release' 134 echo >&2 ' issues) may bypass this checking by running this script again with the' 135 echo >&2 ' single argument of "--release-regardless-of-test-failure", which will skip' 136 echo >&2 ' running the test suite, and will only build the binaries and packages. Please' 137 echo >&2 ' avoid using this if at all possible.' 138 echo >&2 139 echo >&2 'Regardless, we cannot stress enough the scarcity with which this bypass' 140 echo >&2 ' should be used. If there are release issues, we should always err on the' 141 echo >&2 ' side of caution.' 142 echo >&2 143 exit 1 144 fi 145 } 146 147 upload_release_build() { 148 src="$1" 149 dst="$2" 150 latest="$3" 151 152 echo 153 echo "Uploading $src" 154 echo " to $dst" 155 echo 156 s3cmd --follow-symlinks --preserve --acl-public put "$src" "$dst" 157 if [ "$latest" ]; then 158 echo 159 echo "Copying to $latest" 160 echo 161 s3cmd --acl-public cp "$dst" "$latest" 162 fi 163 164 # get hash files too (see hash_files() in hack/make.sh) 165 for hashAlgo in md5 sha256; do 166 if [ -e "$src.$hashAlgo" ]; then 167 echo 168 echo "Uploading $src.$hashAlgo" 169 echo " to $dst.$hashAlgo" 170 echo 171 s3cmd --follow-symlinks --preserve --acl-public --mime-type='text/plain' put "$src.$hashAlgo" "$dst.$hashAlgo" 172 if [ "$latest" ]; then 173 echo 174 echo "Copying to $latest.$hashAlgo" 175 echo 176 s3cmd --acl-public cp "$dst.$hashAlgo" "$latest.$hashAlgo" 177 fi 178 fi 179 done 180 } 181 182 release_build() { 183 echo "Releasing binaries" 184 GOOS=$1 185 GOARCH=$2 186 187 binDir=bundles/$VERSION/cross/$GOOS/$GOARCH 188 tgzDir=bundles/$VERSION/tgz/$GOOS/$GOARCH 189 binary=docker-$VERSION 190 tgz=docker-$VERSION.tgz 191 192 latestBase= 193 if [ -z "$NOLATEST" ]; then 194 latestBase=docker-latest 195 fi 196 197 # we need to map our GOOS and GOARCH to uname values 198 # see https://en.wikipedia.org/wiki/Uname 199 # ie, GOOS=linux -> "uname -s"=Linux 200 201 s3Os=$GOOS 202 case "$s3Os" in 203 darwin) 204 s3Os=Darwin 205 ;; 206 freebsd) 207 s3Os=FreeBSD 208 ;; 209 linux) 210 s3Os=Linux 211 ;; 212 windows) 213 s3Os=Windows 214 binary+='.exe' 215 if [ "$latestBase" ]; then 216 latestBase+='.exe' 217 fi 218 ;; 219 *) 220 echo >&2 "error: can't convert $s3Os to an appropriate value for 'uname -s'" 221 exit 1 222 ;; 223 esac 224 225 s3Arch=$GOARCH 226 case "$s3Arch" in 227 amd64) 228 s3Arch=x86_64 229 ;; 230 386) 231 s3Arch=i386 232 ;; 233 arm) 234 s3Arch=armel 235 # someday, we might potentially support mutliple GOARM values, in which case we might get armhf here too 236 ;; 237 *) 238 echo >&2 "error: can't convert $s3Arch to an appropriate value for 'uname -m'" 239 exit 1 240 ;; 241 esac 242 243 s3Dir="s3://$BUCKET_PATH/builds/$s3Os/$s3Arch" 244 latest= 245 latestTgz= 246 if [ "$latestBase" ]; then 247 latest="$s3Dir/$latestBase" 248 latestTgz="$s3Dir/$latestBase.tgz" 249 fi 250 251 if [ ! -x "$binDir/$binary" ]; then 252 echo >&2 "error: can't find $binDir/$binary - was it compiled properly?" 253 exit 1 254 fi 255 if [ ! -f "$tgzDir/$tgz" ]; then 256 echo >&2 "error: can't find $tgzDir/$tgz - was it packaged properly?" 257 exit 1 258 fi 259 260 upload_release_build "$binDir/$binary" "$s3Dir/$binary" "$latest" 261 upload_release_build "$tgzDir/$tgz" "$s3Dir/$tgz" "$latestTgz" 262 } 263 264 # Upload the 'ubuntu' bundle to S3: 265 # 1. A full APT repository is published at $BUCKET/ubuntu/ 266 # 2. Instructions for using the APT repository are uploaded at $BUCKET/ubuntu/index 267 release_ubuntu() { 268 echo "Releasing ubuntu" 269 [ -e "bundles/$VERSION/ubuntu" ] || { 270 echo >&2 './hack/make.sh must be run before release_ubuntu' 271 exit 1 272 } 273 274 local debfiles=( "bundles/$VERSION/ubuntu/"*.deb ) 275 276 # Sign our packages 277 dpkg-sig -g "--passphrase $GPG_PASSPHRASE" -k "$GPG_KEYID" --sign builder "${debfiles[@]}" 278 279 # Setup the APT repo 280 APTDIR=bundles/$VERSION/ubuntu/apt 281 mkdir -p "$APTDIR/conf" "$APTDIR/db" 282 s3cmd sync "s3://$BUCKET/ubuntu/db/" "$APTDIR/db/" || true 283 cat > "$APTDIR/conf/distributions" <<EOF 284 Codename: docker 285 Components: main 286 Architectures: amd64 i386 287 EOF 288 289 # Add the DEB package to the APT repo 290 reprepro -b "$APTDIR" includedeb docker "${debfiles[@]}" 291 292 # Sign 293 for F in $(find $APTDIR -name Release); do 294 gpg -u "$GPG_KEYID" --passphrase "$GPG_PASSPHRASE" \ 295 --armor --sign --detach-sign \ 296 --output "$F.gpg" "$F" 297 done 298 299 # Upload keys 300 s3cmd sync "$HOME/.gnupg/" "s3://$BUCKET/ubuntu/.gnupg/" 301 gpg --armor --export "$GPG_KEYID" > "bundles/$VERSION/ubuntu/gpg" 302 s3cmd --acl-public put "bundles/$VERSION/ubuntu/gpg" "s3://$BUCKET/gpg" 303 304 local gpgFingerprint=36A1D7869245C8950F966E92D8576A8BA88D21E9 305 local s3Headers= 306 if [[ $BUCKET == test* ]]; then 307 gpgFingerprint=740B314AE3941731B942C66ADF4FD13717AAD7D6 308 elif [[ $BUCKET == experimental* ]]; then 309 gpgFingerprint=E33FF7BF5C91D50A6F91FFFD4CC38D40F9A96B49 310 s3Headers='--add-header=Cache-Control:no-cache' 311 fi 312 313 # Upload repo 314 s3cmd --acl-public $s3Headers sync "$APTDIR/" "s3://$BUCKET/ubuntu/" 315 cat <<EOF | write_to_s3 s3://$BUCKET/ubuntu/index 316 echo "# WARNING! This script is deprecated. Please use the script" 317 echo "# at https://get.docker.com/" 318 EOF 319 320 # Add redirect at /ubuntu/info for URL-backwards-compatibility 321 rm -rf /tmp/emptyfile && touch /tmp/emptyfile 322 s3cmd --acl-public --add-header='x-amz-website-redirect-location:/ubuntu/' --mime-type='text/plain' put /tmp/emptyfile "s3://$BUCKET/ubuntu/info" 323 324 echo "APT repository uploaded. Instructions available at $(s3_url)/ubuntu" 325 } 326 327 # Upload binaries and tgz files to S3 328 release_binaries() { 329 [ -e "bundles/$VERSION/cross/linux/amd64/docker-$VERSION" ] || { 330 echo >&2 './hack/make.sh must be run before release_binaries' 331 exit 1 332 } 333 334 for d in bundles/$VERSION/cross/*/*; do 335 GOARCH="$(basename "$d")" 336 GOOS="$(basename "$(dirname "$d")")" 337 release_build "$GOOS" "$GOARCH" 338 done 339 340 # TODO create redirect from builds/*/i686 to builds/*/i386 341 342 cat <<EOF | write_to_s3 s3://$BUCKET_PATH/builds/index 343 # To install, run the following command as root: 344 curl -sSL -O $(s3_url)/builds/Linux/x86_64/docker-$VERSION && chmod +x docker-$VERSION && sudo mv docker-$VERSION /usr/local/bin/docker 345 # Then start docker in daemon mode: 346 sudo /usr/local/bin/docker daemon 347 EOF 348 349 # Add redirect at /builds/info for URL-backwards-compatibility 350 rm -rf /tmp/emptyfile && touch /tmp/emptyfile 351 s3cmd --acl-public --add-header='x-amz-website-redirect-location:/builds/' --mime-type='text/plain' put /tmp/emptyfile "s3://$BUCKET_PATH/builds/info" 352 353 if [ -z "$NOLATEST" ]; then 354 echo "Advertising $VERSION on $BUCKET_PATH as most recent version" 355 echo "$VERSION" | write_to_s3 "s3://$BUCKET_PATH/latest" 356 fi 357 } 358 359 # Upload the index script 360 release_index() { 361 echo "Releasing index" 362 sed "s,url='https://get.docker.com/',url='$(s3_url)/'," hack/install.sh | write_to_s3 "s3://$BUCKET_PATH/index" 363 } 364 365 release_test() { 366 echo "Releasing tests" 367 if [ -e "bundles/$VERSION/test" ]; then 368 s3cmd --acl-public sync "bundles/$VERSION/test/" "s3://$BUCKET_PATH/test/" 369 fi 370 } 371 372 setup_gpg() { 373 echo "Setting up GPG" 374 # Make sure that we have our keys 375 mkdir -p "$HOME/.gnupg/" 376 s3cmd sync "s3://$BUCKET/ubuntu/.gnupg/" "$HOME/.gnupg/" || true 377 gpg --list-keys "$GPG_KEYID" >/dev/null || { 378 gpg --gen-key --batch <<EOF 379 Key-Type: RSA 380 Key-Length: 4096 381 Passphrase: $GPG_PASSPHRASE 382 Name-Real: Docker Release Tool 383 Name-Email: docker@docker.com 384 Name-Comment: $GPG_KEYID 385 Expire-Date: 0 386 %commit 387 EOF 388 } 389 } 390 391 main() { 392 build_all 393 setup_s3 394 setup_gpg 395 release_binaries 396 release_ubuntu 397 release_index 398 release_test 399 } 400 401 main 402 403 echo 404 echo 405 echo "Release complete; see $(s3_url)" 406 echo "Use the following text to announce the release:" 407 echo 408 echo "We have just pushed $VERSION to $(s3_url). You can download it with the following:" 409 echo 410 echo "Ubuntu/Debian: curl -sSL $(s3_url) | sh" 411 echo "Linux 64bit binary: $(s3_url)/builds/Linux/x86_64/docker-$VERSION" 412 echo "Darwin/OSX 64bit client binary: $(s3_url)/builds/Darwin/x86_64/docker-$VERSION" 413 echo "Darwin/OSX 32bit client binary: $(s3_url)/builds/Darwin/i386/docker-$VERSION" 414 echo "Linux 64bit tgz: $(s3_url)/builds/Linux/x86_64/docker-$VERSION.tgz" 415 echo "Windows 64bit client binary: $(s3_url)/builds/Windows/x86_64/docker-$VERSION.exe" 416 echo "Windows 32bit client binary: $(s3_url)/builds/Windows/i386/docker-$VERSION.exe" 417 echo