blob: 5a4be8ba181b88df0faca725eee11fcc44f66c84 [file] [log] [blame]
Grinberg Moti7aea13f2017-02-22 12:01:00 +02001#!/bin/sh
2# WARNING: REQUIRES /bin/sh
3#
4# - must run on /bin/sh on solaris 9
5# - must run on /bin/sh on AIX 6.x
6#
7# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
8# License:: Apache License, Version 2.0
9#
10# Licensed under the Apache License, Version 2.0 (the "License");
11# you may not use this file except in compliance with the License.
12# You may obtain a copy of the License at
13#
14# http://www.apache.org/licenses/LICENSE-2.0
15#
16# Unless required by applicable law or agreed to in writing, software
17# distributed under the License is distributed on an "AS IS" BASIS,
18# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19# See the License for the specific language governing permissions and
20# limitations under the License.
21#
22
23# helpers.sh
24############
25# This section has some helper functions to make life easier.
26#
27# Outputs:
28# $tmp_dir: secure-ish temp directory that can be used during installation.
29############
30
31# Check whether a command exists - returns 0 if it does, 1 if it does not
32exists() {
33 if command -v $1 >/dev/null 2>&1
34 then
35 return 0
36 else
37 return 1
38 fi
39}
40
41# Output the instructions to report bug about this script
42report_bug() {
43 echo "Version: $version"
44 echo ""
45 echo "Please file a Bug Report at https://github.com/chef/omnitruck/issues/new"
46 echo "Alternatively, feel free to open a Support Ticket at https://www.chef.io/support/tickets"
47 echo "More Chef support resources can be found at https://www.chef.io/support"
48 echo ""
49 echo "Please include as many details about the problem as possible i.e., how to reproduce"
50 echo "the problem (if possible), type of the Operating System and its version, etc.,"
51 echo "and any other relevant details that might help us with troubleshooting."
52 echo ""
53}
54
55checksum_mismatch() {
56 echo "Package checksum mismatch!"
57 report_bug
58 exit 1
59}
60
61unable_to_retrieve_package() {
62 echo "Unable to retrieve a valid package!"
63 report_bug
64 echo "Metadata URL: $metadata_url"
65 if test "x$download_url" != "x"; then
66 echo "Download URL: $download_url"
67 fi
68 if test "x$stderr_results" != "x"; then
69 echo "\nDEBUG OUTPUT FOLLOWS:\n$stderr_results"
70 fi
71 exit 1
72}
73
74http_404_error() {
75 echo "Omnitruck artifact does not exist for version $version on platform $platform"
76 echo ""
77 echo "Either this means:"
78 echo " - We do not support $platform"
79 echo " - We do not have an artifact for $version"
80 echo ""
81 echo "This is often the latter case due to running a prerelease or RC version of chef"
82 echo "or a gem version which was only pushed to rubygems and not omnitruck."
83 echo ""
84 echo "You may be able to set your knife[:bootstrap_version] to the most recent stable"
85 echo "release of Chef to fix this problem (or the most recent stable major version number)."
86 echo ""
87 echo "In order to test the version parameter, adventurous users may take the Metadata URL"
88 echo "below and modify the '&v=<number>' parameter until you successfully get a URL that"
89 echo "does not 404 (e.g. via curl or wget). You should be able to use '&v=11' or '&v=12'"
90 echo "succesfully."
91 echo ""
92 echo "If you cannot fix this problem by setting the bootstrap_version, it probably means"
93 echo "that $platform is not supported."
94 echo ""
95 # deliberately do not call report_bug to suppress bug report noise.
96 echo "Metadata URL: $metadata_url"
97 if test "x$download_url" != "x"; then
98 echo "Download URL: $download_url"
99 fi
100 if test "x$stderr_results" != "x"; then
101 echo "\nDEBUG OUTPUT FOLLOWS:\n$stderr_results"
102 fi
103 exit 1
104}
105
106capture_tmp_stderr() {
107 # spool up /tmp/stderr from all the commands we called
108 if test -f "$tmp_dir/stderr"; then
109 output=`cat $tmp_dir/stderr`
110 stderr_results="${stderr_results}\nSTDERR from $1:\n\n$output\n"
111 rm $tmp_dir/stderr
112 fi
113}
114
115# do_wget URL FILENAME
116do_wget() {
117 echo "trying wget..."
118 wget --user-agent="User-Agent: mixlib-install/2.1.8" -O "$2" "$1" 2>$tmp_dir/stderr
119 rc=$?
120 # check for 404
121 grep "ERROR 404" $tmp_dir/stderr 2>&1 >/dev/null
122 if test $? -eq 0; then
123 echo "ERROR 404"
124 http_404_error
125 fi
126
127 # check for bad return status or empty output
128 if test $rc -ne 0 || test ! -s "$2"; then
129 capture_tmp_stderr "wget"
130 return 1
131 fi
132
133 return 0
134}
135
136# do_curl URL FILENAME
137do_curl() {
138 echo "trying curl..."
139 curl -A "User-Agent: mixlib-install/2.1.8" --retry 5 -sL -D $tmp_dir/stderr "$1" > "$2"
140 rc=$?
141 # check for 404
142 grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
143 if test $? -eq 0; then
144 echo "ERROR 404"
145 http_404_error
146 fi
147
148 # check for bad return status or empty output
149 if test $rc -ne 0 || test ! -s "$2"; then
150 capture_tmp_stderr "curl"
151 return 1
152 fi
153
154 return 0
155}
156
157# do_fetch URL FILENAME
158do_fetch() {
159 echo "trying fetch..."
160 fetch --user-agent="User-Agent: mixlib-install/2.1.8" -o "$2" "$1" 2>$tmp_dir/stderr
161 # check for bad return status
162 test $? -ne 0 && return 1
163 return 0
164}
165
166# do_perl URL FILENAME
167do_perl() {
168 echo "trying perl..."
169 perl -e 'use LWP::Simple; getprint($ARGV[0]);' "$1" > "$2" 2>$tmp_dir/stderr
170 rc=$?
171 # check for 404
172 grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
173 if test $? -eq 0; then
174 echo "ERROR 404"
175 http_404_error
176 fi
177
178 # check for bad return status or empty output
179 if test $rc -ne 0 || test ! -s "$2"; then
180 capture_tmp_stderr "perl"
181 return 1
182 fi
183
184 return 0
185}
186
187# do_python URL FILENAME
188do_python() {
189 echo "trying python..."
190 python -c "import sys,urllib2; sys.stdout.write(urllib2.urlopen(urllib2.Request(sys.argv[1], headers={ 'User-Agent': 'mixlib-install/2.1.8' })).read())" "$1" > "$2" 2>$tmp_dir/stderr
191 rc=$?
192 # check for 404
193 grep "HTTP Error 404" $tmp_dir/stderr 2>&1 >/dev/null
194 if test $? -eq 0; then
195 echo "ERROR 404"
196 http_404_error
197 fi
198
199 # check for bad return status or empty output
200 if test $rc -ne 0 || test ! -s "$2"; then
201 capture_tmp_stderr "python"
202 return 1
203 fi
204 return 0
205}
206
207# returns 0 if checksums match
208do_checksum() {
209 if exists sha256sum; then
210 echo "Comparing checksum with sha256sum..."
211 checksum=`sha256sum $1 | awk '{ print $1 }'`
212 return `test "x$checksum" = "x$2"`
213 elif exists shasum; then
214 echo "Comparing checksum with shasum..."
215 checksum=`shasum -a 256 $1 | awk '{ print $1 }'`
216 return `test "x$checksum" = "x$2"`
217 else
218 echo "WARNING: could not find a valid checksum program, pre-install shasum or sha256sum in your O/S image to get valdation..."
219 return 0
220 fi
221}
222
223# do_download URL FILENAME
224do_download() {
225 echo "downloading $1"
226 echo " to file $2"
227
228 url=`echo $1`
229 if test "x$platform" = "xsolaris2"; then
230 if test "x$platform_version" = "x5.9" -o "x$platform_version" = "x5.10"; then
231 # solaris 9 lacks openssl, solaris 10 lacks recent enough credentials - your base O/S is completely insecure, please upgrade
232 url=`echo $url | sed -e 's/https/http/'`
233 fi
234 fi
235
236 # we try all of these until we get success.
237 # perl, in particular may be present but LWP::Simple may not be installed
238
239 if exists wget; then
240 do_wget $url $2 && return 0
241 fi
242
243 if exists curl; then
244 do_curl $url $2 && return 0
245 fi
246
247 if exists fetch; then
248 do_fetch $url $2 && return 0
249 fi
250
251 if exists perl; then
252 do_perl $url $2 && return 0
253 fi
254
255 if exists python; then
256 do_python $url $2 && return 0
257 fi
258
259 unable_to_retrieve_package
260}
261
262# install_file TYPE FILENAME
263# TYPE is "rpm", "deb", "solaris", "sh", etc.
264install_file() {
265 echo "Installing $project $version"
266 case "$1" in
267 "rpm")
268 if test "x$platform" = "xnexus" || test "x$platform" = "xios_xr"; then
269 echo "installing with yum..."
270 yum install -yv "$2"
271 else
272 echo "installing with rpm..."
273 rpm -Uvh --oldpackage --replacepkgs "$2"
274 fi
275 ;;
276 "deb")
277 echo "installing with dpkg..."
278 dpkg -i "$2"
279 ;;
280 "bff")
281 echo "installing with installp..."
282 installp -aXYgd "$2" all
283 ;;
284 "solaris")
285 echo "installing with pkgadd..."
286 echo "conflict=nocheck" > $tmp_dir/nocheck
287 echo "action=nocheck" >> $tmp_dir/nocheck
288 echo "mail=" >> $tmp_dir/nocheck
289 pkgrm -a $tmp_dir/nocheck -n $project >/dev/null 2>&1 || true
290 pkgadd -G -n -d "$2" -a $tmp_dir/nocheck $project
291 ;;
292 "pkg")
293 echo "installing with installer..."
294 cd / && /usr/sbin/installer -pkg "$2" -target /
295 ;;
296 "dmg")
297 echo "installing dmg file..."
298 hdiutil detach "/Volumes/chef_software" >/dev/null 2>&1 || true
299 hdiutil attach "$2" -mountpoint "/Volumes/chef_software"
300 cd / && /usr/sbin/installer -pkg `find "/Volumes/chef_software" -name \*.pkg` -target /
301 hdiutil detach "/Volumes/chef_software"
302 ;;
303 "sh" )
304 echo "installing with sh..."
305 sh "$2"
306 ;;
307 "p5p" )
308 echo "installing p5p package..."
309 pkg install -g "$2" $project
310 ;;
311 *)
312 echo "Unknown filetype: $1"
313 report_bug
314 exit 1
315 ;;
316 esac
317 if test $? -ne 0; then
318 echo "Installation failed"
319 report_bug
320 exit 1
321 fi
322}
323
324if test "x$TMPDIR" = "x"; then
325 tmp="/tmp"
326else
327 tmp=$TMPDIR
328fi
329# secure-ish temp dir creation without having mktemp available (DDoS-able but not expliotable)
330tmp_dir="$tmp/install.sh.$$"
331(umask 077 && mkdir $tmp_dir) || exit 1
332
333############
334# end of helpers.sh
335############
336
337
338# script_cli_parameters.sh
339############
340# This section reads the CLI parameters for the install script and translates
341# them to the local parameters to be used later by the script.
342#
343# Outputs:
344# $version: Requested version to be installed.
345# $channel: Channel to install the product from
346# $project: Project to be installed
347# $cmdline_filename: Name of the package downloaded on local disk.
348# $cmdline_dl_dir: Name of the directory downloaded package will be saved to on local disk.
349############
350
351# Defaults
352channel="stable"
353project="chef"
354
355while getopts pnv:c:f:P:d: opt
356do
357 case "$opt" in
358
359 v) version="$OPTARG";;
360 c) channel="$OPTARG";;
361 p) channel="current";; # compat for prerelease option
362 n) channel="current";; # compat for nightlies option
363 f) cmdline_filename="$OPTARG";;
364 P) project="$OPTARG";;
365 d) cmdline_dl_dir="$OPTARG";;
366 \?) # unknown flag
367 echo >&2 \
368 "usage: $0 [-P project] [-c release_channel] [-v version] [-f filename | -d download_dir]"
369 exit 1;;
370 esac
371done
372
373shift `expr $OPTIND - 1`
374
375
376# platform_detection.sh
377############
378# This section makes platform detection compatible with omnitruck on the system
379# it runs.
380#
381# Outputs:
382# $platform: Name of the platform.
383# $platform_version: Version of the platform.
384# $machine: System's architecture.
385############
386
387#
388# Platform and Platform Version detection
389#
390# NOTE: This should now match ohai platform and platform_version matching.
391# do not invented new platform and platform_version schemas, just make this behave
392# like what ohai returns as platform and platform_version for the server.
393#
394# ALSO NOTE: Do not mangle platform or platform_version here. It is less error
395# prone and more future-proof to do that in the server, and then all omnitruck clients
396# will 'inherit' the changes (install.sh is not the only client of the omnitruck
397# endpoint out there).
398#
399
400machine=`uname -m`
401os=`uname -s`
402
403if test -f "/etc/lsb-release" && grep -q DISTRIB_ID /etc/lsb-release && ! grep -q wrlinux /etc/lsb-release; then
404 platform=`grep DISTRIB_ID /etc/lsb-release | cut -d "=" -f 2 | tr '[A-Z]' '[a-z]'`
405 platform_version=`grep DISTRIB_RELEASE /etc/lsb-release | cut -d "=" -f 2`
406
407 if test "$platform" = "\"cumulus linux\""; then
408 platform="cumulus_linux"
409 elif test "$platform" = "\"cumulus networks\""; then
410 platform="cumulus_networks"
411 fi
412
413elif test -f "/etc/debian_version"; then
414 platform="debian"
415 platform_version=`cat /etc/debian_version`
416elif test -f "/etc/Eos-release"; then
417 # EOS may also contain /etc/redhat-release so this check must come first.
418 platform=arista_eos
419 platform_version=`awk '{print $4}' /etc/Eos-release`
420 machine="i386"
421elif test -f "/etc/redhat-release"; then
422 platform=`sed 's/^\(.\+\) release.*/\1/' /etc/redhat-release | tr '[A-Z]' '[a-z]'`
423 platform_version=`sed 's/^.\+ release \([.0-9]\+\).*/\1/' /etc/redhat-release`
424
425 # If /etc/redhat-release exists, we act like RHEL by default
426 if test "$platform" = "fedora"; then
427 # FIXME: stop remapping fedora to el
428 # FIXME: remove client side platform_version mangling and hard coded yolo
429 # Change platform version for use below.
430 platform_version="6.0"
431 fi
432
433 if test "$platform" = "xenserver"; then
434 # Current XenServer 6.2 is based on CentOS 5, platform is not reset to "el" server should hanlde response
435 platform="xenserver"
436 else
437 # FIXME: use "redhat"
438 platform="el"
439 fi
440
441elif test -f "/etc/system-release"; then
442 platform=`sed 's/^\(.\+\) release.\+/\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
443 platform_version=`sed 's/^.\+ release \([.0-9]\+\).*/\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
444 # amazon is built off of fedora, so act like RHEL
445 if test "$platform" = "amazon linux ami"; then
446 # FIXME: remove client side platform_version mangling and hard coded yolo, and remapping to deprecated "el"
447 platform="el"
448 platform_version="6.0"
449 fi
450# Apple OS X
451elif test -f "/usr/bin/sw_vers"; then
452 platform="mac_os_x"
453 # Matching the tab-space with sed is error-prone
454 platform_version=`sw_vers | awk '/^ProductVersion:/ { print $2 }' | cut -d. -f1,2`
455
456 # x86_64 Apple hardware often runs 32-bit kernels (see OHAI-63)
457 x86_64=`sysctl -n hw.optional.x86_64`
458 if test $x86_64 -eq 1; then
459 machine="x86_64"
460 fi
461elif test -f "/etc/release"; then
462 machine=`/usr/bin/uname -p`
463 if grep -q SmartOS /etc/release; then
464 platform="smartos"
465 platform_version=`grep ^Image /etc/product | awk '{ print $3 }'`
466 else
467 platform="solaris2"
468 platform_version=`/usr/bin/uname -r`
469 fi
470elif test -f "/etc/SuSE-release"; then
471 if grep -q 'Enterprise' /etc/SuSE-release;
472 then
473 platform="sles"
474 platform_version=`awk '/^VERSION/ {V = $3}; /^PATCHLEVEL/ {P = $3}; END {print V "." P}' /etc/SuSE-release`
475 else
476 platform="suse"
477 platform_version=`awk '/^VERSION =/ { print $3 }' /etc/SuSE-release`
478 fi
479elif test "x$os" = "xFreeBSD"; then
480 platform="freebsd"
481 platform_version=`uname -r | sed 's/-.*//'`
482elif test "x$os" = "xAIX"; then
483 platform="aix"
484 platform_version="`uname -v`.`uname -r`"
485 machine="powerpc"
486elif test -f "/etc/os-release"; then
487 . /etc/os-release
488 if test "x$CISCO_RELEASE_INFO" != "x"; then
489 . $CISCO_RELEASE_INFO
490 fi
491
492 platform=$ID
493 platform_version=$VERSION
494fi
495
496if test "x$platform" = "x"; then
497 echo "Unable to determine platform version!"
498 report_bug
499 exit 1
500fi
501
502#
503# NOTE: platform manging in the install.sh is DEPRECATED
504#
505# - install.sh should be true to ohai and should not remap
506# platform or platform versions.
507#
508# - remapping platform and mangling platform version numbers is
509# now the complete responsibility of the server-side endpoints
510#
511
512major_version=`echo $platform_version | cut -d. -f1`
513case $platform in
514 # FIXME: should remove this case statement completely
515 "el")
516 # FIXME: "el" is deprecated, should use "redhat"
517 platform_version=$major_version
518 ;;
519 "debian")
520 if test "x$major_version" = "x5"; then
521 # This is here for potential back-compat.
522 # We do not have 5 in versions we publish for anymore but we
523 # might have it for earlier versions.
524 platform_version="6"
525 else
526 platform_version=$major_version
527 fi
528 ;;
529 "freebsd")
530 platform_version=$major_version
531 ;;
532 "sles")
533 platform_version=$major_version
534 ;;
535 "suse")
536 platform_version=$major_version
537 ;;
538esac
539
540# normalize the architecture we detected
541case $machine in
542 "x86_64"|"amd64"|"x64")
543 machine="x86_64"
544 ;;
545 "i386"|"i86pc"|"x86"|"i686")
546 machine="i386"
547 ;;
548 "sparc"|"sun4u"|"sun4v")
549 machine="sparc"
550 ;;
551esac
552
553if test "x$platform_version" = "x"; then
554 echo "Unable to determine platform version!"
555 report_bug
556 exit 1
557fi
558
559if test "x$platform" = "xsolaris2"; then
560 # hack up the path on Solaris to find wget, pkgadd
561 PATH=/usr/sfw/bin:/usr/sbin:$PATH
562 export PATH
563fi
564
565echo "$platform $platform_version $machine"
566
567############
568# end of platform_detection.sh
569############
570
571
572# fetch_metadata.sh
573############
574# This section calls omnitruck to get the information about the build to be
575# installed.
576#
577# Inputs:
578# $channel:
579# $project:
580# $version:
581# $platform:
582# $platform_version:
583# $machine:
584# $tmp_dir:
585#
586# Outputs:
587# $download_url:
588# $sha256:
589############
590
591echo "Getting information for $project $channel $version for $platform..."
592
593metadata_filename="$tmp_dir/metadata.txt"
594metadata_url="https://omnitruck-direct.chef.io/$channel/$project/metadata?v=$version&p=$platform&pv=$platform_version&m=$machine"
595
596do_download "$metadata_url" "$metadata_filename"
597
598cat "$metadata_filename"
599
600echo ""
601# check that all the mandatory fields in the downloaded metadata are there
602if grep '^url' $metadata_filename > /dev/null && grep '^sha256' $metadata_filename > /dev/null; then
603 echo "downloaded metadata file looks valid..."
604else
605 echo "downloaded metadata file is corrupted or an uncaught error was encountered in downloading the file..."
606 # this generally means one of the download methods downloaded a 404 or something like that and then reported a successful exit code,
607 # and this should be fixed in the function that was doing the download.
608 report_bug
609 exit 1
610fi
611
612download_url=`awk '$1 == "url" { print $2 }' "$metadata_filename"`
613sha256=`awk '$1 == "sha256" { print $2 }' "$metadata_filename"`
614
615############
616# end of fetch_metadata.sh
617############
618
619
620# fetch_package.sh
621############
622# This section fetchs a package from $download_url and verifies its metadata.
623#
624# Inputs:
625# $download_url:
626# $tmp_dir:
627# Optional Inputs:
628# $cmdline_filename: Name of the package downloaded on local disk.
629# $cmdline_dl_dir: Name of the directory downloaded package will be saved to on local disk.
630#
631# Outputs:
632# $download_filename: Name of the downloaded file on local disk.
633# $filetype: Type of the file downloaded.
634############
635
636filename=`echo $download_url | sed -e 's/^.*\///'`
637filetype=`echo $filename | sed -e 's/^.*\.//'`
638
639# use either $tmp_dir, the provided directory (-d) or the provided filename (-f)
640if test "x$cmdline_filename" != "x"; then
641 download_filename="$cmdline_filename"
642elif test "x$cmdline_dl_dir" != "x"; then
643 download_filename="$cmdline_dl_dir/$filename"
644else
645 download_filename="$tmp_dir/$filename"
646fi
647
648# ensure the parent directory where to download the installer always exists
649download_dir=`dirname $download_filename`
650(umask 077 && mkdir -p $download_dir) || exit 1
651
652# check if we have that file locally available and if so verify the checksum
653cached_file_available="false"
654if test -f $download_filename; then
655 echo "$download_filename already exists, verifiying checksum..."
656 if do_checksum "$download_filename" "$sha256"; then
657 echo "checksum compare succeeded, using existing file!"
658 cached_file_available="true"
659 else
660 echo "checksum mismatch, downloading latest version of the file"
661 fi
662fi
663
664# download if no local version of the file available
665if test "x$cached_file_available" != "xtrue"; then
666 do_download "$download_url" "$download_filename"
667 do_checksum "$download_filename" "$sha256" || checksum_mismatch
668fi
669
670############
671# end of fetch_package.sh
672############
673
674
675# install_package.sh
676############
677# Installs a package and removed the temp directory.
678#
679# Inputs:
680# $download_filename: Name of the file to be installed.
681# $filetype: Type of the file to be installed.
682# $version: The version requested. Used only for warning user if not set.
683############
684
685if test "x$version" = "x"; then
686 echo
687 echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING"
688 echo
689 echo "You are installing an omnibus package without a version pin. If you are installing"
690 echo "on production servers via an automated process this is DANGEROUS and you will"
691 echo "be upgraded without warning on new releases, even to new major releases."
692 echo "Letting the version float is only appropriate in desktop, test, development or"
693 echo "CI/CD environments."
694 echo
695 echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING"
696 echo
697fi
698
699install_file $filetype "$download_filename"
700
701if test "x$tmp_dir" != "x"; then
702 rm -r "$tmp_dir"
703fi
704
705############
706# end of install_package.sh
707############