I'm pretty new to python and fabric and I am trying to do a simple code where I can get the output on two hosts that uses sudo, although I keep getting an error.... Can anyone help me out with what I might be missing ?
My code:
from fabric.api import *
from getpass import getpass
from fabric.decorators import runs_once
env.hosts = ['host1','host2']
env.port = '22'
env.user = 'username'
env.password="password"
def sudo_dsmc(cmd):
sudo("-l")
When I run: fab sudo_dsmc:"-1" :
MacBookPRO:PYTHON username$ fab sudo_dsmc:"-l"
[host1] Executing task 'sudo_dsmc'
[host1] sudo: -l
[host1] out: sudo password:
[host1] out: Sorry, user username is not allowed to execute '/bin/bash -l -c - l' as root on host1.
[host1] out:
Fatal error: sudo() received nonzero return code 1 while executing!
Requested: -l
Executed: sudo -S -p 'sudo password:' /bin/bash -l -c "-l"
Aborting.
Disconnecting from host1... done.
Although I can run the apt-get update with my below function fine without any errors:
def sudo_command(cmd):
sudo("apt-get update")
# run like: fab sudo_command:"apt-get-update"
It looks like your sudoers file is preventing you from running that command as sudo. Check your /etc/sudoers file and read the sudo documentation.
Also "-l" isn't a valid command. sudo takes -l as an optional flag (which lists commands allowed by the user). But Fabric's sudo appears to be taking unknown strings and routing them through /bin/bash instead of using them directly as sudo command parameters.
Related
My request is simple:
ssh to a remote server with user0
switch user to user1 using: 'sudo su user1'
list all items in current folder
My expected code:
def startRedis():
run('sudo su - user1')
print(run('ls'))
However, it ends with out: user1#server:~$
And waiting for my interactive command forever, never executing the second line. It seems sudo su opened a new shell.
Can anyone help solving this simple task?
You can set sudo_user property in env. this way fabric will switch user to the desired user.
Official doc: http://docs.fabfile.org/
Password for switching user can be specified in the env. itself to avoid getting a prompt when the method is invoked.
fabfile.py
from fabric.api import env, sudo
env.sudo_user='user1'
env.password = '***'
def list_items():
sudo('ls')
Run below command & specify the hosts after -H
fab -H host1 list_items
I want to do the following thing :
if condition:
cmd="ssh machine1 && sudo su - && df -h PathThatRequiresRootPriv | grep ..."
proc = subprocess.Popen(cmd,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,env=os.environ)
(out_space,err) = proc.communicate()
if err:
print err
log.warning('%s',err)
exit(1)
But i am clearly missing something because the program doesn't do anything.
Thank you for your help in advance.
You are building commands in the form cmd1 && cmd2 && cmd3. The 3 commands are executed one at a time on the local machine unless one of them return false. And from your title it is not what you expect... And the construct sudo su - will act the same and expect its commands from its own standard input and not from the next command.
The correct way here would be:
if condition:
loc_cmd="ssh machine1"
remcmd="sudo -i 'df -h PathThatRequiresRootPriv | grep ...'"
proc = subprocess.Popen(loc_cmd,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,env=os.environ)
(out_space,err) = proc.communicate(rem_cmd)
Say differently, you should only execute ssh on the local machine, pass sudo -i to the remote as a request to execute a command after simulating an initial login, and finally pass the pipeline as the parameter to sudo.
You must look fabric - if you want use python
or ansible
in fabric you can do different things on remote server like this:
from fabric.api import *
def check_disk_space(username, passw='none'):
host = '%s#%s' % (env.user, env.host)
env.passwords[host] = 'rootPass'
# run from user
run('df -h')
# run from sudo
sudo('df -h')
host='anyuser#10.10.10.101'
execute(check_disk_space, hosts=[host], username='anyuser', passw='')
Both support 'become' methods for execute remote commands through sudo
I'm wondering what is the difference between the function sudo() and the function run('sudo -u user smth')
On the doc there is :
sudo is identical in every way to run, except that it will always wrap
the given command in a call to the sudo program to provide superuser
privileges.
But a few time, sudo('cmd') prompt me a password, but if I switch with run('sudo cmd') it works without prompting me anything. Is there anything that change between the two ? (I remember someone on SO saying that sudo and run(sudo cmd) are not for the same use, but I can't find it back)
I found these two difference.
1: Fabric maintains an in-memory password
2: sudo accepts additional user and group arguments
First, fabric would get password from cache when using sudo(), then you do not need to enter password. But if you use run('sudo cmd'), you need to enter password for each 'sudo cmd'.
Second, if you want to execute a command not under root but other user group like www, you just need to set env.sudo_user = 'www' or sudo('cmd', user='www'). The first would execute each sudo() under www, the second would execute this single cmd under www. But you need to edit to run("sudo -u 'www' cmd") when use run() command.
from fabric.api import sudo, run, env
env.hosts = ['host_ip',]
env.user = 'user_name'
env.sudo_user = 'sudo_user'
def test_1():
run('sudo pwd')
def test_2():
sudo('pwd')
$ fab -I --show=debug test_1 test_2
Initial value for env.password: # enter password
Commands to run: test_1, test_2
Parallel tasks now using pool size of 1
[ip_address] Executing task 'test_1'
[ip_address] run: /bin/bash -l -c "sudo pwd"
[ip_address] out: [sudo] password for billy: # needs to enter password here
[ip_address] out: /home/billy
[ip_address] out:
Parallel tasks now using pool size of 1
[ip_address] Executing task 'test_2'
[ip_address] sudo: sudo -S -p 'sudo password:' -u "root" /bin/bash -l -c "pwd"
[ip_address] out: sudo password: # only prompt, do not need enter password
[ip_address] out: /home/billy
[ip_address] out:
Done.
Disconnecting from ip_address... done.
Since Fabric 2, you can invoke sudo via run(), which will prompt for the password unless you use the auto-responder, details here. Note that the sudo command usually caches the password remotely, so next invocations of sudo during the same connection will not prompt for password.
However, the Fabric sudo() helper makes using sudo much easier, details here. You need to ensure that the sudo.password configuration value is filled in (via config object, config file, environment variable, or --prompt-for-sudo-password). Here's how I do it with the keyring module:
from fabric import task
import keyring
#task
def restart_apache(connection):
# set the password with keyring.set_password('some-host', 'some-user', 'passwd')
connection.config.sudo.password = keyring.get_password(connection.host, 'some-user')
connection.sudo('service apache2 restart')
I have the following configuration on my ~/.ssh/config
Host death-star
HostName deathstar.empire.com
User vader
IdentityFile ~/.ssh/death_id_rsa
And the following fabfile
from fabric.api import env, task
env.use_ssh_config = True
#task
def destroy_rebels():
run("echo Alderaan has been destroyed")
I'm calling the task like this:
$ fab --host death-star destroy_rebels
This is the output I get:
[death-star] Executing task 'destroy_rebels'
[death-star] run: echo Alderaan has been destroyed
Fatal error: run() received nonzero return code -1 while executing!
Requested: echo Alderaan has been destroyed
Executed: /bin/bash -l -c "echo Alderaan has been destroyed"
Aborting.
Disconnecting from vader#deathstar.empire.com... done.
I'm pretty sure the ssh config is correct since I can ssh death-star with no problems.
Also, when I specify the hostname and use the default key for user root instead of using the ssh config file, it works:
$ fab --user root --host deathstar.empire.com destroy_rebels
Any ideas why this happens?
EDIT: This is my fabric version
$ fab --version
Fabric 1.4.1
ssh (library) 1.7.13
EDIT 2:
I've rewritten bits of the original post. I realized that the root (using the default key id_rsa always works, even using .ssh/config, if I add a new entry:
Host root-death-star
HostName deathstar.empire.com
User root
IdentityFile ~/.ssh/id_rsa
$ fab --host root-death-star destroy_rebels # this works
But using the non-root user vader, with its own key death_id_rsa, it doesnt. SSHing to the server is still working though, as root and as vader.
From that output it's nothing to do with the ssh connection but what the return code from the echo being run is returning. As to what would make it the -1, from your additional notes, it could be that something custom in your zsh or zshrc is throwing a bad return code and it's bubbling up.
I am having some problems with commands that have sudo using paramiko
f.ex sudo apt-get update
here is my code:
try:
import paramiko
except:
try:
import paramiko
except:
print "There was an error with the paramiko module"
cmd = "sudo apt-get update"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect("ip",username="lexel",password="password")
print "succesfully conected"
except:
print "There was an Error conecting"
stdin, stdout, stderr = ssh.exec_command(cmd)
stdin.write('password\n')
stdin.flush()
print stderr.readlines()
print stdout.readlines()
This is a quick code. I know that I need to add sys.exit(1) and all that but this is just to demostration
I used this for reference:
Jessenoller.com
Fabric has sudo command. It uses Paramico for ssh connections. Your code would be:
#fabfile.py
from fabric.api import run, sudo
def update():
"""Run `sudo apt-get update`.
lorem ipsum
"""
sudo("apt-get update")
def hostname():
"""Run `hostname`"""
run("hostname")
Usage:
$ fab update -H example.com
[example.com] Executing task 'update'
[example.com] sudo: apt-get update
...snip...
[example.com] out: Reading package lists... Done
[example.com] out:
Done.
Disconnecting from example.com... done.
$ fab --display update
Displaying detailed information for task 'update':
Run `sudo apt-get update`.
lorem ipsum
$ fab --list
Available commands:
hostname Run `hostname`
update Run `sudo apt-get update`.
From the docs:
In addition to use via the fab tool, Fabric’s components may be
imported into other Python code, providing a Pythonic interface to the
SSH protocol suite at a higher level than that provided by e.g.
Paramiko (which Fabric itself leverages.)
I was having the same problem, and I fix with this:
In your sudo file, just add this:
Defaults:your_username !requiretty
or remove Defaults requiretty.
Also make sure your user have permission to run the command with sudo.