22from __future__ import absolute_import , unicode_literals , print_function
33
44# Import python libraries
5- import distutils .spawn
65import logging
76import os .path
87import shutil
1110import textwrap
1211
1312# Import Salt Libraries
14- import salt .client
15- import salt .config
1613import salt .utils .yaml as yaml
1714
1815# Import pytest libraries
1916import pytest
20- from pytestsalt .utils import SaltDaemonScriptBase , start_daemon , get_unused_localhost_port
17+ from pytestskipmarkers .utils import ports
18+ from saltfactories .utils import random_string , running_username
2119
2220# Import Pepper libraries
2321import pepper
2422import pepper .script
2523
26- DEFAULT_MASTER_ID = 'pytest-salt-master'
27- DEFAULT_MINION_ID = 'pytest-salt-minion'
2824
2925log = logging .getLogger (__name__ )
3026
3127
3228@pytest .fixture (scope = 'session' )
33- def install_sshd_server ():
34- if distutils .spawn .find_executable ('sshd' ):
35- return
36- __opts__ = salt .config .minion_config ('tests/minion.conf' )
37- __opts__ ['file_client' ] = 'local'
38- caller = salt .client .Caller (mopts = __opts__ )
39- caller .cmd ('pkg.install' , 'openssh-server' )
29+ def sshd_config_dir (salt_factories ):
30+ config_dir = salt_factories .get_root_dir_for_daemon ("sshd" )
31+ yield config_dir
32+ shutil .rmtree (str (config_dir ), ignore_errors = True )
4033
4134
42- class SaltApi (SaltDaemonScriptBase ):
43- '''
44- Class which runs the salt-api daemon
45- '''
46-
47- def get_script_args (self ):
48- return ['-l' , 'quiet' ]
35+ @pytest .fixture (scope = 'session' )
36+ def session_sshd_server (salt_factories , sshd_config_dir , session_master ):
37+ sshd_config_dict = {
38+ "Protocol" : "2" ,
39+ # Turn strict modes off so that we can operate in /tmp
40+ "StrictModes" : "no" ,
41+ # Logging
42+ "SyslogFacility" : "AUTH" ,
43+ "LogLevel" : "INFO" ,
44+ # Authentication:
45+ "LoginGraceTime" : "120" ,
46+ "PermitRootLogin" : "without-password" ,
47+ "PubkeyAuthentication" : "yes" ,
48+ # Don't read the user's ~/.rhosts and ~/.shosts files
49+ "IgnoreRhosts" : "yes" ,
50+ "HostbasedAuthentication" : "no" ,
51+ # To enable empty passwords, change to yes (NOT RECOMMENDED)
52+ "PermitEmptyPasswords" : "no" ,
53+ # Change to yes to enable challenge-response passwords (beware issues with
54+ # some PAM modules and threads)
55+ "ChallengeResponseAuthentication" : "no" ,
56+ # Change to no to disable tunnelled clear text passwords
57+ "PasswordAuthentication" : "no" ,
58+ "X11Forwarding" : "no" ,
59+ "X11DisplayOffset" : "10" ,
60+ "PrintMotd" : "no" ,
61+ "PrintLastLog" : "yes" ,
62+ "TCPKeepAlive" : "yes" ,
63+ "AcceptEnv" : "LANG LC_*" ,
64+ "UsePAM" : "yes" ,
65+ }
66+ factory = salt_factories .get_sshd_daemon (
67+ sshd_config_dict = sshd_config_dict ,
68+ config_dir = sshd_config_dir ,
69+ )
70+ with factory .started ():
71+ yield factory
4972
50- def get_check_ports (self ):
51- if 'rest_cherrypy' in self .config :
52- return [self .config ['rest_cherrypy' ]['port' ]]
5373
54- if 'rest_tornado' in self .config :
55- return [self .config ['rest_tornado' ]['port' ]]
74+ @pytest .fixture (scope = 'session' )
75+ def session_ssh_roster_config (session_sshd_server , session_master ):
76+ roster_contents = """
77+ localhost:
78+ host: 127.0.0.1
79+ port: {}
80+ user: {}
81+ priv: {}
82+ mine_functions:
83+ test.arg: ['itworked']
84+ """ .format (
85+ session_sshd_server .listen_port ,
86+ running_username (),
87+ session_sshd_server .client_key
88+ )
89+ with pytest .helpers .temp_file (
90+ "roster" , roster_contents , session_master .config_dir
91+ ) as roster_file :
92+ yield roster_file
5693
5794
5895@pytest .fixture (scope = 'session' )
5996def salt_api_port ():
6097 '''
6198 Returns an unused localhost port for the api port
6299 '''
63- return get_unused_localhost_port ()
100+ return ports . get_unused_localhost_port ()
64101
65102
66103@pytest .fixture (scope = 'session' )
@@ -121,7 +158,7 @@ def output_file():
121158
122159
123160@pytest .fixture (params = ['/run' , '/login' ])
124- def pepper_cli (request , session_salt_api , salt_api_port , output_file , install_sshd_server , session_sshd_server ):
161+ def pepper_cli (request , session_salt_api , salt_api_port , output_file , session_sshd_server ):
125162 '''
126163 Wrapper to invoke Pepper with common params and inside an empty env
127164 '''
@@ -154,6 +191,20 @@ def _run_pepper_cli(*args, **kwargs):
154191 return _run_pepper_cli
155192
156193
194+ @pytest .fixture (scope = 'session' )
195+ def session_master_factory (request , salt_factories , session_master_config_overrides ):
196+ return salt_factories .salt_master_daemon (
197+ random_string ("master-" ),
198+ overrides = session_master_config_overrides
199+ )
200+
201+
202+ @pytest .fixture (scope = 'session' )
203+ def session_master (session_master_factory ):
204+ with session_master_factory .started ():
205+ yield session_master_factory
206+
207+
157208@pytest .fixture (scope = 'session' )
158209def session_master_config_overrides (request , salt_api_port , salt_api_backend ):
159210 return {
@@ -175,69 +226,40 @@ def session_master_config_overrides(request, salt_api_port, salt_api_backend):
175226 'token_expire' : 94670856 ,
176227 'ignore_host_keys' : True ,
177228 'ssh_wipe' : True ,
229+ 'netapi_enable_clients' : [
230+ 'local' ,
231+ 'local_async' ,
232+ 'local_subset' ,
233+ 'ssh' ,
234+ 'runner' ,
235+ 'runner_async' ,
236+ 'wheel' ,
237+ 'wheel_async' ,
238+ 'run'
239+ ]
178240 }
179241
180242
181243@pytest .fixture (scope = 'session' )
182- def session_api_log_prefix (master_id ):
183- return 'salt-api/{0}' .format (master_id )
244+ def session_minion_factory (session_master_factory ):
245+ """Return a factory for a randomly named minion connected to master."""
246+ minion_factory = session_master_factory .salt_minion_daemon (random_string ("minion-" ))
247+ minion_factory .after_terminate (
248+ pytest .helpers .remove_stale_minion_key , session_master_factory , minion_factory .id
249+ )
250+ return minion_factory
184251
185252
186253@pytest .fixture (scope = 'session' )
187- def cli_api_script_name ():
188- '''
189- Return the CLI script basename
190- '''
191- return 'salt-api'
192-
193-
194- @pytest .yield_fixture (scope = 'session' )
195- def session_salt_api_before_start ():
196- '''
197- This fixture should be overridden if you need to do
198- some preparation and clean up work before starting
199- the salt-api and after ending it.
200- '''
201- # Prep routines go here
202-
203- # Start the salt-api
204- yield
205-
206- # Clean routines go here
207-
208-
209- @pytest .yield_fixture (scope = 'session' )
210- def session_salt_api_after_start (session_salt_api ):
211- '''
212- This fixture should be overridden if you need to do
213- some preparation and clean up work after starting
214- the salt-api and before ending it.
215- '''
216- # Prep routines go here
217-
218- # Resume test execution
219- yield
220-
221- # Clean routines go here
254+ def session_minion (session_master , session_minion_factory ): # noqa
255+ assert session_master .is_running ()
256+ with session_minion_factory .started ():
257+ yield session_minion_factory
222258
223259
224260@pytest .fixture (scope = 'session' )
225- def _salt_fail_hard (request , salt_fail_hard ):
226- '''
227- Return the salt fail hard value
228- '''
229- fail_hard = request .config .getoption ('salt_fail_hard' )
230- if fail_hard is not None :
231- # We were passed --salt-fail-hard as a CLI option
232- return fail_hard
233-
234- # The salt fail hard was not passed as a CLI option
235- fail_hard = request .config .getini ('salt_fail_hard' )
236- if fail_hard != []:
237- # We were passed salt_fail_hard as a INI option
238- return fail_hard
239-
240- return salt_fail_hard
261+ def session_minion_id (session_minion ):
262+ return session_minion .id
241263
242264
243265@pytest .fixture (scope = 'session' )
@@ -257,91 +279,15 @@ def salt_api_backend(request):
257279
258280
259281@pytest .fixture (scope = 'session' )
260- def master_id (salt_master_id_counter ):
261- '''
262- Returns the master id
263- '''
264- return DEFAULT_MASTER_ID + '-{0}' .format (salt_master_id_counter ())
282+ def session_salt_api_factory (session_master_factory ):
283+ return session_master_factory .salt_api_daemon ()
265284
266285
267286@pytest .fixture (scope = 'session' )
268- def minion_id (salt_minion_id_counter ):
269- '''
270- Returns the minion id
271- '''
272- return DEFAULT_MINION_ID + '-{0}' .format (salt_minion_id_counter ())
273-
274-
275- @pytest .fixture (scope = 'session' )
276- def session_salt_api (request ,
277- session_salt_minion ,
278- session_master_id ,
279- session_master_config ,
280- session_salt_api_before_start , # pylint: disable=unused-argument
281- session_api_log_prefix ,
282- cli_api_script_name ,
283- log_server ,
284- _cli_bin_dir ,
285- session_conf_dir ):
286- '''
287- Returns a running salt-api
288- '''
289- return start_daemon (request ,
290- daemon_name = 'salt-api' ,
291- daemon_id = session_master_id ,
292- daemon_log_prefix = session_api_log_prefix ,
293- daemon_cli_script_name = cli_api_script_name ,
294- daemon_config = session_master_config ,
295- daemon_config_dir = session_conf_dir ,
296- daemon_class = SaltApi ,
297- bin_dir_path = _cli_bin_dir ,
298- start_timeout = 30 )
299-
300-
301- @pytest .fixture (scope = 'session' )
302- def session_sshd_config_lines (session_sshd_port ):
303- '''
304- Return a list of lines which will make the sshd_config file
305- '''
306- return [
307- 'Port {0}' .format (session_sshd_port ),
308- 'ListenAddress 127.0.0.1' ,
309- 'Protocol 2' ,
310- 'UsePrivilegeSeparation yes' ,
311- '# Turn strict modes off so that we can operate in /tmp' ,
312- 'StrictModes no' ,
313- '# Logging' ,
314- 'SyslogFacility AUTH' ,
315- 'LogLevel INFO' ,
316- '# Authentication:' ,
317- 'LoginGraceTime 120' ,
318- 'PermitRootLogin without-password' ,
319- 'StrictModes yes' ,
320- 'PubkeyAuthentication yes' ,
321- '#AuthorizedKeysFile %h/.ssh/authorized_keys' ,
322- '#AuthorizedKeysFile key_test.pub' ,
323- '# Don\' t read the user\' s ~/.rhosts and ~/.shosts files' ,
324- 'IgnoreRhosts yes' ,
325- '# similar for protocol version 2' ,
326- 'HostbasedAuthentication no' ,
327- '#IgnoreUserKnownHosts yes' ,
328- '# To enable empty passwords, change to yes (NOT RECOMMENDED)' ,
329- 'PermitEmptyPasswords no' ,
330- '# Change to yes to enable challenge-response passwords (beware issues with' ,
331- '# some PAM modules and threads)' ,
332- 'ChallengeResponseAuthentication no' ,
333- '# Change to no to disable tunnelled clear text passwords' ,
334- 'PasswordAuthentication no' ,
335- 'X11Forwarding no' ,
336- 'X11DisplayOffset 10' ,
337- 'PrintMotd no' ,
338- 'PrintLastLog yes' ,
339- 'TCPKeepAlive yes' ,
340- '#UseLogin no' ,
341- 'AcceptEnv LANG LC_*' ,
342- 'Subsystem sftp /usr/lib/openssh/sftp-server' ,
343- '#UsePAM yes' ,
344- ]
287+ def session_salt_api (session_master , session_salt_api_factory ):
288+ assert session_master .is_running ()
289+ with session_salt_api_factory .started ():
290+ yield session_salt_api_factory
345291
346292
347293def pytest_addoption (parser ):
0 commit comments