vagrant-salt 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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))