0
votes

So I've heard that it's an incredibly bad idea to host media on the same server as your Django/Apache web framework. So to solve this problem with my iOS app and greatly improve server side performance in the long run would be to upload the images to the Django server and then right after that, transfer the newly uploaded image to a separate server dedicated to hosting user profile images.

So using Paramiko I can send files directly to the directory of my choosing, but this does not seem to be working in my Django view.

Here's an incredible simple python script using Paramiko that allows you to upload files to a remote server via SMTP:

import base64
import getpass
import os
import socket
import sys
import traceback

import paramiko
#from paramiko.py3compat import input


# setup logging
#paramiko.util.log_to_file('demo_sftp.log')
port = 22
hostname = '198.199.101.115'
password = 'XXXXXXXXX'
username = 'root'
hostkeytype = 'ecdsa-sha2-nistp256'
hostkey = 'XXXXXXXXX'


try:
    host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
except IOError:
    try:
        # try ~/ssh/ too, because windows can't have a folder named ~/.ssh/
        host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
    except IOError:
        print('*** Unable to open host keys file')
        host_keys = {}

if hostname in host_keys:
    hostkeytype = host_keys[hostname].keys()[0]
    hostkey = host_keys[hostname][hostkeytype]
    print('Using host key of type %s' % hostkeytype)


# now, connect and use paramiko Transport to negotiate SSH2 across the connection
t = paramiko.Transport((hostname, port))
t.connect(username=username, password=password, hostkey=hostkey)
sftp = paramiko.SFTPClient.from_transport(t)

    # dirlist on remote host
dirlist = sftp.listdir('.')
print("Dirlist: %s" % dirlist)

    # copy this demo onto the server
target_directory = '3COOL'

sftp.put('test_image.jpg', target_directory+'/test_image.jpg')

t.close()

So this script works perfectly fine when I run the script on my remote server which successfully transfers the jpeg image to another remote server I own. So I'd like to just cut and paste this script into my Django view which will transfer all freshly uploaded images to a different server, here's how this looks:

def profile_picture(request):
    if request.POST:
        form = UserProfileForm(request.POST, request.FILES)
        obj = form.save(commit=False)
        obj.user_id = request.user.id
        obj.profile_picture = obj.profile_picture

        check = UserProfile.objects.filter(user_id=request.user.id)
        if check:
            oldup = UserProfile.objects.get(user_id=request.user.id)
            oldup.delete()
        obj.save()
        formNew = UserProfileForm()
        args = {}
        args.update(csrf(request))
        args['uid'] = request.user.id
        args['form'] = formNew

        # CONVERT THE IMAGE TO A SMALLER SIZE
        basewidth = 256
        img = Image.open('var/www/bitcraft/static/'+str(obj.profile_picture))
        wpercent = (basewidth/float(img.size[0]))
        hsize = int((float(img.size[1])*float(wpercent)))
        img = img.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
        img.save('var/www/bitcraft/static/'+str(obj.profile_picture))

        import getpass
        import os
        import socket
        import sys
        import traceback
        import paramiko
        from paramiko.py3compat import input

        # TRANSFER THIS IMAGE TO MEDIA HOSTING SERVER  
        port = 22
        hostname = '198.199.101.115'
        password = 'pcorysatqwrw'
        username = 'root'
        hostkeytype = 'ecdsa-sha2-nistp256'
        hostkey = 'pcorysatqwrw'
        try:
            host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
        except IOError:
            try:
                host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
            except IOError:
                print('*** Unable to open host keys file')
                host_keys = {}
        if hostname in host_keys:
            hostkeytype = host_keys[hostname].keys()[0]
            hostkey = host_keys[hostname][hostkeytype]
            print('Using host key of type %s' % hostkeytype)
        t = paramiko.Transport((hostname, port))
        t.connect(username=username, password=password, hostkey=hostkey)
        sftp = paramiko.SFTPClient.from_transport(t)
        dirlist = sftp.listdir('.')
        print("Dirlist: %s" % dirlist)
        target_directory = '3COOL'
        sftp.put('var/www/bitcraft/static/'+str(obj.profile_picture), target_directory+str(obj.profile_picture))
        t.close()    
        return render_to_response('profile.html', args, RequestContext(request))

    else:
        formNew = UserProfileForm()
        args = {}
        args.update(csrf(request))
        args['uid'] = request.user.id
        args['form'] = formNew
        return render_to_response('profile.html', args, RequestContext(request))

Ultimately though, adding the simple Python script has not worked due to a strange error:

AttributeError at /upload_profile/ 'str' object has no attribute 'get_name'

Exception Location: /usr/local/lib/python2.7/dist-packages/paramiko-1.14.0-py2.7.egg/paramiko/transport.py in connect, line 873

/srv/www/django/chatfeed/views.py in profile_picture t.connect(username=username, password=password, hostkey=hostkey)

I don't understand what's causing this... is this related to directory permission denied??

2
As a side note, If the reason you're avoiding putting the images directly on the server is security, having passwords embedded in your script in plain text is probably an even worse idea. Use authorized_keys instead. - abarnert

2 Answers

3
votes

The problem is that you're passing a string for hostkey. As the docs show, that's supposed to be a PKey—that is, an object that wraps a private key.

And if you click on PKey, you'll see that a PKey has a get_name method. A string obviously doesn't. Hence the error.


You have some code that's supposed to use Paramiko to load a hostkey out of ~/.ssh/known_hosts at the top of your script. But if that hostname in host_keys is false, it won't do anything, and you'll end up with the default values you stuck at the top of the script:

hostkeytype = 'ecdsa-sha2-nistp256'
hostkey = 'XXXXXXXXX'

I don't know what you have in place of that 'XXXXXXXXX' in your real code, but presumably it's a string, and therefore not a valid hostkey.


I don't understand what's causing this... is this related to directory permission denied??

You'd have to tell us what you're talking about. Exactly what error or warning or whatever are you getting, and where? If the server is running as a user who doesn't have access to its own ~/.ssh, so you're seeing a "directory permission denied" warning of some kind and your host keys aren't getting loaded, then yes, this problem is indirectly related to that one—as in, if the host actually was in known_keys, and you solved the permissions problem, that would mask the error in your code, so you wouldn't notice it. But there are plenty of other things you could mean where the answer would be no, that has nothing to do with anything.

2
votes
key = paramiko.RSAKey.from_private_key_file(filename='openssh key f',password='passphrase')  

The keys file does not support .ppk format.