vagrant-salt 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/README.rst +131 -170
  2. data/example/complete/Vagrantfile +67 -0
  3. data/example/complete/salt/custom-bootstrap-salt.sh +2425 -0
  4. data/example/complete/salt/key/master.pem +30 -0
  5. data/example/complete/salt/key/master.pub +14 -0
  6. data/example/complete/salt/key/minion.pem +30 -0
  7. data/example/complete/salt/key/minion.pub +14 -0
  8. data/example/complete/salt/master +459 -0
  9. data/example/{salt/minion.conf → complete/salt/minion} +1 -2
  10. data/example/{salt → complete/salt}/roots/pillar/top.sls +0 -0
  11. data/example/complete/salt/roots/salt/nginx.sls +5 -0
  12. data/example/complete/salt/roots/salt/top.sls +3 -0
  13. data/example/masterless/Vagrantfile +18 -0
  14. data/example/masterless/salt/minion +219 -0
  15. data/example/{salt/roots/salt → masterless/salt/roots/pillar}/top.sls +0 -0
  16. data/example/masterless/salt/roots/salt/nginx.sls +5 -0
  17. data/example/masterless/salt/roots/salt/top.sls +3 -0
  18. data/lib/vagrant-salt.rb +16 -3
  19. data/lib/vagrant-salt/config.rb +103 -0
  20. data/lib/vagrant-salt/errors.rb +11 -0
  21. data/lib/vagrant-salt/plugin.rb +31 -0
  22. data/lib/vagrant-salt/provisioner.rb +211 -104
  23. data/lib/vagrant-salt/version.rb +5 -0
  24. data/scripts/.travis.yml +16 -0
  25. data/scripts/ChangeLog +39 -0
  26. data/scripts/LICENSE +16 -0
  27. data/scripts/README.rst +124 -35
  28. data/scripts/bootstrap-salt-minion.sh +1815 -381
  29. data/scripts/bootstrap-salt.sh +2425 -0
  30. data/scripts/salt-bootstrap.sh +2425 -0
  31. data/scripts/tests/README.rst +38 -0
  32. data/scripts/tests/bootstrap/__init__.py +11 -0
  33. data/{example/salt/key/KEYPAIR_GOES_HERE → scripts/tests/bootstrap/ext/__init__.py} +0 -0
  34. data/scripts/tests/bootstrap/ext/console.py +100 -0
  35. data/scripts/tests/bootstrap/ext/os_data.py +199 -0
  36. data/scripts/tests/bootstrap/test_install.py +586 -0
  37. data/scripts/tests/bootstrap/test_lint.py +27 -0
  38. data/scripts/tests/bootstrap/test_usage.py +28 -0
  39. data/scripts/tests/bootstrap/unittesting.py +216 -0
  40. data/scripts/tests/ext/checkbashisms +640 -0
  41. data/scripts/tests/install-testsuite-deps.py +99 -0
  42. data/scripts/tests/runtests.py +207 -0
  43. data/templates/locales/en.yml +14 -0
  44. data/vagrant-salt.gemspec +2 -2
  45. metadata +43 -10
  46. data/example/Vagrantfile +0 -26
  47. data/lib/vagrant_init.rb +0 -1
@@ -0,0 +1,38 @@
1
+ Salt Bootstrap Script - Integration Testing
2
+ ===========================================
3
+
4
+ Testing ``salt-bootstrap`` requires both Python and Perl.
5
+
6
+ Yes, it's weird that a shell script uses either one of the above languages for testing itself, the
7
+ explanation though, is simple.
8
+
9
+ Perl is required because we use a script, `checkbashisms`_, which does exactly what it's name says.
10
+ In our case, it tries it's best to find non ``POSIX`` compliant code in our bootstrap script since
11
+ we require the script to be able to properly execute in any ``POSIX`` compliant shell.
12
+
13
+ Python is used in the integration tests. It greatly simplifies running these tests and can even
14
+ provide some JUnit compliant XML used to generate reports of those tests. Doing this job in shell
15
+ scripting would be too cumbersome and too complicated.
16
+
17
+ Running the tests suite
18
+ -----------------------
19
+
20
+ .. warning:: The test suite is **destructive**. It will install/un-install packages on your system.
21
+ You must run the suite using ``sudo`` or most / all of the tests will be skipped.
22
+
23
+ Running the tests suite is as simple as:
24
+
25
+ .. code:: console
26
+
27
+ sudo python tests/runtests.py
28
+
29
+ For additional information on the available options:
30
+
31
+ .. code:: console
32
+
33
+ python tests/runtests.py --help
34
+
35
+
36
+
37
+ .. _`checkbashisms`: http://sourceforge.net/projects/checkbaskisms/
38
+ .. vim: fenc=utf-8 spell spl=en cc=100 tw=99 fo=want sts=2 sw=2 et
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ bootstrap
4
+ ~~~~~~~~~
5
+
6
+ salt-bootstrap script unittesting
7
+
8
+ :codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)`
9
+ :copyright: © 2013 by the SaltStack Team, see AUTHORS for more details.
10
+ :license: Apache 2.0, see LICENSE for more details.
11
+ """
@@ -0,0 +1,100 @@
1
+ # -*- coding: utf-8 -*-
2
+ # vim: sw=4 ts=4 fenc=utf-8
3
+ '''
4
+ getTerminalSize()
5
+ - get width and height of console
6
+ - works on linux,os x,windows,cygwin(windows)
7
+ - taken from http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python
8
+ '''
9
+
10
+ # Import python libs
11
+ import os
12
+ import platform
13
+ import struct
14
+ import ctypes
15
+ import subprocess
16
+ import fcntl
17
+ import termios
18
+
19
+ __all__ = ['getTerminalSize']
20
+
21
+
22
+ def getTerminalSize():
23
+ current_os = platform.system()
24
+ tuple_xy=None
25
+ if current_os == 'Windows':
26
+ tuple_xy = _getTerminalSize_windows()
27
+ if tuple_xy is None:
28
+ tuple_xy = _getTerminalSize_tput()
29
+ # needed for window's python in cygwin's xterm!
30
+ if current_os == 'Linux' or current_os == 'Darwin' or current_os.startswith('CYGWIN'):
31
+ tuple_xy = _getTerminalSize_linux()
32
+ if tuple_xy is None:
33
+ print 'default'
34
+ tuple_xy = (80, 25) # default value
35
+ return tuple_xy
36
+
37
+
38
+ def _getTerminalSize_windows():
39
+ res=None
40
+ try:
41
+ # stdin handle is -10
42
+ # stdout handle is -11
43
+ # stderr handle is -12
44
+
45
+ h = ctypes.windll.kernel32.GetStdHandle(-12)
46
+ csbi = ctypes.create_string_buffer(22)
47
+ res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
48
+ except Exception:
49
+ return None
50
+ if res:
51
+ (bufx, bufy, curx, cury, wattr,
52
+ left, top, right, bottom, maxx, maxy) = struct.unpack('hhhhHhhhhhh', csbi.raw)
53
+ sizex = right - left + 1
54
+ sizey = bottom - top + 1
55
+ return sizex, sizey
56
+ else:
57
+ return None
58
+
59
+
60
+ def _getTerminalSize_tput():
61
+ # get terminal width
62
+ # src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
63
+ try:
64
+ proc=subprocess.Popen(['tput', 'cols'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
65
+ output=proc.communicate(input=None)
66
+ cols=int(output[0])
67
+ proc=subprocess.Popen(['tput', 'lines'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
68
+ output=proc.communicate(input=None)
69
+ rows=int(output[0])
70
+ return (cols,rows)
71
+ except Exception:
72
+ return None
73
+
74
+
75
+ def _getTerminalSize_linux():
76
+ def ioctl_GWINSZ(fd):
77
+ try:
78
+ cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,'1234'))
79
+ except Exception:
80
+ return None
81
+ return cr
82
+ cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
83
+ if not cr:
84
+ try:
85
+ fd = os.open(os.ctermid(), os.O_RDONLY)
86
+ cr = ioctl_GWINSZ(fd)
87
+ os.close(fd)
88
+ except Exception:
89
+ pass
90
+ if not cr:
91
+ try:
92
+ cr = (os.environ['LINES'], os.environ['COLUMNS'])
93
+ except Exception:
94
+ return None
95
+ return int(cr[1]), int(cr[0])
96
+
97
+
98
+ if __name__ == '__main__':
99
+ sizex,sizey=getTerminalSize()
100
+ print 'width =',sizex,'height =',sizey
@@ -0,0 +1,199 @@
1
+ '''
2
+ This file was copied and adapted from salt's source code
3
+ '''
4
+
5
+ import os
6
+ import re
7
+ import sys
8
+ import platform
9
+ # Extend the default list of supported distros. This will be used for the
10
+ # /etc/DISTRO-release checking that is part of platform.linux_distribution()
11
+ from platform import _supported_dists
12
+ _supported_dists += ('arch', 'mageia', 'meego', 'vmware', 'bluewhite64',
13
+ 'slamd64', 'ovs', 'system', 'mint', 'oracle')
14
+
15
+ _REPLACE_LINUX_RE = re.compile(r'linux', re.IGNORECASE)
16
+
17
+ # This maps (at most) the first ten characters (no spaces, lowercased) of
18
+ # 'osfullname' to the 'os' grain that Salt traditionally uses.
19
+ # Please see os_data() and _supported_dists.
20
+ # If your system is not detecting properly it likely needs an entry here.
21
+ _OS_NAME_MAP = {
22
+ 'redhatente': 'RedHat',
23
+ 'gentoobase': 'Gentoo',
24
+ 'archarm': 'Arch ARM',
25
+ 'arch': 'Arch',
26
+ 'debian': 'Debian',
27
+ 'debiangnu/': 'Debian',
28
+ 'fedoraremi': 'Fedora',
29
+ 'amazonami': 'Amazon',
30
+ 'alt': 'ALT',
31
+ 'oracleserv': 'OEL',
32
+ }
33
+
34
+ # Map the 'os' grain to the 'os_family' grain
35
+ # These should always be capitalized entries as the lookup comes
36
+ # post-_OS_NAME_MAP. If your system is having trouble with detection, please
37
+ # make sure that the 'os' grain is capitalized and working correctly first.
38
+ _OS_FAMILY_MAP = {
39
+ 'Ubuntu': 'Debian',
40
+ 'Fedora': 'RedHat',
41
+ 'CentOS': 'RedHat',
42
+ 'GoOSe': 'RedHat',
43
+ 'Scientific': 'RedHat',
44
+ 'Amazon': 'RedHat',
45
+ 'CloudLinux': 'RedHat',
46
+ 'OVS': 'RedHat',
47
+ 'OEL': 'RedHat',
48
+ 'Mandrake': 'Mandriva',
49
+ 'ESXi': 'VMWare',
50
+ 'Mint': 'Debian',
51
+ 'VMWareESX': 'VMWare',
52
+ 'Bluewhite64': 'Bluewhite',
53
+ 'Slamd64': 'Slackware',
54
+ 'SLES': 'Suse',
55
+ 'SUSE Enterprise Server': 'Suse',
56
+ 'SUSE Enterprise Server': 'Suse',
57
+ 'SLED': 'Suse',
58
+ 'openSUSE': 'Suse',
59
+ 'SUSE': 'Suse',
60
+ 'Solaris': 'Solaris',
61
+ 'SmartOS': 'Solaris',
62
+ 'Arch ARM': 'Arch',
63
+ 'ALT': 'RedHat',
64
+ 'Trisquel': 'Debian'
65
+ }
66
+
67
+
68
+ def os_data():
69
+ '''
70
+ Return grains pertaining to the operating system
71
+ '''
72
+ grains = {
73
+ 'num_gpus': 0,
74
+ 'gpus': [],
75
+ }
76
+
77
+ # Windows Server 2008 64-bit
78
+ # ('Windows', 'MINIONNAME', '2008ServerR2', '6.1.7601', 'AMD64', 'Intel64 Fam ily 6 Model 23 Stepping 6, GenuineIntel')
79
+ # Ubuntu 10.04
80
+ # ('Linux', 'MINIONNAME', '2.6.32-38-server', '#83-Ubuntu SMP Wed Jan 4 11:26:59 UTC 2012', 'x86_64', '')
81
+ (grains['kernel'], grains['nodename'],
82
+ grains['kernelrelease'], version, grains['cpuarch'], _) = platform.uname()
83
+ if sys.platform.startswith('win'):
84
+ grains['osrelease'] = grains['kernelrelease']
85
+ grains['osversion'] = grains['kernelrelease'] = version
86
+ grains['os'] = 'Windows'
87
+ grains['os_family'] = 'Windows'
88
+ return grains
89
+ elif sys.platform.startswith('linux'):
90
+ # Add lsb grains on any distro with lsb-release
91
+ try:
92
+ import lsb_release
93
+ release = lsb_release.get_distro_information()
94
+ for key, value in release.iteritems():
95
+ grains['lsb_{0}'.format(key.lower())] = value # override /etc/lsb-release
96
+ except ImportError:
97
+ # if the python library isn't available, default to regex
98
+ if os.path.isfile('/etc/lsb-release'):
99
+ with open('/etc/lsb-release') as ifile:
100
+ for line in ifile:
101
+ # Matches any possible format:
102
+ # DISTRIB_ID="Ubuntu"
103
+ # DISTRIB_ID='Mageia'
104
+ # DISTRIB_ID=Fedora
105
+ # DISTRIB_RELEASE='10.10'
106
+ # DISTRIB_CODENAME='squeeze'
107
+ # DISTRIB_DESCRIPTION='Ubuntu 10.10'
108
+ regex = re.compile('^(DISTRIB_(?:ID|RELEASE|CODENAME|DESCRIPTION))=(?:\'|")?([\w\s\.-_]+)(?:\'|")?')
109
+ match = regex.match(line.rstrip('\n'))
110
+ if match:
111
+ # Adds: lsb_distrib_{id,release,codename,description}
112
+ grains['lsb_{0}'.format(match.groups()[0].lower())] = match.groups()[1].rstrip()
113
+ elif os.path.isfile('/etc/os-release'):
114
+ # Arch ARM linux
115
+ with open('/etc/os-release') as ifile:
116
+ # Imitate lsb-release
117
+ for line in ifile:
118
+ # NAME="Arch Linux ARM"
119
+ # ID=archarm
120
+ # ID_LIKE=arch
121
+ # PRETTY_NAME="Arch Linux ARM"
122
+ # ANSI_COLOR="0;36"
123
+ # HOME_URL="http://archlinuxarm.org/"
124
+ # SUPPORT_URL="https://archlinuxarm.org/forum"
125
+ # BUG_REPORT_URL="https://github.com/archlinuxarm/PKGBUILDs/issues"
126
+ regex = re.compile('^([\w]+)=(?:\'|")?([\w\s\.-_]+)(?:\'|")?')
127
+ match = regex.match(line.rstrip('\n'))
128
+ if match:
129
+ name, value = match.groups()
130
+ if name.lower() == 'name':
131
+ grains['lsb_distrib_id'] = value.strip()
132
+ elif os.path.isfile('/etc/altlinux-release'):
133
+ # ALT Linux
134
+ grains['lsb_distrib_id'] = 'altlinux'
135
+ with open('/etc/altlinux-release') as ifile:
136
+ # This file is symlinked to from:
137
+ # /etc/fedora-release
138
+ # /etc/redhat-release
139
+ # /etc/system-release
140
+ for line in ifile:
141
+ # ALT Linux Sisyphus (unstable)
142
+ comps = line.split()
143
+ if comps[0] == 'ALT':
144
+ grains['lsb_distrib_release'] = comps[2]
145
+ grains['lsb_distrib_codename'] = \
146
+ comps[3].replace('(', '').replace(')', '')
147
+ # Use the already intelligent platform module to get distro info
148
+ (osname, osrelease, oscodename) = platform.linux_distribution(
149
+ supported_dists=_supported_dists)
150
+ # Try to assign these three names based on the lsb info, they tend to
151
+ # be more accurate than what python gets from /etc/DISTRO-release.
152
+ # It's worth noting that Ubuntu has patched their Python distribution
153
+ # so that platform.linux_distribution() does the /etc/lsb-release
154
+ # parsing, but we do it anyway here for the sake for full portability.
155
+ grains['osfullname'] = grains.get('lsb_distrib_id', osname).strip()
156
+ grains['osrelease'] = grains.get('lsb_distrib_release', osrelease).strip()
157
+ grains['oscodename'] = grains.get('lsb_distrib_codename', oscodename).strip()
158
+ distroname = _REPLACE_LINUX_RE.sub('', grains['osfullname']).strip()
159
+ # return the first ten characters with no spaces, lowercased
160
+ shortname = distroname.replace(' ', '').lower()[:10]
161
+ # this maps the long names from the /etc/DISTRO-release files to the
162
+ # traditional short names that Salt has used.
163
+ grains['os'] = _OS_NAME_MAP.get(shortname, distroname)
164
+ elif grains['kernel'] == 'SunOS':
165
+ grains['os'] = 'Solaris'
166
+ if os.path.isfile('/etc/release'):
167
+ with open('/etc/release', 'r') as fp_:
168
+ rel_data = fp_.read()
169
+ if 'SmartOS' in rel_data:
170
+ grains['os'] = 'SmartOS'
171
+ #grains.update(_sunos_cpudata(grains))
172
+ elif grains['kernel'] == 'VMkernel':
173
+ grains['os'] = 'ESXi'
174
+ elif grains['kernel'] == 'Darwin':
175
+ grains['os'] = 'MacOS'
176
+ # grains.update(_bsd_cpudata(grains))
177
+ else:
178
+ grains['os'] = grains['kernel']
179
+ if grains['kernel'] in ('FreeBSD', 'OpenBSD'):
180
+ grains['os'] = grains['kernel']
181
+ grains['os_family'] = grains['os']
182
+ grains['osfullname'] = "{0} {1}".format(grains['kernel'], grains['kernelrelease'])
183
+ grains['osrelease'] = grains['kernelrelease']
184
+ # grains.update(_bsd_cpudata(grains))
185
+ if not grains['os']:
186
+ grains['os'] = 'Unknown {0}'.format(grains['kernel'])
187
+ grains['os_family'] = 'Unknown'
188
+ else:
189
+ # this assigns family names based on the os name
190
+ # family defaults to the os name if not found
191
+ grains['os_family'] = _OS_FAMILY_MAP.get(grains['os'], grains['os'])
192
+
193
+ return grains
194
+
195
+ GRAINS = os_data()
196
+
197
+ if __name__ == '__main__':
198
+ import pprint
199
+ pprint.pprint(GRAINS)
@@ -0,0 +1,586 @@
1
+ # -*- coding: utf-8 -*-
2
+ '''
3
+ bootstrap.test_install
4
+ ~~~~~~~~~~~~~~~~~~~~~~
5
+
6
+ Run installation tests.
7
+
8
+ :codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)`
9
+ :copyright: © 2013 by the SaltStack Team, see AUTHORS for more details.
10
+ :license: Apache 2.0, see LICENSE for more details.
11
+ '''
12
+
13
+ import glob
14
+ import shutil
15
+ from bootstrap.unittesting import *
16
+
17
+
18
+ CLEANUP_COMMANDS_BY_OS_FAMILY = {
19
+ 'Arch': [
20
+ 'pacman -Qs python2-crypto && pacman -Rsc --noconfirm python2-crypto && exit $? || exit 0',
21
+ 'pacman -Qs python2-distribute && pacman -Rsc --noconfirm python2-distribute && exit $? || exit 0',
22
+ 'pacman -Qs python2-jinja && pacman -Rsc --noconfirm python2-jinja && exit $? || exit 0',
23
+ 'pacman -Qs python2-m2crypto && pacman -Rsc --noconfirm python2-m2crypto && exit $? || exit 0',
24
+ 'pacman -Qs python2-markupsafe && pacman -Rsc --noconfirm python2-markupsafe && exit $? || exit 0',
25
+ 'pacman -Qs python2-msgpack && pacman -Rsc --noconfirm python2-msgpack && exit $? || exit 0',
26
+ 'pacman -Qs python2-psutil && pacman -Rsc --noconfirm python2-psutil && exit $? || exit 0',
27
+ 'pacman -Qs python2-pyzmq && pacman -Rsc --noconfirm python2-pyzmq && exit $? || exit 0',
28
+ 'pacman -Qs zeromq && pacman -Rsc --noconfirm zeromq && exit $? || exit 0',
29
+ ],
30
+ 'Debian': [
31
+ 'apt-get remove -y -o DPkg::Options::=--force-confold '
32
+ '--purge salt-master salt-minion salt-syndic python-crypto '
33
+ 'python-jinja2 python-m2crypto python-yaml msgpack-python python-zmq',
34
+ 'apt-get autoremove -y -o DPkg::Options::=--force-confold --purge',
35
+ 'rm -rf /etc/apt/sources.list.d/saltstack-salt-*'
36
+ ],
37
+ 'RedHat': [
38
+ 'yum -y remove salt-minion salt-master',
39
+ 'yum -y remove python{0}-m2crypto m2crypto python{0}-crypto '
40
+ 'python{0}-msgpack python{0}-zmq python{0}-jinja2'.format(
41
+ GRAINS['osrelease'].split('.')[0] == '5' and '26' or ''
42
+ ),
43
+ ],
44
+ 'FreeBSD': [
45
+ 'pkg delete -y swig sysutils/py-salt',
46
+ 'pkg autoremove -y'
47
+ ],
48
+ 'Solaris': [
49
+ 'pkgin -y rm libtool-base autoconf automake libuuid gcc-compiler '
50
+ 'gmake py27-setuptools py27-yaml py27-crypto swig',
51
+ 'svcs network/salt-minion >/dev/null 2>&1 && svcadm disable network/salt-minion >/dev/null 2>&1 || exit 0',
52
+ 'svcs network/salt-minion >/dev/null 2>&1 && svccfg delete network/salt-minion >/dev/null 2>&1 || exit 0',
53
+ 'svcs network/salt-master >/dev/null 2>&1 && svcadm disable network/salt-master >/dev/null 2>&1 || exit 0',
54
+ 'svcs network/salt-master >/dev/null 2>&1 && svccfg delete network/salt-master >/dev/null 2>&1 || exit 0',
55
+ 'svcs network/salt-syndic >/dev/null 2>&1 && svcadm disable network/salt-syndic >/dev/null 2>&1 || exit 0',
56
+ 'svcs network/salt-syndic >/dev/null 2>&1 && svccfg delete network/salt-syndic >/dev/null 2>&1 || exit 0'
57
+ ],
58
+ 'Suse': [
59
+ '(zypper --non-interactive se -i salt-master || exit 0 && zypper --non-interactive remove salt-master && exit 0) || '
60
+ '(rpm -q salt-master && rpm -e --noscripts salt-master || exit 0)',
61
+ '(zypper --non-interactive se -i salt-minion || exit 0 && zypper --non-interactive remove salt-minion && exit 0) || '
62
+ '(rpm -q salt-minion && rpm -e --noscripts salt-minion || exit 0)',
63
+ '(zypper --non-interactive se -i salt-syndic || exit 0 && zypper --non-interactive remove salt-syndic && exit 0) || '
64
+ '(rpm -q salt-syndic && rpm -e --noscripts salt-syndic || exit 0)',
65
+ '(zypper --non-interactive se -i salt || exit 0 && zypper --non-interactive remove salt && exit 0) || '
66
+ '(rpm -q salt && rpm -e --noscripts salt || exit 0)',
67
+ 'pip uninstall -y salt >/dev/null 2>&1 || exit 0',
68
+ 'pip uninstall -y PyYaml >/dev/null 2>&1 || exit 0',
69
+ 'zypper --non-interactive remove libzmq3 python-Jinja2 '
70
+ 'python-M2Crypto python-PyYAML python-msgpack-python '
71
+ 'python-pycrypto python-pyzmq',
72
+ ]
73
+ }
74
+
75
+ OS_REQUIRES_PIP_ALLOWED = (
76
+ # Some distributions can only install salt or some of its dependencies
77
+ # passing -P to the bootstrap script.
78
+ # The GRAINS['os'] which are in this list, requires that extra argument.
79
+ 'Debian',
80
+ 'SmartOS',
81
+ 'Suse' # Need to revisit openSUSE and SLES for the proper OS grain.
82
+ )
83
+
84
+ # SLES grains differ from openSUSE, let do a 1:1 direct mapping
85
+ CLEANUP_COMMANDS_BY_OS_FAMILY['SUSE Enterprise Server'] = CLEANUP_COMMANDS_BY_OS_FAMILY['Suse']
86
+
87
+
88
+ class InstallationTestCase(BootstrapTestCase):
89
+
90
+ def setUp(self):
91
+ if os.geteuid() is not 0:
92
+ self.skipTest('you must be root to run this test')
93
+
94
+ if GRAINS['os_family'] not in CLEANUP_COMMANDS_BY_OS_FAMILY:
95
+ self.skipTest(
96
+ 'There is not `tearDown()` clean up support for {0!r} OS '
97
+ 'family.'.format(
98
+ GRAINS['os_family']
99
+ )
100
+ )
101
+
102
+ def tearDown(self):
103
+ for cleanup in CLEANUP_COMMANDS_BY_OS_FAMILY[GRAINS['os_family']]:
104
+ print 'Running cleanup command {0!r}'.format(cleanup)
105
+ self.assert_script_result(
106
+ 'Failed to execute cleanup command {0!r}'.format(cleanup),
107
+ (
108
+ 0, # Proper exit code without errors.
109
+
110
+ 4, # ZYPPER_EXIT_ERR_ZYPP: A problem reported by ZYPP
111
+ # library.
112
+
113
+ 65, # FreeBSD throws this error code when the packages
114
+ # being un-installed were not installed in the first
115
+ # place.
116
+
117
+ 100, # Same as above but on Ubuntu with a another errno
118
+
119
+ 104, # ZYPPER_EXIT_INF_CAP_NOT_FOUND: Returned by the
120
+ # install and the remove command in case any of
121
+ # the arguments does not match any of the available
122
+ # (or installed) package names or other capabilities.
123
+ ),
124
+ self.run_script(
125
+ script=None,
126
+ args=cleanup.split(),
127
+ timeout=15 * 60,
128
+ stream_stds=True
129
+ )
130
+ )
131
+
132
+ # As a last resort, by hand house cleaning...
133
+ for glob_rule in ('/tmp/git', '/usr/lib*/python*/site-packages/salt*',
134
+ '/usr/bin/salt*', '/usr/lib/systemd/system/salt*',
135
+ '/etc/init*/salt*', '/usr/share/doc/salt*',
136
+ '/usr/share/man/man*/salt*', '/var/*/salt*',
137
+ '/etc/salt'):
138
+ for entry in glob.glob(glob_rule):
139
+ if os.path.isfile(entry):
140
+ print 'Removing file {0!r}'.format(entry)
141
+ os.remove(entry)
142
+ elif os.path.isdir(entry):
143
+ print 'Removing directory {0!r}'.format(entry)
144
+ shutil.rmtree(entry)
145
+
146
+ def test_install_using_bash(self):
147
+ if not os.path.exists('/bin/bash'):
148
+ self.skipTest('\'/bin/bash\' was not found on this system')
149
+
150
+ args = []
151
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
152
+ args.append('-P')
153
+
154
+ self.assert_script_result(
155
+ 'Failed to install using bash',
156
+ 0,
157
+ self.run_script(
158
+ args=args,
159
+ executable='/bin/bash',
160
+ timeout=15 * 60,
161
+ stream_stds=True
162
+ )
163
+ )
164
+
165
+ # Try to get the versions report
166
+ self.assert_script_result(
167
+ 'Failed to get the versions report (\'--versions-report\')',
168
+ 0,
169
+ self.run_script(
170
+ script=None,
171
+ args=('salt-minion', '--versions-report'),
172
+ timeout=15 * 60,
173
+ stream_stds=True
174
+ )
175
+ )
176
+
177
+ def test_install_using_sh(self):
178
+ args = []
179
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
180
+ args.append('-P')
181
+
182
+ self.assert_script_result(
183
+ 'Failed to install using sh',
184
+ 0,
185
+ self.run_script(
186
+ args=args,
187
+ timeout=15 * 60,
188
+ stream_stds=True
189
+ )
190
+ )
191
+
192
+ # Try to get the versions report
193
+ self.assert_script_result(
194
+ 'Failed to get the versions report (\'--versions-report\')',
195
+ 0,
196
+ self.run_script(
197
+ script=None,
198
+ args=('salt-minion', '--versions-report'),
199
+ timeout=15 * 60,
200
+ stream_stds=True
201
+ )
202
+ )
203
+
204
+ def test_install_explicit_stable(self):
205
+ args = []
206
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
207
+ args.append('-P')
208
+
209
+ args.append('stable')
210
+
211
+ self.assert_script_result(
212
+ 'Failed to install explicit stable using sh',
213
+ 0,
214
+ self.run_script(
215
+ args=args,
216
+ timeout=15 * 60,
217
+ stream_stds=True
218
+ )
219
+ )
220
+
221
+ # Try to get the versions report
222
+ self.assert_script_result(
223
+ 'Failed to get the versions report (\'--versions-report\')',
224
+ 0,
225
+ self.run_script(
226
+ script=None,
227
+ args=('salt-minion', '--versions-report'),
228
+ timeout=15 * 60,
229
+ stream_stds=True
230
+ )
231
+ )
232
+
233
+ def test_install_daily(self):
234
+ args = []
235
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
236
+ args.append('-P')
237
+
238
+ args.append('daily')
239
+
240
+ rc, out, err = self.run_script(
241
+ args=args, timeout=15 * 60, stream_stds=True
242
+ )
243
+ if GRAINS['os'] in ('Ubuntu', 'Trisquel'):
244
+ self.assert_script_result(
245
+ 'Failed to install daily',
246
+ 0, (rc, out, err)
247
+ )
248
+
249
+ # Try to get the versions report
250
+ self.assert_script_result(
251
+ 'Failed to get the versions report (\'--versions-report\')',
252
+ 0,
253
+ self.run_script(
254
+ script=None,
255
+ args=('salt-minion', '--versions-report'),
256
+ timeout=15 * 60,
257
+ stream_stds=True
258
+ )
259
+ )
260
+ else:
261
+ self.assert_script_result(
262
+ 'Although system is not Ubuntu, we managed to install',
263
+ 1, (rc, out, err)
264
+ )
265
+
266
+ def test_install_stable_piped_through_sh(self):
267
+ args = 'cat {0} | sh '.format(BOOTSTRAP_SCRIPT_PATH).split()
268
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
269
+ args.extend('-s -- -P'.split())
270
+
271
+ self.assert_script_result(
272
+ 'Failed to install stable piped through sh',
273
+ 0,
274
+ self.run_script(
275
+ script=None,
276
+ args=args,
277
+ timeout=15 * 60,
278
+ stream_stds=True
279
+ )
280
+ )
281
+
282
+ # Try to get the versions report
283
+ self.assert_script_result(
284
+ 'Failed to get the versions report (\'--versions-report\')',
285
+ 0,
286
+ self.run_script(
287
+ script=None,
288
+ args=('salt-minion', '--versions-report'),
289
+ timeout=15 * 60,
290
+ stream_stds=True
291
+ )
292
+ )
293
+
294
+ #def test_install_latest_from_git_develop(self):
295
+ # args = []
296
+ # if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
297
+ # args.append('-P')
298
+ #
299
+ # args.extend(['git', 'develop'])
300
+ #
301
+ # self.assert_script_result(
302
+ # 'Failed to install using latest git develop',
303
+ # 0,
304
+ # self.run_script(
305
+ # args=args,
306
+ # timeout=15 * 60,
307
+ # stream_stds=True
308
+ # )
309
+ # )
310
+ #
311
+ # # Try to get the versions report
312
+ # self.assert_script_result(
313
+ # 'Failed to get the versions report (\'--versions-report\')',
314
+ # 0,
315
+ # self.run_script(
316
+ # script=None,
317
+ # args=('salt', '--versions-report'),
318
+ # timeout=15 * 60,
319
+ # stream_stds=True
320
+ # )
321
+ # )
322
+
323
+ def test_install_specific_git_tag(self):
324
+ args = []
325
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
326
+ args.append('-P')
327
+
328
+ args.extend(['git', 'v0.13.1'])
329
+
330
+ self.assert_script_result(
331
+ 'Failed to install using specific git tag',
332
+ 0,
333
+ self.run_script(
334
+ args=args,
335
+ timeout=15 * 60,
336
+ stream_stds=True
337
+ )
338
+ )
339
+
340
+ # Try to get the versions report
341
+ self.assert_script_result(
342
+ 'Failed to get the versions report (\'--versions-report\')',
343
+ 0,
344
+ self.run_script(
345
+ script=None,
346
+ args=('salt', '--versions-report'),
347
+ timeout=15 * 60,
348
+ stream_stds=True
349
+ )
350
+ )
351
+
352
+ def test_install_specific_git_sha(self):
353
+ args = []
354
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
355
+ args.append('-P')
356
+
357
+ args.extend(['git', '2b6264de62bf2ea221bb2c0b8af36dfcfaafe7cf'])
358
+
359
+ self.assert_script_result(
360
+ 'Failed to install using specific git sha',
361
+ 0,
362
+ self.run_script(
363
+ args=args,
364
+ timeout=15 * 60,
365
+ stream_stds=True
366
+ )
367
+ )
368
+
369
+ # Try to get the versions report
370
+ self.assert_script_result(
371
+ 'Failed to get the versions report (\'--versions-report\')',
372
+ 0,
373
+ self.run_script(
374
+ script=None,
375
+ args=('salt', '--versions-report'),
376
+ timeout=15 * 60,
377
+ stream_stds=True
378
+ )
379
+ )
380
+
381
+ def test_config_only_without_config_dir_fails(self):
382
+ '''
383
+ Test running in configuration mode only without providing the necessary
384
+ configuration directory fails.
385
+ '''
386
+ self.assert_script_result(
387
+ 'The script successfully executed even though no configuration '
388
+ 'directory was provided.',
389
+ 1,
390
+ self.run_script(args=('-C',))
391
+ )
392
+
393
+ def test_config_with_a_non_existing_configuration_dir_fails(self):
394
+ '''
395
+ Do we fail if the passed configuration directory passed does not exits?
396
+ '''
397
+ self.assert_script_result(
398
+ 'The script successfully executed even though the configuration '
399
+ 'directory provided does not exist.',
400
+ 1,
401
+ self.run_script(
402
+ args=('-C', '-c', '/tmp/this-directory-must-not-exist')
403
+ )
404
+ )
405
+
406
+ def test_config_only_without_actually_configuring_anything_fails(self):
407
+ '''
408
+ Test running in configuration mode only without actually configuring
409
+ anything fails.
410
+ '''
411
+ rc, out, err = self.run_script(
412
+ args=('-C', '-n', '-c', '/tmp'),
413
+ )
414
+
415
+ self.assert_script_result(
416
+ 'The script did not show a warning even though no configuration '
417
+ 'was done.',
418
+ 0, (rc, out, err)
419
+ )
420
+ self.assertIn(
421
+ 'WARN: No configuration or keys were copied over. No '
422
+ 'configuration was done!',
423
+ '\n'.join(out)
424
+ )
425
+
426
+ def test_install_salt_master(self):
427
+ '''
428
+ Test if installing a salt-master works
429
+ '''
430
+ args = []
431
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
432
+ args.append('-P')
433
+
434
+ args.extend(['-N', '-M'])
435
+
436
+ self.assert_script_result(
437
+ 'Failed to install salt-master',
438
+ 0,
439
+ self.run_script(
440
+ args=args,
441
+ timeout=15 * 60,
442
+ stream_stds=True
443
+ )
444
+ )
445
+
446
+ # Try to get the versions report
447
+ self.assert_script_result(
448
+ 'Failed to get the versions report from salt-master',
449
+ 0,
450
+ self.run_script(
451
+ script=None,
452
+ args=('salt-master', '--versions-report'),
453
+ timeout=15 * 60,
454
+ stream_stds=True
455
+ )
456
+ )
457
+
458
+ def test_install_salt_syndic(self):
459
+ '''
460
+ Test if installing a salt-syndic works
461
+ '''
462
+ if GRAINS['os'] == 'Debian':
463
+ self.skipTest(
464
+ 'Currently the debian stable package will have the syndic '
465
+ 'waiting for a connection to a master.'
466
+ )
467
+
468
+ args = []
469
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
470
+ args.append('-P')
471
+
472
+ args.extend(['-N', '-S'])
473
+
474
+ self.assert_script_result(
475
+ 'Failed to install salt-syndic',
476
+ 0,
477
+ self.run_script(
478
+ args=args,
479
+ timeout=15 * 60,
480
+ stream_stds=True
481
+ )
482
+ )
483
+
484
+ # Try to get the versions report
485
+ self.assert_script_result(
486
+ 'Failed to get the versions report from salt-syndic',
487
+ 0,
488
+ self.run_script(
489
+ script=None,
490
+ args=('salt-syndic', '--versions-report'),
491
+ timeout=15 * 60,
492
+ stream_stds=True
493
+ )
494
+ )
495
+
496
+ def test_install_pip_not_allowed(self):
497
+ '''
498
+ Check if distributions which require `-P` to allow pip to install
499
+ packages, fail if that flag is not passed.
500
+ '''
501
+ if GRAINS['os'] not in OS_REQUIRES_PIP_ALLOWED:
502
+ self.skipTest(
503
+ 'Distribution {0} does not require the extra `-P` flag'.format(
504
+ GRAINS['os']
505
+ )
506
+ )
507
+
508
+ self.assert_script_result(
509
+ 'Even though {0} is flagged as requiring the extra `-P` flag to '
510
+ 'allow packages to be installed by pip, it did not fail when we '
511
+ 'did not pass it'.format(GRAINS['os']),
512
+ 1,
513
+ self.run_script(
514
+ timeout=15 * 60,
515
+ stream_stds=True
516
+ )
517
+ )
518
+
519
+ def test_install_from_git_on_checked_out_repository(self):
520
+ '''
521
+ Check if the script properly updates an already checked out repository.
522
+ '''
523
+ if not os.path.isdir('/tmp/git'):
524
+ os.makedirs('/tmp/git')
525
+
526
+ # Clone salt from git
527
+ self.assert_script_result(
528
+ 'Failed to clone salt\'s git repository',
529
+ 0,
530
+ self.run_script(
531
+ script=None,
532
+ args=('git', 'clone', 'https://github.com/saltstack/salt.git'),
533
+ cwd='/tmp/git',
534
+ timeout=15 * 60,
535
+ stream_stds=True
536
+ )
537
+ )
538
+
539
+ # Check-out a specific revision
540
+ self.assert_script_result(
541
+ 'Failed to checkout v0.12.1 from salt\'s cloned git repository',
542
+ 0,
543
+ self.run_script(
544
+ script=None,
545
+ args=('git', 'checkout', 'v0.12.1'),
546
+ cwd='/tmp/git/salt',
547
+ timeout=15 * 60,
548
+ stream_stds=True
549
+ )
550
+ )
551
+
552
+ # Now run the bootstrap script over an existing git checkout and see
553
+ # if it properly updates.
554
+ args = []
555
+ if GRAINS['os'] in OS_REQUIRES_PIP_ALLOWED:
556
+ args.append('-P')
557
+
558
+ args.extend(['git', 'v0.13.1'])
559
+
560
+ self.assert_script_result(
561
+ 'Failed to install using specific git tag',
562
+ 0,
563
+ self.run_script(
564
+ args=args,
565
+ timeout=15 * 60,
566
+ stream_stds=True
567
+ )
568
+ )
569
+
570
+ # Get the version from the salt binary just installed
571
+ # Do it as a two step so we can check the returning output.
572
+ rc, out, err = self.run_script(
573
+ script=None,
574
+ args=('salt', '--version'),
575
+ timeout=15 * 60,
576
+ stream_stds=True
577
+ )
578
+
579
+ self.assert_script_result(
580
+ 'Failed to get the salt version',
581
+ 0, (rc, out, err)
582
+ )
583
+
584
+ # Make sure the installation updated the git repository to the proper
585
+ # git tag before installing.
586
+ self.assertIn('0.13.1', '\n'.join(out))