=============== Sultan Examples =============== This tutorial will go through various examples to help in better understanding how to use Sultan. Each example will build on the lessons learned from the previous examples. WARNING * WARNING * WARNING --------------------------- When you're using Sultan, you are running commands directly on your local shell, so please, do not run untested and untrusted code. You are taking the risk if you are running untrusted code. Sultan runs *POpen* with *shell=True*, and according to Python documentation, this can be a security hazard if combined with untrusted input. More information can be found here: * Python 2: https://docs.python.org/2/library/subprocess.html#frequently-used-arguments * Python 3: https://docs.python.org/3/library/subprocess.html#frequently-used-arguments Example 1: Getting Started -------------------------- We typically use `yum` or `apt-get` to install a package on our system. This example installs a package on our system using Sultan. Here is how to get started:: from sultan.api import Sultan s = Sultan() s.yum("install", "-y", "tree").run() Sultan allows multiple syntaxes depending on what your first command is. Suppose you want to not use separate tokens, and instead you want to use one string, you can write the above example as such:: from sultan.api import Sultan s = Sultan() s.yum("install -y tree").run() Suppose your user is not a root-user, and you want to call to sudo to install the `tree` package. You'd do the following:: from sultan.api import Sultan with Sultan.load(sudo=True) as s: s.yum('install -y tree').run() **NOTE:** For the sake of brevity, this tutorial will now start to assume that `Sultan` has been imported from `sultan.api` and, the variable `s` has been instantiated as an instance of `Sultan` (`s = Sultan()`). This will change in situations where the documentation requires a different usage. Example 2: Sultan with Context Management ----------------------------------------- There are times when we want to manage the context of where Sultan executes your code. To aid with this, we use Sultan in Context Management mode. Suppose we want to cat out the contents of `/etc/hosts`, we'd do the following:: with Sultan.load(cwd="/etc") as s: s.cat("hosts").run() Example 3: Compounding with And (&&) and Or (||) ------------------------------------------------ There are times when we need multiple commands to run at once. We use the `and_()` command to get through this. Here is an example:: # runs: 'cd /tmp && touch foobar.txt' with Sultan.load() as s: s.cd("/tmp").and_().touch("foobar.txt").run() There are also times that we want to run 2 commands, but run the 2nd command even if the first command fails. For this, you will need to use the `or_()` command. Here is an example:: # runs: 'mkdir /tmp || mkdir /bar' with Sultan.load() as s: s.mkdir('/tmp').or_().mkdir('/bar').run() Example 4: Redirecting with Pipes (|) ------------------------------------- In Bash, we use the pipe `|` operator to redirect the output of the call to a command to another command. We do this in Sultan with the `pipe` command. Here is an example:: # runs: 'ls -l | sed -e "s/[aeio]/u/g"' with Sultan.load() as s: s.ls('-l').pipe().sed('-e', '"s/[aeio]/u/g"').run() Example 5: Redirecting Output to File ------------------------------------- In Bash, we often want to redirect the output of a command to file. Whether the output is in `stdout` or `stderr`, we can redirect it to a file with Sultan. Here is an example:: # runs: 'cat /etc/hosts > ~/hosts' with Sultan.load() as s: s.cat("/etc/hosts").redirect( "~/hosts", append=False, stdout=True, stderr=False).run() In the example above, we redirected the output of `/etc/hosts` to `~/hosts`. We only outputted the `stdout`, and didn't append to the file if it existed. Feel free to customize this method as it fits your needs. Example 6: Read from Standard Input ----------------------------------- Python has the `raw_input` built-in to read from standard input. Sultan's API wraps around `raw_input` to ask the user for their input from the command line and returns the value. Here is the example:: name = s.stdin("What is your name?") print "Hello %s" % name Example 7: Running as Another User ---------------------------------- Sultan can run commands as another user. You need to enable `sudo` mode to do this. Here is an example:: # runs: sudo su - hodor -c 'cd /home/hodor && ls -lah .;' with Sultan.load(sudo=True, user='hodor', cwd='/home/hodor') as s: sultan.ls('-lah', '.').run() Example 8: Running as Root -------------------------- Sultan can run commands as the `root` user. You need to only enable `sudo` mode to do this. Here is an example:: # runs: sudo su - root -c 'ls -lah /root;' with Sultan.load(sudo=True) as sultan: sultan.ls('-lah', '/root').run() Example 9: Disable Logging -------------------------- If you need to disable logging all together, simply add set 'logging' to False while loading Sultan with Context. Here is an example:: # runs without logging with Sultan.load(logging=False) as sultan: sultan.ls('-lah', '/tmp').run() Example 10: Commands with Hyphones (i.e.: apt-get) -------------------------------------------------- There are commands that are available in the shell that use hyphens which conflict with the function naming conventions of Python, for example **apt-get**. To get around this, use double underscores (__). Here is an example:: with Sultan.load(sudo=True) as sultan: sultan.apt__get('install', 'httpd').run() which runs:: sudo apt-get install httpd; Example 11: Sourcing a File before Running a Command ---------------------------------------------------- This is rare, but there are times that we would like to source a file before running a command. We can manually do this with the Bash And Operator (&&) but Sultan has the ability to do this automatically for you. Here is an example:: with Sultan.load( cwd='/home/davydany/projects/sultan', src='/home/davydany/.virtualenv/sultan/bin/activate') as s: s.pip('install', '-r', 'requirements.txt').run() which runs:: source /home/davydany/.virtualenv/sultan/bin/activate && cd /home/davydany/projects/sultan && pip install -r requirements.txt; Example 12: Results from a Command ---------------------------------- When you run a command, your shell gives back results in stdout and stderr. Sultan returns a Result object which has **stdout**, **stderr**, **traceback** and **rc** attributes. Here is an example that shows how to get the results of a command:: with Sultan.load() as s: result = s.yum('install', '-y', 'postgresql').run() result.stdout # the stdout result.stderr # the stderr result.traceback # the traceback result.rc # the return code **stdout** and **stderr** returns a list, where each element is a line from **stdout** and **stderr**; **rc** is an integer. Most times, you don't need to access the results of a command, but there are times that you need to do so. For that, the **Result** object will be how you access it. Example 13: Streaming Results from a Command ---------------------------------- Here is an example that shows how to get real-time output from a command:: with Sultan.load() as s: result = s.yum('install', '-y', 'postgresql').run(streaming=True) while True: # if full output is needed, read the pipes one last time # after `is_complete == True` to avoid a race condition complete = result.is_complete for line in result.stdout: print(line) for line in result.stderr: print(line) if complete: break time.sleep(1) Example 14: Custom Executable ---------------------------------- By default python's `subprocess ` executes the program through **/bin/sh** on POSIX systems. In the rare circumstances when that's not desired, you can change it with the 'executable' argument while loading Sultan with Context. Here is an example:: Here is an example that shows how to get the results of a command:: with Sultan.load(executable='/bin/bash') as sultan_bash: result = sultan_bash.ps('-p', '$$', '-ocomm=') assert result == 'bash' with Sultan.load(executable='/bin/dash') as sultan_other: result = sultan_other.ps('-p', '$$', '-ocomm=') assert result == 'dash'