Skip to content

Commit 14ae0c9

Browse files
authored
executer: support run with sudo. (#140)
* executer: support run with sudo. exec = host.executor(sudo=True) * Update README * Fix tests * test to cover sudo * Fix test * Fix tests * Fix tests
1 parent 0827dd7 commit 14ae0c9

File tree

5 files changed

+139
-43
lines changed

5 files changed

+139
-43
lines changed

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ that means SSH server must be running there already.
2525
host.executor_factory = rrmngmnt.ssh.RemoteExecutorFactory(use_pkey=True)
2626
2727
exec = h.executor()
28+
# Run with sudo
29+
exec = h.executor(sudo=True)
30+
2831
print exec.run_cmd(['echo', 'Hello World'])
2932
3033

rrmngmnt/host.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def __init__(self, ip, service_provider=None):
7373
self._package_manager = PackageManagerProxy(self)
7474
self.os = OperatingSystem(self)
7575
self.add() # adding host to inventory
76+
self.sudo = False
7677

7778
def __str__(self):
7879
return "Host(%s)" % self.ip
@@ -210,7 +211,7 @@ def package_manager(self):
210211
def power_manager(self):
211212
return self.get_power_manager()
212213

213-
def executor(self, user=None, pkey=False):
214+
def executor(self, user=None, pkey=False, sudo=False):
214215
"""
215216
Gives you executor to allowing command execution
216217
@@ -219,6 +220,9 @@ def executor(self, user=None, pkey=False):
219220
user. when it is None, the default executor user is used,
220221
see set_executor_user method for more info.
221222
"""
223+
if sudo:
224+
self.sudo = True
225+
222226
if user is None:
223227
user = self.executor_user
224228
if pkey:
@@ -229,7 +233,7 @@ def executor(self, user=None, pkey=False):
229233
ef = copy.copy(ssh.RemoteExecutorFactory)
230234
ef.use_pkey = pkey
231235
return ef(self.ip, user)
232-
return self.executor_factory.build(self, user)
236+
return self.executor_factory.build(self, user, sudo=self.sudo)
233237

234238
def run_command(
235239
self, command, input_=None, tcp_timeout=None, io_timeout=None,

rrmngmnt/ssh.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ def command(self, cmd):
122122
return RemoteExecutor.Command(cmd, self)
123123

124124
def run_cmd(self, cmd, input_=None, timeout=None):
125+
if self._executor.sudo:
126+
cmd.insert(0, "sudo")
127+
125128
cmd = self.command(cmd)
126129
return cmd.run(input_, timeout)
127130

@@ -206,18 +209,20 @@ def run(self, input_, timeout=None, get_pty=False):
206209
self.err = normalize_string(err.read())
207210
return self.rc, self.out, self.err
208211

209-
def __init__(self, user, address, use_pkey=False, port=22):
212+
def __init__(self, user, address, use_pkey=False, port=22, sudo=False):
210213
"""
211214
Args:
212215
use_pkey (bool): Use ssh private key in the connection
213216
user (instance of User): User
214217
address (str): Ip / hostname
215218
port (int): Port to connect
219+
sudo (bool): Use sudo to execute command.
216220
"""
217221
super(RemoteExecutor, self).__init__(user)
218222
self.address = address
219223
self.use_pkey = use_pkey
220224
self.port = port
225+
self.sudo = sudo
221226

222227
def session(self, timeout=None):
223228
"""
@@ -306,6 +311,6 @@ def __init__(self, use_pkey=False, port=22):
306311
self.use_pkey = use_pkey
307312
self.port = port
308313

309-
def build(self, host, user):
314+
def build(self, host, user, sudo=False):
310315
return RemoteExecutor(
311-
user, host.ip, use_pkey=self.use_pkey, port=self.port)
316+
user, host.ip, use_pkey=self.use_pkey, port=self.port, sudo=sudo)

tests/common.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def session(self, timeout=None):
117117
return FakeExecutor.Session(self, timeout)
118118

119119
def run_cmd(self, cmd, input_=None, tcp_timeout=None, io_timeout=None):
120+
cmd = list(cmd)
120121
with self.session(tcp_timeout) as session:
121122
return session.run_cmd(cmd, input_, io_timeout)
122123

@@ -126,8 +127,9 @@ def __init__(self, cmd_to_data, files_content):
126127
self.cmd_to_data = cmd_to_data.copy()
127128
self.files_content = files_content
128129

129-
def build(self, host, user):
130+
def build(self, host, user, sudo):
130131
fe = FakeExecutor(user, host.ip)
131132
fe.cmd_to_data = self.cmd_to_data.copy()
132133
fe.files_content = self.files_content
134+
fe.sudo = sudo
133135
return fe

tests/test_package_manager.py

Lines changed: 119 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# -*- coding: utf-8 -*-
2+
import pytest
3+
24
from rrmngmnt import Host, User
35
from .common import FakeExecutorFactory
46
import rrmngmnt.package_manager as pm
@@ -8,19 +10,41 @@
810
host_executor_factory = Host.executor_factory
911

1012

11-
def extend_cmd(cmd, *args):
13+
def _extend_cmd(cmd, sudo, *args):
1214
cmd = list(cmd)
15+
if sudo:
16+
cmd.insert(0, "sudo")
17+
1318
cmd.extend(args)
1419
return list2cmdline(cmd)
1520

1621

17-
def join_cmds(*args):
22+
def extend_cmd(cmd, *args):
23+
return _extend_cmd(cmd, False, *args)
24+
25+
26+
def sudo_extend_cmd(cmd, *args):
27+
return _extend_cmd(cmd, True, *args)
28+
29+
30+
def _join_cmd(sudo, *args):
1831
cmd = []
32+
if sudo:
33+
cmd.append("sudo")
34+
1935
for _cmd in args:
2036
cmd += list(_cmd)
2137
return list2cmdline(cmd)
2238

2339

40+
def join_cmds(*args):
41+
return _join_cmd(False, *args)
42+
43+
44+
def sudo_join_cmds(*args):
45+
return _join_cmd(True, *args)
46+
47+
2448
def teardown_module():
2549
Host.executor_factory = host_executor_factory
2650

@@ -29,6 +53,7 @@ def fake_cmd_data(cmd_to_data, files=None):
2953
Host.executor_factory = FakeExecutorFactory(cmd_to_data, files)
3054

3155

56+
@pytest.mark.parametrize("sudo", [False, True])
3257
class BasePackageManager(object):
3358
__test__ = False
3459

@@ -43,7 +68,7 @@ class BasePackageManager(object):
4368
'not_installed': 'p-not-installed',
4469
'non_existing': 'p-non-existing',
4570
'list': 'p-installed-1\np-installed-2\np-installed-3\n',
46-
'pattern': 'p-installed-(1|2)'
71+
'pattern': 'p-installed-(1|2)',
4772
}
4873
rc1 = (1, '', '')
4974
rc0 = (0, '', '')
@@ -63,7 +88,14 @@ def setup_class(cls):
6388
grep_xargs_command,
6489
cls.managers[cls.manager].remove_command_d
6590
)
91+
sudo_remove_pattern_cmd = sudo_join_cmds(
92+
cls.managers[cls.manager].list_command_d,
93+
grep_xargs_command,
94+
cls.managers[cls.manager].remove_command_d
95+
)
6696
cls.data.update({
97+
remove_pattern_cmd: cls.rc0,
98+
sudo_remove_pattern_cmd: cls.rc0,
6799
extend_cmd(
68100
cls.managers[cls.manager].exist_command_d,
69101
cls.packages['installed_1']
@@ -101,16 +133,63 @@ def setup_class(cls):
101133
cls.managers[cls.manager].remove_command_d,
102134
cls.packages['installed_2']
103135
): cls.rc0,
104-
remove_pattern_cmd: cls.rc0,
105136
extend_cmd(
106137
cls.managers[cls.manager].update_command_d,
107138
cls.packages['installed_1']
108139
): cls.rc0,
109-
list2cmdline(
140+
extend_cmd(
141+
cls.managers[cls.manager].update_command_d,
142+
): cls.rc0,
143+
extend_cmd(
144+
cls.managers[cls.manager].list_command_d,
145+
): (0, cls.packages['list'], ''),
146+
# For sudo tests.
147+
sudo_extend_cmd(
148+
cls.managers[cls.manager].exist_command_d,
149+
cls.packages['installed_1']
150+
): cls.rc0,
151+
sudo_extend_cmd(
152+
cls.managers[cls.manager].exist_command_d,
153+
cls.packages['installed_2']
154+
): cls.rc0,
155+
sudo_extend_cmd(
156+
cls.managers[cls.manager].exist_command_d,
157+
cls.packages['installed_3']
158+
): cls.rc0,
159+
sudo_extend_cmd(
160+
cls.managers[cls.manager].exist_command_d,
161+
cls.packages['not_installed']
162+
): cls.rc1,
163+
sudo_extend_cmd(
164+
cls.managers[cls.manager].install_command_d,
165+
cls.packages['not_installed']
166+
): cls.rc0,
167+
# for negative install test
168+
sudo_extend_cmd(
169+
cls.managers[cls.manager].exist_command_d,
170+
cls.packages['non_existing']
171+
): cls.rc1,
172+
sudo_extend_cmd(
173+
cls.managers[cls.manager].install_command_d,
174+
cls.packages['non_existing']
175+
): cls.rc1,
176+
sudo_extend_cmd(
177+
cls.managers[cls.manager].remove_command_d,
178+
cls.packages['installed_1']
179+
): cls.rc0,
180+
sudo_extend_cmd(
181+
cls.managers[cls.manager].remove_command_d,
182+
cls.packages['installed_2']
183+
): cls.rc0,
184+
sudo_extend_cmd(
185+
cls.managers[cls.manager].update_command_d,
186+
cls.packages['installed_1']
187+
): cls.rc0,
188+
sudo_extend_cmd(
110189
cls.managers[cls.manager].update_command_d,
111190
): cls.rc0,
112-
list2cmdline(
113-
cls.managers[cls.manager].list_command_d
191+
sudo_extend_cmd(
192+
cls.managers[cls.manager].list_command_d,
114193
): (0, cls.packages['list'], ''),
115194
})
116195
fake_cmd_data(cls.data)
@@ -121,55 +200,58 @@ def set_base_data(cls):
121200
rc = cls.rc1
122201
if manager_ == cls.manager:
123202
rc = cls.rc0
124-
cls.data.update({
125-
list2cmdline(['which', manager_]): rc,
126-
})
127203

128-
def get_host(self, ip='1.1.1.1'):
204+
for val in (['which'], ['sudo', 'which']):
205+
cls.data.update({
206+
list2cmdline(val + [manager_]): rc,
207+
})
208+
209+
def get_host(self, ip='1.1.1.1', sudo=False):
129210
h = Host(ip)
130211
h.add_user(User('root', '11111'))
212+
h.executor(sudo=sudo)
131213
return h
132214

133-
def get_pm(self):
134-
return self.get_host().package_manager
215+
def get_pm(self, sudo=False):
216+
return self.get_host(sudo=sudo).package_manager
135217

136-
def test_info(self):
137-
assert not self.get_pm().info(self.packages['installed_1'])
218+
def test_info(self, sudo):
219+
assert not self.get_pm(sudo).info(self.packages['installed_1'])
138220

139-
def test_info_negative(self):
140-
assert not self.get_pm().info(self.packages['not_installed'])
221+
def test_info_negative(self, sudo):
222+
assert not self.get_pm(sudo).info(self.packages['not_installed'])
141223

142-
def test_exist(self):
143-
assert self.get_pm().exist(self.packages['installed_1'])
224+
def test_exist(self, sudo):
225+
assert self.get_pm(sudo).exist(self.packages['installed_1'])
144226

145-
def test_exist_negative(self):
146-
assert not self.get_pm().exist(self.packages['not_installed'])
227+
def test_exist_negative(self, sudo):
228+
assert not self.get_pm(sudo).exist(self.packages['not_installed'])
147229

148-
def test_install_installed(self):
149-
assert self.get_pm().install(self.packages['installed_1'])
230+
def test_install_installed(self, sudo):
231+
assert self.get_pm(sudo).install(self.packages['installed_1'])
150232

151-
def test_install_new(self):
152-
assert self.get_pm().install(self.packages['not_installed'])
233+
def test_install_new(self, sudo):
234+
assert self.get_pm(sudo).install(self.packages['not_installed'])
153235

154-
def test_install_negative(self):
155-
assert not self.get_pm().install(self.packages['non_existing'])
236+
def test_install_negative(self, sudo):
237+
assert not self.get_pm(sudo).install(self.packages['non_existing'])
156238

157-
def test_remove(self):
158-
assert self.get_pm().remove(self.packages['installed_1'])
239+
def test_remove(self, sudo):
240+
assert self.get_pm(sudo).remove(self.packages['installed_1'])
159241

160-
def test_remove_pattern(self):
242+
def test_remove_pattern(self, sudo):
161243
assert (
162-
self.get_pm().remove(self.packages['pattern'], pattern=True)
244+
self.get_pm(sudo).remove(self.packages['pattern'], pattern=True)
163245
)
164246

165-
def test_update(self):
166-
assert self.get_pm().update([self.packages['installed_1']])
247+
def test_update(self, sudo):
248+
assert self.get_pm(sudo).update([self.packages['installed_1']])
167249

168-
def test_update_all(self):
169-
assert self.get_pm().update()
250+
def test_update_all(self, sudo):
251+
assert self.get_pm(sudo).update()
170252

171-
def test_list(self):
172-
assert self.get_pm().list_() == self.packages['list'].split('\n')
253+
def test_list(self, sudo):
254+
assert self.get_pm(sudo).list_() == self.packages['list'].split('\n')
173255

174256

175257
class TestYumPM(BasePackageManager):

0 commit comments

Comments
 (0)