Recent Entries 10
- pattern minor 112d agoLog Retrieval ScriptI wrote a simple script to retrieve the logs from my website, and place them in a subdirectory called `logs`. It fetches the logs using sftp. I would like help with the error handling. I'm sure that there are errors I did not see, and I would like to make it so that it fails gracefully. ``` #!/bin/bash # gets the logs # Location to place downloaded logs PlaceLogs=./logs # ssh connection to sftp files from SSHLocation=hjsblog # Location and pattern of logs GetLogs=../logs/access* ####################################### ####################################### CWD=$(pwd) # move to get location if [ "$(ls -A $PlaceLogs)" ] then echo $PlaceLogs is not empty return fi mkdir -p $PlaceLogs cd $PlaceLogs # perform the get operation sftp $SSHLocation << EOF cd $(dirname $GetLogs) get $(basename $GetLogs) EOF # uncompress files bunzip2 *.bz2 # return to script dir cd $CWD ```
- pattern minor 112d agoFetching system info using pythonThe following piece of code does ssh do different servers and fetches the system info and display it to the user: ``` import paramiko #list variables : ["IP_ADDR", "USERNAME", "PASSWD", "ROOT_PASSWD"] ip_list = [ ["192.168.11.44", "root", "****", "****"], ["192.168.11.8", "root", "****", "****"], ["192.168.11.30", "root", "****", "****"], ["192.168.11.6", "****", "****", "****"] ] os_check_list = ["DISTRIB_DESCRIPTION"] hard_disks = [ 'sda', 'sdb', 'sdc', 'sdd', 'sde', 'sdf', 'sdg', 'sdh', 'sdi', 'sdj', 'sdk', 'sdl', 'sdm', 'sdn', 'sdo', 'sdp', 'sdq', 'sdr', 'sds' ] os = None ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) for ip in ip_list: ssh.connect(ip[0], username = ip[1], password = ip[2]) print("\n \n ************************************************************ \ \n IP ADDR = {} SYSTEM INFO \ \n ******************************************************************". format(ip[0])) stdin, stdout, stderr = ssh.exec_command("cat /etc/*release") stdin.write(ip[3]+"\n") for line in stdout.readlines(): if any(x in line for x in os_check_list): os_dist = line.split("=") os = os_dist[1] print(" Operating System is {}" .format(os)) if not os: stdin, stdout, stderr = ssh.exec_command("cat /etc/system-release") for line in stdout.readlines(): os = line print(" Operating System is {}" .format(os)) os = None stdin, stdout, stderr = ssh.exec_command("sudo -k udisksctl status", get_pty = True) stdin.write(ip[3]+"\n") for line in stdout.readlines(): if any(x in line for x in hard_disks): print(line) elif "command not found" in line: print("udisksctl not installed on target server") stdin, stdout, stderr = ssh.exec_command("sudo
- pattern minor 112d agoBasic automation of SSH tasks in a restricted environmentI'm trying to implement a simple automation solution in a restricted environment. I have actually implemented something but it took a bit longer than I wanted. I want to improve the solution and I'll probably have to extend it in the future so I'm asking for code review - my boss will probably be happier if I can deliver things faster! :) Anyway, the current setup: Python 2.6 - installed as a portable package since I don't have administrative rights on my machine. Fabric - simplest (only Paramiko, pyasn1 and cyrptography as pypi dependencies; a strong bonus in such a restrictive environment) and most robust solution I could find for running on Python 2.6 Git Bash - for smaller scripts that launch Fabric. - ./launcher - as the name says, the entry point for the tool, a shell script - ./commands/ - shell scripts that are just parametrized launches of Fabric - ./configurations/ - shell scripts that contain just environment variables split per environment and application - ./bash/completion - bash completion script for use with the launcher And the actual code, starting with the launcher: ./launcher ``` #!/bin/bash set -o errexit # set -e set -o nounset # set -u set -o pipefail script_usage="Script usage: ${0} ." if [[ -z "${1-}" ]] then echo "Environment name parameter not provided. $script_usage" exit 1 fi if [[ -z "${2-}" ]] then echo "Application parameter not provided. $script_usage" exit 1 fi if [[ -z "${3-}" ]] then echo "Command parameter not provided. $script_usage" exit 1 fi export FAB_ENVIRONMENT="${1}" cd fabfile python -c "from common import *; environment_prompt(\"${FAB_ENVIRONMENT}\")"; cd .. source "configurations/${1}/${2}" ./commands/"${3}" ``` ./fabfile/common.py ``` ##- Imports. from fabric.api import * from getpass import getpass import os #-## ##- Environment, user, password. def get_base_info(): try: environment = os.environ['FAB_ENVIRONMENT'] except KeyError: abort('FAB_ENVIRONMENT
- pattern minor 112d agoSFTP Ruby script for downloading files from serverI have written this Ruby script to download some file from server using SFTP. Help me improve this one. Find the original script at this link ``` #This script is used to download file from the server to your local machine #The implementation is based on pure Ruby implementation of SFTP using gem Net SFTP #To install this on your local machine please run the following command in your terminal 'gem install net-sftp' #Author : Ashish Wadekar #Date : 18 December 2016 #This is the gem / library required for the SFTP connection management require 'net/sftp' #The host address HOST = "www.example.com" #User for connection USER = "admin" #The location of the authentication key in pem format SERVER_KEY_LOC = "/location/of/serverauthenticationkey.pem" #The location on server where DB backups are done SERVER_BACKUP = "/location/of/file/on/server" #The location on local machine where the db has to be downloaded LOCAL_BACKUP = "/location/on/local/machine/where/file/needs/to/be/downloaded" #Array to hold the file names for easier sorting files = Array.new #Array to hold the file details for easier sorting files_details = Array.new #Inititalising the connection Net::SFTP.start(HOST, USER, :keys => [SERVER_KEY_LOC]) do |sftp| puts "Connection to Server successful" entries = sftp.dir.entries([SERVER_BACKUP]).sort_by(&:name) #Sorting the files by name as timestamp is used as filename entries.each do |entry| files #{args[0].local}" puts "Perhaps you can sip a coffee till then!" when :get then # args[0] : file metadata # args[1] : byte offset in remote file # args[2] : data that was received STDOUT.write "Downloading complete: #{args[1].to_i/1048576}MB, #{args[1].to_i}bytes of #{download_size} bytes, #{((args[1].to_i / download_size) * 100.0)}% \r" unless args[1].to_i == 0 when :close then # args[0] : file metadata puts "Done! Closing connection to server." when :mkdir then # args[0] : local path name
- pattern moderate 112d agoSend commands over SSH to serverHere's a very small and basic script that sends commands over SSH to another computer on my network: ``` #!/bin/python import sys, os commands = "" for i in sys.argv[1:]: commands += " " + i; if len(sys.argv) <= 1: os.system("sshpass -p VerySecrectPassword ssh pi@172.16.0.141") else: os.system("sshpass -p VerySecrectPassword ssh pi@172.16.0.141" + commands) ``` Am I being very "Pythonic"? Is it better to use a for loop to join all the commands or the join function? ``` commands = " ".join(sys.argv[1:]) ``` Personally, I think the for loop reads better, but that's just my opinion and I'm a newbie. Which is considered the better way to do things? Furthermore: - Are there any other areas in this script that could be improved? - Is it a bad idea to store the password in the script (located at /usr/bin)? Note: This script is stored on a computer where I am the only user (except root).
- pattern minor 112d agoMoving WordPress database and files to new hostI've written a script in an attempt to try to automate moving hosts from old hosts to our new docker containers. All feedback and input appreciated! ``` #!/bin/bash # Generate private public ssh-keys if [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_rsa.pub" ]; then ssh-keygen -b 4096 fi read -p "Enter your ssh host:" ssh_host read -p "Enter your ssh username:" ssh_user read -p "Enter your remote ssh port:" ssh_port # REMOTE SSH if [ -z "$ssh_user" ]; then echo -e "Config: SSH Username missing" echo $ssh_user exit fi if [ -z "$ssh_host" ]; then echo -e "Config: SSH Host is missing" exit fi if [ -z "$ssh_port" ]; then echo -e "Config: SSH Port missing" exit fi ssh-copy-id $ssh_user@$ssh_host -p $ssh_port -i "$HOME/.ssh/id_rsa" &>/dev/null # REMOTE DATABASE read -p "Enter path for wp-config.php:" wp_config_path # INIT db_details="cat $wp_config_path/wp-config.php" scp -P $ssh_port -r $ssh_user@$ssh_host:"$wp_config_path/*" . # Might be dangerous if file contains malicious input in the values? eval $(awk -F "[()']" '/^define\(/{printf "%s='\''%s'\''\n", $3, $5;}' $HOME/.ssh/authorized_keys' ssh_user= ssh_host= ssh_port= DB_USER= DB_PASSWORD= DB_NAME= local_db_name= local_db_password= local_db_user= wp_config_path= echo -e "Exiting" ```
- pattern minor 112d agoFinding all non-empty directories and their files on an SFTP server with ParamikoThe purpose of the following function is to find all non-empty directories, and the files in those non-empty directories. It recursively checks each directory on an SFTP server to see if it has any files, and if it does, adds it to a default dict using the path as the key. The function uses `paramiko.SFTPClient` and `stat`. I am specifically concerned about the performance; it is rather slow. Prereqsuite information - `sftp.listdir_attr` returns a list of `SFTPAttribute`s which represent either files, directories, symlinks, etc., and contain a `st_mode`, which is used to determine if it is a directory or file. This can throw an IOException for example if you don't have permissions to inspect the path. - `stat.S_ISDIR` will inspect the mode to determine if its a directory The function in question: ``` def recursive_ftp(sftp, path='.', files=None): if files is None: files = defaultdict(list) # loop over list of SFTPAttributes (files with modes) for attr in sftp.listdir_attr(path): if stat.S_ISDIR(attr.st_mode): # If the file is a directory, recurse it recursive_ftp(sftp, os.path.join(path,attr.filename), files) else: # if the file is a file, add it to our dict files[path].append(attr.filename) return files ``` Use: ``` import paramiko import stat transport = paramiko.Transport((host, port)) transport.connect(username=username, password=password) sftp = paramiko.SFTPClient.from_transport(transport) files = recursive_ftp(sftp) ``` If we have an SFTP server that looks like this: ``` /foo ----a.csv ----b.csv /bar ----c.csv /baz ``` The function will return a dictionary like so: ``` { './foo': ['a.csv', 'b.csv'], './bar': ['c.csv'] } ```
- pattern moderate 112d agoSSH passing your Public key to all the users on remote hostI've grown tired of typing my password back and forth to all the hosts you connect to, i want to be able to jump to every single user on all the hosts with ease. So i've made this script with a quite messy oneliner at the end of it. The script first reads user input where to connect to. remote_user, remote_host and remote_port. ``` echo "Enter the user you want to connect with (sudo needs to be enabled and installed)" read -e rUser echo "Enter the host you want to connect to" read -e rHost echo "Enter the SSH-port" read -e rPort read -s -p "Enter Password: " password ``` Checks if ssh-key is generated, if not proceeds with ssh-keygen for the user to generate a strong key. ``` if [ ! -d "$HOME/.ssh" ] && [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_rsa.pub" ]; then echo -e "Private / Public keys not generated" echo -e "Generating..." ssh-keygen -b 4096 fi ``` After that we proceed with establishing ssh-connection and creating the authorized_keys file on the remote host. (Annoying 'bug' here you have to enter the password twice, since it doesnt seem possible to read ssh-password from stdin.) ``` cat "$HOME/.ssh/id_rsa.pub" | ssh "$rUser@$rHost" -p $rPort "cat >> ~/.ssh/authorized_keys" ``` Since the script will only be run once per remote host, its acceptable. We continue with the quite messy oneliner. We're establishing an SSH connection, to solve the problem with password over SSH we pass the -S parameter to SUDO that lets us read the password from STDIN. Now our subsequent SUDO calls will work. We proceed and create the .ssh directories for all the users on the system if they dont exist. We create the authorized_keys file for all users and set correct owner, then we append authorized_keys file of the user we connected with. ``` remoteUsers=($(ssh "$rUser@$rHost" -p $remotePort 'echo '"$password"' | sudo -S ls /home/ && for localUser in $(ls /home | grep -v $USER); do sudo mkdir -p /home/$localUser/.ssh && sudo touch /home/
- pattern minor 112d agoKilling a tunnel and establishing a tunnel through SSHI have two functions right now: ``` TUNNEL_COMMAND = "ssh -L 27017:localhost:27017 username@ip -f -N" def kill_tunnel(): p = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE) out, err = p.communicate() for line in out.splitlines(): if TUNNEL_COMMAND in line: pid = int(line.split()[1]) print "killing pid", pid os.kill(pid, signal.SIGKILL) def connect_tunnel(): subprocess.Popen(TUNNEL_COMMAND) ``` `connect_tunnel()` establishes the connection, which I am ok with, but `kill_tunnel()` looks very ugly. Is there a better way to find the PID of a process based off the command?
- pattern minor 112d agoCancel those hung print jobsI've created a program that will list all hung print jobs on a specified server, from there it will load them and strip the jobs down to their `Job ID` then cancel the jobs on that server only. I would like a critique of my work please. - How does this look as an OOP script? - Is there anything I can do differently? - Is calling the `Net::SSH.start` twice really necessary? Source: ``` #!/usr/local/bin/ruby require 'rubygems' require 'net/ssh' require 'etc' class PrintJobs HOST = ARGV[0] USERNAME = Etc.getlogin PASSWORD = nil def scan_for_jobs check_jobs = Net::SSH.start(HOST, USERNAME, :password => PASSWORD) do |ssh| cmd = "prt_jobs" info = ssh.exec!(cmd) if info == nil puts "No print jobs on server #{HOST}" else res = info.split("\n").reject {|line| line.match(/\s+2016\s+/)}.join("\n") puts res print "Process into kill que: " input = STDIN.gets.chomp.upcase if input == "YES" kill_que(check_jobs, res) else exit 1 end end end end def kill_que(check_jobs, res) puts "Loading jobs into kill que.." column = 0 job_ids = res.lines.map { |job| job.split(/\s+/)[0] }.each do |task_id| kill_jobs(task_id) end end def kill_jobs(task_id) execute = Net::SSH.start(HOST, USERNAME, :password => PASSWORD) id_to_strip = task_id.gsub(/\-/," ") column = 1 stripping_id = id_to_strip.lines.map { |task| task.split(/\s+/)[1] }.each do |id| id.strip puts "Cancelling job: #{id}" #`sudo cancel #{id}` execute.exec!("sudo cancel #{id}") end end end killer = PrintJobs.new killer.scan_for_jobs ``` Usage example: ``` closing_2-254128 root 933888 Thu 03 Dec 2015 03:49:13 PM CST closing_2-254129 root 933888 Thu 03 Dec 2015 03:50:16 PM CST laser42-254144 root 192512 Thu 03 Dec 2015 04:24:02 PM CST laser42-254145 ro